Вопросы по библиотеке ServoSmooth

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
Приветствую. Это мое первое сообщение на этом форуме. В первую очередь хочу выразить благодарность Алексу за его просветительскую работу! Я совсем начинающий ардуинщик и очень многое почерпнул из из его публикаций. Еще раз огромное спасибо!
Для моего проекта сейчас требуется обеспечить наиболее плавное (с ускорением и замедлением) вращение серв. Несколько дней курил сеть и не обнаружил ни одного решения кроме библиотеки от AlexGyver. В проекте используются сервы SG90, MG996R, DS3230mg, RDS5160
Протестировав, выявил некоторые непонятки
  • со всеми испытанными сервами при движении от меньшего угла к большему не доворачивает 1градус, от большего угла к меньшему доворачивает полностью. Почему?
  • c SG90 работает удовлетворительно, даже хорошо не считая недоворот 1градус в большую сторону.
  • с MG996 и DS3230 при движении от большего угла к меньшему эффект торможениея есть, эффект ускорения не заметен. В чем причина?
  • есть ли возможность изменения длин (углов) разгона и торможения в идеале раздельного?
Свой тестовый код привожу ниже. Очень надеюсь на помощь.
/*
*/
// c SG90 работает удовлетворительно, даже хорошо не считая недоворот 1градус.
// с MG996 и DS3230 при движении от большего угла к меньшему эффект торможениея есть, эффект ускорения не заметен.
// при движении от меньшего угла к большему ускорение еле заметно, замедление отсутствувет.
// со всеми испытанными сервами при движении от меньшего угла к большему не доворачивает 1градус.
// от большего угла к меньшему доворачивает полностью.
// изменение диапазона широты импульсов проблему не решает, или не те диапазоны, или баг библиотеки.
// не хватает настройки длинны разгона и торможения.

#include "ServoSmooth.h"
ServoSmooth servo_name;
int new_angle;
int carrent_angle;
int v;
float g;

void setup() {
Serial.begin(9600);
servo_name.attach(7, 544, 2400, 0);
// 7-номер пина, 600 и 2400 - длины импульсов, 0-начальный угол.
// по умолчанию 544-2400 мкс
// DS3230 500-2500 мкс
// длины импульсов при которых серво поворачивается максимально в одну и другую сторону, зависят от самой серво
// и обычно указываются производителем
servo_name.setAutoDetach(false); // отключить автоотключение (detach) при достижении целевого угла (по умолчанию включено)
delay(1000); // для наглядности
}

void turn_smooth(int new_angle, int v, float g)
// желаемая позиция задаётся методом setTarget (импульс) или setTargetDeg (угол), далее
// при вызове tick() производится автоматическое движение сервы
// с заданным ускорением и ограничением скорости
{
servo_name.setSpeed(v); // ограничить скорость (условные единицы, 1 – 200)
servo_name.setAccel(g); // установить разгон и торможение (0.01 – 1)
carrent_angle = servo_name.getCurrentDeg(); // текущий угол

//почему-то не доходит 1 градус до new_angle, если carrent_angle < new_angle.
//для решения проблемы отнимаем 1,
if (carrent_angle < new_angle)
{
while (carrent_angle != new_angle-1)
{
carrent_angle = servo_name.getCurrentDeg(); // текущий угол
Serial.println(carrent_angle); // для наглядности
servo_name.tick(); // здесь происходит движение серво по встроенному таймеру!
servo_name.setTargetDeg(new_angle); // и отправляем на серво
}
}
if (carrent_angle > new_angle)
{
while (carrent_angle != new_angle)
{
carrent_angle = servo_name.getCurrentDeg(); // текущий угол
Serial.println(carrent_angle); // для наглядности
servo_name.tick(); // здесь происходит движение серво по встроенному таймеру!
servo_name.setTargetDeg(new_angle); // и отправляем на серво
}
}
}

void loop()
{
new_angle = 180; // задаваемый угол поворота (0-180)
v = 150; // макс скорость (1 – 200)
g = 0.1; // ускорение/торможение (0.01 – 1)
turn_smooth(new_angle, v, g); // дергаем функцию поворота сервы
delay (1000);

new_angle = 0; // задаваемый угол поворота (0-180)
v = 30; // макс скорость (1 – 200)
g = 0.1; // ускорение/торможение (0.01 – 1)
turn_smooth(new_angle, v, g); // дергаем функцию поворота сервы
delay (1000);
}
 
