RC Car with FlySky: Project Help

Hello all! I am very new to coding and am trying an early project. I am trying to make an RC car controlled by a FlySky controller. I have been having a problem with what I believe is the order of operations. I can have the motors create a forward, reverse, and clockwise rotation, but it does not respond to the counterclockwise rotation.

I think it is the order of the "if" and "else if" statements, but I have not been able to solve the problem. Some code from the DroneBot workshop has been used for the initial information gathered from the receiver.

Any help is greatly appreciated and constructive criticism is very welcome!! My goal is to start learning with smaller projects and scale up with input from other sensors.

// Define Input Connections
#define CH1 A3
#define CH2 A1
#define CH3 A2
#define CH4 A0
#define CH5 10
#define CH6 11

#define motorSpeedPinLeft 11 //analogs 
#define motorSpeedPinRight 10

#define motorDirectionLeft1A 13 //digitals
#define motorDirectionLeft1B 12

#define motorDirectionRight1A 8
#define motorDirectionRight1B 7

// Integers to represent values from sticks and pots
int ch1Value;
int ch2Value;
int ch3Value;
int ch4Value; 
int ch5Value;

int dt=50;

float motorSpeedLeft;
float motorSpeedRight;

// Boolean to represent switch value
bool ch6Value;
 
// Read the number of a specified channel and convert to the range provided.
// If the channel is off, return the default value
int readChannel(int channelInput, int minLimit, int maxLimit, int defaultValue){
  int ch = pulseIn(channelInput, HIGH, 30000);
  if (ch < 100) return defaultValue;
  return map(ch, 1000, 2000, minLimit, maxLimit);
}
 
// Read the switch channel and return a boolean value
bool readSwitch(byte channelInput, bool defaultValue){
  int intDefaultValue = (defaultValue)? 100: 0;
  int ch = readChannel(channelInput, 0, 100, intDefaultValue);
  return (ch > 50);
}
 
void setup(){
  // Set up serial monitor
  Serial.begin(115200);
  
//Channel inputs 
  pinMode(CH1, INPUT);
  pinMode(CH2, INPUT);
  pinMode(CH3, INPUT);
  pinMode(CH4, INPUT);
  pinMode(CH5, INPUT);
  pinMode(CH6, INPUT);

//Motor outputs 
  pinMode(motorSpeedPinLeft, OUTPUT);
  pinMode(motorSpeedPinRight, OUTPUT);
  pinMode(motorDirectionLeft1A, OUTPUT);
  pinMode(motorDirectionLeft1B, OUTPUT);
  pinMode(motorDirectionRight1A, OUTPUT);
  pinMode(motorDirectionRight1B, OUTPUT);

}
 
 
void loop() {
  
  // Get values for each channel
  ch1Value = readChannel(CH1, -100, 100, 0);
  ch2Value = readChannel(CH2, -100, 100, 0);
  ch3Value = readChannel(CH3, -100, 100, -100);
  ch4Value = readChannel(CH4, -100, 100, 0);
  ch5Value = readChannel(CH5, -100, 100, 0);
  ch6Value = readSwitch(CH6, false);
  
// Print to Serial Monitor

  Serial.print("Ch1: ");
  Serial.print(ch1Value);
  Serial.print(" | Ch2: ");
  Serial.print(ch2Value);
  Serial.print(" | Ch3: ");
  Serial.print(ch3Value);
  Serial.print(" | Ch4: ");
  Serial.print(ch4Value);
  Serial.print(" | Ch5: ");
  Serial.print(ch5Value);
  Serial.print(" | Ch6: ");
  Serial.println(ch6Value);
 

//Turning/////////////////////////////////////////////////////////////////////////////
 
 if (ch1Value>0) { //clockwise 

    motorSpeedLeft= 2.55*abs(ch1Value);
    motorSpeedRight= 2.55*abs(ch1Value);

    digitalWrite(motorDirectionRight1A, LOW);
    digitalWrite(motorDirectionRight1B, HIGH);

    digitalWrite(motorDirectionLeft1A, HIGH);
    digitalWrite(motorDirectionLeft1B, LOW);

 } else if (ch1Value<0) { //counterclockwise 

    motorSpeedLeft= 2.55*abs(ch1Value);
    motorSpeedRight= 2.55*abs(ch1Value);

    digitalWrite(motorDirectionLeft1A, LOW);
    digitalWrite(motorDirectionLeft1B, HIGH);

    digitalWrite(motorDirectionRight1A, HIGH);
    digitalWrite(motorDirectionRight1B, LOW);

   if (ch2Value>=0) { //forward

    motorSpeedLeft= 2.55*abs(ch2Value);
    motorSpeedRight= 2.55*abs(ch2Value);

    digitalWrite(motorDirectionRight1A, HIGH);
    digitalWrite(motorDirectionRight1B, LOW);

    digitalWrite(motorDirectionLeft1A, HIGH);
    digitalWrite(motorDirectionLeft1B, LOW);

}  else if (ch2Value<0) { //reverse 

    motorSpeedLeft= 2.55*abs(ch2Value);
    motorSpeedRight= 2.55*abs(ch2Value);

    digitalWrite(motorDirectionLeft1A, LOW);
    digitalWrite(motorDirectionLeft1B, HIGH);

    digitalWrite(motorDirectionRight1A, LOW);
    digitalWrite(motorDirectionRight1B, HIGH);


  } }

    


motorSpeedLeft=constrain(motorSpeedLeft, 0, 255);
motorSpeedRight=constrain(motorSpeedRight, 0, 255);

analogWrite(motorSpeedPinLeft, motorSpeedLeft);
analogWrite(motorSpeedPinRight, motorSpeedRight);
delay(dt);
  
}
#define CH5 10
#define CH6 11

