Две сервы

maks
Offline
Зарегистрирован: 10.03.2013

Если скажу что новичек,то это мягко сказанно.Из опыта лишь робот по линии.

Три дня пытался написать что путное для управления двумя сервами,но воз и ныне там.

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

Первоначально обои сервы установлены в нейтраль тобишь 90 градусов.

Меньше 90 градусов наклон влево,больше 90 наклон вправо

Аналогично и с передвижениями вперед-назад

#include <Servo.h> 

Servo myservo1;
Servo myservo2; 
void setup() 
{ 
  myservo1.attach(9);  // наклоны влево впрво
  myservo2.attach(11); // движения вперед назад

} 

void loop() 
{

  myservo2.write(95);  // движение правой ноги
  delay(50);
  myservo2.write(100); 
  delay(50);
  myservo2.write(105);  
  delay(50);
  myservo2.write(110);  
  delay(50);
  myservo2.write(115);  
  delay(50);
  myservo2.write(120);  
  delay(50);
  myservo2.write(115);
  delay(50);
  myservo2.write(110); 
  delay(50);
  myservo2.write(100);  
  delay(50);
  myservo2.write(95);  
  delay(50);
  myservo2.write(90);  
  delay(2000);  
  
   myservo2.write(85);  // движение левой ноги
  delay(50);
  myservo2.write(80); 
  delay(50);
  myservo2.write(75);  
  delay(50);
  myservo2.write(70);  
  delay(50);
  myservo2.write(65);  
  delay(50);
  myservo2.write(60);  
  delay(50);
  myservo2.write(65);
  delay(50);
  myservo2.write(70); 
  delay(50);
  myservo2.write(75);  
  delay(50);
  myservo2.write(80);  
  delay(50);
  myservo2.write(85);  
  delay(50);
  myservo2.write(90);  
  delay(50);
  
  
myservo1.write(95);  // наклон влево
  delay(50);
  myservo1.write(100); 
  delay(50);
  myservo1.write(105);  
  delay(50);
  myservo1.write(110);  
  delay(50);
  myservo1.write(115);  
  delay(50);
  myservo1.write(120);  
  delay(50);
  myservo1.write(125);  
  delay(50);
  myservo1.write(130);  
  delay(50);
  myservo1.write(135);  
  delay(1200);




  myservo1.write(90);  // наклон вправо
  delay(50);
  myservo1.write(85); 
  delay(50);
  myservo1.write(80);  
  delay(50);
  myservo1.write(75);  
  delay(50);
  myservo1.write(70);  
  delay(50);
  myservo1.write(65);  
  delay(50);
  myservo1.write(60);  
  delay(50);
  myservo1.write(55);  
  delay(50);
  myservo1.write(50);  
  delay(1200);

}

 

maksim
Offline
Зарегистрирован: 12.02.2012
#include <Servo.h> 

Servo myservo1;
Servo myservo2;

void setup() 
{ 
  myservo1.attach(9);  // наклоны влево впрво
  myservo2.attach(11); // движения вперед назад
} 

void loop() 
{
  for(byte i = 95; i <= 120; i += 5)
  {
    myservo2.write(i);  // движение правой ноги
    myservo1.write(i);  // наклон влево
    delay(50);
  }
  for(byte i = 115; i >= 90; i -= 5)
  {
    myservo2.write(i);  // движение правой ноги
    myservo1.write(i);  // наклон влево
    delay(50);
  }
  delay(1000);

  for(byte i = 85; i >= 60; i -= 5)
  {
    myservo2.write(i);  // движение левой ноги
    myservo1.write(i);  // наклон вправо
    delay(50);
  }
  for(byte i = 65; i <= 90; i += 5)
  {
    myservo2.write(i);  // движение левой ноги
    myservo1.write(i);  // наклон вправо
    delay(50);
  }
  delay(1000);
}

 

maks
Offline
Зарегистрирован: 10.03.2013

Спасибо, на счет медленого движения стало попроще.Но не совсем выполняется условие перемещения.Обои серы ведь начинают двигаться одновременно,а необходимо вначале наклон и после этого движение вперед.Пытался с паузами,и менял 17 и 18 строку  ставил над 16,чтобы наклон начинался раньше движения.

timur2008
Offline
Зарегистрирован: 06.03.2013

Попробуй условия выставить что пока один тип движения не отработает другой тип движения не запуститься.

maks
Offline
Зарегистрирован: 10.03.2013

Знал бы прикуп,то сделал бы обязательно.Первоначально вся механика тестилась на радиоуправлении,проблем не было,можно было выставить любые и миксы и расходы.Левым стиком передатчика управлялись наклоны,правым передвижения.Теперь чешу репу.

leshak
Offline
Зарегистрирован: 29.09.2011