Изменено:

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
актуально.
сейчас все сервы MG996 буду менять на DS3230
 
Изменено:

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
//почему-то не доходит 1 градус до new_angle, если carrent_angle < new_angle.
//для решения проблемы отнимаем 1,
if (carrent_angle < new_angle)
{
while (carrent_angle != new_angle-1)
{
странное "решение проблемы". Если раньше не доворачивало на 1 градус. то с этим исправлением будет недоворачивать на два.
Вы внимательнее смотрите, что у вас в коде написано. Вы выводите положение сервы на печать только пока оно меньше требуемого, а когда оно приходит в нужную точку - ваш код об этом ничего не сообщает. Поэтому вам и кажется, что "недоворачивает".

Или вы этот код писали не сами и ничего в нем не понимаете?
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
Писал сам, возможно не все понимаю, поэтому и задаю здесь вопрос. Но так работает, а без отнимания единицы останавливается (постоянно шлет одно и тоже значение-"блокируется") не доходя 1 градус до заданной величины и только в сторону увеличения угла. При отнимании 1 да, поворачивает на величину на 1 меньше, но не "блокируется".
По существу будет у кого что полезное?
 
Изменено:

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
По существу будет у кого что полезное?
по существу - вставьте вывод текущего угла в Сериал ПОСЛЕ выполнения своей процедуры turn_smooth(), а не внутри ее. И выкиньте (пока временно) свое "решение проблемы" с вычитанием единицы. Ставлю на то, что все будет доворачивать полностью и без этого "костыля"
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
ок. смогу попробовать только завтра. обязательно сообщу результат. однако, если принт вынести их цикла (или вообще убрать), мы не увидим процесс изменения угла.
а как с остальными вопросами?
а вы эту библиотеку тестили и было все ок?
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
если принт вынести их цикла (или вообще убрать), мы не увидим процесс изменения угла.
не надо выносить из цикла или убирать - просто добавьте еще один принт после функции.
У вас сейчас код написан так. что вы не получите сообщение о том, что угол достиг заданного значения

Библиотеку я не тестил - я лишь разбираю логические ошибки в вашем собственном коде
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
тогда извини не понимаю.. "не надо выносить из цикла или убирать " противоречит с " вставьте вывод текущего угла в Сериал ПОСЛЕ выполнения своей процедуры turn_smooth(), а не внутри ее. "
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
противоречит :) - поймал
Смотри - если ты хочешь видеть, как меняется угол - оставь печать внутри функции.
Но главное, на что я обращаю твое внимание - эта печать не покажет тебе. что угол достиг заданного значения. она всегда будет останавливатся либо за градус до нужного значения. либо за два. И вовсе не потому. что серва не доворачивает - а потому что ты печатаешь угол только тогда, когда он НЕ РАВЕН нужному.
Чтобы увидеть, дошла ли серва до нужного угла или нет - надо вставить вывод ПОСЛЕ функции.
 
  • Лойс +1
Реакции: MrBob

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
ок. но весь этот костыль с принтом угла и отниманием 1 я сделал только потому, что серва "блокировалась". т.е к примеру задаешь вначале 180 (или любой другой), затем любой меньший. она должна с заданным ускорением и торможением туда-сюда качаться, а она поворачивается в сторону большего и останавливается. когда посмотрел, что происходит внутри то понял, что код шлет постоянно один и тот-же угол на 1 меньший заданного.
потести, сам увидишь

да, я ни кого не "ловлю". просто хочу разобраться
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
а что не взять какую-нить стандартную библиотеку. типа Servo.h ? - проверенную миллионами юзеров?
библиотеки Алекса. вообще говоря. вещь в себе... хотя на этом форуме это лучше не говорить :)
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
может есть другие методы, может другие библиотеки для обеспечения именно плавного вращения, что мне пока не попадались? ведь казалось задача-то такая не только вчера у меня появилась...

Servo.h конечно с этого и начал, но кроме задания постоянной скорости методом задержки я не нашел

