Car doesnt move straight using rotary encoders

Hi guys,

I am trying to move a car straight using encoders, but the issue I'm having is that the car deviates towards right. The codes that I've used and modified is from Sparksfun in the link below:

My version of the codes are as follows.

#include <AFMotor.h>

// parameters
const int drive_distance = 100;       // 100 cm
const int motor_power = 150;          // 0-255
const int motor_offset = 5;           // difference when driving straight
const int wheel_d = 60;               // Wheel diameter (mm)
const float wheel_c = PI * wheel_d;   // Wheel Circumference (mm)
const int counts_per_rev = 6;         // (3 pairs N-S) * (48:1 gearbox) * (2 falling/rising edges) = 288,
                                      // but in my case there are 6 counts per revolution as I've mounted the magnet
                                      // onto the output shaft instead of the motor shaft.


// Globals
volatile unsigned long enc_l = 0;
volatile unsigned long enc_r = 0;

// Pins
const int enc_l_pin = 18;          // Motor A
const int enc_r_pin = 19;          // Motor B


// Motors

//AF_DCMotor motor1(1, MOTOR12_64KHZ);                               // create motor #1, 64KHz pwm  (Left Back wheel)
AF_DCMotor motor2(2, MOTOR12_64KHZ);                               // create motor #2, 64KHz pwm  (Left Front wheel)
//AF_DCMotor motor3(3, MOTOR12_64KHZ);                               // create motor #3, 64KHz pwm  (Right Back wheel)
AF_DCMotor motor4(4, MOTOR12_64KHZ);                               // create motor #4, 64KHz pwm  (Right Front wheel)

void setup() {

  // Set up pins
  pinMode(enc_l_pin, INPUT);
  pinMode(enc_r_pin, INPUT);

  // Set up interrupts
  attachInterrupt(digitalPinToInterrupt(enc_l_pin), countLeft, CHANGE);
  attachInterrupt(digitalPinToInterrupt(enc_r_pin), countRight, CHANGE);

}

void loop() {
  bluetooth();      // Calling the driveStraight() function through bluetooth
}


void driveStraight(float drive_distance, int motor_power)
{
  unsigned long num_ticks_l;
  unsigned long num_ticks_r;

  // Set initial motor power
  int power_l = motor_power;
  int power_r = motor_power;

  // Used to determine which way to turn to adjust
  unsigned long diff_l;
  unsigned long diff_r;

  // Reset encoder counts
  enc_l = 0;
  enc_r = 0;

  // Remember previous encoder counts
  unsigned long enc_1_prev = enc_l;
  unsigned long enc_r_prev = enc_r;

  // Calculate targer number of ticks
  float num_rev = (drive_distance * 10) / wheel_c;   // Convert to mm
  unsigned long target_count = num_rev * counts_per_rev;
  
  // Debug
  Serial.print("Driving for ");
  Serial.print(drive_distance);
  Serial.print(" cm(");
  Serial.print(target_count);
  Serial.print(" ticks) at ");
  Serial.print(motor_power);
  Serial.println(" Motor Power");

  
  //Drive until on of the encoders reaches desired count
  while ((enc_l < target_count) && (enc_r < target_count))
  {
    num_ticks_l = enc_l;
    num_ticks_r = enc_r;
    
    Serial.println("enc_l = \t enc_r = ");
    Serial.print(enc_1_prev);
    Serial.print("\t");
    Serial.println(enc_r_prev);
    
  
    
    // Sample out current number of ticks
    
    Serial.print(num_ticks_l);
    Serial.print("\t");
    Serial.println(num_ticks_r);

    // Drive
    drive(power_l, power_r);

    // Number of ticsk counted since last time
    diff_l = num_ticks_l - enc_1_prev;
    diff_r = num_ticks_r - enc_r_prev;

    // Store current ticks counter for next time
    unsigned long enc_l_prev = num_ticks_l;
    unsigned long enc_r_prev = num_ticks_r;

    // If left is faster, slow it down and speed up right
    if ( diff_l > diff_r) {
      power_l -= motor_offset;
      power_r += motor_offset;
    }

    // If right is faster, slow it down and speed up right
    if ( diff_l < diff_r) {
      power_l += motor_offset;
      power_r -= motor_offset;
    }
  
    // Brif pause to let motors respond
    delay(20);
  }
  StopCar();
}

