# Rotary encoders to ensure 2 wheel robot goes straight!

I have successfully counted the rotary encoders on the wheel of my robot so this is not a problem.

My problem is what to do with this number.

Basically, the bigger problem is that I need my robot to go straight and I want to do it using only two encoders (one on every wheel).

Even if I send the same amount of power to both motors the robot does not go straight. This is why I decided to use encoders, so no matter the power on the batteries, or the conditions of the motors; the robot will go straight.

So, now that I have successfully counted the "clicks" on the encoder I need to know what to do with the number to make sure the tow wheels are synchronized.

This is the code I am using (Arduino):

  digitalWrite(dirMotO, HIGH);
digitalWrite(dirMotE, HIGH);
//digitalWrite(motO, HIGH);
analogWrite(motO, 150);
//digitalWrite(motE, HIGH);
analogWrite(motE, 150);

PololuWheelEncoders::getCountsAndResetM1();
PololuWheelEncoders::getCountsAndResetM2();

while(PololuWheelEncoders::getCountsM1()<clicks && PololuWheelEncoders::getCountsM1()<clicks){
if(PololuWheelEncoders::getCountsM1()>=clicks){
digitalWrite(motO, LOW);
}
if(PololuWheelEncoders::getCountsM2()>=clicks){
digitalWrite(motE, LOW);
}
}


I thought this code would make sure that if one wheel gets to counts before the other it would stop and wait for the other wheel but the robot does not go straight.

I would really appreciate some help on this.

Thank you!

• Is there the same amount of weight on each wheel, ie the batteries are on the left circuit on the right so it is off balance? – Dean Apr 21 '11 at 22:59
• I made sure it was as balanced as possible, but I thought with the use of encoders I could avoid any distortion caused by external factors... Maybe it was not the way to go. – Zebs Apr 22 '11 at 0:18
• A friend with robotics experience once told me that just because your wheel "turned" the same distance, does not mean that the wheels moved the same distance - especially when you're dealing with potentially uneven, slippery, or resistant surfaces. – Toybuilder Apr 22 '11 at 0:47
• To illustrate @Toybuilder's point, imagine a robot on a frictionless plane. The wheel encoders keep ticking over, but robot goes no where. Encoders can't help with slipping or different wheel radius, etc. – freespace Apr 22 '11 at 4:34

Your while loop logic is incompatible with the conditions inside it.

Your while loop is saying:

as long as BOTH wheel encoders read less than clicks, execute the code inside

and your if statements are saying:

if any of the wheel encoders is greater or equal to clicks, stop the corresponding motor

This is generally false except for the rare condition where one of the encoders happen to increment between the arduino evaluating the while and the if statements. In order words just about never.

So the first thing you need to do is fix your logic. Then you need to investigate more sophisticated means of keeping the wheels in sync, such as computing an error term from the different in ticks, and employing a PID controller algorithm to adjust the speed of both motors via analogWrite.

I assume clicks is the number of encoder ticks you want to go forward. This answer depends on clicks being slightly large- more then a few multiples of the wheel tick count- below that I'm not sure of the performance of this method.

Part of the problem is that you're correcting by completely turning off one motor. That means that those wheels are effectively stuck, and start to act as a pivot. You want to make corrections with both wheels moving.

What you need to do is try and keep the difference between ticks of the two motors as small as possible while running. As an example, if you have 16 ticks per rev, and want to go 100 ticks, you want to keep the difference in ticks as near to 0 as possible, by applying more power to the slower motor, and less to the faster one. Code left as an exercise to the reader (it depends on how you want to manage the variability: update the analogWrite's 10 times a second? 20? 5?).

This probably wont work as well for a small number of ticks (1 rev), and the various laws of accumulating error mean it probably won't be perfectly straight for large numbers of ticks either; but it should give better results then what you have now.

Have you considered closing a velocity loop instead of a position loop? Initially, accelerate at a reasonably slow rate so there's less of a chance of the two wheels getting out of sync. If both wheels are moving at the same velocity, then your robot must be moving straight, barring any sort of coupling slippage or slipping between the wheels and the surface your robot is riding on.

a simple way i got my robot to go straight was by using three while loops, while one wheel is counting slower, increase the speed on that wheel. one loop is for the left, one for the right and the last just tells the program to write equal speeds if count is equal but you can leave it out. hope this helps. and dont forget to inpu a break; command at the end opf each loop other wise it will stay in the loop even after condition has been met

Sorry I'm a bit late to the party, but in case anyone else wants to do something similar, a simplistic approach which may be worth trying is to continuously compute the number of ticks each wheel should have moved, and then within a timer tick do something like:

volatile unsigned long expected_left_distance, expected_right_distance;
volatile unsigned int left_speed, right_speed;
unsigned long left_distance, right_distance;

void timer_tick(void)  // Run this at a rate faster than once per encoder pulse
{
int delta;

Add or subtract 65536 from left_distance if encoder has moved +/- a click
Add or subtract 65536 from right_distance if encoder has moved +/- a click
expected_left_distance += left_speed;
expected_right_distance += right_speed;
if ((left_distance - expected_left_distance) & 0x80000000) // Assumes long is 32-bit
left_motor_on();
else
left_motor_off();
if ((right_distance - expected_right_distance) & 0x80000000)
right_motor_on();
else
right_motor_off();
}


A speed value of 1 will move the robot at a rate of one encoder pulse every 65536 interrupts; a speed of 64 would move it 64 times as fast (once every 1024 interrupts), etc. Depending upon the design of the motors, the mass of the system, and the encoder count rates, this motion might be adequately smooth, or it might be unacceptably jerky and uneven. It may be worth trying the approach, though, to see if it works.

 while (decimal0>decimal1)
{
analogWrite(pin1,(pulsewidth+1));
analogWrite(pin0,pulsewidth);
break;
}

while (decimal0<decimal1)
{
analogWrite(pin0,(pulsewidth+1));
analogWrite(pin1,pulsewidth);
break;
}

while (decimal0=decimal1)
{
analogWrite(pin1,(pulsewidth+1));
analogWrite(pin0,pulsewidth);
break;
}

• while (condition) { statement; break; } is equivalent to if (condition) { statement; } -- and the latter is clearer. – Tom Davies Oct 30 '11 at 9:47