для моего проекта градус туда\сюда не так уж и важно конечно.. мне нужно плавное движение, а на протестированных мной сервах я это не получил
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
а не пробовали задавать угол меньше 180? - я смотрю в библиотеке 180 - это максимум. может для пробы 170 поставить?

и еще, процедуру изменения угла я бы так переписал
C++:
// отправляем на серво до цикла и ОДИН РАЗ
servo_name.setTargetDeg(new_angle);

while (carrent_angle != new_angle-1)
{
servo_name.tick(); // здесь происходит движение серво по встроенному таймеру!
carrent_angle = servo_name.getCurrentDeg(); // текущий угол
Serial.println(carrent_angle); // для наглядности
// servo_name.setTargetDeg(new_angle); // в цикле отправлять не надо

}
ЗЫ и еще , поправте название переменной , текущий это current, а не carrent, смотрите как в библиотеке - getCurrentDeg(); // текущий угол
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
а не пробовали задавать угол меньше 180? - я смотрю в библиотеке 180 - это максимум. может для пробы 170 поставить?
я писал, что это происходит при вращении на любой угол в большую сторону
ЗЫ и еще , поправте название переменной , текущий это current, а не carrent, смотрите как в библиотеке - getCurrentDeg(); // текущий угол
поймал. сорри за безграмотность. 1\1 :)
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
дальше я бы до предела упростил код. оставил бы только один поворот до угла "вверх" и разобрался бы. доворачивает ли библиотека, а если нет - то почему. Не бойтесь лезть внутрь кода библиотеки. там точно такой же код. как пишете вы.
 
  • Лойс +1
Реакции: MrBob

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
// отправляем на серво до цикла и ОДИН РАЗ
servo_name.setTargetDeg(new_angle);

while (carrent_angle != new_angle-1)
{
servo_name.tick(); // здесь происходит движение серво по встроенному таймеру!
carrent_angle = servo_name.getCurrentDeg(); // текущий угол
Serial.println(carrent_angle); // для наглядности
// servo_name.setTargetDeg(new_angle); // в цикле отправлять не надо

}
что-то мне подсказывает, что так вообще работать не будет

оставил бы только один поворот до угла "вверх" и разобрался бы
с этого и начинал разбираться
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
Не бойтесь лезть внутрь кода библиотеки
смотрел, мало чего понял... я в си совсем слаб и уже ненавижу его. начал делать "тело" для своего бота, вот и пришлось... возможно потом все перепишу под малину. в питоне получше разбираюсь, но это наверное не по теме ветки

что именно привело вас к такому мнению?
ну там во всех примерах поворот работает непосредственно в void loop() c использованием tick() , мне так не надо. поэтому я сделал отдельную функцию с циклом while c tick()
 
Изменено:
  • Лойс +1
Реакции: MrBob

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
я сделал отдельную функцию с циклом while c tick()
Отдельная функция или в луп - собой разницы нет.
Я про другое. Зачем значение TargetAngle надо задавать каждый проход while?.
Задали один раз - и потом в цикле ждите. пока серва не повернет
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
вообще протести сам, тогда будет предметный разговор

Задали один раз - и потом в цикле ждите. пока серва не повернет
обязательно завтра попробую. думаю если и заработает, проблем не решит
 

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
думаю если и заработает, проблем не решит
может и нет.
На самом деле, сначала вам надо в каждой строчке своей программы точно понимать. что вы делаете и почему.
А когда вы убедитесь. что все делаете правильно - а код все равно не работает - придется разбираться с библиотекой

Другого пути отлаживания программ я не знаю

вообще протести сам, тогда будет предметный разговор
если ты будешь так стаить вопрос - ни на одном форуме помощи не получишь.
Тебе могут указать на ошибки или подкинуть идеи, а уж проверять это все - твоя задача.
 

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
Протестил предложение b707 по изменению кода. Действительно крутится, но без костыля останавливается за градус до конечного угла.
Если я правильно понял b707, код должен был выглядеть так:
C++:
#include "ServoSmooth.h"
ServoSmooth servo_name;
int new_angle;
int current_angle;
int v;
float g;

