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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Открою новую тему.
Тележка о четырёх колёсах с алиэкспреса, бралась как конструктор, была собрана и ездила по комнате в автоматическом режиме, захотелось, чтобы внучки порулили )))
Аппаратрура радиоуправления FlySky FS-GT3C c приёмником  FS-GR3E но возможна любая с числом каналов два и более.

Скетч, буквально набросок выполненный за вечер, будет дальнейшее расширение возможностей, остален ультразвуковой датчик и попытка научить объезжать препятствия подруливая в автоматическом режиме )))

Не проверялся в железе, в мониторе порта всё изумительно (после небольшого триммирования руля), пока реализовано движение только прямо, реверс будет попозжее.

Критика для улучшения приветствуется!!!

    volatile unsigned int rc1_data = 1500;
    volatile unsigned int rc2_data = 1500;
    volatile unsigned int rc3_data = 1500;
    volatile unsigned long start_timeRC1 = 0;
    volatile unsigned long start_timeRC2 = 0;
    volatile byte flag_RC1 = 0;
    volatile byte flag_RC2 = 0;
    
 /***LM398***/   
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 5;    // PWM pin to change speed
const int in3 = 8;    // direction pin 1
const int in4 = 12;   // direction pin 2
const int enb = 6;    // PWM pin to change speed
int fspeed;           // forward speed 
int lr;               // положение руля    
 
    
    void setup() {
    Serial.begin(115200);
    pinMode(in1, OUTPUT);      // connection to L298n
    pinMode(in2, OUTPUT);      // connection to L298n
    pinMode(ena, OUTPUT);      // connection to L298n
    pinMode(in3, OUTPUT);      // connection to L298n
    pinMode(in4, OUTPUT);      // connection to L298n
    pinMode(enb, OUTPUT);      // connection to L298n
    analogWrite(ena, 0);
    analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту сигнала
    attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту сигнала
     attachInterrupt(1, Rc2, CHANGE);
    }

    void loop() {
      // Serial.println(rc1_data);
       lr = map(rc1_data,1000,2000, -20,20);
     //  Serial.println(rc2_data);
       if(rc2_data >=1520){
        fspeed=map(rc2_data,1520,2000,20,230);
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    analogWrite(ena, fspeed+lr);
    
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);
    analogWrite(enb, fspeed-lr);
    Serial.println(fspeed+lr);
    Serial.println(fspeed-lr);
       }
    }

/******Обработчик прерывания на возрастание сигнала ******/
    void Rc1() {
    if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
    start_timeRC1 = micros();
    flag_RC1=1;
    }
    if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса
    rc1_data = micros() - start_timeRC1; 
    flag_RC1=0; 
    }}
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }}

                                                                                          

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

 

    volatile unsigned int rc1_data = 1500;
    volatile unsigned int rc2_data = 1500;
    volatile unsigned int rc3_data = 1500;
    volatile unsigned long start_timeRC1 = 0;
    volatile unsigned long start_timeRC2 = 0;
    volatile byte flag_RC1 = 0;
    volatile byte flag_RC2 = 0;
    
             /***L298N***/   
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 5;    // PWM pin to change speed
const int in3 = 8;    // direction pin 1
const int in4 = 12;   // direction pin 2
const int enb = 6;    // PWM pin to change speed
int fspeed;           // forward speed 
int lr;               // положение руля    
 
    
    void setup() {
    Serial.begin(115200);
    pinMode(in1, OUTPUT);      // connection to L298n
    pinMode(in2, OUTPUT);      // connection to L298n
    pinMode(ena, OUTPUT);      // connection to L298n
    pinMode(in3, OUTPUT);      // connection to L298n
    pinMode(in4, OUTPUT);      // connection to L298n
    pinMode(enb, OUTPUT);      // connection to L298n
    analogWrite(ena, 0);
    analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту сигнала
    attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту сигнала
     attachInterrupt(1, Rc2, CHANGE);
    }

    void loop() {
      // Serial.println(rc1_data);
       lr = map(rc1_data,1000,2000, -20,20);
     //  Serial.println(rc2_data);
       if(rc2_data >=1520){
        fspeed=map(rc2_data,1520,2000,20,230);
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    analogWrite(ena, fspeed+lr);
    
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);
    analogWrite(enb, fspeed-lr);
    Serial.println(fspeed+lr);
    Serial.println(fspeed-lr);
       }
  
       /*** Если включили реверс ***/
       if(rc2_data <=1480){
        fspeed=map(rc2_data,1480,1000,20,230);
    digitalWrite(in2, LOW);
    digitalWrite(in1, HIGH);
    analogWrite(ena, fspeed+lr);
    
    digitalWrite(in4, LOW);
    digitalWrite(in3, HIGH);
    analogWrite(enb, fspeed-lr);
    Serial.println(fspeed+lr);
    Serial.println(fspeed-lr);
       }
    }

/******Обработчик прерывания на возрастание сигнала ******/
    void Rc1() {
    if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
    start_timeRC1 = micros();
    flag_RC1=1;
    }
    if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса
    rc1_data = micros() - start_timeRC1; 
    flag_RC1=0; 
    }}
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }}

 

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

