Управление двумя сервомашинками

sedeca
Offline
Зарегистрирован: 16.07.2012

Сразу скажу, что  не программист. Необходимо управлять 2мя сервомашинками. Алгоритм простой. Первая серва поворачивается на угол 15 град останавливается и ждет пока вторая прошагает от 0 до 150 град и вернется назад, затем поворачивается еще на 15 и вновь ждет танго от второй. Так первая серва должна пробраться до 150 градусов. Написал топорный код. Проблема в том, что все вроде и работает но при выполнении второго цикла сервы начинают бесится, постоянно загорается L светодиод (как я понял ардуино перезагружается). Питание не просаживается. Проверял на нескольких платах. Исход один - слезы, печаль и уныние.

#include <Servo.h> 
 
Servo myservov;  // создаём объект для контроля сервы (вертикаль)
Servo myservog;  // создаём объект для контроля сервы (горизонталь)
 
int posv = 0;    // переменная для хранения позиции сервы (вертикаль)
int posg = 0;    // переменная для хранения позиции сервы (горизонталь)
int PhotoPin=9;  // переменная для фотопина

void setup() 
{ 
  myservog.attach(4);  // серва горизонтали подключена у 4-му пину
  myservov.attach(7);  // серва вертикали подключена у 7-му пину
  pinMode(PhotoPin, OUTPUT); // девятый пин на выход (управление фото)
} 
 
 void loop() 
{    
 myservog.write(30);                    // горизонтальную серву повернули на 30 градусов
 delay(1000);                           // ждем 1 с
 
 for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
 //////////////////////////////////////////////////////////////// 
 myservog.write(60);                    // горизонтальную серву повернули до 60 градусов
 delay(1000);                           // ждем 1 с
 
 for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
 //////////////////////////////////////////////////////////////// 
 myservog.write(90);                    // горизонтальную серву повернули до 90 градусов
 delay(1000);                           // ждем 1 с
 
 for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
 //////////////////////////////////////////////////////////////// 
 for(posg = 180; posg>=1; posg-=1)      // вернули горизонтальную серву в 0 градусов
  {                                
    myservog.write(posg);               
    delay(15);                       
  } 
 return; 
 } 

   

 

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

sedeca пишет:
Питание не просаживается. Проверял на нескольких платах.

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

sedeca
Offline
Зарегистрирован: 16.07.2012

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

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

А какая батарея? и как вы сервы подключаете?

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

Если севрвы подключены к +5В дуины, то естественно на батарее вы никакой просадки не увидите. Если батарея не больше 7,5 вольт то можно подключить питание серв напрямую к батарее.

sedeca
Offline
Зарегистрирован: 16.07.2012

 Батарея на 7.4 1500 мАч. Сервы действительно сидят на 5 В ардуины. Напругу смотрю непосредственно на батареи. И она вполне себе ничего. Загвоздка в том, что прошивая сторонний код, написанный программистом сервы крутят вполне приемлемо. Плата не перезагружается. Правда код сложноват для меня. Вот и пытаюсь написать свой понятный и простой. 

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

Скорее всего в том коде реализован плавный старт сервы для уменьшения токов и увеличения ресурса шестерней. Просто подключите питание серв к аккумулятору напрямую.

А сервы наверное что то типа HX12K, HX5010, MG995 или SG5010 ?

sedeca
Offline
Зарегистрирован: 16.07.2012

 У меня SA1135 

http://sferahobby.ru/item/view/id/143

Плавный ход в сторонней программе действительно есть. Появилась проблемка - при старте серва крутится на все 180 сначала в одну затем в другую стороны. И так 2 - 3 захода затем пошел на исполнение код.  Видимо тяжело ей нуль найти.

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

sedeca пишет:
Появилась проблемка - при старте серва крутится на все 180 сначала в одну затем в другую стороны. И так 2 - 3 захода затем пошел на исполнение код. Видимо тяжело ей нуль найти.

Это при подключении напрямую к аккумулятору?

sedeca
Offline
Зарегистрирован: 16.07.2012

запитал сервы отдельно от аккум. Плата запитана от отдельного источника. Объеденил землю ардуины с минусом аккум. ноль эффекта. Теперь сервы вообще молчат. Нужно ли объеденить нейтраль источника для ардуины и минус батареи?

