Control 2 BTS with Arduino & Flysky fs6x

So I am using the following the code to control 2 BTS 7960 to run motors. Turned on Evelin on Flysky. Now when I run it the direction of the motors is okay. Everything is working but I can only control speed of one BTS 7960 thus one motor only. The other one runs on a constant speed. Even though direction is correct. Can anyone please find out why the other BTS 7960's speed control (I am guessing "pot2") is not working?

#define RPWM 5
#define LPWM 6
#define RPWM2 10
#define LPWM2 11


int pot;
int pot2;
int out1;
int out2;
int out3;
int out4;

void setup() {
  Serial.begin(9600);
  pinMode(RPWM,OUTPUT);
  pinMode(LPWM,OUTPUT);
  pinMode(RPWM2,OUTPUT);
  pinMode(LPWM2,OUTPUT);
  pinMode(pot,INPUT);
  pinMode(pot2,INPUT);
}
 
 
void loop() {
  
  pot=pulseIn(A0, HIGH, 25000);
  pot2=pulseIn(A1, HIGH, 25000);
  
if((pot==0)&&(pot2==0))
  {
    analogWrite(RPWM,0);
    analogWrite(LPWM,0);
    analogWrite(RPWM2,0);
    analogWrite(LPWM2,0);
  }  

else if((pot>1530)&&(pot2>1530)){
    out1=map(pot, 1530, 2000, 0, 255);
    out4=map(pot2, 1530, 2000, 0, 255);
    analogWrite(RPWM,out1);
    analogWrite(LPWM,0);
    analogWrite(RPWM2,0);
    analogWrite(LPWM2,out4);
  }

else if((pot>1530)&&(pot2<1460)){
    out1=map(pot, 1530, 2000, 0, 255);
    out3=map(pot2, 1460, 1000, 0, 255);
    analogWrite(RPWM,out1);
    analogWrite(LPWM,0);
    analogWrite(RPWM2,out3);
    analogWrite(LPWM2,0);
  }

else if((pot<1460)&&(pot2>1530)){
    out2=map(pot, 1460, 1000, 0, 255);
    out4=map(pot2, 1530, 2000, 0, 255);
    analogWrite(RPWM,0);
    analogWrite(LPWM,out2);
    analogWrite(RPWM2,0);
    analogWrite(LPWM2,out4);
  }

else if((pot<1460)&&(pot2<1460)){
    out2=map(pot, 1460, 1000, 0, 255);
    out3=map(pot2, 1460, 1000, 0, 255);
    analogWrite(RPWM,0);
    analogWrite(LPWM,out2);
    analogWrite(RPWM2,out3);
    analogWrite(LPWM2,0);
    
  }
else
  {
    analogWrite(RPWM,0);
    analogWrite(LPWM,0);
    analogWrite(RPWM2,0);
    analogWrite(LPWM2,0);
  }
  delay(10);
}

Would you post a system drawing and a photo? It will help in diagnosing the issue.

If "everything is working but one motor does not change speed", it is probably pin mis-wire or pin mis-code, or power supplied is not enough for two (one motor has less resistance, and electricity finds the path of least resistance).


I know it is hard to understand from the photo. This is basically the circuit.

The drawing is good.

How much current do the motors and motor drivers require, and how much current will the battery (written on side?) supply?

To test the "good" motor versus the "bad" motor, either change the code to send "good" motor signals to the "bad" motor (and bad to good), or change B+/B- wires from the battery to the driver boards for "good" and "bad" battery. The problem will either stay with a motor or move to the other motor (or will start working both motors or will stop working both motors)

