Управление серво приводом и регулятором скорости (ESC)

rustam
Offline
Зарегистрирован: 25.01.2015

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

Плата Arduino Duemilanove (328)

Написал небольшой скетч управление серво приводом (SG-5010) через COM порт.

#include <Servo.h> 
int val;
Servo servo;

void setup()
{
servo.attach(9);
Serial.begin(9600);
}

void loop()
{
if (Serial.available())
  {
    val = Serial.read();
  if (val == 119) // w = 119 in dec
    {
      servo.write(170);
    }
  else if (val == 115) //s = 115 in dec
    {
      servo.write(10);
    }
}

Купил бесщеточный двигатель A2212/13T + ESC (отдельно для него написал скетч, что бы проверить все работает)

Не получается объединить в рамках 1 скетча управление cерво приводом и ESC. 

Хотел нажатием пробела (ASCII = 32) запустить двигатель и с каждым нажатием увеличивать обороты.

Если есть, у кого то опыт поделитесь пожалуйста. 

rustam
Offline
Зарегистрирован: 25.01.2015

Тогда может кто подскажит как организовать 2-а независимых цикла в 1 скетч ?

vvadim
Offline
Зарегистрирован: 23.05.2012

Так покажите ваш код для безколлекторника

rustam
Offline
Зарегистрирован: 25.01.2015
Серво библиотека.
 
Servo motor1;
void arm(){
  setSpeed(0); 
  delay(1000);
}
void setSpeed(int speed){
  int angle = map(speed, 0, 100, 0, 180);
  motor1.write(angle);    
}

void setup()
{
 motor1.attach(7);
 arm();  
}

void loop()
{
 int speed;
   for(speed = 0; speed <= 100; speed += 5) {
      setSpeed(speed);
      delay(1000);
   }
   for(speed = 95; speed > 0; speed -= 5) {
      setSpeed(speed);
      delay(1000);
    }
 setSpeed(0);  
 delay(5000); 
}

Это тестовый скетч для проверки работы двигателя и регулировки скорости вращения.  

Мои попытки написать скетч для одновременной работы с условием значения переменной не привели к успеху, я даже понимаю почему это происходит, при последующих циклах значение переменной исчезает и условие не выполняется, также для двигателя нужен  delay (задержка), в цикле с задержкой серва приводы начинают реагировать на 1 сек позже, по этой причине и нужно разделять циклы. 

 

bwn
Offline
Зарегистрирован: 25.08.2014

Чтобы значение переменной не "исчезало", ее надо определить как глобальную. Delay() исключить использовав millis() с проверкой периода задержки. Соответственно For Вам здесь не поможет (он даст задержку в любом случае, пока колностью не выполнится), модифицируем на другие методы -

http://arduino.ru/Reference/If

http://arduino.ru/Reference/While

rustam
Offline
Зарегистрирован: 25.01.2015

Спасибо по результату отпишусь. 

Можете направить как определить глобальную переменую?

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

Servo motor1;
 
void setup(){
 motor1.attach(7);
 arm();  
}
 
void loop(){
   for(byte i = 0; i <= 100; i += 5) {
      setSped(i);
      delay(1000);
   }
   for(byte i = 95; i >= 0; i -= 5) {
      setSped(i);
      delay(1000);
    }
 setSped(0);  
 delay(5000); 
}

void arm(){
  setSped(0); 
  delay(1000);
}
void setSped(byte sped){
  motor1.write(map(sped, 0, 100, 0, 180));    
}

если компилятор выделяет цветом названия которые ты даешь, значит лучше их поменять

значит эти названия зарезервированы, и возможны глюки

bwn
Offline
Зарегистрирован: 25.08.2014

rustam пишет:

Спасибо по результату отпишусь. 

Можете направить как определить глобальную переменую?

http://arduino.ru/Tutorial/Variables

rustam
Offline
Зарегистрирован: 25.01.2015

Решил задачу разбить по шагам, для начала разобраться как использовать цикл while
Написал простой скетч

#include <Servo.h> 

Servo motor1;

void setSpeed(int speed1){
  //Скорость от 0 до 100, где 0 выключен, и 100, является максимальной скоростью
  int angle = map(speed1, 0, 100, 0, 180);
  motor1.write(angle);
}

void setup() {
  int speed1;
  motor1.attach(7);
  setSpeed(0);  // Начальная скорость 
  delay(1000);
}

void loop()
{
  //задал в ручную значение переменной speed1
  int speed1 = 40;
  while (speed1 <= 100){
     setSpeed(speed1);
     delay(1000);
  }
}

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

rustam
Offline
Зарегистрирован: 25.01.2015

Что если так попробывать.

#include <Servo.h> 

Servo motor1;

void setup() {
  int speed1;
  motor1.attach(7);
  // калибровка esc в течении 1 секунды
  while (millis() < 1000) {
   if (speed1 <= 0) {
      motor1.write(0);
   }
   if (speed1 > 0) {
      motor1.write(speed1);
   }
 }
}
void loop()
{
  //задал в ручную значение переменной speed1
  int speed1 = 40;
  while (millis() < 1000){
     motor1.write(speed1);
  }
}

У меня 1 микроконтроллер я его уже до дыр затер :). Думаю что у него ограниченое количество раз записей.