void drive(int power_a, int power_b)
{
  // Constrain power to between -255 and 255
  power_a = constrain(power_a, -255, 255);
  power_b = constrain(power_b, -255, 255);

  // Left motor direction
  if ( power_a < 0)
  {
    motor2.setSpeed(power_a);       // Motor is the front left wheel
    motor2.run(BACKWARD);
  }
  else
  {
    motor2.setSpeed(power_a);       // Motor is the front left wheel
    motor2.run(FORWARD);
  }

  // Right Motor direction
  if ( power_b < 0)
  {
    motor4.setSpeed(power_b);       // Motor is the front left wheel
    motor4.run(BACKWARD);
  }
  else
  {
    motor4.setSpeed(power_b);       // Motor is the front left wheel
    motor4.run(FORWARD);
  }

}

void StopCar()
{
  //motor1.run(RELEASE);
  motor2.run(RELEASE);
  //motor3.run(RELEASE);
  motor4.run(RELEASE);
}

And here is a picture of my robot:

Hi,
OPs image.


Where are the encoder pickups on your robot?

Have you swapped wheels from left to right to see if the robot drifts the other way?
Have you checked the alignment of the motors so that the wheels are parallel?
What Arduino controller are you using?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :slight_smile:

  // Set up interrupts
  attachInterrupt(digitalPinToInterrupt(enc_l_pin), countLeft, CHANGE);
  attachInterrupt(digitalPinToInterrupt(enc_r_pin), countRight, CHANGE);

Your code is incomplete. Where are the two ISRs defined?

Hi Tom thanks for the reply :slight_smile: .

A picture of the top side of my robot is shown in the attachments.

Those two blue wires as circled in the picture are the two output signals from the hall effect sensor and are connected to the interrupt pins of the arduino mega (pin 18 and 19). The hall effect sensor that I'm using is the ugn3503ua, which I purchased from jaycar:

https://www.jaycar.com.au/ugn3503ua-hall-effect-sensor/p/ZD1902.

When I observe the number of ticks on both encoders through the serial monitor I see that the number of ticks sometimes don't increase by increments of 1. So I guess the issue may be here.

And as for the ISR portion of the codes, which I forgot to include in the main post:

void countLeft()
{
 enc_l ++;
}

void countRight()
{
 enc_r ++;
}

Your post is titled:

Car doesnt move straight using rotary encoders

So, where are the rotary encoders?

These are the two encoders

From the picture and your Reply #3, those appear to be Hall sensors -- not rotary encoders.

I see a lot of Serial.print with no Serial.begin. What baud rate are you using? At the common 9600 baud rate, you are printing so much that the 20ms delay isn't long enough to send all of that. So the timing won't be 20ms like you expect and it will be somewhat random.

I'm thinking that perhaps one wheel is a little bigger than the other. Or maybe one has more grease on the tire so it consistently slips more than the other. Add an offset to make it drive straight...

const int StraightDriveOffset = 1; //increase this or even make it a negative number to tweak the straight drive...

    // Number of ticsk counted since last time
    diff_l = num_ticks_l - enc_1_prev - StraightDriveOffset ;
    diff_r = num_ticks_r - enc_r_prev;

If it's possible to put the encoders on un-driven wheels, there will be less slip problem. If you find you need to add 0.5 to the offset, that won't work with integers. So increase the integration time until you get to a whole number adjustment.

Look into using the BlinkWithoutDelay method to only sample at a specific period that isn't dependent on how long it takes to print. Then you can check important sensors (bumpers, emergency stop) at high frequency and only do this straightness adjustment in 500ms intervals.

Hi
If the circled in red devices are hall-effect, and it is interrupt driven and the robot is STILL going right, I would say the hall-effects aren't working.

If those black disk shaped things on the axle shaft are magnets, I fail to see how the assembly will work.

Do you have a DMM?

Can you tell us your electronics, programming, arduino, hardware experience?

Thanks.. Tom.. :slight_smile:

Thanks for the replies.

I changed the wheels and it somewhat helped with the car moving straight.

I have attached the terminal values I got for the two encoders for a target count of 50. Initially, the car move straights, however, close to the end it still slightly moves towards the right.

Tom, what do you mean by DMM? and yeah I have some past experience with programming, such as MatLab, Rasberry Pi, C, and assembly (Tiva). This project that I'm working on is my first project on arduino.

rotary encoders.pdf (252 KB)

Hi,
DMM, digital multimeter, a very helpful device.
Even the el-cheepo under $20 ones in this low voltage Arduino environment.

Tom.... :slight_smile:

Yes, I do have a digital multimeter. I've tested the hall effect sensor using the DMM and I'm sure its working as the voltage increases and decreases above and below the threshold value and changes state. the max voltage it goes up to is like 3.3V and minimum is like 1.2V on the output signal.