Не было проблем и снова здорово. Если вы собираетесь делать большой проект, то начинайте учится структурировать код а не программировать "росыпью".  http://arduino.ru/reference/functiondeclaration

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

qwone пишет:

Не было проблем и снова здорово. Если вы собираетесь делать большой проект, то начинайте учится структурировать код а не программировать "росыпью".  http://arduino.ru/reference/functiondeclaration

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

поправил скетч, как-то заёрзала тележка, но очень плохо управляется, особенно при движении вперёд )))
 

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 5;    // PWM pin to change speed
//Двигатель правого борта (А)
const int in3 = 8;    // direction pin 1
const int in4 = 9;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
int lr;               // положение руля    
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
      // Serial.println(rc1_data);
lr = map(rc1_data,1000,2000, -50,50);
     //  Serial.println(rc2_data);
     
     // Если движение вперёд
if(rc2_data >=1520){
fspeed=map(rc2_data,1520,2000,50,200);
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
analogWrite(ena, fspeed+lr);
    
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
analogWrite(enb, fspeed-lr);
Serial.println(fspeed+lr);
Serial.println(fspeed-lr);
       }
  
       /*** Если включили реверс ***/
if(rc2_data <=1480){
fspeed=map(rc2_data,1480,1000,50,200);
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
analogWrite(ena, fspeed+lr);
    
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
analogWrite(enb, fspeed-lr);
Serial.println(fspeed+lr);
Serial.println(fspeed-lr);
       }
    }