По этому пишу тут что бы вы как профи посмотрели и сказали где я ошибся до заливки скетча на контроллер. 

vvadim
Offline
Зарегистрирован: 23.05.2012

Если честно, не понятно, что вы за скетч пишите и что вам нужно.

Чётко формулируем задачу, делим на более простые кусочки и в сети находим практически любой ответ.

Если что то не получается, то на форум.

 

Ну и не плохо было бы почитать вначале http://arduino.ru/forum/obshchii/prezhde-chem-sprosit-pro-servomashinku-servo-posmotri-tut

rustam
Offline
Зарегистрирован: 25.01.2015

Цитата из первого поста. 

rustam пишет:

Не получается объединить в рамках 1 скетча управление cерво приводом и ESC. 

Хотел нажатием пробела (ASCII = 32) запустить двигатель и с каждым нажатием увеличивать обороты.

Далее весь сюжет проб и ошибок:)

Если вам интересен конечный результат то его пока нет. Есть процесс обучения, но данная схема где используется серво привод и безколекторный двигатель много например: Машины, катер, вертолет, коптер может еще что то.

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

Надеюсь я ответил на ваш вопрос, что я за скетч пишу и что мне надо.

rustam
Offline
Зарегистрирован: 25.01.2015

Взрыв мозга :) я что то не по нимаю почему двигатель не запускается

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

#include <Servo.h>

Servo motor1;
unsigned long currentTime;
unsigned long loopTime;

void arm(){
 setSpeed(0); 
 delay(1000); 
}

void setSpeed(int speed1){
  int angle = map(speed1, 0, 100, 0, 180);
  motor1.write(angle);
}

void setup() {
currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
loopTime = currentTime;
Serial.begin(9600);
motor1.attach(7);                                      //  подсоединен к выводу 7
Serial.println("Program begin...");
arm();                                                 // 
}

void loop() {
  int speed1 = 40;
  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
  Serial.print(currentTime);
  Serial.println("TIME PROGRAM START");
  if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
    setSpeed(speed1);                               // запускаем двигатель
    loopTime = currentTime;                         // в loopTime записываем новое значение
    Serial.print(speed1);                           // показывает значение переменой
    Serial.println("SPEED");
    Serial.print(loopTime);                         // новое время
    Serial.println("NEW TIME");
 }
  // Здесь могут быть другие команды
}

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

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

А минимум-максимум-минимум   последовательность вы делаете? https://dronesandrovs.wordpress.com/2012/11/24/how-to-control-a-brushless-motor-esc-with-arduino/

rustam
Offline
Зарегистрирован: 25.01.2015

Дабавил вывод лога в рабочий скетч

 

Понял что 1 цикол от 0 до 100 и от 100 до 0 он проходит не включая двигатель, как бы калибруя ESC

Последующий круг запускает двигатель 

rustam
Offline
Зарегистрирован: 25.01.2015

trembo пишет:

А минимум-максимум-минимум   последовательность вы делаете? https://dronesandrovs.wordpress.com/2012/11/24/how-to-control-a-brushless-motor-esc-with-arduino/

