Problem with else if

Hello

I am having a little issue with a code I have.
The idea is I'm controlling a motor via an ESC with an RC controller
the stop command works, the reverse command works, but the forward command only kinda works, the motor turns but will intermittently stop and start again.
if I remove the ( digitalWrite (RMotorDir, HIGH); ) from the second 'else if' the forward command works fine

#include <Servo.h>

#define RCPinFWD 2    //Right RC stick
#define RCPinSide 3   // Left RC stick
#define RMotorStop 4  //Right mortor stop contorll
#define RMotorDir 5   //Right mortor stop contorll
#define LMotorStop 6  //Left mortor stop contorll
#define LMotorDir 7   //Left mortor stop contorll

Servo RightMotor;
Servo LeftMotor;

volatile long StartTimeFWD = 0;
volatile long CurrentTimeFWD = 0;
volatile long PulsesFWD = 0;
int PulseWidthFWD = 0;

volatile long StartTimeSide = 0;
volatile long CurrentTimeSide = 0;
volatile long PulsesSide = 0;
int PulseWidthSide = 0;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
  pinMode(RCPinFWD, INPUT_PULLUP);
  pinMode(RCPinSide, INPUT_PULLUP);
  pinMode(RMotorStop, OUTPUT);
  pinMode(RMotorDir, OUTPUT);
  pinMode(LMotorStop, OUTPUT);
  pinMode(LMotorDir, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(RCPinFWD),PulseTimerFWD,CHANGE);
  attachInterrupt(digitalPinToInterrupt(RCPinSide),PulseTimerSide,CHANGE);
  RightMotor.attach(10);
  LeftMotor.attach(11);
  digitalWrite (RMotorStop, HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
 //only save pulse lengths that are less than 2000 microseconds
  if (PulsesFWD < 2000){
    PulseWidthFWD = PulsesFWD;
  } 
  if (PulsesSide < 2000){
    PulseWidthSide = PulsesSide;
  } 
  Serial.print(PulseWidthFWD);
  Serial.print("    ");
  Serial.println(PulseWidthSide);

  if ((PulseWidthFWD < 1540) && (PulseWidthFWD > 1480)){      //If the stick is centered stop
    digitalWrite (RMotorStop, HIGH);
  } 
  else if (PulseWidthFWD > 1540){                             //if stick is up motor forward
    digitalWrite (RMotorStop, LOW);
    digitalWrite (RMotorDir, LOW);
    PulseWidthFWD = map(PulseWidthFWD, 1540, 1900, 0, 180);
    RightMotor.write(PulseWidthFWD);
  } 
  else if (PulseWidthFWD < 1480){                           //if stick is down motor backwards
    digitalWrite (RMotorStop, LOW);
    digitalWrite (RMotorDir, HIGH);
    PulseWidthFWD = map(PulseWidthFWD, 1480, 1100, 0, 180);
    RightMotor.write(PulseWidthFWD);
    }
}

void PulseTimerFWD(){
  CurrentTimeFWD = micros();
  if (CurrentTimeFWD > StartTimeFWD){
    PulsesFWD = CurrentTimeFWD - StartTimeFWD;
    StartTimeFWD = CurrentTimeFWD;
  }
}
void PulseTimerSide(){
  CurrentTimeSide = micros();
  if (CurrentTimeSide > StartTimeSide){
    PulsesSide = CurrentTimeSide - StartTimeSide;
    StartTimeSide = CurrentTimeSide;
  }
}

Hi @bdbobo, welcome to the forum.

I can't run your code from where I am, so for now I suggest that you turn up the band rate on your serial comms, make sure it matches in the serial monitor window, and…

be liberal with Serial.print statements to verify the values of key variables and confirm that they inform flow through your code correctly.

Like 115200. Mostly so the printing is less likely to add stray milliseconds in significant numbers.

Also, I now see you using interrupts. The variables look properly volatalised, but it does not appear that you are protecting access to muktibyte variables outside the ISR.

Most use

  noInterrupts();
  unsinged long myCopy = isrLongVariabke;
  interrupts()

and use myCopy further down instead of isrLongVariabke.

a7

i not understand what is problem. you say your code working fine. what you want more?

i not understand the purpose: you have PWM from RC and generate same PWM for servo modules. why not connect them directly?

it almost works mostly fine, but when the motor spins forward it stops briefly and then continuies, I will try and get a video of the issue.
I'm not connecting it directly cus I will be running 2 motors, but I need to be able to control turning and forwards and backwards from just 2 channels

don't forget to provide type of ESC, it is not usual to have DIR signal

and where is the code part for left motor? are you sure they are BLDC motors?