#define motorSpeedPinLeft 11 //analogs 
#define motorSpeedPinRight 10
  pinMode(CH5, INPUT);
  pinMode(CH6, INPUT);

//Motor outputs 
  pinMode(motorSpeedPinLeft, OUTPUT);
  pinMode(motorSpeedPinRight, OUTPUT);

Right off the bat I can tell you that won't work.

Thank you for finding that. However, those pins are just placeholders. I am using only channels 1 and 2 for the control. But I did disable those inputs in the meantime. Unfortunately, changing that did not fix the counterclockwise turn

And that's something you could, and should, have mentioned up front. Good-bye.

So sorry to offend you with my first forum post. I appreciate the... help?

Can you post your schematic? Hand drawn is fine just be sure to make it clear as to what is connected to what.

Can you also explain what is CH1 and CH2, are they on the same joystick like the X and Y axis or two separate joysticks?

@b083rt, welcome to the forum. It's Friday, so don't worry too much. It's been quite the week.

Please use the IDE Autoformat tool. At a glance, the structure of your code does not look right, perhaps if the IDE were to show the indentation it would be easier to see.

It looks like the entirety of the forward/reverse logic is incorrectly being made part of the clockwise-anticlockwise logic.

Like you need the { braces } distributed differently, or some else parts where you don't have them.

I'd look at it that way myself except I am in transit. I will if you haven't when.

a7

Surely! Working on the schematic now. Trying CAD to make it clear.

They are on the same joystick. CH1 moves left and right and CH2 moves up and down, springing back to the center when released in all directions

@alto777 Thank you so much! That auto format is so simple but works great. I thought that might be a part of the problem but I can't quite figure out where the {braces} go


// Define Input Connections
#define CH1 A3
#define CH2 A1
#define CH3 A2
#define CH4 A0
// #define CH5 10
// #define CH6 11

#define motorSpeedPinLeft 11  //analogs
#define motorSpeedPinRight 10

#define motorDirectionLeft1A 13  //digitals
#define motorDirectionLeft1B 12

#define motorDirectionRight1A 8
#define motorDirectionRight1B 7

// Integers to represent values from sticks and pots
int ch1Value;
int ch2Value;
int ch3Value;
int ch4Value;
int ch5Value;

int dt = 50;

float motorSpeedLeft;
float motorSpeedRight;

// Boolean to represent switch value
bool ch6Value;

// Read the number of a specified channel and convert to the range provided.
// If the channel is off, return the default value
int readChannel(int channelInput, int minLimit, int maxLimit, int defaultValue) {
  int ch = pulseIn(channelInput, HIGH, 30000);
  if (ch < 100) return defaultValue;
  return map(ch, 1000, 2000, minLimit, maxLimit);
}