Да вы скорее всего правы проблема в колибровки, завтра отпишусь по результату.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Не в калибровке, а в безопасности, это последовательность старта моторчика, чтобы лопастями  пальцы не отрубило.

fayvlad
Offline
Зарегистрирован: 27.03.2014

Вы хоть раз видели как запускается бесколекторный двигатель? регулятор программируется, часто бывает такая схема - 

1 опустить вниз рычаг (для вас - 0 градусов сервы)

2 подождать пока отпикается регулятор

3 поднять рычаг вверх( для вас - 180 градусов)

4 подождать сигнал

5 потом уже с 0 градусов управлять

1 и 3 шаги порядок может быть наоборот

rustam
Offline
Зарегистрирован: 25.01.2015

В моем коде есть функция arm () говорит о положении рычага вниз.

Как мне поднять рычаг вверх что бы обозначить двигателю 180 градусов?

Что написать в функцию arm()?

Так я пробовал!

void arm(){
 setSpeed(0);          //внизу
 delay(1000); 
 setSpeed(100);     //вверху
 delay(1000); 
}

Может задержку увеличить?

Обязательно ставить в положение 0 ?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Да, обязательно на ноль. Добавьте в конце

setSpeed(0);          //внизу

ДА, именно рычаг снизу  вверх и обратно вниз. И только потом он начнёт управлятся . Я обычно такое сервотестером проверяю.

http://www.ebay.com/itm/Multi-Servo-Tester-3CH-ECS-Consistency-Speed-Con...

 

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

Servo motor1;
unsigned long currentTime;
unsigned long loopTime;
Servo servo;
int val;
int speed1;

void arm(){
   for(speed1 = 0; speed1 <= 100; speed1 += 5) {
      setSpeed(speed1);
      delay(1000);
      Serial.print(speed1);                           // показывает значение переменой
      Serial.println("MIN > MAXI");
   }
   for(speed1 = 95; speed1 > 0; speed1 -= 5) {
      setSpeed(speed1);
      delay(1000);
      Serial.print(speed1);                           // показывает значение переменой
      Serial.println("MAXI > MIN");
      if ( speed1 == 5 ) break;                       //конец теста или колибровки
    }

 setSpeed(0);
 delay(1000);
}

void setSpeed(int speed1){
  int angle = map(speed1, 0, 100, 0, 180);
  motor1.write(angle);
}

void setup() {
servo.attach(9);
currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
loopTime = currentTime;
Serial.begin(9600);
motor1.attach(7);                                      // подсоединен к выводу 7
Serial.println("Program begin...");
arm();
}

void loop() {
  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
  Serial.print(currentTime);
  Serial.println("TIME PROGRAMM START");
  if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
    if (Serial.available())
      {
       val = Serial.read();
       if (val == 101)                               // клавиша e на клавиатуре
        {
          speed1 = speed1 + 5;                       
          setSpeed(speed1);                          // повышение скорости
        }
       if (val == 114)                               // клавиша r на клавиатуре
       {
          speed1 = speed1 - 5;
          setSpeed(speed1);                         //  понижение скорости
       }
      }                                
    loopTime = currentTime;                         // в loopTime записываем новое значение
    Serial.print(speed1);                           // показывает значение переменой
    Serial.println("SPEED");
    Serial.print(loopTime);                         // новое время
    Serial.println("NEW TIME");
 }
 if (Serial.available())
  {
    val = Serial.read();
  if (val == 119)                                   // w = 119 in dec
    {
      servo.write(170);                             // поворот серво привода на 170 градусов
     }
  else if (val == 115)                              //s = 115 in dec
    {
      servo.write(10);                             // поворот серва привода на 10 градусов
    }
  else if (val == 106)                            //j = 106 in dec
    {
      servo.write(80);                            // поворост серва привода на 80 градусов
     }
  }
  // Здесь могут быть другие команды
}

 

Этот код работает, при нажатии клавиши e [EN] значение переменной speed1 меняется на +5 (причем двигатель начинает вращается только на speed1 == 15), ну и при нажатии r [EN] значение меняется на -5 он вращается медленнее, при этом как я и хотел серво приводы работают независимо от безколекторника и время реакции очень хорошее.  

