Управление серво приводом и регулятором скорости (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
Серво библиотека.
 
01Servo motor1;
02void arm(){
03  setSpeed(0);
04  delay(1000);
05}
06void setSpeed(int speed){
07  int angle = map(speed, 0, 100, 0, 180);
08  motor1.write(angle);   
09}
10 
11void setup()
12{
13 motor1.attach(7);
14 arm(); 
15}
16 
17void loop()
18{
19 int speed;
20   for(speed = 0; speed <= 100; speed += 5) {
21      setSpeed(speed);
22      delay(1000);
23   }
24   for(speed = 95; speed > 0; speed -= 5) {
25      setSpeed(speed);
26      delay(1000);
27    }
28 setSpeed(0); 
29 delay(5000);
30}

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

Мои попытки написать скетч для одновременной работы с условием значения переменной не привели к успеху, я даже понимаю почему это происходит, при последующих циклах значение переменной исчезает и условие не выполняется, также для двигателя нужен  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

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

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

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

rustam пишет:

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

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

http://arduino.ru/Tutorial/Variables

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

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

01#include <Servo.h>
02 
03Servo motor1;
04 
05void setSpeed(int speed1){
06  //Скорость от 0 до 100, где 0 выключен, и 100, является максимальной скоростью
07  int angle = map(speed1, 0, 100, 0, 180);
08  motor1.write(angle);
09}
10 
11void setup() {
12  int speed1;
13  motor1.attach(7);
14  setSpeed(0);  // Начальная скорость
15  delay(1000);
16}
17 
18void loop()
19{
20  //задал в ручную значение переменной speed1
21  int speed1 = 40;
22  while (speed1 <= 100){
23     setSpeed(speed1);
24     delay(1000);
25  }
26}

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

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

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

01#include <Servo.h>
02 
03Servo motor1;
04 
05void setup() {
06  int speed1;
07  motor1.attach(7);
08  // калибровка esc в течении 1 секунды
09  while (millis() < 1000) {
10   if (speed1 <= 0) {
11      motor1.write(0);
12   }
13   if (speed1 > 0) {
14      motor1.write(speed1);
15   }
16 }
17}
18void loop()
19{
20  //задал в ручную значение переменной speed1
21  int speed1 = 40;
22  while (millis() < 1000){
23     motor1.write(speed1);
24  }
25}

У меня 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

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

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

01#include <Servo.h>
02 
03Servo motor1;
04unsigned long currentTime;
05unsigned long loopTime;
06 
07void arm(){
08 setSpeed(0);
09 delay(1000);
10}
11 
12void setSpeed(int speed1){
13  int angle = map(speed1, 0, 100, 0, 180);
14  motor1.write(angle);
15}
16 
17void setup() {
18currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
19loopTime = currentTime;
20Serial.begin(9600);
21motor1.attach(7);                                      //  подсоединен к выводу 7
22Serial.println("Program begin...");
23arm();                                                 //
24}
25 
26void loop() {
27  int speed1 = 40;
28  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
29  Serial.print(currentTime);
30  Serial.println("TIME PROGRAM START");
31  if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
32    setSpeed(speed1);                               // запускаем двигатель
33    loopTime = currentTime;                         // в loopTime записываем новое значение
34    Serial.print(speed1);                           // показывает значение переменой
35    Serial.println("SPEED");
36    Serial.print(loopTime);                         // новое время
37    Serial.println("NEW TIME");
38 }
39  // Здесь могут быть другие команды
40}

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

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()?

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

1void arm(){
2 setSpeed(0);          //внизу
3 delay(1000);
4 setSpeed(100);     //вверху
5 delay(1000);
6}

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

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

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

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

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

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

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

 

rustam
Offline
Зарегистрирован: 25.01.2015
01#include <Servo.h>
02 
03Servo motor1;
04unsigned long currentTime;
05unsigned long loopTime;
06Servo servo;
07int val;
08int speed1;
09 
10void arm(){
11   for(speed1 = 0; speed1 <= 100; speed1 += 5) {
12      setSpeed(speed1);
13      delay(1000);
14      Serial.print(speed1);                           // показывает значение переменой
15      Serial.println("MIN > MAXI");
16   }
17   for(speed1 = 95; speed1 > 0; speed1 -= 5) {
18      setSpeed(speed1);
19      delay(1000);
20      Serial.print(speed1);                           // показывает значение переменой
21      Serial.println("MAXI > MIN");
22      if ( speed1 == 5 ) break;                       //конец теста или колибровки
23    }
24 
25 setSpeed(0);
26 delay(1000);
27}
28 
29void setSpeed(int speed1){
30  int angle = map(speed1, 0, 100, 0, 180);
31  motor1.write(angle);
32}
33 
34void setup() {
35servo.attach(9);
36currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
37loopTime = currentTime;
38Serial.begin(9600);
39motor1.attach(7);                                      // подсоединен к выводу 7
40Serial.println("Program begin...");
41arm();
42}
43 
44void loop() {
45  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
46  Serial.print(currentTime);
47  Serial.println("TIME PROGRAMM START");
48  if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
49    if (Serial.available())
50      {
51       val = Serial.read();
52       if (val == 101)                               // клавиша e на клавиатуре
53        {
54          speed1 = speed1 + 5;                      
55          setSpeed(speed1);                          // повышение скорости
56        }
57       if (val == 114)                               // клавиша r на клавиатуре
58       {
59          speed1 = speed1 - 5;
60          setSpeed(speed1);                         //  понижение скорости
61       }
62      }                               
63    loopTime = currentTime;                         // в loopTime записываем новое значение
64    Serial.print(speed1);                           // показывает значение переменой
65    Serial.println("SPEED");
66    Serial.print(loopTime);                         // новое время
67    Serial.println("NEW TIME");
68 }
69 if (Serial.available())
70  {
71    val = Serial.read();
72  if (val == 119)                                   // w = 119 in dec
73    {
74      servo.write(170);                             // поворот серво привода на 170 градусов
75     }
76  else if (val == 115)                              //s = 115 in dec
77    {
78      servo.write(10);                             // поворот серва привода на 10 градусов
79    }
80  else if (val == 106)                            //j = 106 in dec
81    {
82      servo.write(80);                            // поворост серва привода на 80 градусов
83     }
84  }
85  // Здесь могут быть другие команды
86}

 