/******Обработчик прерывания на возрастание и спаду******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А в чём проявляется проблема? Как едет без управления? Ровно?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Едет ровно! Нормальное движение при ШИМ от 75% ручки газа, АРХАТ говорит, что для танкового управления регулировка на ШИМ должна быть квадратичной, а для большей резвости даже кубической, Ваш ТАНК у внука как себя ведёт при поворотах?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нормально, но у нас по жизни квадратичное управление, просто в силу теоремы Пифагора, мы для этого никаких усилий не прикладываем.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Нормально, но у нас по жизни квадратичное управление, просто в силу теоремы Пифагора, мы для этого никаких усилий не прикладываем.

Для квадратичной мысль математика требуется, чтобы смиксировать сигналы должным образом и уложить в граничные значения шим, то-есть, есть скрость выставляем максимальную, ШИМ должен принимать максимальное значение

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

Для квадратичной мысль математика требуется

Всё намного проще.

Вот тут недавно Ворота пульсметр показывал. У него там совсем снимается сигнал с АЦП, а потом совсем нетривиально программно интегрируется не уходя от целых числе. для этого ему ажно int64_t потребовался. Хотя простенькая интегрирующая цепочка из резистора и конденсатора дала бы этот результат уже готовым с того же АЦП и считать не надо вообще ничего.

Так и здесь.

У нас стоит джйстик и мы подаём ШИМ пропорционально размерам катета ттреугольника, который образует ручка джойстика с ветрикальным направлением. Даже это объяснение черечур словжное -  настоьлькот там всё тривиально. В итога изменения именно квадратичные, т.к. зависимость размеров катетов квадратичная по теореме Пифагора. Если всё ещё непонятно, , я могу разрисовать картинку джойстика и что именно мы подаём.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

имею, по одному каналу принимаю уровень педали газа -1000 -1500 -2000 мксек
по второму каналу уровень с руля 1000 -1500 -2000 мксек, 1500 и руль и педаль газа - нулевое положение

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

Arhat109-2
Offline
Зарегистрирован: 24.09.2015
void aForward()
{
  digitalWrite(in1, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in3, HIGH);
}

void bForward()
{
  digitalWrite(in4, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in3, HIGH);
}

void aBackward()
{
  digitalWrite(in2, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in1, HIGH);
}

void bBackward()
{
  digitalWrite(in3, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in4, HIGH);
}

void aStop(){
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
}

void bStop()
{
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
}

void loop()
{
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -50,50);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    long speedA = (long)fspeed + lr*lr;
    long speedB = (long)fspeed - lr*lr;

    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    elseif( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    elseif( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

Доопределите, чего не хватает и подбирайте масштаб рулевого управления в map() так, чтобы скорость могла меняться

Не оптимально, ибо переключалки задействованы при каждом управлении, но тут оно как раз "без разницы" и даже повышает надежность ПО.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Мысль понятна, попробую

Получилось так, работает неправильно при старте назад едет прямо, вперёд - крутится только одна сторона

   volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;

volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (А)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -50,50);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    long speedA = (long)fspeed + lr*lr;
    long speedB = (long)fspeed - lr*lr;

    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

/******Обработчик прерывания на возрастание и спаду******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2


    void aForward()
{
  digitalWrite(in1, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in2, HIGH); // был неправильно указан контакт входа
}

void bForward()
{
  digitalWrite(in4, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in3, HIGH);
}

void aBackward()
{
  digitalWrite(in2, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in1, HIGH);
}

void bBackward()
{
  digitalWrite(in3, LOW);
  delayMicroseconds(4); // блокируем сквозняки на всякий случай
  digitalWrite(in4, HIGH);
}

void aStop(){
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
}

void bStop()
{
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
}


 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

if от else отделите. Накидал как идею, надеялся справитесь самостоятельно. Там ещё надо грамотно типизацию целых расставить, дабы лишнее в лонгах не гонять и на расширение до целого не нарваться. :)

Я бы ваще всё в байтовых переменных сделал. Изменение ШИМ на 1..2 практически не сказываются даже на легких тележках со скоростями под 5м/сек. Стало быть ШИМ можно считать в диапазоне -127 .. 127 и тупо домножать на 2, сдвигом при подаче на analogWrite() .. :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

отрабатывает следующим образом:
ручка газа вперёд, крутится правая сторона, поворачиваем руль вправо, в какой-то момент колёса правой стороны останавливаются и начинают крутиться назад, руль влево, то-же самое, в какой то момент поворота руля колёса правой стороныостанавливаюся и начинают крутится назад ))) левая сторона не дышит

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

)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, зачем Вам руль? Сделайте джойстик, как у нас и проблемы вообще не будет от слова совсем.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Да, зачем Вам руль? Сделайте джойстик, как у нас и проблемы вообще не будет от слова совсем.

у меня джойстик тоже выдает стандартизованные сигналы 1000 - 2000 )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Блин, Вы его не так используете. Ладно, чейчас мне надо убегать, завтра нарисую как его надо ставить и как интерпретировать сигналы.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Блин, Вы его не так используете. Ладно, чейчас мне надо убегать, завтра нарисую как его надо ставить и как интерпретировать сигналы.

я прикручиваю к стандартному комплекту радиоуправления, а там никакой самодеятельности )))

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Где-то, что-то напутано.

Закомментируйте if-else блоки непосредственного управления моторами и раскоментируйте вывод в Сериал, только сделайте подписи параметров, хотя бы так:

Serial.print(", spA="); Serial.print(speedA, DEC);

Перевод строки стараюсь ставить 1 раз в начале loop(), так видней что творится на одном проходе loop().

Посмотрите, что у вас получается в управляющих сигналах по результату приема в прерываниях, посмотрите что получается в качестве скоростей speedA,B ..

Скорее всего при квадратичной функции lr*lr у Вас слишком велико управление, но почему только на 1 мотор? В целом ШИМ в пределах 512 (от -255 до 255), соответственно квадрат рулевого должен попадать в эти пределы и макс рулевого маппинга нормально должен быть как SQRT(255) = 16, то есть подбор надо начинать примерно с такого:

map(rul, 1000, 2000, -16, 16)

и там вряд ли будет большое изменение .. 1,2 вряд ли больше 3,4. :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

Где-то, что-то напутано.

 по левому борту нашёл, строка 131, поправил
направление поиска понятно, вечером поищу

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Тогда проверьте и все остальные пины в блоках элементарного управления. Такие ошибки не ходят по одиночке. :) О результате отпишитесь - уже интересно что получится.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

Тогда проверьте и все остальные пины в блоках элементарного управления. Такие ошибки не ходят по одиночке. :) О результате отпишитесь - уже интересно что получится.

понятно, строки 74 и 75 при умножении на самое себя теряем знак, а он важен

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

lr*lr*sign(lr) домножить на знак, стало быть.

или так: fspeed + (lr*lr*(lr>=0? 1: -1))  :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

lr*lr*sign(lr) домножить на знак, стало быть.

или так: fspeed + (lr*lr*(lr>=0? 1: -1))  :)

так как языками не владею, хотел сделать как во второй строке только через if )))
Поправил, вечером попробую

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;

volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (А)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -50,50);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    long speedA = (long)fspeed +  (lr*lr*(lr>=0? 1: -1));
    long speedB = (long)fspeed -  (lr*lr*(lr>=0? 1: -1));

    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

/******Обработчик прерывания по возрастанию и спаду сигнала с приёмника RC******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2

//************** Функции работы с моторами привода *************//
void aForward(){digitalWrite(in1, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in2, HIGH);}

void bForward(){digitalWrite(in4, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in3, HIGH);}

void aBackward(){digitalWrite(in2, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in1, HIGH);}

void bBackward(){digitalWrite(in3, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in4, HIGH);}

void aStop(){ digitalWrite(in1, LOW);
              digitalWrite(in2, LOW);}

void bStop(){ digitalWrite(in3, LOW);
              digitalWrite(in4, LOW);}

немного изменил, чтобы при педали газа в нейтральном положении не ездила при вращении руля

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;
volatile long speedA;
volatile long speedB;
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (Б)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -12,12);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    if(rc2_data <=1480 || rc2_data >= 1520){
    speedA = (long)fspeed +  (lr*lr*(lr>=0? 1: -1));
    speedB = (long)fspeed -  (lr*lr*(lr>=0? 1: -1));
                                           } // ход только при нажатии педали газа 
    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

/******Обработчик прерывания по возрастанию и спаду сигнала с приёмника RC******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2

//************** Функции работы с моторами привода *************//
void aForward(){digitalWrite(in1, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in2, HIGH);}

