Ошибка в коде на управление Серво

Otto
Offline
Зарегистрирован: 26.06.2016

Такая проблема, слепил 2 кода для плавных поворотов серво, по отдельности работают отлично, но вместе очень глючино...  Когда в void setup() комментируешь любую из двух строчек для назначения серво, то один код работает стабильно, то же самое наоборот.

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

Вот сам код:

#include <VarSpeedServo.h>  // Библиотека для Servo-Мотора с регулировкой скорости
#include <IRremote.h>      // Библиотека для ИК приёмника

byte RECV_PIN = 11;       // вход ИК приемника
IRrecv irrecv(RECV_PIN);  // Объект ИК
decode_results results;

VarSpeedServo servoPovorot; //даём имя servo

// переменные для контроля за процессом поворотов Servo
bool Right_Pin_1   = false;   //для ручного поворота вправо при зажатии кнопки
bool Left_Pin_1    = false;   //для ручного поворота влево при зажатии кнопки
bool Auto_Povorot  = false;   //для Автоповорота при кратковременном нажатии


class Sweeper
{
    VarSpeedServo servoAutoPovorot; // сервопривод для автоповорота

    int pos; // текущее положение сервы
    int increment; // увеличиваем перемещение на каждом шаге
    int updateInterval; // промежуток времени между обновлениями
    unsigned long lastUpdate; // последнее обновление положения

  public:
    Sweeper(int interval)
    {
      updateInterval = interval;
      increment = 1;
    }

    void attach(int pin)
    {
      servoAutoPovorot.attach(pin);
    }

    void detach()
    {
      servoAutoPovorot.detach();
    }

    void Update()
    {
      if ((millis() - lastUpdate) > updateInterval) // время обновлять
      {
        lastUpdate = millis();
        pos += increment;
        servoAutoPovorot.write(pos);
        if ((pos >= 130) || (pos <= 0)) // конец вращения
        {
          // обратное направление
          increment = -increment;
        }
      }
    }
};

Sweeper servoAutoPovorot(35);  // скорость Авто-вращения серво



/* Переменная для плавного вращения servo,чтобы не использовать delay.
  промежуточная переменная для хранения (увеличенного диапазона от 0 до 20000)значений (увеличения или уменьшения)PWM,
  с последующей конвертации в переменную(val_1) диапазон градусов поворота доступных для servo.*/
int L = 0;

//переменная для конвертации (увеличенного диапазона значений от 0 до 20000) (L),в значения требуемые для поворота servo.
int val_1;

//переменная для (увеличения или уменьшения)скорости поворота servo.
int speed_PWM = 1;

//переменная eventTime, для паузы, вместо delay,будем использовать функцию millis.
unsigned long eventTime = 0;


void setup()
{
  irrecv.enableIRIn();          // включить ИК приёмник
  servoPovorot.attach(9);       // Servo подключён на цифровой вход (pin 9)
  servoAutoPovorot.attach(9);   // для автоповоротов класса Sweeper
}