// Read the switch channel and return a boolean value
bool readSwitch(byte channelInput, bool defaultValue) {
  int intDefaultValue = (defaultValue) ? 100 : 0;
  int ch = readChannel(channelInput, 0, 100, intDefaultValue);
  return (ch > 50);
}

void setup() {
  // Set up serial monitor
  Serial.begin(115200);

  //Channel inputs
  pinMode(CH1, INPUT);
  pinMode(CH2, INPUT);
  pinMode(CH3, INPUT);
  pinMode(CH4, INPUT);
  // pinMode(CH5, INPUT);
  // pinMode(CH6, INPUT);

  //Motor outputs
  pinMode(motorSpeedPinLeft, OUTPUT);
  pinMode(motorSpeedPinRight, OUTPUT);
  pinMode(motorDirectionLeft1A, OUTPUT);
  pinMode(motorDirectionLeft1B, OUTPUT);
  pinMode(motorDirectionRight1A, OUTPUT);
  pinMode(motorDirectionRight1B, OUTPUT);
}


void loop() {

  // Get values for each channel
  ch1Value = readChannel(CH1, -100, 100, 0);
  ch2Value = readChannel(CH2, -100, 100, 0);
  ch3Value = readChannel(CH3, -100, 100, -100);
  ch4Value = readChannel(CH4, -100, 100, 0);
  // ch5Value = readChannel(CH5, -100, 100, 0);
  // ch6Value = readSwitch(CH6, false);

  // Print to Serial Monitor

  Serial.print("Ch1: ");
  Serial.print(ch1Value);
  Serial.print(" | Ch2: ");
  Serial.print(ch2Value);
  Serial.print(" | Ch3: ");
  Serial.print(ch3Value);
  Serial.print(" | Ch4: ");
  Serial.print(ch4Value);
  Serial.print(" | Ch5: ");
  Serial.print(ch5Value);
  Serial.print(" | Ch6: ");
  Serial.println(ch6Value);

  // delay(500);


  //Turning

  if (ch1Value > 0) {  //clockwise

    motorSpeedLeft = 2.55 * abs(ch1Value);
    motorSpeedRight = 2.55 * abs(ch1Value);

    digitalWrite(motorDirectionRight1A, LOW);
    digitalWrite(motorDirectionRight1B, HIGH);

    digitalWrite(motorDirectionLeft1A, HIGH);
    digitalWrite(motorDirectionLeft1B, LOW);

  } else if (ch1Value < 0) {  //counterclockwise

    motorSpeedLeft = 2.55 * abs(ch1Value);
    motorSpeedRight = 2.55 * abs(ch1Value);

    digitalWrite(motorDirectionLeft1A, LOW);
    digitalWrite(motorDirectionLeft1B, HIGH);

    digitalWrite(motorDirectionRight1A, HIGH);
    digitalWrite(motorDirectionRight1B, LOW);

    if (ch2Value >= 0) {  //forward

      motorSpeedLeft = 2.55 * abs(ch2Value);
      motorSpeedRight = 2.55 * abs(ch2Value);

      digitalWrite(motorDirectionRight1A, HIGH);
      digitalWrite(motorDirectionRight1B, LOW);

      digitalWrite(motorDirectionLeft1A, HIGH);
      digitalWrite(motorDirectionLeft1B, LOW);

    } else if (ch2Value < 0) {  //reverse

      motorSpeedLeft = 2.55 * abs(ch2Value);
      motorSpeedRight = 2.55 * abs(ch2Value);

      digitalWrite(motorDirectionLeft1A, LOW);
      digitalWrite(motorDirectionLeft1B, HIGH);

      digitalWrite(motorDirectionRight1A, LOW);
      digitalWrite(motorDirectionRight1B, HIGH);
    }
  }




  motorSpeedLeft = constrain(motorSpeedLeft, 0, 255);
  motorSpeedRight = constrain(motorSpeedRight, 0, 255);

  analogWrite(motorSpeedPinLeft, motorSpeedLeft);
  analogWrite(motorSpeedPinRight, motorSpeedRight);
  delay(dt);
}

OK, before trying to place the brackets or otherwise change the flow through your logic, some questions.

It looks like two channels of control information and two motors. I am guessing it is a tank drive vehicle.

The four code blocks that run the motors means that whatever block last qualified to serve as input wins.