`#define RPWM2 3


Not sure about the current. Motor works on 12V max. And BTS 7960 can take upto 43A current. Also cannot find the battery current supply.

Battery looks right for the RC behind it. Refer to @ua6em pin change, and verify what works (and what does not) and post your results here.

Check drivers individually!!!

// #define DEBUG

#include "FlexPWM.h"

const uint8_t EN    = 10; // № вывода Arduino к которому подключены входы драйвера L_EN и R_EN. Можно указать любой вывод Arduino поддерживающий ШИМ.
const uint8_t L_PWM = 7;  // № вывода Arduino к которому подключён  вход  драйвера L_PWM.       Можно указать любой вывод Arduino, как цифровой, так и аналоговый.
const uint8_t R_PWM = 8;  // № вывода Arduino к которому подключён  вход  драйвера R_PWM.       Можно указать любой вывод Arduino, как цифровой, так и аналоговый.
#define R_IS A6
#define L_IS A7
#define CW_R_IS 58
#define CW_L_IS 30
#define CCW_R_IS 35
#define CCW_L_IS 46

volatile int current_Ris, current_Lis;
uint32_t old_m = 0;
uint16_t tau = 3000;

volatile int aread5, aread6, aread7;

void setup() {
  Serial.begin(115200);
  pinMode(EN,    OUTPUT);     // Конфигурируем вывод EN    как выход (выход Arduino, вход драйвера)
  pinMode(L_PWM, OUTPUT);     // Конфигурируем вывод L_PWM как выход (выход Arduino, вход драйвера)
  pinMode(R_PWM, OUTPUT);     // Конфигурируем вывод R_PWM как выход (выход Arduino, вход драйвера)
  pwmInit(16); // ШИМ 16 бит используем на Pin10 (Timer1) 244Hz

  // ADC
  OCR0A = 0xAF;
  TIMSK0 |= 1 << OCIE0A;
  ADMUX = 1 << REFS0; // AVCC with external capacitor at AREF pin
  ADCSRA = (1 << ADEN) | (1 << ADATE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  ADCSRB = (1 << ADTS1) | (1 << ADTS0); // Timer/Counter0 Compare Match A
  // END-SETUP
}

ISR(TIMER0_COMPA_vect) {
  static uint8_t n = 5;
  ADMUX = ADMUX & 0b11111000 | n;
  switch (n) {
    case 5: aread7 = ADC; n = 6;  current_Lis = RunMiddleArifmLis(aread7); break;
    case 6: aread5 = ADC; n = 7;   break;
    case 7: aread6 = ADC; n = 5;  current_Ris = RunMiddleArifmRis(aread6); break;
  }
}


// фильтр среднее с буфером R_IS
uint32_t RunMiddleArifmRis(uint32_t newVal) {
#define NUM_Array 8  // порядок фильтра
  static uint32_t ret, buff, buffer[NUM_Array];
  static uint8_t i;
  if (++i >= NUM_Array) {
    i = 0;
  }
  buff += newVal;
  buff -= buffer[i];
  buffer[i] = newVal;
  ret = buff / NUM_Array;
  return ret;
}
//
// фильтр среднее с буфером L_IS
uint32_t RunMiddleArifmLis(uint32_t newVal) {
#define NUM_Array 8  // порядок фильтра
  static uint32_t ret, buff, buffer[NUM_Array];
  static uint8_t i;
  if (++i >= NUM_Array) {
    i = 0;
  }
  buff += newVal;
  buff -= buffer[i];
  buffer[i] = newVal;
  ret = buff / NUM_Array;
  return ret;
}
//

void loop() {
  //  Движение вперёд на 50% скорости:
  digitalWrite(L_PWM, LOW );  // Устанавливаем логический 0 на входе драйвера L_PWM, значит на выходе драйвера M- будет установлен потенциал S-
  digitalWrite(R_PWM, HIGH);  // Устанавливаем логическую 1 на входе драйвера R_PWM, значит на выходе драйвера M+ будет установлен потенциал S+
  pwmWrite10(32767);
  // analogWrite (EN,    127 );  // Устанавливаем 50% ШИМ на входах драйвера L_EN и R_EN, это скорость, можно установить от 0 (0%) до 255 (100%).
  old_m = millis();
  Serial.println();
  Serial.println("Вперёд на 50%");
  while (millis() - old_m <= tau)
  {
    if (millis() % 250 == 0)
    {
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CW_L_IS);
#endif
    }
  }
  
  // delay(3000);             // Ждём 3 секунды. ШИМ и логические уровни останутся без изменений, значит мотор продолжит вращаться с указанной скоростью и направлением.

  //  Движение вперёд на 100% скорости:
  digitalWrite(L_PWM, LOW );  // Устанавливаем логический 0 на входе драйвера L_PWM, значит на выходе драйвера M- будет установлен потенциал S-
  digitalWrite(R_PWM, HIGH);  // Устанавливаем логическую 1 на входе драйвера R_PWM, значит на выходе драйвера M+ будет установлен потенциал S+
  pwmWrite10(65535);
  //  analogWrite (EN,    255 );  // Устанавливаем 100% ШИМ на входах драйвера L_EN и R_EN, это скорость. Если устанавливаемое значение 255, то функцию можно заменить на digitalWrite(EN, HIGH);
  Serial.println();
  Serial.println("Вперёд на 100%");

  old_m = millis();
  while (millis() - old_m <= tau)
  {
    if (millis() % 250 == 0) 
    {
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CW_L_IS);
#endif
    }
  }
  // delay(3000);               // Ждём 3 секунды. ШИМ и логические уровни останутся без изменений, значит мотор продолжит вращаться с указанной скоростью и направлением.
  //  Свободное вращение:

  digitalWrite(EN,    LOW );  // Устанавливаем логический 0 на входах драйвера L_EN и R_EN, значит выходы M+ и M- перейдут в состояние высокого импеданса и мотор будет электрически отключён.
  Serial.println();
  Serial.println("Свободное вращение");
  //  pwmWrite10(0);
  old_m = millis();
  while (millis() - old_m <= tau) 
  {
    if (millis() % 250 == 0) 
    { 
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CW_L_IS);
#endif
    }
  }

  //  delay(3000);            // Ждём 3 секунды. Логические уровни на входах драйвера L_PWM и R_PWM не имеют значения (могут быть любыми).

  //  Движение назад на 50% скорости:
  digitalWrite(L_PWM, HIGH);  // Устанавливаем логическую 1 на входе драйвера L_PWM, значит на выходе драйвера M- будет установлен потенциал S+
  digitalWrite(R_PWM, LOW );  // Устанавливаем логический 0 на входе драйвера R_PWM, значит на выходе драйвера M+ будет установлен потенциал S-
  pwmWrite10(32767);
  //  analogWrite (EN,    127 );  // Устанавливаем 50% ШИМ на входах драйвера L_EN и R_EN, это скорость, можно установить от 0 (0%) до 255 (100%).
  Serial.println();
  Serial.println("Назад на 50%");
  old_m = millis();
  while (millis() - old_m <= tau) 
  {
    if (millis() % 250 == 0) 
    {
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CCW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CCW_L_IS);
#endif
    }
  }
  //  delay(3000);            // Ждём 3 секунды. ШИМ и логические уровни останутся без изменений, значит мотор продолжит вращаться с указанной скоростью и направлением.

  //  Движение назад на 100% скорости:
  digitalWrite(L_PWM, HIGH);  // Устанавливаем логическую 1 на входе драйвера L_PWM, значит на выходе драйвера M- будет установлен потенциал S+
  digitalWrite(R_PWM, LOW );  // Устанавливаем логический 0 на входе драйвера R_PWM, значит на выходе драйвера M+ будет установлен потенциал S-
  pwmWrite10(65535);
  //  digitalWrite(EN,    HIGH);  // Эта функция выполнит те же действия что и функция analogWrite(EN, 255);
  Serial.println();
  Serial.println("Назад на 100%");
  old_m = millis();
  while (millis() - old_m <= tau) 
  {
    if (millis() % 250 == 0) 
    {
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CCW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CCW_L_IS);
#endif
    }
  }
  //  delay(3000);            // Ждём 3 секунды. Логические уровни останутся без изменений, значит мотор продолжит вращаться с указанной скоростью и направлением.
 
  //  Торможение с силой 50%:
  digitalWrite(L_PWM, HIGH);  // Устанавливаем логическую 1, но можно установить и логический 0, главное что бы уровни на входах драйвера L_PWM и R_PWM совпадали.
  digitalWrite(R_PWM, HIGH);  // Устанавливаем логическую 1, но можно установить и логический 0, главное что бы уровни на входах драйвера L_PWM и R_PWM совпадали.
  pwmWrite10(32767);
  //  analogWrite (EN,    127 );  // Устанавливаем 50% ШИМ на входах драйвера L_EN и R_EN, это сила торможения, можно установить от 0 (0%) до 255 (100%).
  Serial.println();
  Serial.println("Торможение с силой 50%");

  old_m = millis();
  while (millis() - old_m <= tau) 
  {
    if (millis() % 250 == 0) 
    {
#ifdef DEBUG
      Serial.print("R_IS="); Serial.print(current_Ris);
      Serial.print(" L_IS="); Serial.println(current_Lis);
#else
      Serial.print("R_IS="); Serial.print(current_Ris * CW_R_IS);
      Serial.print(" L_IS="); Serial.println(current_Lis * CCW_L_IS);
#endif
    }
  }
  // delay(3000);
}

FlexPWM.h

// <a href="https://arduino.ru/forum/programmirovanie/shim-proizvolnogo-razresheniya-na-unonano-328" rel="nofollow">https://arduino.ru/forum/programmirovanie/shim-proizvolnogo-razresheniya-na-unonano-328</a>
/*
Бит Макс                               Частота контроллера (МГц)
             1            2           4             8             16           20
2   3      250 000,0   500 000,0  1 000 000,0     2 000 000,0   4 000 000,0   5 000 000,0
3   7      125 000,0   250 000,0    500 000,0     1 000 000,0   2 000 000,0   2 500 000,0
4   15      62 500,0   125 000,0    250 000,0       500 000,0   1 000 000,0   1 250 000,0
5   31      31 250,0    62 500,0    125 000,0       250 000,0     500 000,0     625 000,0
6   63      15 625,0    31 250,0     62 500,0       125 000,0     250 000,0     312 500,0
7   127      7 812,5    15 625,0     31 250,0        62 500,0     125 000,0     156 250,0
8   255      3 906,3     7 812,5     15 625,0        31 250,0      62 500,0      78 125,0
9   511      1 953,1     3 906,3      7 812,5        15 625,0      31 250,0      39 062,5
10  1 023      976,6     1 953,1      3 906,3         7 812,5      15 625,0      19 531,3
11  2 047      488,3       976,6      1 953,1         3 906,3       7 812,5       9 765,6
12  4 095      244,1       488,3        976,6         1 953,1       3 906,3       4 882,8
13  8 191      122,1       244,1        488,3           976,6       1 953,1       2 441,4
14  16 383      61,0       122,1        244,1           488,3         976,6       1 220,7
15  32 767      30,5        61,0        122,1           244,1         488,3         610,4
16  65 535      15,3        30,5         61,0           122,1         244,1         305,2
 */
 
#ifndef  FlexPWM_h
#define FlexPWM_h

#define __bit(b) (1u << (b))

inline void pwmInit(const int8_t bitRate = 16) {
  noInterrupts();
  TCCR1A = __bit(WGM11);
  TCCR1B = __bit(WGM13) | __bit(WGM12) | __bit(CS10);
  TCCR1C = TCNT1 = OCR1A = OCR1B = TIMSK1 = TIFR1 = 0;
  ICR1 = (1u << bitRate) - 1u;
  interrupts();
}

inline void pwmWrite9(const uint16_t v) { 
  DDRB |= __bit(PB1);
  TCCR1A |= __bit(COM1A1);
  OCR1A = v;
}

inline void digitalWrite9(const uint8_t v) {
  DDRB |= __bit(PB1);
  TCCR1A &= ~__bit(COM1A1); 
  if (v) PORTB |= __bit(PB1); else PORTB &= ~__bit(PB1);
}

inline void pwmWrite10(const uint16_t v) {
  DDRB |= __bit(PB2);
  TCCR1A |= __bit(COM1B1);
  OCR1B = v;
}

inline void digitalWrite10(const uint8_t v) {
  DDRB |= __bit(PB2);
  TCCR1A &= ~__bit(COM1B1);
  if (v) PORTB |= __bit(PB2); else PORTB &= ~__bit(PB2);
}

#endif  // FlexPWM_h

The drivers seems alright. If I switch 5,6 pin with 10,11 pin then the opposite motors doesn't work (speed control does not work). It means the problem is with my code. Changed define pin to 3, results are same as before.

MY SKETCH

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);}

1 Like

Thank you for sharing this.
Although code for L298N motor driver shield is a bit different then mine BTS 7960.
It has one speed controlling pin for 1 motor where I have two (RPWM, LPWM) for a single motor.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.