sedeca
Offline
Зарегистрирован: 16.07.2012

sedeca пишет:

запитал сервы отдельно от аккум. Плата запитана от отдельного источника. Объеденил землю ардуины с минусом аккум. ноль эффекта. Теперь сервы вообще молчат. Нужно ли объеденить нейтраль источника для ардуины и минус батареи?

Косяк нашел. Все работат. Действительно для серв нужен отдельный источник. maksim спасибо за помощь.

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

Ну почему же... можно использовать тот же источник, только питание нужно брать не с дуины, а либо с аккумулятора, либо с отдельного стабилизатора (DC-DC преобразователя) , подключенного к аккумулятору. 

sedeca
Offline
Зарегистрирован: 16.07.2012

 Уже заказал инвертер. Вот теперь то мы развернемся. Может вы мне подскажете как из цикла void loop выходить? А то они у меня до третьей мировой крутят. 

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

Самый простой способ - это в него не заходить.  

#include <Servo.h> 

Servo myservov;  // создаём объект для контроля сервы (вертикаль)
Servo myservog;  // создаём объект для контроля сервы (горизонталь)

int posv = 0;    // переменная для хранения позиции сервы (вертикаль)
int posg = 0;    // переменная для хранения позиции сервы (горизонталь)
int PhotoPin=9;  // переменная для фотопина

void setup() 
{ 
  myservog.attach(4);  // серва горизонтали подключена у 4-му пину
  myservov.attach(7);  // серва вертикали подключена у 7-му пину
  pinMode(PhotoPin, OUTPUT); // девятый пин на выход (управление фото)


  myservog.write(30);                    // горизонтальную серву повернули на 30 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(60);                    // горизонтальную серву повернули до 60 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(90);                    // горизонтальную серву повернули до 90 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  for(posg = 180; posg>=1; posg-=1)      // вернули горизонтальную серву в 0 градусов
  {                                
    myservog.write(posg);               
    delay(15);                       
  }  

} 

void loop() {
} 

Я так понимаю это какая-то панорамная головка?

sedeca
Offline
Зарегистрирован: 16.07.2012

 Да панорамка простейшая. А без цикла совсем никак. Ругань и слезы. Но я так понимаю можно цикл loop вообще не использовать?

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

Можно не использовать, но быть должен. Я же вам выше код написал, не работает?

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

Кстати, для вращения на 360 градусов можно серву переделать, но тогда положение можно будет определить только по времени работы сервы. 

sedeca
Offline
Зарегистрирован: 16.07.2012

Код не проверил разберать макетку лень. Но смысл понял. По поводу 360 не совсем понял. Если стандартой серве задается угол, то после переделки под 360, задается скорость? Тоесть после переделки получается серва постоянного вращения?

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

Да, при переделке потенциометр внутри сервы фиксируют так, что бы серва стояла на месте при myservo.write(90); и при меньших значениях она крутится в одну сторону, а при больших в другую и чем больше отклонение от 90 тем выше скорость вращения.

sedeca
Offline
Зарегистрирован: 16.07.2012

 Проверил ваш вариант кода. Цикл все равно есть. И выползти из него никак. Спасаюсь дикой задержкой в конце кода. 

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

 >Цикл все равно есть.

Конечно. Его не может не быть. В любом скетче, в неявном виде, присутсвует "главная функция". 

static void main(){
  setup();
  while(true)loop();
}

Ее добавляет ArduinoIDE без вашего желания. Замечу, так же что если бы этого не делала она - это обязательно должны было-бы делать вы.

>И выползти из него никак

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

>Спасаюсь

Да от чего спасаетесть-то? Чем вам пустой цикл "колет"? Какой негативный эффект вы в этом усматриваете?

>дикой задержкой в конце кода

Fail. Не спаслись. Все умерли. :)   Как вы думаете реализованна задержка?  Функция delay() не вызывает локальной инкапсуляции пространственно временного континиума :). 