Проблема в том, что предполагаете наличие телепатов. Прочитайте свое стартовое сообщение и попробуйте найти в нем описание чем же вас не устраивает написанный вами скетч. В чем проблема состоит-то? Догадайтесь?  Вот Максим и попытался догадатся, предположил что проблема именно не в одновременности движении серв.  И решил именно эту проблему. А оказывается вам как раз и не нужно одновременно, значит он зря потратил время :(

Если же вам нужно "по очереди", то ваш изначальный скетч - как раз то что нужно. Просто вы не дали первой серве достаточно времени для поворота. Просто увеличте вермя delay-ев, что-бы она гарантированно успевала встать в нужную позицию до того как пойдут команды для второй сервы (да и свою черду команд успевала отработать).

maks
Offline
Зарегистрирован: 10.03.2013

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

Проблема как раз в том, что не удавалось расставить грамотно паузы.

Максиму ОГРОМНОЕ спасибо понял что можно упростить плавное движение серв,а на счет ЕГО зря потраченного времени-пусть напишет об этом сам.

leshak
Offline
Зарегистрирован: 29.09.2011

>удерживая в таком положении

Для этого не нужно ничего специально делать. Суть сервы в том и состоит что-бы удерживать последний заданный угол. Пока у нее хватает физических сил и на нее идет управляющий PWM (то есть пока вы не сдеалете detach)

>Проблема как раз в том, что не удавалось расставить грамотно паузы.

Ну вот это и нужно было в старт написать.  А время задержки  их нужно либо методом "научного тыка" (и никто вам их не скажет, так как это зависит именно от скорости ваших серв), либо "вычислять". Делаете тестовый скетч. В нем поворачиваете серву на 180-градусов. И засекаете сколько времени это занимает. Опят-таки, либо "на глаз", либо можно два проводочка прикрепить, что-бы в положении 180 она их замыкала и в сериал выводить когда это произошло  (ну либо секундомер в руки).

Делите намерянное время на 180 и получаете сколько занимает поворот на один градус.  Далее когда вам нужно повернуть серву берете ее текущие положение отнимаете его от требуемого нового и разницу умножаете на время поворота на один градус. На полученное время и делаете delay(). Тогда она будет и "успевать" и "не будет лишнего дуплить". Можно еще к этому высчитанному времени, накинуть 10-20 миллисекунд для верности (погрешности измерений и вычислений). Подбираем эту цифру "что-бы на глаз рывков видно небыло".

>-пусть напишет об этом сам

Не нужно топорщить перья. Даже если Максим ничего не имеет против подобного время-провождения - это не отменяет способности других дать оценку. Воспринимайте это как совет/сторонее мнение "как это выглядело со стороны". Конечно вы имеете полное право наплевать на это мнение, но неповторение подобных ошибок (осутсвие четкого описание проблемы) - поможет ВАМ в будущем быстрее находить решение проблем с помощью форума.

 

 

maksim
Offline
Зарегистрирован: 12.02.2012
#include <Servo.h> 

Servo myservo1;
Servo myservo2;

void setup() 
{ 
  myservo1.attach(9);  // наклоны влево впрво
  myservo2.attach(11); // движения вперед назад
  myservo1.write(90);
  myservo2.write(90);
} 

void loop() 
{
  Tuda(myservo1, 1);  
  Tuda(myservo2, 1);  
  Obratno(myservo1, 1);
  Obratno(myservo2, 1);
  Tuda(myservo1, 0);  
  Tuda(myservo2, 0);  
  Obratno(myservo1, 0);
  Obratno(myservo2, 0);
}

void Tuda(Servo myservo, bool dir)
{
  if(dir)
  {
    for(byte i = 95; i <= 120; i += 5)
    {
      myservo.write(i); 
      delay(50);
    }
  }
  else
  {
    for(byte i = 85; i >= 60; i -= 5)
    {
      myservo.write(i); 
      delay(50);
    }
  }
  delay(200);
}

void Obratno(Servo myservo, bool dir)
{
  if(dir)
  {
    for(byte i = 115; i >= 90; i -= 5)
    {
      myservo.write(i);  
      delay(50);
    }
  }
  else
  {
    for(byte i = 65; i <= 90; i += 5)
    {
      myservo.write(i);  
      delay(50);
    }
  }
  delay(200);
}

 

maks
Offline
Зарегистрирован: 10.03.2013

Принцип работы сервы прекрасно знаю,не понятно можно ли перед командой myservo.write ставить delay

 

>Не нужно топорщить перья

Даже и в мыслях не было,я гладкошерстный

maks
Offline
Зарегистрирован: 10.03.2013

Максим, ОГРОМНОЕ СПАСИБО,попытаюсь уразуметь весь код до конца.Но если тяму не хватит то необессутьте за глупые вопросы.

leshak
Offline
Зарегистрирован: 29.09.2011

maks пишет:

Принцип работы сервы прекрасно знаю,не понятно можно ли перед командой myservo.write ставить delay

Ну а почему нет? (тем более что так или иначе вы все равно это делаете). delay - это просто остановить скетч и ничего не делать. При этом на выходы продолжают поступать те pwm-мы которые который вы дали последней командой myserwo.write. delay() перед новой write означает только одно - серве не поступет НОВАЯ команда пока не пройдет время delay(). И в это время она будет держать "старую позицию".

А вообще - использовать delay() (а также pulseIn и т.п.) в более-менее сложных скетчах - практически не возможно. В данном случае у вас он подходит (и оправдан своей простотой), так как вам нужно по очереди... но предположим что вы захотите еще реагировать на какие-то сонары, или нажатие кнопок пока идет движение сервы... и delay будет вам портить всю малину. Так как в момент его исполнение датчики не опрашиваются, реакции на кнопки - нет (если не использовать прерывания, а их мало).

И тут вам нужно будет пойти посмотреть на пример "мигаем диодом без delay()", а также кучу подобных веток как работать со временем без delay()

Да и в более менее правдоподобном роботе - вероятность одновременного и согласованного движения серв рано или поздно потребуется (так что в этом смысле Максим не зря тратил время). Можете еще попробовать поиском поискать. Была пара месяцев назад тема где решалась проблема именно синхронного и плавного вращения двух серв одновременно.

>Не нужно топорщить перья

maks пишет:

Даже и в мыслях не было,я гладкошерстный

Ну и у меня, сегодня, гавкатся настроения нет ;) Тем более что до "нормальной темы" вы не дотянули совсем чуть-чуть ;)  Некоторые и тему назовут уникально "помогите новичку" и скетч не покажут и проблему опишут "а... караул...ничего не работает". Первые два пункта вы все-таки нормально прошли ;) Да еще и код вставили по человечески ;)