Но меня не совсем устраивает! Во первых должен быть способ избавиться от цикла в функции arm(). Пока у меня без него не работает. Во вторых клавиши e и r нужна держать бывает секунду для переключения скорости (если делать коптер это существенное время реакции на события, если машинку или катер то и так нормально)

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

delay(100) попробуйте. А вообще-то на пультах- джойстиках это туда-сюда делается за меньше полсекунды.... Махнул ручкой и всё....

А сразу с мин  до мах,  100 паузы и снова минимум без цикла разве не работает?

fayvlad
Offline
Зарегистрирован: 27.03.2014

Все дело в делай.
Сделай типа
void start(){
servo.write(0); //ну мотор, не смотрел как он по коду, бо с телефона
delay(500);
Servo.write(180);
delay(500);
servo.write(0);
}
Вызови ее еще в цикле void setup после того как описал моторы и сервы. - это даст старт моторам.
Я не очень понял смысла цикла в arm . Это просто тест? Зачем через секунду Аж добавлять обороты? Просто когда вызывается эта функция, программа тормозится на 100раз / 5 шаг = 20циклов* 1сек. - за 20 секунд ты ничего не можешь делать, бо выполняется цикл.
Сформулируй свою задачу, ты хочешь квадрокоптер сделать? Чем управлять будешь, если только прототип через сериал , то прикину, напишу програмку, в меру своего понимания, посмотришь

rustam
Offline
Зарегистрирован: 25.01.2015

Не хотел расписывать думал, очевидно.

Во первых: При выполнении функция arm () двигатель не вращается! Цикл проходит 1 круг от минимального значения к максимальному и обратно в положение 0 после чего я нажимаю клавишу E увеличивая обороты на +5 и клавишу R уменьшая обороты на -5.

Сказать честно не могу понять что функция arm() делает с ECS, если бы понимял решил задачу без цикла. Есть предположение что выставляет минимальное и максимальное значение, может калибрует обучая ECS на значении в цикле arm и устанавливает таймаут, может просто тест безколекторника, кто то пишет что просто безопасность что бы пальцы не оторвало (у меня нет доку на мой ECS я его в китаи заказал).  Но на реакцию клавиатуры он ни как не влияет, потому что он выполняется в:

void setup() {

}

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

if ( speed1 == 5 ) break; 

Во вторых: на реакцию клавиатуры E и R влияет:


if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
    if (Serial.available())
      {
       val = Serial.read();
       if (val == 101)                               // клавиша e на клавиатуре
        {
          speed1 = speed1 + 5;                       
          setSpeed(speed1);                          // повышение скорости
        }
       if (val == 114)                               // клавиша r на клавиатуре
       {
          speed1 = speed1 - 5;
          setSpeed(speed1);                         //  понижение скорости
       }
      }                                
    loopTime = currentTime;                         // в loopTime записываем новое значение

Я выше уже приводил лог из терминала где видно что SPEED1 переменная считывается и передается функции каждую секунду, по этой причине нужно максимум держать 1 секунду клавишу чтобы она в нужный момент изменила значение переменной. Такой способ избавляет нас от использование функции delay(); и не влият на управление серво приводов. 

Что касается реализации: Для того что бы что то реализовать коптер или другое, нужно, я считаю понять как это работает. Serial порт дает возможность тестировать код и видит что происходить при выполнении тех или иных действий функци.  

За написать под задачу спасибо, но все же это не то чего я хотел бы.  

rustam
Offline
Зарегистрирован: 25.01.2015

trembo пишет:

А сразу с мин  до мах,  100 паузы и снова минимум без цикла разве не работает?

Нет не получилось. 

rustam
Offline
Зарегистрирован: 25.01.2015

Мои изыскания привели к тому что цикл  все же калибровка ESC и можно сделать в отдельном скетче.

Слизал скетч от суда http://robots.dacloughb.com/project-2/esc-calibration-programming/

#include <Servo.h>

#define MAX_SIGNAL 2000
#define MIN_SIGNAL 700
#define MOTOR_PIN 7

Servo motor;