void bForward(){digitalWrite(in4, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in3, HIGH);}

void aBackward(){digitalWrite(in2, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in1, HIGH);}

void bBackward(){digitalWrite(in3, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in4, HIGH);}

void aStop(){ digitalWrite(in1, LOW);
              digitalWrite(in2, LOW);}

void bStop(){ digitalWrite(in3, LOW);
              digitalWrite(in4, LOW);}

Немно поразмыслив добавил еще пару строк, как по мне получилась неплохая основа для скетча вездехода, что имеем - при движения прямо или назад "программная блокировка дифференциала всех ведущих колёс", поворотом руля влево или вправо можно добиться передачи усилия на пару из левых или правых колёс...
Машинка на аккумуляторах литий-ион бегает очень резво )))
 

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;
volatile long speedA;
volatile long speedB;
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (Б)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -12,12);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    if(rc2_data >=1481 && rc2_data <= 1519){speedA=0; speedB=0;}
    if(rc2_data <=1480 || rc2_data >= 1520){
    speedA = (long)fspeed +  (lr*lr*(lr>=0? 1: -1));
    speedB = (long)fspeed -  (lr*lr*(lr>=0? 1: -1));
                                           } // ход только при нажатии педали газа 
    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

/******Обработчик прерывания по возрастанию и спаду сигнала с приёмника RC******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2

//************** Функции работы с моторами привода *************//
void aForward(){digitalWrite(in1, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in2, HIGH);}

void bForward(){digitalWrite(in4, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in3, HIGH);}

void aBackward(){digitalWrite(in2, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in1, HIGH);}

void bBackward(){digitalWrite(in3, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in4, HIGH);}

void aStop(){ digitalWrite(in1, LOW);
              digitalWrite(in2, LOW);}

void bStop(){ digitalWrite(in3, LOW);
              digitalWrite(in4, LOW);}

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Здорово.

Но .. Вы так устранили чисто "танковый разворот" одной педалью руля, без газа.. может здря строки 75,76 и 79? :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

Здорово.

Но .. Вы так устранили чисто "танковый разворот" одной педалью руля, без газа.. может здря строки 75,76 и 79? :)

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

Баловства ради добавлю скетч переделанный под библиотеку PWM.hpp, точность библиотеки конечно ни о чём, зато позволяет обрабатывать до 20 каналов )))
 

#include "PWM.hpp"
PWM ch1(2); // Setup pin 2 for input
PWM ch2(3); // Setup pin 3 for input
PWM ch3(12); // Setup pin 12 for input

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
//volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
//volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;
volatile long speedA;
volatile long speedB;
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (Б)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
ch1.begin(true); // ch1 on pin 2 reading PWM HIGH duration
ch2.begin(true); // ch2 on pin 3 reading PWM HIGH duration
ch3.begin(true); // ch3 on pin 12 reading PWM HIGH duration

pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);

    } // END SETUP

    
void loop() {
  rc1_data = ch1.getValue();
    rc2_data = ch2.getValue();
      rc3_data = ch3.getValue();
     
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -12,12);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1520)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1520,2000,minPwm,200);
  }
  else if( rc2_data <= 1480 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1480,1000,-minPwm,-200);
  }
  else
  {
    // , иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    if(rc2_data >=1481 && rc2_data <= 1519){speedA=0; speedB=0;}
    if(rc2_data <=1480 || rc2_data >= 1520){
    speedA = (long)fspeed +  (lr*lr*(lr>=0? 1: -1));
    speedB = (long)fspeed -  (lr*lr*(lr>=0? 1: -1));
                                           } // ход только при нажатии педали газа 
    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}


//************** Функции работы с моторами привода *************//
void aForward(){digitalWrite(in1, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in2, HIGH);}

void bForward(){digitalWrite(in4, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in3, HIGH);}

void aBackward(){digitalWrite(in2, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in1, HIGH);}

void bBackward(){digitalWrite(in3, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in4, HIGH);}

void aStop(){ digitalWrite(in1, LOW);
              digitalWrite(in2, LOW);}

void bStop(){ digitalWrite(in3, LOW);
              digitalWrite(in4, LOW);}

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Да ну что тут такого-то .. главное что оно ездит у Вас, то бишь доведено до ума. Дитенок - доволен?

А то вот дорисовал мотор-редуктор на базе 4-х ступенчатого редуктора, т.с. "универсальный" с к-том передачи от 27.5 до 165 со "сменными шестеренками" .. и? Начал ваять "пробную версию" и столкнулся с проблемами: требуется точность изготовления менее 0.1мм, корпус имеет зазоры 0.3-0.5мм до шестеренок, толщина стенок 1мм - это ещё вольготно .. да, все это под "лего формат" редуктор со встроенным энкодером, типа EV3 "большой мотор", только в размере "средний мотор" .. сижу ломаю голову: КАК это воплотить в натуре в количестве хотя бы 4шт?

3Д принтер - не потянет, лазерная резка - как показал жопыт, аналогично .. а хочется. ;) Я понимаю, что китаезы способны сделать форму и наштамповать корпусов к этому чуду .. тока "цена вопроса" за 4-8шт ..