I'm looking at it. I'm in transit and can't, but I would throw the hole thing into the simulator

)or even just IRL) and ditch the interrupts for now and instead use potentiometers on analog inputs to let you put a known signal into the motion algorithm.

I would further disconnect any motors or ESCs or whatever and just use the LEDs and serial printing to see if the code is the problem or not.

At the glance I can give it through the tiniest of windows, the code looks plausible. Playing first with only the software and leaving off the table interrupts and all the issues real hardware can ache your head with would not be a waste of time.

I see where you are headed and why you want to insert an Arduino bewteen the input from the radio and the output to the motor drivers.

What ultimate loop frequency do you hope to achieve?

a7

#include <Servo.h>

Servo RightMotor;
Servo LeftMotor;

const int RCPinFWD = 2;  //Right RC stick
const int RCPinSide = 3;  // Left RC stick
const uint16_t middle = 1500;
const int FiveHundred = 500;
volatile unsigned long LowTimeFWD = 0;
volatile unsigned long LowTimeSide = 0;


void setup() {
  Serial.begin(9600);
  pinMode(RCPinFWD, INPUT_PULLUP);
  pinMode(RCPinSide, INPUT_PULLUP);
  RightMotor.attach(10);
  LeftMotor.attach(11);

  attachInterrupt(digitalPinToInterrupt(RCPinFWD), PulseTimerFWD, CHANGE);
  attachInterrupt(digitalPinToInterrupt(RCPinSide), PulseTimerSide, CHANGE);
}

void loop() {
  static int PulseWidthFWD = 0;
  static int PulseWidthSide = 0;

  noInterrupts();
  PulseWidthFWD = LowTimeFWD - middle;
  PulseWidthSide = LowTimeSide - middle ;
  interrupts();

  Serial.print(PulseWidthFWD);
  Serial.print("    ");
  Serial.println(PulseWidthSide);

  PulseWidthSide /= 2;   //change for turn speed, 1 is max turning speed, 500 is no turning

  if (abs(PulseWidthSide) > 10 || abs(PulseWidthSide) > 10) {
    int Right = constrain(PulseWidthFWD + (PulseWidthSide < 0) ? PulseWidthSide : 0, -FiveHundred, FiveHundred);
    int Left = constrain(PulseWidthFWD - (PulseWidthSide > 0) ? PulseWidthSide : 0, -FiveHundred, FiveHundred);
    RightMotor.writeMicroseconds(Right + middle);
    LeftMotor.writeMicroseconds(Left + middle);
  }
}

void PulseTimerFWD() {
  static unsigned long StartTime = 0;
  if (RCPinFWD) LowTimeFWD = micros() - StartTime;
  else StartTime = micros();
}
void PulseTimerSide() {
  static unsigned long StartTime = 0;
  if (RCPinSide)LowTimeSide = micros() - StartTime;
  else StartTime = micros();
}

maybe this variant is better

#include <Servo.h>

Servo RightMotor;
Servo LeftMotor;

const int RCPinFWD = 2;  //Right RC stick
const int RCPinSide = 3;  // Left RC stick
const uint16_t middle = 1500;
const int FiveHundred = 500;
volatile unsigned long LowTimeFWD = 0;
volatile unsigned long LowTimeSide = 0;


void setup() {
  Serial.begin(9600);
  pinMode(RCPinFWD, INPUT_PULLUP);
  pinMode(RCPinSide, INPUT_PULLUP);
  RightMotor.attach(10);
  LeftMotor.attach(11);

  attachInterrupt(digitalPinToInterrupt(RCPinFWD), PulseTimerFWD, CHANGE);
  attachInterrupt(digitalPinToInterrupt(RCPinSide), PulseTimerSide, CHANGE);
}

void loop() {
  static int PulseWidthFWD = 0;
  static int PulseWidthSide = 0;

  noInterrupts();
  PulseWidthFWD = LowTimeFWD - middle;
  PulseWidthSide = LowTimeSide - middle ;
  interrupts();

  Serial.print(PulseWidthFWD);
  Serial.print("    ");
  Serial.println(PulseWidthSide);

  PulseWidthSide /= 2;   //change for turn speed, 1 is max turning speed, 500 is no turning

  int Right = constrain(PulseWidthFWD +  PulseWidthSide, -FiveHundred, FiveHundred);
  int Left = constrain(PulseWidthFWD - PulseWidthSide, -FiveHundred, FiveHundred);
  RightMotor.writeMicroseconds(Right + middle);
  LeftMotor.writeMicroseconds(-Left + middle);
}

void PulseTimerFWD() {
  static unsigned long StartTime = 0;
  if (RCPinFWD) LowTimeFWD = micros() - StartTime;
  else StartTime = micros();
}
void PulseTimerSide() {
  static unsigned long StartTime = 0;
  if (RCPinSide)LowTimeSide = micros() - StartTime;
  else StartTime = micros();
}

