Differential Steering Robot with Encoders

I’m hoping someone could give me guidance on figuring out how to make my two wheeled robot go in a straight line using the DAGU encoders found here. basically, when the robot is going forward or backwards I want the wheels to behave as though they’re attached with an axis so both wheels go the same speed. I have one encoder per wheel connected to D2 and D3 and interrupts occur each state change of an encoder. My code is below which seems like it would work however, when I test it, the speed of the wheels seems to be rather slow even with the desired speeds being maxed. In addition, when one wheel is stuck on something (not turning), the other wheel keeps turning which I’d like to avoid.

// Pins used on arduino
#define rEncoder 2
#define lEncoder 3
#define rpwm 6
#define ldir 4
#define rdir 7
#define lpwm 5

// Variables used in interrupts
volatile unsigned int rightPulse;
volatile unsigned long rightTime;
volatile unsigned long rightWheel;

volatile unsigned int leftPulse;
volatile unsigned long leftTime;
volatile unsigned long leftWheel;

float rightSpeed, leftSpeed; // Actual Speed in Relvolutions Per Second (RPS)
float desiredRPS = 0.70; // Desired Speed in Relvolutions Per Second (RPS)
int desiredBotSpeed = 255; // Fixed disired Robot Wheel Speed (PWM value to motor)
int rightWheelSpeed = 255; // Variable Robot Wheel Speed (PWM value to motor)
int leftWheelSpeed = 255; // Variable Robot Wheel Speed (PWM value to motor)

void setup(){
  
  Serial.begin(9600);
  
  pinMode(rEncoder, INPUT);
  pinMode(lEncoder, INPUT);
  
  pinMode(rpwm, OUTPUT);
  pinMode(rdir, OUTPUT);
  pinMode(lpwm, OUTPUT);
  pinMode(ldir, OUTPUT);
  
  // Enable the pull up resistors for the encoders
  digitalWrite(rEncoder, HIGH);
  digitalWrite(lEncoder, HIGH);
  // Enable interrupts 0 and 1 on pins D2 and D3
  attachInterrupt(0, rightEncoderISR, CHANGE);
  attachInterrupt(1, leftEncoderISR, CHANGE);
  
  // Turn on motors
  analogWrite(rpwm, rightWheelSpeed);
  analogWrite(lpwm, leftWheelSpeed);
  
}// End Setup

void loop(){
  digitalWrite(ldir, HIGH);
  digitalWrite(rdir, LOW);
  
  if(micros()-rightTime > 2000 && desiredBotSpeed!=0) rightWheelSpeed+=2;
  if(micros()-leftTime > 2000 && desiredBotSpeed!=0) leftWheelSpeed+=2;

  rightSpeed = 0.000384*rightPulse; // 1000000 * (8 * 48) = 0.000384
  if(rightSpeed > desiredRPS && rightWheelSpeed<254) rightWheelSpeed--;
  if(rightSpeed < desiredRPS && rightWheelSpeed>0) rightWheelSpeed++;
  analogWrite(rpwm, rightWheelSpeed);

  leftSpeed = 0.000384*leftPulse; // 1000000 * (8 * 48) = 0.000384
  if(leftSpeed > desiredRPS && leftWheelSpeed<254) leftWheelSpeed--;
  if(leftSpeed < desiredRPS && leftWheelSpeed>0) leftWheelSpeed++;
  analogWrite(lpwm, leftWheelSpeed);
  
} // End Loop

// Interrupts
void rightEncoderISR(){
  rightPulse = micros() - rightTime;
  rightTime = micros();
  rightWheel++;
}

void leftEncoderISR(){
  leftPulse = micros() - leftTime;
  leftTime = micros();
  leftWheel++;
}

Parts used on robot:

  • Sparkfun Magician Chassis (motor gear ratio: 48:1)
  • 4 Alkaline Batteries
  • Arduino Uno
  • L293d (for motor direction)
  • 74ls04 Inverter (inverts input pins on l293d so when 1 is HIGH the other is LOW which saves 2 pins on arduino)
  • DAGU Wheel Encoder Kit

Thanks for the help in advance and if I left any information out let me know.

You need to measure the difference in time between the ticks in microseconds.

Not sure if I'm understanding you correctly HazardsMind but I believe I already did what you are saying within the interrupts with the line:
rightPulse = micros() - rightTime;
rightTime = micros();

Sorry, I didn't see any code when I wrote that. My Google Chrome is acting up. (I need to reinstall it)

Where are you finding the difference between leftSpeed and rightSpeed?

if( leftSpeed > rightSpeed ) rightwheelspeed++;
if( rightSpeed > leftSpeed ) leftwheelspeed++;

In my original code I had it checking actual revolutions per second for each wheel and then comparing that to the desired RPS. I didn't compare the left and right wheels to one another. I commented out my IF statements and tried yours, unfortunately, the wheel speeds don't match and if I force the right wheel to stop moving it just reduces the right PWM to ~0 and the left wheel just keeps turning.

You need to setup an algorithm to do the calculations only when the robot is said to be going straight. If one wheel stops or slows down indicating you are turning, then everything else will be wrong.

At the moment the robot's code only allows for it to go straight. In other words, there should be no turning of the robot at all. Therefore, I don't think an algorithm for that is necessary at the moment but I might be misunderstanding you.

There is a very long thread about just this from 6 months or a year ago. It was started by a school teacher! Hopefully you (or some one else) can find it. But the upshot is that you can't real do it even over short distances.

Mark

holmes4 I guess I didn't explain it well enough what I am trying to accomplish because I am certain it is possible. Therefore, I found this video that demonstrates essentially what i'm trying to achieve.

Good luck, you need it.

Mark

lol it shouldn’t be too hard. I think I already got it to work by measuring the time between pulses and then comparing them like this:

  while(rightPulse > leftPulse){
    analogWrite(rpwm, 255);
    analogWrite(lpwm, 0);
  }
  while(rightPulse < leftPulse){
    analogWrite(rpwm, 0);
    analogWrite(lpwm, 255);
  }
  while(rightPulse == leftPulse){
    analogWrite(rpwm, 255);
    analogWrite(lpwm, 255);
  }

The only problem I’m having right now is that the batteries seem to be messing it up so instead of using Alkaline I’m about to try Nickel-metal hydride. By any chance Mark, can you remember the title or link of that thread you were talking about? I’d like to check it out