Ладно, это я так .. завидую..

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

Да ну что тут такого-то .. главное что оно ездит у Вас, то бишь доведено до ума. Дитенок - доволен?

Еще не доделал, сенсор надо сделать и окультурить, чуть попозжее, пока есть возможность и с другими бублиотеками поэкспериментировать

Да, у тележки база коротковата, надо за основу брать пропорции Вазовской НИВА 4х4
Подправил немного константы так как подключил аппаратуту FUTABA и добивался минимальных значений для триммирования (получилось уложиться в 5 единиц)
Всё управление на одном стике
 

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1500;
volatile unsigned int rc3_data = 1500;
volatile unsigned long start_timeRC1 = 0; //Канал 1 - руль
volatile unsigned long start_timeRC2 = 0; //Канал 2 - ход/педаль газа
volatile unsigned long prevTime;
volatile long speedA;
volatile long speedB;
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***L298N***/   
//Двигатель левого борта (А)
const int in1 = 4;    // direction pin 1
const int in2 = 7;    // direction pin 2
const int ena = 9;    // PWM pin to change speed
//Двигатель правого борта (Б)
const int in3 = 8;    // direction pin 1
const int in4 = 5;    // direction pin 2
const int enb = 6;    // PWM pin to change speed

int fspeed;           // скорость (ШИМ сигнал)
unsigned int fspeed_l = 0;
unsigned int fspeed_r = 0;
int lr;               // положение руля   
int minPwm = 50; 
int period = 10;
 
    
void setup() {
Serial.begin(115200);
pinMode(in1, OUTPUT);      // connection to L298n
pinMode(in2, OUTPUT);      // connection to L298n
pinMode(ena, OUTPUT);      // connection to L298n
pinMode(in3, OUTPUT);      // connection to L298n
pinMode(in4, OUTPUT);      // connection to L298n
pinMode(enb, OUTPUT);      // connection to L298n
analogWrite(ena, 0);
analogWrite(enb, 0);
    
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
//  Serial.println(rc1_data);
  lr = map(rc1_data,1000,2000, -12,12);
//  Serial.println(rc2_data);
     
  if(rc2_data >=1505)
  {
    // Если движение вперёд
    fspeed=map(rc2_data,1505,2000,minPwm,200);
  }
  else if( rc2_data <= 1495 )
  {
    // Если включили реверс .. д.б. ваще-то "иначе если .."
    fspeed=map(rc2_data,1495,1000,-minPwm,-200);
  }
  else
  {
    //  иначе стоп
    fspeed = 0;
  }

  // а теперь управляем моторами и нормируем скорости
  // только если прошел цикл (Fpwm=490гц или 2мсек!)
  // управлять моторами чаще чем раз в 10мсек - бессмысленно..

  if( millis() - prevTime >= period )
  {
    if(rc2_data >=1496 && rc2_data <= 1504){speedA=0; speedB=0;}
    if(rc2_data <=1495 || rc2_data >= 1505){
    speedA = (long)fspeed +  (lr*lr*(lr>=0? 1: -1));
    speedB = (long)fspeed -  (lr*lr*(lr>=0? 1: -1));
                                           } // ход только при нажатии педали газа 
    if( speedA > 255    ){ speedA =  255; }
    if( speedB > 255    ){ speedB =  255; }
    if( speedA < -255   ){ speedA = -255; }
    if( speedB < -255   ){ speedB = -255; }
    if( abs(speedA) < minPwm ){ speedA = 0; } // мотор не тянет, нет смысла жечь батарейку..
    if( abs(speedB) < minPwm ){ speedB = 0; }

    if( speedA > 0     ){ aForward();  analogWrite(ena,  (int)speedA); }
    else if( speedA < 0 ){ aBackward(); analogWrite(ena, -(int)speedA); }
    else                { aStop(); }
    
    if( speedB > 0     ){ bForward();  analogWrite(enb,  (int)speedB); }
    else if( speedB < 0 ){ bBackward(); analogWrite(enb, -(int)speedB); }
    else                { bStop(); }

    prevTime = millis();

//  Serial.println(speedA, DEC);
//  Serial.println(speedB, DEC);
  }
}

/******Обработчик прерывания по возрастанию и спаду сигнала с приёмника RC******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2

//************** Функции работы с моторами привода *************//
void aForward(){digitalWrite(in1, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in2, HIGH);}

void bForward(){digitalWrite(in4, LOW);
                delayMicroseconds(4); // блокируем сквозняки на всякий случай
                digitalWrite(in3, HIGH);}

void aBackward(){digitalWrite(in2, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in1, HIGH);}

void bBackward(){digitalWrite(in3, LOW);
                 delayMicroseconds(4); // блокируем сквозняки на всякий случай
                 digitalWrite(in4, HIGH);}

void aStop(){ digitalWrite(in1, LOW);
              digitalWrite(in2, LOW);}

void bStop(){ digitalWrite(in3, LOW);
              digitalWrite(in4, LOW);}

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Как вам квадратичное управление поворотом на "ручке управления", особенно на скоростях? Ощущается как верное или нет? Интересно..

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Arhat109-2 пишет:

Как вам квадратичное управление поворотом на "ручке управления", особенно на скоростях? Ощущается как верное или нет? Интересно..

Хотел даже ролик снять, крутиться можно очень неплохо

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

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

P.S. отсюда следствие (можно улучшить поведение): предпочтительней разгонять внешнее колесо чем тормозить внутренее. Можно сделать неравновесное управление внешним и внутренним колесом домножая квадрат управляющей величины lr на разные к-ты в зависимости от того цнутренне колесо или внешнее (больше/меньше нуля величина управления) .. попробуйте.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ну .. всегда приходится выбирать что-то одно (или трусы или крестик). В этом и состоит работа конструктора изделия. :) а так - да, улучшая динамику поворотов без снижения скорости вынужденно снижаем среднюю скорость движения по прямой и уменьшаем диапазон скоростей. Поэтому и писал и говорил всем страждущим на соревнованиях: хотите иметь агрессивную динамику в поворотах и неплохую скорость на прямой .. выводите макс. движение по прямой (ШИМ 255) на 5м/сек, тогда можно ехать 2.5-3 метра по прямой на трассе и оч. хорошо вилять в поворотах и давить колебания тележки а-ля ПИДом. Запас. Но .. тут он как раз "тянет карман"..

Onkel
Offline
Зарегистрирован: 22.02.2016

Arhat109-2 пишет:

Да ну что тут такого-то . .. сижу ломаю голову: КАК это воплотить в натуре в количестве хотя бы 4шт?

3Д принтер - не потянет, л  ..

Ладно, это я так .. завидую..

Я себе для решения таких задач фотополимерник Photon Any Cubic купил, работает из коробки с одной настройкой - высотой.

 

Onkel
Offline
Зарегистрирован: 22.02.2016

ua6em пишет:

 

Хотел даже ролик снять, крутиться можно очень неплохо

у меня дети в кружке сделали на линейной, тут вариант на BT, но есть такой же на FlySky 3- канальной (скорость, угол, свет), если интересно код могу выложить, или можно скачать с hackaday.
https://youtu.be/jDATptM75Ew

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Onkel пишет:

ua6em пишет:

 

Хотел даже ролик снять, крутиться можно очень неплохо

у меня дети в кружке сделали на линейной, тут вариант на BT, но есть такой же на FlySky 3- канальной (скорость, угол, свет), если интересно код могу выложить, или можно скачать с hackaday.
https://youtu.be/jDATptM75Ew

я бы посмотрел, интересно как реализовали обработку приёмника

Onkel
Offline
Зарегистрирован: 22.02.2016

Код обработки приемника - пины А0-А2 задействованы для входов с приемника, для них прерывания включены, в setup

  EICRA = 0x00; //  INT0 INT1 Type didn't matter
  EIMSK = 0x00; //       INT0 INT1 disabled

  PCMSK0 = 0x00; // маска прерываний по пинам B
  PCMSK1 = 0x07; // Pin change mask pins C0 C1 C2 ENABLE any change
  PCMSK2 = 0x00;// маска прерываний по пинам D
  PCIFR = 0x02; //PCINT 14-8 Flag   clear на всякий пожарный
  PCICR = 0x02; //Pins C0 - C5 interruptions enable  разрешить прерывание по пинам C по маске 3 стр. выше

а сам обработчик прерывания- включается при change, когда соотв. пин ввер- записывает таймер micros() в переменную, когда пин вниз- считает длину импульса, ну и дуракозащита некая, часть в обработчике (что вобщем неправильно - должно быть минимально), часть в основном коде. Кто вверх - кто вниз вычисляем исходя из предыдущего состояния пинов. Поскольку обработчик должен действовать по принципу "ударил - убежал", то напрямую юзаем регистры вместо медленных (4-7 мкс)  digitalRead, ну может пропустили где. Дискретностью micros() (4 мкс) пренебрегаем, все равно это меньше шим шума нашего комплекта (до 12 доходит). ModeLight управляется переключателем пульта, вкл/выкл, а Speed и Turn - курок и крутилка соотв. RC FlySky 3 канала автомобильный.