I think i figured out the motor stuttering issue
after a bit of testing the input signal was dropping very low
the code below seems to fix it

else if ((PulseWidthFWD < 1480) && (PulseWidthFWD >1000)){                           //if stick is down motor backwards
    digitalWrite (RMotorStop, LOW);
    digitalWrite (RMotorDir, HIGH);
    PulseWidthFWD = map(PulseWidthFWD, 1480, 1100, 0, 180);
    RightMotor.write(PulseWidthFWD);

with potentiometer code looks like:

#include <Servo.h>

Servo RightMotor;
Servo LeftMotor;

void setup() {
  RightMotor.attach(2);
  LeftMotor.attach(3);
}

void loop() {
  static long PulseWidthFWD = 0;
  static long PulseWidthSide = 0;

 
   PulseWidthFWD = analogRead(A0) - 512;
   PulseWidthSide = analogRead(A1) - 512 ;
  
  //PulseWidthSide /= 2;   //change for turn speed, 1 is max turning speed, 500 is no turning
 
    int Right = PulseWidthFWD + PulseWidthSide ;
    int Left = PulseWidthFWD -  PulseWidthSide ;

    RightMotor.write(90+Right/5 );
    LeftMotor.write(90-Left/5 );
}

wokwi diagram.json

{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-uno", "id": "uno", "top": 190, "left": 90, "attrs": {} },
    {
      "type": "wokwi-servo",
      "id": "servo1",
      "top": 2.23,
      "left": -23.05,
      "rotate": 0,
      "attrs": { "hornColor": "DarkBlue" }
    },
    {
      "type": "wokwi-servo",
      "id": "servo2",
      "top": -3.72,
      "left": 149.07,
      "rotate": 180,
      "attrs": { "hornColor": "DarkBlue" }
    },
    {
      "type": "wokwi-slide-potentiometer",
      "id": "pot1",
      "top": 186.58,
      "left": 389.46,
      "rotate": 270,
      "attrs": { "value": "512","travelLength": "60" }
    },
    {
      "type": "wokwi-slide-potentiometer",
      "id": "pot2",
      "top": 185.1,
      "left": 465.54,
      "rotate": 90,
      "attrs": { "value": "512","travelLength": "60" }
    }
  ],
  "connections": [
    [ "uno:GND.1", "servo1:GND", "black", [ "v-29", "h-1" ] ],
    [ "uno:GND.1", "servo2:GND", "black", [ "v-29", "h19" ] ],
    [ "uno:5V", "servo1:V+", "red", [ "v21", "h-174" ] ],
    [ "uno:5V", "servo2:V+", "red", [ "v21", "h-167", "v-237", "h106" ] ],
    [ "uno:3", "servo1:PWM", "DarkMagenta", [ "v-13", "h-187" ] ],
    [ "uno:2", "servo2:PWM", "DarkMagenta", [ "v-19", "h-96" ] ],
    [ "uno:5V", "pot1:VCC", "red", [ "v21", "h78" ] ],
    [ "uno:5V", "pot2:VCC", "red", [ "v21", "h134.05", "v-262.9" ] ],
    [ "uno:GND.3", "pot1:GND", "black", [ "v27", "h118.03", "v-263.7" ] ],
    [ "uno:GND.3", "pot2:GND", "black", [ "v27", "h160" ] ],
    [ "uno:A0", "pot1:SIG", "DarkOliveGreen", [ "v13", "h120" ] ],
    [ "uno:A1", "pot2:SIG", "DarkOliveGreen", [ "v17", "h77.3", "v-258.9" ] ]
  ],
  "dependencies": {}
}

Yay! Saved me some time I don't have.

Bur, was not the printing you did include, viz:

  Serial.print(PulseWidthFWD);
  Serial.print("    ");
  Serial.println(PulseWidthSide);

an immediate clue that you were feeding nonsense into the map functions later on?

You really should not process any received pulse that is not between 1000 and 2000, or whatever your stick throws.

As a safety matter, getting bad pulse widths in the software should be brought to the attention of the operator as a matter for diagnosis and repair.

a7

@bdbobo - also, you may not realize or be accounting for the fact that map will happily extrapolate.

That is why map() is such good friends with constrain(), they show up working together fairly often.

TBH map() has, for me, been a source of more trouble than joy. It's simple maths and I suggest you look at the source code for map and then write your own version.

a7

I think the problem is here where you change global variable that is used on the next iteration. Try:

    RightMotor.write(map(PulseWidthFWD, 1480, 1100, 0, 180));

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