void loop()
{

  if (Auto_Povorot == true) {        //Если Auto_Povorot истина...
    servoAutoPovorot.Update();      // ...тогда включаем автоповорот серво
  }

  /* Делаем, что бы система работала в режиме удержания кнопки для Серво.
    После приёма определённого кода кнопки,сразу перехватывать идущий за ним (кодом), (пустой инфракрасный сигнал)
    и считать его - (пустой инфракрасный сигнал), за код кнопки.
    После пропадания (пустого инфракрасного сигнала) - будем считать, что код перестал слаться.*/

  /* 1. После приёма определённого кода кнопки, перехватывать (пустой инфракрасный сигнал).
     2. Конвертировать пульсирующий (-) с (ИК) преемника сигнал в постоянный.
    После появления и пропадания сигнала, состояние сразу не меняется! а ждет  100 миллисекунд.
    Если 100 миллисекунд не прошло, и поступил еще один ИК сигнал с пульта,
    тогда таймер заново запускается на 100 миллисекунд.*/

  if (digitalRead(RECV_PIN) == LOW)
    eventTime = millis();
  if (millis() - eventTime > 100) (Right_Pin_1 = false), (Left_Pin_1 = false);

  /* Если Right_Pin_1) ==, выставляем ограничение для переменной(L) до (&& L<20000) и начинаем увеличивать
    значения переменной(L), на значение переменной speed_PWM,
    и также выставляем ограничение при убывании (&& a>0).*/

  if (Right_Pin_1 ==  true && L < 20000  ) L = L + speed_PWM;
  if (Left_Pin_1  ==  true && L > 0  ) L = L - speed_PWM;


  //читаем значение (L) и конвертируем его в значение val_1, то бишь в значение поворота в градусов доступных для servo.
  val_1 = L;
  val_1 = map(val_1, 0, 20000, 1, 130);     // Задаём диапазон скорости и поворота Серво (углы поворота от 1 до 130 градусов)
  servoPovorot.write(val_1);                // Положение Серво в соответствии с val_1.


  if (irrecv.decode(&results)) {
    // 2 Команды с пульта отвечающие за ручные повороты Серво.
    if (results.value == 0xFFC23D) Right_Pin_1  = true;  // Поворот Вправо
    if (results.value == 0xFF22DD) Left_Pin_1   = true;  // Поворот Влуво
    if (results.value == 0xFF629D) Auto_Povorot = true;   //Автоповорот вкл.
    if (results.value == 0xFFA857) Auto_Povorot = false;  //Автоповорот откл.

    irrecv.resume(); // получаем следующие значения
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну это разумеется не то , но может пригодится.

/* 
Принцип кода: нажатие на кнопку 1 вкл авторотации сервы
              нажатие на кнопку 2 выкл авторотации сервы
#2 Серва  упр. выв -> 9    (servo_pin)
               +5В -> +5В
               GND -> GND
#3       кнопка  1 -> 2 (btn1_pin) Влево  0 нажата /1 нет
#4       кнопка  2 -> 3 (btn2_pin) Вправо 0 нажата /1 нет
*/
// #2
#include <Servo.h>
Servo servo;
const int servo_pin = 9   ;// нога сервы
const int angle_min = 0   ;// 0   угол сервы
const int angle_max = 180 ;// 180 угол сервы
int angle = angle_min     ;// angle_min..angle_max угол сервы
const int angle_step = 5  ;// шаг поворота сервы
bool auto_rotation   = 0  ;// автоповорот 1 -включен / 0 -выключен
bool dir = 0                ; // направление вращение автоповорота   0 -влево / 1 -вправо
// #3
// короткое нажатие автоповорот вкл
const int btn1_pin = 2; // вывод кнопки 1 Влево
bool btn1, btn1_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn1 = 0; // антидребезговый флаг
// #4
// короткое нажатие автоповорот выкл
const int btn2_pin = 3; // вывод кнопки 2 Вправо
bool btn2, btn2_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn2 = 0; // антидребезговый флаг
void setup() {
  Serial.begin(9600);
  // #2
  servo.attach(servo_pin)       ; // подключить серву
  servo.write(angle);           ; // серву установить на нужный угол
  // #3
  pinMode(btn1_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn1 = digitalRead(btn1_pin);
  // #4
  pinMode(btn2_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn2 = digitalRead(btn2_pin);

}

void loop() {
  //#2  200 миллисекунд вычислит. поток 2
  static uint32_t past_2 = 0 ;
  if (millis() - past_2 >= 200) {
    past_2 = millis() ;
    if (auto_rotation) { // если автоповорот включен
      if (dir) {  // если вращение направо
        angle += angle_step;
        if (angle > angle_max) {
          angle -= angle_step;
          dir = 0;
        }
      }
      else {      // если вращение налево
        angle -= angle_step;
        if (angle < angle_min) {
          angle += angle_step;
          dir = 1;
        }
      }
      servo.write(angle);
    }
  }
  // #3
  static uint32_t past_3 = 0 ;
  if (! bounce_btn1 && btn1 != digitalRead(btn1_pin)) { // если прошел фронт изм на выводн
    bounce_btn1 = 1;                                 // выставить флаг
    past_3 = millis();                          // сделать временую засветку
  }
  else if ( bounce_btn1 && millis() - past_3 >= 40 ) { // если прошло антидребезговое время
    bounce_btn1 = 0;      // то снять флаг
    btn1_old = btn1;
    btn1 = digitalRead(btn1_pin) ; // прочитать реальное значение на выводе
    if (btn1_old && ! btn1) {      // если обнаружилось что это было нажатие
      auto_rotation = 1; // включить авторотацию
      Serial.println("Press btn1 down");
    }
  }
  // #4
  static uint32_t past_4 = 0 ;
  if (! bounce_btn2 && btn2 != digitalRead(btn2_pin)) { // если прошел фронт изм на выводн
    bounce_btn2 = 2;                                 // выставить флаг
    past_4 = millis();                          // сделать временую засветку
  }
  else if ( bounce_btn2 && millis() - past_4 >= 40 ) { // если прошло антидребезговое время
    bounce_btn2 = 0;      // то снять флаг
    btn2_old = btn2;
    btn2 = digitalRead(btn2_pin) ; // прочитать реальное значение на выводе
    if (btn2_old && ! btn2) {      // если обнаружилось что это было нажатие
      auto_rotation = 0; // выключить авторотацию
      Serial.println("Press btn2 down");
    }
  }
}

Вот еще вариант

/*
Принцип кода: нажатие на кнопку 1 поворот налево до упора
              нажатие на кнопку 2 поворот направо до упора
#2 Серва  упр. выв -> 9    (servo_pin)
               +5В -> +5В
               GND -> GND
#3       кнопка  1 -> 2 (btn1_pin) Влево  0 нажата /1 нет
#4       кнопка  2 -> 3 (btn2_pin) Вправо 0 нажата /1 нет
*/
// #2
#include <Servo.h>
Servo servo;
const int servo_pin = 9   ;// нога сервы
const int angle_min = 0   ;// 0   угол сервы
const int angle_max = 180 ;// 180 угол сервы
int angle = angle_min     ;// angle_min..angle_max угол сервы
const int angle_step = 5  ;// шаг поворота сервы
bool auto_rotation   = 0  ;// автоповорот 1 -включен / 0 -выключен
bool dir = 0              ;// направление вращение автоповорота   0 -влево / 1 -вправо
// #3
// короткое нажатие автоповорот вкл
const int btn1_pin = 2; // вывод кнопки 1 Влево
bool btn1, btn1_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn1 = 0; // антидребезговый флаг
// #4
// короткое нажатие автоповорот выкл
const int btn2_pin = 3; // вывод кнопки 2 Вправо
bool btn2, btn2_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn2 = 0; // антидребезговый флаг

void setup() {
  // #2
  servo.attach(servo_pin)       ; // подключить серву
  servo.write(angle);           ; // серву установить на нужный угол
  // #3
  pinMode(btn1_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn1 = digitalRead(btn1_pin);
  // #4
  pinMode(btn2_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn2 = digitalRead(btn2_pin);
}

void loop() {
  //#2  200 миллисекунд вычислит. поток 2
  static uint32_t past_2 = 0 ;
  if (millis() - past_2 >= 200) {
    past_2 = millis() ;
    if (! btn1 && btn2) { // если нажата кнопка 1 а кнопка 2 отпущена
      angle += angle_step;
      if (angle > angle_max) {
        angle -= angle_step;
      }
      servo.write(angle);
    }
    if (btn1 && ! btn2) { // если нажата кнопка 2 а кнопка 1 отпущена
      angle -= angle_step;
      if (angle < angle_min) {
        angle += angle_step;
      }
      servo.write(angle);
    }
  }
  // #3
  static uint32_t past_3 = 0 ;
  if (! bounce_btn1 && btn1 != digitalRead(btn1_pin)) { // если прошел фронт изм на выводн
    bounce_btn1 = 1;                                    // выставить флаг
    past_3 = millis();                                  // сделать временую засветку
  }
  else if ( bounce_btn1 && millis() - past_3 >= 40 ) { // если прошло антидребезговое время
    bounce_btn1 = 0;                                  // то снять флаг
    btn1 = digitalRead(btn1_pin) ; // прочитать реальное значение на выводе
  }
  // #4
  static uint32_t past_4 = 0 ;
  if (! bounce_btn2 && btn2 != digitalRead(btn2_pin)) { // если прошел фронт изм на выводн
    bounce_btn2 = 2;                                    // выставить флаг
    past_4 = millis();                                  // сделать временую засветку
  }
  else if ( bounce_btn2 && millis() - past_4 >= 40 ) { // если прошло антидребезговое время
    bounce_btn2 = 0;      // то снять флаг
    btn2 = digitalRead(btn2_pin) ; // прочитать реальное значение на выводе
  }
}

И 3 скетч совмещенный

/*
Принцип кода: короткое нажатие на кнопку 1 вкл авторотации сервы
              короткое нажатие на кнопку 2 выкл авторотации сервы
              длиное нажатие на кнопку 1 медленный поворот направо до упора
              длиное нажатие на кнопку 2 медленный поворот налево до упора
#2 Серва  упр. выв -> 9    (servo_pin)
               +5В -> +5В
               GND -> GND
#3       кнопка  1 -> 2 (btn1_pin) Влево  0 нажата /1 нет
#4       кнопка  2 -> 3 (btn2_pin) Вправо 0 нажата /1 нет
*/
// #2
#include <Servo.h>
Servo servo;
const int servo_pin = 9   ;// нога сервы
const int angle_min = 0   ;// 0   угол сервы
const int angle_max = 180 ;// 180 угол сервы
int angle = angle_min     ;// angle_min..angle_max угол сервы
const int angle_step = 2  ;// шаг поворота сервы
bool auto_rotation   = 0  ;// автоповорот 1 -включен / 0 -выключен
bool dir = 0                ; // направление вращение автоповорота   0 -влево / 1 -вправо
// #3
// короткое нажатие автоповорот вкл
const int btn1_pin = 2; // вывод кнопки
bool btn1, btn1_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn1 = 0; // антидребезговый флаг
uint32_t time_btn1  ; // длительность нажатия
const uint32_t const_time_btn1 = 200  ; // константа длительности нажатия ниже короткое нажатие выше длиное,миллисек
// #4
// короткое нажатие автоповорот выкл
const int btn2_pin = 3; // вывод кнопки
bool btn2, btn2_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn2 = 0; // антидребезговый флаг
uint32_t time_btn2  ; // длительность нажатия
const uint32_t const_time_btn2 = 200  ; // константа длительности нажатия ниже короткое нажатие выше длиное,миллисек
void setup() {
  // #2
  servo.attach(servo_pin)       ; // подключить серву
  servo.write(angle);           ; // серву установить на нужный угол
  // #3
  pinMode(btn1_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn1 = digitalRead(btn1_pin);
  // #4
  pinMode(btn2_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn2 = digitalRead(btn2_pin);

}

void loop() {
  //#2  200 миллисекунд вычислит. поток 2
  static uint32_t past_2 = 0 ;
  static uint32_t past1_3 = 0 ; // перенесена из потока #3
  static uint32_t past1_4 = 0 ; // перенесена из потока #4
  if (millis() - past_2 >= 100) {
    past_2 = millis() ;

    if (! btn1 && ( millis() - past1_3 > const_time_btn1 ) && btn2) { // если долго нажата кнопка 1, а кнопка 2 отпущена
      dir = 1;
      angle += angle_step;
      if (angle > angle_max) {
        angle -= angle_step;
      }
      servo.write(angle);
    }
    if (btn1 && ! btn2 && ( millis() - past1_4 > const_time_btn2 )) { // если долго нажата кнопка 2, а кнопка 1 отпущена
      dir = 0;
      angle -= angle_step;
      if (angle < angle_min) {
        angle += angle_step;
      }
      servo.write(angle);
    }

    if (auto_rotation) { // если автоповорот включен
      if (dir) {  // если вращение направо
        angle += angle_step;
        if (angle > angle_max) {
          angle -= angle_step;
          dir = 0;
        }
      }
      else {      // если вращение налево
        angle -= angle_step;
        if (angle < angle_min) {
          angle += angle_step;
          dir = 1;
        }
      }
      servo.write(angle);
    }
  }
  // #3
  static uint32_t past_3 = 0 ;
  if (! bounce_btn1 && btn1 != digitalRead(btn1_pin)) { // если прошел фронт изм на выводн
    bounce_btn1 = 1;                                 // выставить флаг
    past_3 = millis();                          // сделать временую засветку
  }
  else if ( bounce_btn1 && millis() - past_3 >= 40 ) { // если прошло антидребезговое время
    bounce_btn1 = 0;      // то снять флаг
    btn1_old = btn1;
    btn1 = digitalRead(btn1_pin) ; // прочитать реальное значение на выводе
    if (btn1_old && ! btn1) {      // если обнаружилось что это было нажатие
      past1_3 = millis();
    }
    if (! btn1_old && btn1) {      // если обнаружилось что это было отжатие
      time_btn1 = millis() - past1_3;
      if (time_btn1 < const_time_btn1) // если было до этого короткое нажатие кнопки 1
        auto_rotation = 1; // выключить авторотацию;
    }
  }
  // #4
  static uint32_t past_4 = 0 ;
  if (! bounce_btn2 && btn2 != digitalRead(btn2_pin)) { // если прошел фронт изм на выводн
    bounce_btn2 = 2;                                 // выставить флаг
    past_4 = millis();                          // сделать временую засветку
  }
  else if ( bounce_btn2 && millis() - past_4 >= 40 ) { // если прошло антидребезговое время
    bounce_btn2 = 0;      // то снять флаг
    btn2_old = btn2;
    btn2 = digitalRead(btn2_pin) ; // прочитать реальное значение на выводе
    if (btn2_old && ! btn2) {      // если обнаружилось что это было нажатие
      past1_4 = millis();
    }
    if (! btn2_old && btn2) {      // если обнаружилось что это было отжатие
      time_btn2 = millis() - past1_4;
      if (time_btn2 < const_time_btn2) // если было до этого короткое нажатие кнопки 2
        auto_rotation = 0; // выключить авторотацию;
    }
  }
}