void setup() {
  Serial.begin(9600);
  servo_name.attach(7, 544, 2400, 180);
  servo_name.setAutoDetach(false);  // отключить автоотключение (detach) при достижении целевого угла (по умолчанию включено)
  delay(1000);                      // для наглядности
}

void turn_smooth(int new_angle, int v, float g)
{
  servo_name.setSpeed(v);   // ограничить скорость (условные единицы, 1 – 200)
  servo_name.setAccel(g);   // установить разгон и торможение (0.01 – 1)
  servo_name.setTargetDeg(new_angle);
  while (current_angle != new_angle)
     {
      current_angle = servo_name.getCurrentDeg(); // текущий угол
      servo_name.tick();                          // здесь происходит движение серво по встроенному таймеру!
      Serial.println(current_angle);              // для наглядности
     }
}

void loop()
{
  new_angle = 0; // задаваемый угол поворота (0-180)
  v = 60;         // макс скорость (1 – 200)
  g = 0.05;         // ускорение/торможение (0.01 – 1)
  turn_smooth(new_angle, v, g);  // дергаем функцию поворота сервы
  delay (1000);

  new_angle = 90;  // задаваемый угол поворота (0-180)
  v = 60;         // макс скорость (1 – 200)
  g = 0.05;        // ускорение/торможение (0.01 – 1)
  turn_smooth(new_angle, v, g);  // дергаем функцию поворота сервы
  delay (1000);
}
 

Вложения

Изменено:

b707

★✩✩✩✩✩✩
4 Июн 2020
54
18
в коде та же ошибка. что и раньше - вы выводите на печать угол, только если он не равен заданному.
В итоге вы не сможете увидеть, достигает ли угол нужного значения или нет.
попробуйте вот так измениить loop()
C++:
void loop()
{
  new_angle = 0;  // задаваемый угол поворота (0-180)
  v = 60;         // макс скорость (1 – 200)
  g = 0.05;         // ускорение/торможение (0.01 – 1)new_angle = 0; // задаваемый угол поворота (0-180)
  turn_smooth(new_angle, v, g);  // дергаем функцию поворота сервы
  current_angle = servo_name.getCurrentDeg(); // текущий угол
   Serial.print("Final position = ");
   Serial.println(current_angle);
   delay (1000);

  new_angle = 90;  // задаваемый угол поворота (0-180)
  turn_smooth(new_angle, v, g);  // дергаем функцию поворота сервы
  current_angle = servo_name.getCurrentDeg(); // текущий угол
   Serial.print("Final position = ");
   Serial.println(current_angle);
  delay (1000);
}
хотя я думаю. что с проблемой "недокрута" это не поможет.
Похоже, что в библиотеке ошибка, может быть в погоне за плавностью она не докручивает серву до конца
 
Изменено:

Ivin

✩✩✩✩✩✩✩
19 Июн 2020
13
1
Это не ошибка, это вывод текущего угла в динамике. В вашем случае это вывод текущего угла после выполнения функции поворота. И да, это проблему "недоворота" не решает.
Без вычитания 1 серво останавливается, функция turn_smooth не заканчивает свою работу посылая бесконечно значение угла на 1 меньше заданного, дело до print в loop просто не доходит и естественно ни чего не печатает.
Пока заканчиваю мучить эту библиотеку, обнаружил еще пару
После тестов могу сюда сообщить результаты.
Ниже скрин с принтом в лупе и с вычитанием 1:
 

Вложения

danik

✩✩✩✩✩✩✩
12 Фев 2020
19
0
Привет!

Простите за глупый, вопрос, но...

В приведенном выше скрипте все работает, но почему не работает в данной, облегченной форме? Серва устанавливается на исходную позицию и дальше не двигается совсем.. Заранее огромнейшее спасибо!

C:
#include <ServoSmooth.h>


ServoSmooth servo;

uint32_t tmr;
boolean flag;

void setup() {
  Serial.begin(9600);
  servo.attach(9,0);        // подключить
  servo.smoothStart();
  servo.setSpeed(140);    // ограничить скорость
  servo.setAccel(0.5);         // установить ускорение (разгон и торможение)

}

void loop() {
servo.tick();

servo.setTarget(10);
delay(3000);
servo.setTarget(180);
delay(3000);
  }