Этот код работает, при нажатии клавиши 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 я его в китаи заказал).  Но на реакцию клавиатуры он ни как не влияет, потому что он выполняется в:

1void setup() {
2 
3}

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

1if ( speed1 == 5 ) break;

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

01if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
02    if (Serial.available())
03      {
04       val = Serial.read();
05       if (val == 101)                               // клавиша e на клавиатуре
06        {
07          speed1 = speed1 + 5;                      
08          setSpeed(speed1);                          // повышение скорости
09        }
10       if (val == 114)                               // клавиша r на клавиатуре
11       {
12          speed1 = speed1 - 5;
13          setSpeed(speed1);                         //  понижение скорости
14       }
15      }                               
16    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/

01#include <Servo.h>
02 
03#define MAX_SIGNAL 2000
04#define MIN_SIGNAL 700
05#define MOTOR_PIN 7
06 
07Servo motor;
08 
09void setup() {
10  Serial.begin(9600);
11  Serial.println("Program begin...");
12  Serial.println("This program will calibrate the ESC.");
13 
14  motor.attach(MOTOR_PIN);
15 
16  Serial.println("Now writing maximum output.");
17  Serial.println("Turn on power source, then wait 2 seconds and press any key.");
18  motor.writeMicroseconds(MAX_SIGNAL);
19 
20  // Wait for input
21  while (!Serial.available());
22  Serial.read();
23 
24  // Send min output
25  Serial.println("Sending minimum output");
26  motor.writeMicroseconds(MIN_SIGNAL);
27 
28}
29 
30void loop() { 
31}

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

01#include <Servo.h>
02 
03Servo motor1;
04unsigned long currentTime;
05unsigned long loopTime;
06Servo servo;
07int val;
08int speed1;
09 
10void setSpeed(int speed1){
11  int angle = map(speed1, 0, 100, 0, 180);
12  motor1.write(angle);
13}
14 
15void setup() {
16servo.attach(9);
17currentTime = millis();                                // считываем время, прошедшее с момента запуска программы
18loopTime = currentTime;
19Serial.begin(9600);
20motor1.attach(7);                                      // подсоединен к выводу 7
21Serial.println("Program begin...");
22setSpeed (10)                                          // Нужен что бы избежать травмы, если отключится от терминала двигатель начинает вращаться.
23}
24 
25void loop() {
26  currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
27  Serial.print(currentTime);
28  Serial.println("TIME PROGRAMM START");
29  if(currentTime >= (loopTime + 100)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
30    if (Serial.available())
31      {
32       val = Serial.read();
33       if (val == 101)                               // клавиша e на клавиатуре
34        {
35          speed1 = speed1 + 5;                      
36          setSpeed(speed1);                          // повышение скорости
37        }
38       if (val == 114)                               // клавиша r на клавиатуре
39       {
40          speed1 = speed1 - 5;
41          setSpeed(speed1);                         //  понижение скорости
42       }
43      }                               
44    loopTime = currentTime;                         // в loopTime записываем новое значение
45    Serial.print(speed1);                           // показывает значение переменой
46    Serial.println("SPEED");
47    Serial.print(loopTime);                         // новое время
48    Serial.println("NEW TIME");
49 }
50 if (Serial.available())
51  {
52    val = Serial.read();
53  if (val == 119)                                   // w = 119 in dec
54    {
55      servo.write(170);                             // поворот серво привода на 170 градусов
56     }
57  else if (val == 115)                              //s = 115 in dec
58    {
59      servo.write(10);                             // поворот серва привода на 10 градусов
60    }
61  else if (val == 106)                            //j = 106 in dec
62    {
63      servo.write(80);                            // поворост серва привода на 80 градусов
64     }
65  }
66  // Здесь могут быть другие команды
67}

Выводы:

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

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

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

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

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

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

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

01currentTime = millis();                             // считываем время, прошедшее с момента запуска программы
02 Serial.print(currentTime);
03 Serial.println("TIME PROGRAMM START");
04  if (Serial.available())
05     {
06      val = Serial.read();
07      if (val == 101)                               // e = 101 in dec
08       {
09       speed1 = speed1 + 5;
10       if(currentTime >= (loopTime + 100)){         // сравниваем текущий таймер с переменной loopTime + 1 секунда
11         setSpeed(speed1);                          // повышение скорости
12         loopTime = currentTime; 
13       }
14       }
15      if (val == 114)                               // r = 114 in dec
16      {
17       speed1 = speed1 - 5;
18       if(currentTime >= (loopTime + 100)){
19         setSpeed(speed1);                         //  понижение скорости
20         loopTime = currentTime;
21       }
22      }
23                                     
24   loopTime = currentTime;                         // в loopTime записываем новое значение
25   Serial.print(speed1);                           // показывает значение переменой
26   Serial.println("SPEED");
27   Serial.print(loopTime);                         // новое время
28   Serial.println("NEW TIME");
29}

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

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

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