Two Motor Drive Steering of Vehicle Not Working As Expected

Hi Alto,

can you explain why using a library that uses interrupts does complicate things?

If a beginner starts writing code with interrupts without knowing anything about them and uses one of those sadly badly coded examples with serial-output inside the ISR I agree. But a well tested library shouldn't be a problem.

best regards Stefan

Thank you, @alto777, @david_2018, and @StefanL38. I was outside for the last 8 hours working on a new electronics enclosure for this project (I made the Arduino's usb port more accessible, as well). I directed our coder to this thread, so perhaps he'll weigh in at some point. I'll definitely give your rewrite a try tomorrow, david2018 - very nice of you to put some time into it. I apologize this is so slow-going.

For what it's worth, @david_2018 , your code does have the wheels spinning in sync with the position of the throttle, again - thank you for the effort. Sadly, we've kind of run out of time with this attempt. Between my 9-month old and all the work I had to physically do to the vehicle, this was just too big a task for someone with my level of knowledge. If I get another chance at it, I hope to start from the beginning and be a better student with my coding.

Kudos to our coder in China for trying to do it so far from the hardware. I didn't realize at first how much I was asking of him.

I usually don't give complete code to someone who is doing a project as a student, since they are suppose to be learning from the experience, but since it appears you are going to abandon the project for a while here is my implementation of the steering function. This is a simple linear method, with no attempt to match it to your throttle vs motor voltage table, but modifying the code to use a lookup table would be trivial.

void steerFunct() {
  unsigned int pwm = 0;
  if (throttle >= (pulseMin + deadband)) {
    pwm = map(throttle, (pulseMin + deadband), pulseMax, 0, 255);
  }
  pwmL = pwm;
  pwmR = pwm;

  //the actual steering code goes here
  if (steer >= (pulseMid + deadband)) { //steer right - allow for deadband
    unsigned int steerPercentage = map(steer, (pulseMid + deadband), pulseMax, 100, 0);
    pwmR = pwmR * steerPercentage / 100u; // decrease right motor

    //direct mapping to maximum pwm value
    //pwmR = map(steer, (pulseMid + deadband), pulseMax, pwmR, 0)

    //using 255 instead of 100 for greater precision
    //unsigned int steerPercentage = map(steer, (pulseMid + deadband), pulseMax, 255, 0);
    //pwmR = pwmR * steerPercentage / 255u;
  }
  else if (steer <= (pulseMid - deadband)) { //left turn - allow for deadband
    unsigned int steerPercentage = map(steer, (pulseMid - deadband), pulseMin, 100, 0);
    pwmL = pwmL * steerPercentage / 100u; // decrease left motor
  }
}

Hi again, @david_2018. I recently revisited this thread and realized I'd failed to fully appreciate at the time your contribution.

The project did indeed need my attention again when the previous steering design caused one of the motors to fail. I spent a portion of the last two months watching Arduino tutorials, hoping again to pull this off. In reality, I learned just enough to realize that you'd written the code in two parts, but I didn't see how to put them together at the time. That was really very kind of you. I shouldn't even be the one doing this, let alone a stranger who no doubt has better things to do. So I really need to give a huge thank you for your time. If you're comfortable providing me with a mailing address via PM, I'd love to send you something nice for your efforts. Seriously.

When I uploaded the code I was amazed that it straight away did virtually everything I was hoping it would. You used commands in it that I've never even seen before (in my limited learning of this topic), so I don't know if I'd have ever put together a useful code. I will say it only seems to work in one direction (reverse, unless I swap the wires on the motor driver), so if you have any insight on why that might be, I'd love to hear it. Your code is below, along with a project description and a few small changes to more accurately reflect the joystick readings I pulled. Let me know if you don't want your username in the heading - I just wanted credit to go where credit was due.

Thanks again.

/*  File: RC_V3
 *  Purpose: Control two motors mounted on opposite sides of a kart with a remote control transmitter. 
 *  The user must be able to control the throttle and direction of each motor simultaneously, 
 *  as well as independently for the purpose of steering.
 *  Version 2.0 : Updated software to work with new controller
 *  Developed by: david_2018 (as identified on arduino.cc)
 */

#define MTR 5     //Motor right 
#define MTL 6     //Motor left
#define DIR_R 7   //right direction 
#define DIR_L 8   //left direction
#define FWD LOW
#define RVS HIGH
const byte steerPin = 10;
const byte throttlePin = 11;
const byte direcPin = 9;

const unsigned int pulseMin = 983; //minimum length of pulse
const unsigned int pulseMax = 1971; //maximum length of pulse
const unsigned int pulseMid = (983 + 1971) / 2; //centerpoint of pulse (1486);
const unsigned int deadband = 50; //dead band range for input pulses

unsigned int steer;        //steering number
unsigned int throttle;     //throttle number
unsigned int direc;

unsigned int pwmL;    //pwm for left motor
unsigned int pwmR;    //pwm for right motor

bool runMotors;

void setup() {
  pinMode(steerPin, INPUT);
  pinMode(throttlePin, INPUT);
  pinMode(direcPin, INPUT);
  pinMode(MTR, OUTPUT);
  pinMode(MTL, OUTPUT);
  pinMode(FWD, OUTPUT);
  pinMode(RVS, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  steer = pulseIn(steerPin, HIGH, 250000);
  throttle = pulseIn(throttlePin, HIGH, 250000);
  direc = pulseIn (direcPin, HIGH, 250000);
  Serial.print(F("pulse length steer: "));
  Serial.print(steer);
  Serial.print(F("\npulse length throttle: "));
  Serial.print(throttle);
  Serial.print(F("\npulse length direc: "));
  Serial.print(direc);
  Serial.print('\n');
  //ensure pulse lengths are within allowed range
  steer = constrain(steer, pulseMin, pulseMax);
  throttle = constrain(throttle, pulseMin, pulseMax);
  direc = constrain(direc, pulseMin, pulseMax);

  steerFunct();
  direcFunct();
  speedFunct();
}

void steerFunct() {
  unsigned int pwm = 0;
  if (throttle >= (pulseMin + deadband)) {
    pwm = map(throttle, (pulseMin + deadband), pulseMax, 0, 255);
  }
  pwmL = pwm;
  pwmR = pwm;

  //the actual steering code goes here
  if (steer >= (pulseMid + deadband)) { //steer right - allow for deadband
    unsigned int steerPercentage = map(steer, (pulseMid + deadband), pulseMax, 100, 0);
    pwmR = pwmR * steerPercentage / 100u; // decrease right motor

    //direct mapping to maximum pwm value
    //pwmR = map(steer, (pulseMid + deadband), pulseMax, pwmR, 0)

    //using 255 instead of 100 for greater precision
    //unsigned int steerPercentage = map(steer, (pulseMid + deadband), pulseMax, 255, 0);
    //pwmR = pwmR * steerPercentage / 255u;
  }
  else if (steer <= (pulseMid - deadband)) { //left turn - allow for deadband
    unsigned int steerPercentage = map(steer, (pulseMid - deadband), pulseMin, 100, 0);
    pwmL = pwmL * steerPercentage / 100u; // decrease left motor
  }
}

void direcFunct() {
  //forward
  if (direc <= (pulseMid - deadband)) {
    runMotors = true;
    digitalWrite(DIR_R, FWD);
    digitalWrite(DIR_L, FWD);
    Serial.print(F("Direction: Forward\n\n"));
  }
  //Reverse
  else if (direc >= (pulseMid + deadband)) {
    runMotors = true;
    digitalWrite(DIR_R, RVS);
    digitalWrite(DIR_L, RVS);
    Serial.print(F("Direction: Reverse\n\n"));
  }
  // dead zone
  else {
    runMotors = false;
    Serial.print(F("Direction: Stop\n\n"));
  }
}

void speedFunct() {
  if (runMotors == true) {
    // send pwm signal to motor
    analogWrite(MTR, pwmR);
    analogWrite(MTL, pwmL);
  } else {
    //stop motors
    analogWrite(MTR, 0);
    analogWrite(MTL, 0);
  }
}

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