I don't think that will work but it's your trip so maybe give me a link to any advices you have followed on this kind of transmission, or just explain how these four code blocks do what you want just not quite yet.

a7

OK, I can't code but I can read.

Your logic is usable but does limit what you can do with the vehicle.

The problem now is solved by fixing the structure of your code, so all four control blocks are able to be entered, each joystick never mind the other, still winner take all.

But the test against zero is almost never going to be testing for zero. You need to implement a dead zone in each axis, to make it easier to move the stick into the forward, reverse, left or right zone without it getting caught.

Here it looks simple but I can't test: just make entry into a given zone's control code be based on not greater or less than zero, but greater than some upper dead zone for forward and less than some lower dead zone for reverse. Rinse and repeat that adjustment for the steering axis.

Later the other thing, mixing. Or not.

a7

Being that you are using a single joystick for tank steering (aka Differential Steering). You may want to first normalize your pot readings to go from 1.0 to -1.0. Then using sine and cosine you basically plot the point on a Cartesian graph.

Now you can certainly do the calculations yourself, in fact that is what we encourage everyone to do, this way they can have a better understanding of how their code works. It also helps with problem solving skills if the code doesn't work.

You can also use someones else's library that handles all of this for you if you are not yet confident in your calculations. Click this here -> Differential_Steering library.

There is a lot of documentation out there and especially right here in the forum, many others have done similar projects and they all learned along the way and shared what they learned too. You never know what you will find, but you definitely won't know unless you start looking.

1 Like

Thank you both! So I think I'll try to library to then try to replicate it essentially with an answer key. I appreciate it, being new finding the right questions and terms to use can be tough.

For my own learning I do have a couple follow up questions.

It is a tank drive type vehicle. The code got so close doing all directions except a counterclockwise/left turn.

@alto777 What would a deadzone look like in code? Rather than ch>=0, make it say 5 or 10 etc?

@HazardsMind Differential steering is the exact term I've been trying to identify so that's helpful. Honestly I dont know how I would have found those libraries on my own yet so thank you!

1 Like

Here's your origianl steering section, with a brace moved and jettisoning the else part:

  if (ch1Value > 0) {  //clockwise
    motorSpeedLeft = 2.55 * abs(ch1Value);
    motorSpeedRight = 2.55 * abs(ch1Value);

    digitalWrite(motorDirectionRight1A, LOW);
    digitalWrite(motorDirectionRight1B, HIGH);

    digitalWrite(motorDirectionLeft1A, HIGH);
    digitalWrite(motorDirectionLeft1B, LOW);
  } 
  
  if (ch1Value < 0) {  //counterclockwise
    motorSpeedLeft = 2.55 * abs(ch1Value);
    motorSpeedRight = 2.55 * abs(ch1Value);

    digitalWrite(motorDirectionLeft1A, LOW);
    digitalWrite(motorDirectionLeft1B, HIGH);

    digitalWrite(motorDirectionRight1A, HIGH);
    digitalWrite(motorDirectionRight1B, LOW);
  }

  if (ch2Value >= 0) {  //forward
    motorSpeedLeft = 2.55 * abs(ch2Value);
    motorSpeedRight = 2.55 * abs(ch2Value);

    digitalWrite(motorDirectionRight1A, HIGH);
    digitalWrite(motorDirectionRight1B, LOW);

    digitalWrite(motorDirectionLeft1A, HIGH);
    digitalWrite(motorDirectionLeft1B, LOW);
  }
  
  if (ch2Value < 0) {  //reverse
    motorSpeedLeft = 2.55 * abs(ch2Value);
    motorSpeedRight = 2.55 * abs(ch2Value);

    digitalWrite(motorDirectionLeft1A, LOW);
    digitalWrite(motorDirectionLeft1B, HIGH);

    digitalWrite(motorDirectionRight1A, LOW);
    digitalWrite(motorDirectionRight1B, HIGH);
  }

So the four sections can all be invoked, I mean any one of them can on a given pass.

Add: initially set zero for both motor speed variables, so if no section zone triggers, it doesn't energize the motors.

And you are right, the deadzone is just comparing to thresholds away from zero, like

// up top where you can change it to taste
const int deadband = 64;

// later in the code
  if (ch2Value < -deadband) {  //reverse

// and so forth

a7

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