ISR (PCINT1_vect)// pin change interrupt for A0 to A5
{

  if (  ( (PINC & 0x01) == 0 )     && ((OldC & 0x01) == 1)      )
    {
    Turn= int(micros()-Time0 )-1500;
    if(Turn<-20)
    {
    ModeLight|=0x08;
    ModeLight&= ~0x10;
    }
    else if (Turn>20)
{
    ModeLight&=  ~0x08;
    ModeLight |= 0x10;
    }
else
{
ModeLight&=  ~0x08;
  ModeLight&= ~0x10;
}
    
    }

  if (  ( (PINC & 0x01) == 1 )     && ((OldC & 0x01) == 0)      )
  {
    Time0=micros();
  }

   if (  ( (PINC & 0x02) == 0 )     && ((OldC & 0x02) == 2)      )
    {
    Speed= 1500-int(micros()-Time1 ) ;

      if(Speed>300)
      ModeLight |= 0x40;
      else
      ModeLight &=~0x40;
      

      if(Speed< -300)
      ModeLight |= 0x20;
      else
      ModeLight &=~0x20;

      if(Speed>10)
      ModeLight |=0x01;
      else
      ModeLight &= ~0x01;

 if(Speed < -10)
      ModeLight |=0x02;
      else
      ModeLight &= ~0x02;

      

Aavr=(2* (Speed-OldSpeed)+ (NEXP-1)*Aavr)/(NEXP+1);
if (Aavr<-4  && Speed> -4)
{
ModeLight |= 0x80;
}
else if(Aavr>-4)
{
ModeLight &= ~0x80;
}

OldSpeed=Speed;



    
    }

  if (  ( (PINC & 0x02) == 2 )     && ((OldC & 0x02) == 0)      )
  {
    Time1=micros();
  }

  if (  ( (PINC & 0x04) == 0 )     && ((OldC & 0x04) == 4)      )
    {
    Mode= int(micros()-Time2 )-1500;
    if (Mode <-100)
    ModeLight &= ~0x04;
    else
    ModeLight |= 0x04;
    }

  if (  ( (PINC & 0x04) == 4 )     && ((OldC & 0x04) == 0)      )
  {
    Time2=micros();
  }
  

  OldC = PINC;
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Понятно!!!
А вместо micros() 16 битный счетчик не пробовали использовать?
Кстати у меня аналогичная аппаратура есть, так сильно не моросит, максимум 1 микросекунда

Onkel
Offline
Зарегистрирован: 22.02.2016

Пока задача столь высокой точности не стоит - используются analogWrite(), а они все равно 8 бит, а обратная связь только по азимуту, по скорости не контролируем. Была задача постоянной скорости, там по энкодерам считали.

 

Fenicksnet
Offline
Зарегистрирован: 25.03.2019

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

Вопрос: что дописать чтобы при потере связи всё остоновилось? Это машинка в которой ездит ребенок.

volatile unsigned int rc1_data = 1500;
volatile unsigned int rc2_data = 1330;

volatile unsigned long start_timeRC1 = 0; //Канал 1 -диг
volatile unsigned long start_timeRC2 = 0; //Канал 2 руль
volatile byte flag_RC1 = 0;
volatile byte flag_RC2 = 0;
    
             /***MMSHILD***/   
//Дрыгатель левого борта (А)
const int in1 = 7;    //  INA 1
const int in2 = 8;    //  INB 1
const int ena = 5;    // PWM 1
//Дрыгатель правого борта (А)
const int in3 = 4;    // INA 2
const int in4 = 9;    // INB 2
const int enb = 6;    // PWM 2

int fspeed;           // скорость (ШИМ сигнал)

 int sp = 0;          // ПОТЕНЦИЯ ЛОКАЛЬНАЯ СКОРОСТИ
 int spt;            // ПЕРЕМЕННАЯ ПОТЕНЦИИ ЛОКАЛЬНОЙ
 int rev = 5;         // АНАЛОГ ПИН А5 КВЛ ВПЕРЕД ИЛИ НАЗАД
//руль
int lr;               // положение руля    
int reve;             // ПЕРЕМЕННАЯ 



 const int rl = 11;  // pwm РУЛЬ  
 const int l = 12;   //ЛЕВО
 const int r = 13;   //ПРАВО
 
void setup() {
Serial.begin(9600);
pinMode(in1, OUTPUT);      //
pinMode(in2, OUTPUT);      // 
pinMode(ena, OUTPUT);      // 
pinMode(in3, OUTPUT);      // 
pinMode(in4, OUTPUT);      // 
pinMode(enb, OUTPUT);      // 
analogWrite(ena, 0);
analogWrite(enb, 0);
pinMode (sp, INPUT);
pinMode (rev, INPUT);
 pinMode(rl, OUTPUT);
 pinMode(l, OUTPUT);
 pinMode(r, OUTPUT);   
 
    // Привязываем к Pin2 прерывание по фронту и спаду сигнала
attachInterrupt(0, Rc1, CHANGE);
    // Привязываем к Pin3 прерывание по фронту и спаду сигнала
attachInterrupt(1, Rc2, CHANGE);
    } // END SETUP

    
void loop() {
  
  Serial.print("      rc1_data    ==  ");
  Serial.print(rc1_data);

  Serial.print("      rc2_data    ==  ");
  Serial.print(rc2_data);

  Serial.print("       REVE    ==  ");
  Serial.print(reve);


  Serial.print("       SP    ==  ");
  Serial.println(spt);
reve = analogRead(rev);
spt = analogRead(sp);
   if (reve <= 500 && reve >= 801 )
   { spt = 0; 
     analogWrite(enb, spt);
     analogWrite(ena, spt);
      fspeed=0;
     digitalWrite(in1, LOW);
     digitalWrite(in2,LOW);
     analogWrite(ena, fspeed);
     digitalWrite(in3, LOW);
     digitalWrite(in4,LOW );
     analogWrite(enb, fspeed);
   }
     
     if (spt<=10 && rc1_data <=1530 && rc1_data >= 1490 )
   { 
     fspeed=0;
     digitalWrite(in1, LOW);
     digitalWrite(in2,LOW);
     analogWrite(ena, fspeed);
     digitalWrite(in3, LOW);
     digitalWrite(in4,LOW );
     analogWrite(enb, fspeed);
   } 
// Если движение вперёд
   if (spt >=10 && rc1_data <=1530 && rc1_data >= 1490 && reve >= 700 && reve <=800)
   {
      spt= map ( spt,11, 1023, 0,255);
     digitalWrite(in1,LOW);
     digitalWrite(in2,HIGH);
     analogWrite(ena, spt);
     digitalWrite(in3, LOW);
     digitalWrite(in4,HIGH );
     analogWrite(enb, spt);
   }
     
     if (spt >=10 && rc1_data <=1530 && rc1_data >= 1490 && reve <= 699 && reve >= 650)
   {
      spt= map ( spt,11, 1023, 0,255);
     digitalWrite(in1,HIGH);
     digitalWrite(in2,LOW);
     analogWrite(ena, spt);
     digitalWrite(in3,HIGH);
     digitalWrite(in4,LOW );
     analogWrite(enb, spt);
   }

     // ВПЕРЕД ПУЛЬТ
  else if(rc1_data >=1530)
  {
    fspeed=map(rc1_data,1531,2100,10,255);
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    analogWrite(ena, fspeed);
    
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);
    analogWrite(enb, fspeed);
  }
  
       // НАЗАД ПУЛЬТ 
   else if(rc1_data <=1489)
   {
   fspeed=map(rc1_data,1488,930,30,255);
   digitalWrite(in1, HIGH);
   digitalWrite(in2, LOW);
   analogWrite(ena, fspeed);
    
   digitalWrite(in3, HIGH);
   digitalWrite(in4, LOW);
   analogWrite(enb, fspeed);
   }
////////////////////////руль(пока так)
   if (rc2_data >= 1320 && rc2_data <= 1355)
    {
    lr = 0;
    digitalWrite(l, LOW);
    digitalWrite(r, LOW);
    analogWrite(rl, lr);
    }
    else if (rc2_data >= 1356)
    {lr = map(rc2_data, 1357,1850,100,255);
    digitalWrite(l, HIGH);
    digitalWrite(r, LOW);
    analogWrite(rl, lr);
    }
    else if (rc2_data <= 1319)
    {
    lr = map(rc2_data, 1318,885,100,255);
    digitalWrite(l, LOW);
    digitalWrite(r, HIGH);
    analogWrite(rl, lr);
    }
}