maks
Offline
Зарегистрирован: 10.03.2013

Ходит прекрастно,поиграюсь с расходами серв.Кому интерестно пишите, выложу фото или видео.

maksim
Offline
Зарегистрирован: 12.02.2012

Ну так видео выложите.

maks
Offline
Зарегистрирован: 10.03.2013

И тут вам нужно будет пойти посмотреть на пример "мигаем диодом без delay()", а также кучу подобных веток как работать со временем без delay()

Спасибо,веское замечание-учту.

Как новичек думал если поставлю delay() перед или после myserwo.write то эта пауза будет влиять только на данную серву а не на весь скетч

Максим видео ближе к вечеру

leshak
Offline
Зарегистрирован: 29.09.2011

maks пишет:

Как новичек думал если поставлю delay() перед или после myserwo.write то эта пауза будет влиять только на данную серву а не на весь скетч

К радости (или печали) в ардуино нет аспектно-ориентированного и декларативного программирования (без танцев с бубном). Только императивное. То есть каждый скетч - это просто пошаговая инструкция. И, в отличие от больших PC и старших версий микроконтроллеров - тут нет понятия потоков. Только один поток. То есть скетч выполняется пошагово. И только один шаг за раз. Никаких одновременностей - не бывает.

delay - фунция общего назначения. Не специально "серво-оринтированная", следовательно про сервы - она ничего не знает. Ее задача "остановить скетч на какое-то время". С сервами он или нет. Пример - базовый Мигаем светодиодом | Аппаратная платформа Arduino

Все функции условно можно разделить на "блокирующие" и "не блокирующие".

Блокирующие это которые останавливают (блокируют) скетч на время своего исполнения (и это время - ощутимо). Не блокирующие - это которые стараются выполнится как можно быстрее и передать управление дальше (таких большинство).

Примеры блокирующих - delay(), pulseIn(), стандартная библиотека stepper и т.п.

Не блокирующие - математические, servo.write, analogWrite, библиотека acelStepper и т.п. (вообщем все остальные)

Servo.write занимается тем, что побыстрому выставляет на пин какой-то PWM и передает управление дальше. Скетч пошел выполнять следующие команды. А сама серва крутится в этот момент, пытается занять положение указаное PWM-мом. Так как она не может сделать это моментально - это занимает какое-то время.  

Тут у нас возникает как-бы одновременность. Скетч уже занимаетеся чем-то своим, а серва в этот момент крутитися и PWM генерируется. Но эта одновременность существует только за счет того что задачи PWM и вращение выплняются отдельными аппаратными блоками, а не основным ядром контроллера. Тот только "дал им указание".

Если мы в момент вращения сервы  сделаем новые servo.write, то серва пойдет уже к новому положению, забудет про "старую команду", даже если еще не успела выполнить ее до конца. "Отставить, новый курс..."