void setup() {
  Serial.begin(9600);
  Serial.println("Program begin...");
  Serial.println("This program will calibrate the ESC.");

  motor.attach(MOTOR_PIN);

  Serial.println("Now writing maximum output.");
  Serial.println("Turn on power source, then wait 2 seconds and press any key.");
  motor.writeMicroseconds(MAX_SIGNAL);

  // Wait for input
  while (!Serial.available());
  Serial.read();

  // Send min output
  Serial.println("Sending minimum output");
  motor.writeMicroseconds(MIN_SIGNAL);

}

void loop() {  
}

После чего залил свой код 

#include <Servo.h>

Servo motor1;
unsigned long currentTime;
unsigned long loopTime;
Servo servo;
int val;
int speed1;

void setSpeed(int speed1){
  int angle = map(speed1, 0, 100, 0, 180);
  motor1.write(angle);
}

void setup() {
servo.attach(9);
currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
loopTime = currentTime;
Serial.begin(9600);
motor1.attach(7);                                      // подсоединен к выводу 7
Serial.println("Program begin...");
setSpeed (10)                                          // Нужен что бы избежать травмы, если отключится от терминала двигатель начинает вращаться. 
}

void loop() {
  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
  Serial.print(currentTime);
  Serial.println("TIME PROGRAMM START");
  if(currentTime >= (loopTime + 100)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
    if (Serial.available())
      {
       val = Serial.read();
       if (val == 101)                               // клавиша e на клавиатуре
        {
          speed1 = speed1 + 5;                       
          setSpeed(speed1);                          // повышение скорости
        }
       if (val == 114)                               // клавиша r на клавиатуре
       {
          speed1 = speed1 - 5;
          setSpeed(speed1);                         //  понижение скорости
       }
      }                                
    loopTime = currentTime;                         // в loopTime записываем новое значение
    Serial.print(speed1);                           // показывает значение переменой
    Serial.println("SPEED");
    Serial.print(loopTime);                         // новое время
    Serial.println("NEW TIME");
 }
 if (Serial.available())
  {
    val = Serial.read();
  if (val == 119)                                   // w = 119 in dec
    {
      servo.write(170);                             // поворот серво привода на 170 градусов
     }
  else if (val == 115)                              //s = 115 in dec
    {
      servo.write(10);                             // поворот серва привода на 10 градусов
    }
  else if (val == 106)                            //j = 106 in dec
    {
      servo.write(80);                            // поворост серва привода на 80 градусов
     }
  }
  // Здесь могут быть другие команды
}

Выводы:

1. Я избавился от цикла.

2. Понял как калибровать ESC. 

3. Уменшил время отклика от клавиатуры (loopTime + 100)

Задача решина может кому то мои коментарии помогут. 

rustam
Offline
Зарегистрирован: 25.01.2015

Немного модернизировал скетч (нет приделу совершенства).

Заменил кусок 

 currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
  Serial.print(currentTime);
  Serial.println("TIME PROGRAMM START");
   if (Serial.available())
      {
       val = Serial.read();
       if (val == 101)                               // e = 101 in dec
        {
        speed1 = speed1 + 5; 
        if(currentTime >= (loopTime + 100)){         // сравниваем текущий таймер с переменной loopTime + 1 секунда
          setSpeed(speed1);                          // повышение скорости
          loopTime = currentTime;  
        }
        }
       if (val == 114)                               // r = 114 in dec
       {
        speed1 = speed1 - 5;
        if(currentTime >= (loopTime + 100)){
          setSpeed(speed1);                         //  понижение скорости
          loopTime = currentTime;
        }
       }
                                     
    loopTime = currentTime;                         // в loopTime записываем новое значение
    Serial.print(speed1);                           // показывает значение переменой
    Serial.println("SPEED");
    Serial.print(loopTime);                         // новое время
    Serial.println("NEW TIME");
 }

Стало работать почти идиально :)

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Идём  к совершенству дальше :    101 на 'e'  и  114   на 'r'  поменяйте- было бы  понятнее что это такое...

rustam
Offline
Зарегистрирован: 25.01.2015

Это кодировка ASCII, в данной кодировки работает контроллер. 

Или  эту кодировку преобразует среда Arduino.

Пока опыта не так много, не все понимаю. 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011
rustam
Offline
Зарегистрирован: 25.01.2015

Спасибо понял.