void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();

	while (ms > 0) {
		if (((uint16_t)micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

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

А раз задержка вас "спасает" - значит проблема не техническая. Так как "задержка" в данном случае это "плацебо" в чистом виде. Что-то "лечить" она может только если эта "болезнь" - не существует.

Вообщем сформулируйте проблему, а не способ которым вы пытаетесть ее решить (выход из цикла).

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

Цикличности (если я правильно понимаю) не может быть никак, так как я весь ваш код поместил в функцию setup(), пока не нажмется ресет или не выключите-включите питание программа выполнятся по новой не будет. Вы может не тот скейтч залили? Он находится в #13 сообщении в свернутом виде.

Еще раз его копирую вот он:

#include <Servo.h> 

Servo myservov;  // создаём объект для контроля сервы (вертикаль)
Servo myservog;  // создаём объект для контроля сервы (горизонталь)

int posv = 0;    // переменная для хранения позиции сервы (вертикаль)
int posg = 0;    // переменная для хранения позиции сервы (горизонталь)
int PhotoPin=9;  // переменная для фотопина

void setup() 
{ 
  myservog.attach(4);  // серва горизонтали подключена у 4-му пину
  myservov.attach(7);  // серва вертикали подключена у 7-му пину
  pinMode(PhotoPin, OUTPUT); // девятый пин на выход (управление фото)


  myservog.write(30);                    // горизонтальную серву повернули на 30 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(60);                    // горизонтальную серву повернули до 60 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(90);                    // горизонтальную серву повернули до 90 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  for(posg = 180; posg>=1; posg-=1)      // вернули горизонтальную серву в 0 градусов
  {                                
    myservog.write(posg);               
    delay(15);                       
  }  

} 

void loop() {
} 

Да и кстати, еще можно сделать вместо дикой задержки безконечную задержку:

#include <Servo.h> 

Servo myservov;  // создаём объект для контроля сервы (вертикаль)
Servo myservog;  // создаём объект для контроля сервы (горизонталь)

int posv = 0;    // переменная для хранения позиции сервы (вертикаль)
int posg = 0;    // переменная для хранения позиции сервы (горизонталь)
int PhotoPin=9;  // переменная для фотопина

void setup() 
{ 
  myservog.attach(4);  // серва горизонтали подключена у 4-му пину
  myservov.attach(7);  // серва вертикали подключена у 7-му пину
  pinMode(PhotoPin, OUTPUT); // девятый пин на выход (управление фото)
} 

void loop() {
  myservog.write(30);                    // горизонтальную серву повернули на 30 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(60);                    // горизонтальную серву повернули до 60 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  myservog.write(90);                    // горизонтальную серву повернули до 90 градусов
  delay(1000);                           // ждем 1 с

  for(posv = 0; posv < 150; posv += 30)  // вертикальную серву с шагом 30 прогнали до 150 град
  {                                     
    myservov.write(posv);               // 
    delay(1000);                        // ждём 1000 с пока серва займёт новое положение
  } 
  myservov.write(0);                    // вернули вертикальную серву в 0 градусов
  delay(1000);                          // ждем 1 с
  //////////////////////////////////////////////////////////////// 
  for(posg = 180; posg>=1; posg-=1)      // вернули горизонтальную серву в 0 градусов
  {                                
    myservog.write(posg);               
    delay(15);                       
  }  
  
  while(1){
  }
} 

 

sedeca
Offline
Зарегистрирован: 16.07.2012

  Скейтч работает на ура. И даже задержки не потребовалось. Спасибо.

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Ещё бы в одну функцию все это засунуть. Красивей и экономней.

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

Что "все это" ? И если имелся ввиду код, то он и так в одной функции находится, в первом случае в функции setup() , а во втором в функции loop(). 

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

 

maksim пишет:

Что "все это" ? И если имелся ввиду код, то он и так в одной функции находится, в первом случае в функции setup() , а во втором в функции loop().

Скорее всего имелся ввиду рефакторинг: вынос похожих кусков кода в функцию. снижения дублирования.

Топикстартеру:

Кстати, если воспользоватся  поиском, то можно найти обсуждения подобных задачь

http://arduino.ru/forum/programmirovanie/preryvanie-i-servy#comment-11697

В #13 я там как раз и дал функцию. При этом еще сервы поворачиваются синхронно и с регулируемой скоростью.

И, опять-таки похожее было в http://arduino.ru/forum/programmirovanie/zapominanie-poziii-servo#comment-10321