Вернемся к вашей задаче. Итак стандартная servo.write - не блокирующая (к счастью, часто именно это и нужно), но вам потребовалась - блокирующая. Которая гарантирует что на серву не поступит новая команда (или команда для другой сервы) отменяющая предыдущую.  Которая заставит скетч стоять на месте пока серва не станет в указанное положение .  Для этого ее приходится комбинировать Servo.write с блокирующим delay(), выдавать всегда пару write/delay. Первое - команда, второе - ждать минимально необходимое время что-бы выполнить комаду прежде чем идти дальше.

Чем точнее мы будем давать вот это "время ждать" - тем лучше. Если следаем его слишком маленьким - серва не будет успевать докручиватся до нужно положения до того как скетч пойдет дальше, если слишком большим - мы будет видеть это как "остановки ненужные". Серва выкрутилась на какой-то угол и стоит ждет непонятно чего. Поэтому и желательно рассчитывать это время исходя из того на какой угол нам нужно повернуть серву (разницу между текущим и желательным положением), а не "забивать задержки прямо в код".

Другим подходом может быть - организация обратной связи от сервы. Ставить какие-то концевики, энкодер и т.п. - что-то что позволит узнать текущие РЕАЛЬНОЕ положение сервы. То есть работать по принципу - дали команду на серву, а потом крутимся в каком-то цикле, ждем пока наши сенсоры не доложат что серва заняла указанное положение и можно идти дальше. Такое решение будет намного более точным и менее подвержено влиянию температуры, качеству акума (если он просел - серва будет крутится медленее), но... сильно сложней как програмно, так и аппаратно, так что редко используется, особенно в домашних поделках. Бывают еще сервы которые уже имеют встроенный энкодер и могут сами доложить о своем настоящем положении, но... цена. 

Кстати, раз вспомнил о шаговиках, то они тоже могут быть альтернативой в вашей задаче. Родная библиотека как раз "блокирующая". Пока он не выполнит указанное количество шагов - скетч дальше не пойдет. Но встанет вопрос о том "в какой позиции" он стоит при включении контроллера. Какую-то обратную-связь концевик, хотя-бы для нулевого положения прийдется городить. Зато крутится можем 360 град. И как правило шаговики менее мощны чем сервы (хотя за деньги конечно можно и силачей найти).

 

maks
Offline
Зарегистрирован: 10.03.2013

Видео с телефона,качество не ахти      https://www.youtube.com/watch?v=AN45zEM9Z9Q

leshak
Offline
Зарегистрирован: 29.09.2011

Нормальное качество. Чай не студийная съемка. И робот "симпатяжка". По доброму выглядит :)

Вы молодец. Видно что руки из нужного места растут (эх, а у меня логику - могу, а механику - обе руки левые :)

А вот этот его "ход по кругу", из-за движения ногами когда задняя серва в среднем положении, это "так задуманно" или "так вышло"?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Хорош цыплёнок ;)

И "музыка" звука достаточно забавная.
Зачёт!

Теперь всё это рихтовать, допиливать, донастраивать, эхх.. Удачи!

 

maks
Offline
Зарегистрирован: 10.03.2013

Конечно так вышло,надо коректировать углы и время поворота серв.

Вот видео на РУ,конечно поболее степеней свободы,плюс возможность танца что то типа степа.И понять динамику работы было попроще.

http://www.youtube.com/watch?v=AR_nRaI6OdU&feature=youtu.be

Собрать его особых проблем не было,благо стеклотекстолит двухсторонний,легко обрабатывается и быстро паяется.Да и возможность переделки на "ходу" тоже играет большую роль,что-то подрезать,где-то изменить угол крепления.Сами ноги от первоначального прототипа были укорочены на 4-5 см.Увеличена полосками площать стопы

leshak
Offline
Зарегистрирован: 29.09.2011

Супер!!!!! Офигенно!!!  Наверное первый робот которого мне захотелось повторить (хотя - руки не дойдут, но ведь - захотелось).

Если посчтитать дробь "возможности поделить на сложность" - думаю ваша платформа может дать фору многим заводским решениям за сотни (тысячи) баксов. Делать "просто" - это сложно, не каждому дано :)  У вас - получилось.

alpino
Offline
Зарегистрирован: 30.10.2014

Добрый день!

Подскажите плиз, что означает эта часть кода

{

16   Tuda(myservo1, 1); 
17   Tuda(myservo2, 1); 
18   Obratno(myservo1, 1);
19   Obratno(myservo2, 1);
20   Tuda(myservo1, 0); 
21   Tuda(myservo2, 0); 
22   Obratno(myservo1, 0);
23   Obratno(myservo2, 0);
24 }

 

Dorrin
Offline
Зарегистрирован: 06.12.2014

Все проще, тебе нужно создать 2 мпеременные и прописывать их в сервы+ написать код для изменения этих переменных. Вот тут есть целый диплом с похожей темой