/******Обработчик прерывания на возрастание и спаду******/
void Rc1() {
if(digitalRead(2) == HIGH && flag_RC1==0){
     //сохраняем значение времени начала импульса
start_timeRC1 = micros();
flag_RC1=1;
    }
if(digitalRead(2) == LOW && flag_RC1==1){
    //сохраняем значение длительности импульса канала 1
rc1_data = micros() - start_timeRC1; 
flag_RC1=0; 
    }
   }//END RC1
    
 void Rc2() {
    if(digitalRead(3) == HIGH && flag_RC2==0){
     //сохраняем значение времени начала импульса канала 2
    start_timeRC2 = micros();
    flag_RC2=1;
    }
    if(digitalRead(3) == LOW && flag_RC2==1){
    //сохраняем значение длительности импульса
    rc2_data = micros() - start_timeRC2; 
    flag_RC2=0; 
    }
   }//END RC2 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

выставить на аппаратуре файлсэйв по газу на 1500 и включить его, тогда при потере связи с пультом машинка остановится

Fenicksnet
Offline
Зарегистрирован: 25.03.2019

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

Onkel
Offline
Зарегистрирован: 22.02.2016

Заведите счетчик, например NoSignalCounter , в прерываниях его обнуляйте, а в loop напишите

if(NoSignalCounter++> CriticalNumber)

Stop=1;

else

Stop=0;

 и введите во все if, в которых задается скорость,  условие  Stop==0

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Onkel пишет:

Заведите счетчик, например NoSignalCounter , в прерываниях его обнуляйте, а в loop напишите

if(NoSignalCounter++> CriticalNumber)

Stop=1;

else

Stop=0;

 и введите во все if, в которых задается скорость,  условие  Stop==0

при обрыве связи, если не выставлен файлсэйв приёмник гонит последнее принятое значение

Onkel
Offline
Зарегистрирован: 22.02.2016

Все верно, но так я и предлагаю выдавать нуль на пины силового H-моста после CriticalNumber прокруток loop() если не было ни одного прерывания. Когда срабатывают прерывания, то у нас выставляется NoSignalCounter=0; , а в каждой прокрутке loop() выполняется NoSignalCounter++. Как только петля прокрутилась большее чем надо раз - выставляем флаг Stop=0.
 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

можно еще подключить 3-й канал и на нём выставить файлсейв, по третьему каналу при файлсэйве выставите 0, этим нулём и тушите моторы, то-есть при обрыве связи приёмник выставит вам на канале 0, третий канал можно подцепить на PCINT

Fenicksnet
Offline
Зарегистрирован: 25.03.2019

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Fenicksnet пишет:

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

вот, код оказался полезен не только для игрушки )))