I'm trying to work a car that's being controlled by an Arduino. I'm using the following chassis: New 2WD car chassis DC gear motor, wheels easy assembly and expansion and an L298N motor driver.

The problem is that it's hard to make the car go straight. Giving the same PWM value to the motors still makes them spin in different speeds, trying to calibrate the value is hard and every time I recharge my batteries the value changes.

What are my options on making the car go straight when I want (well, sometimes I'll want to turn it around of course)?

I've thought about using an encoder but I wish to avoid that since it will complicate the whole project, is there any other viable option? and even when using an encoder, Does it means I will need to keep track all the time and always adjust the motors value continuously? is there some built-in library for that?

  • $\begingroup$ To make one sought of guess for the problems 1. Everything might not be perfectly symmetric with your car 2. Not all transistors in your drivers will have the same gain value so the output might differ from these drivers.... $\endgroup$
    – Jasser
    Commented Feb 10, 2016 at 12:40
  • 1
    $\begingroup$ I appreciate that you wish to avoid using encoders to keep things simple, but realistically they are probably the simplest sensor method available. Odometry-based navigation can be done on an arduino, it's not too complicated. $\endgroup$
    – Andy
    Commented Feb 10, 2016 at 13:01
  • $\begingroup$ I agree that it may be a duplicate, but here OP is open (though resistant) to using feedback, and is curious how to use the feedback to drive straight. $\endgroup$
    – Chuck
    Commented Feb 10, 2016 at 14:20

1 Answer 1


If you're driving a car down a road, even if that road is straight, you still need to use the steering wheel occasionally to keep the car on the road. This means looking at your surroundings to determine if you're drifting, and (somewhat) constantly interfacing with the steering wheel to adjust your heading.

If you want the vehicle to go straight, you need feedback. Mark Booth gives a great answer to a similar-ish question, but there that OP wanted to go in a straight line at a speed proportional to distance remaining.

I think the way I would consider approaching the problem would be to generate a PID controller using the difference in motor speeds as the reference and feedback channel. The output of the controller would be an adjustment you would add to one motor and subtract from the other.

Consider this pseudo-code:

vehicleSpeed = <joystickYAxis>;
steeringRef = <joystickXAxis>;
leftMotorSpeed = pollEncoder(leftMotor);
rightMotorSpeed = pollEncoder(rightMotor);

steeringFbk = leftMotorSpeed - rightMotorSpeed;

So, at this point, steeringFbk is positive if the left motor is running faster than the right motor, which would indicate you're turning right. Now, to correct this, you would want something like:

steeringError = steeringRef - steeringFbk;

setMotorSpeed(leftMotor, vehicleSpeed + steeringError);
setMotorSpeed(rightMotor, vehicleSpeed - steeringError);

So here steeringError is now a negative number (desired - actual), so you add that to the desired vehicle speed. This means that the left motor will be set to some value slightly under the desired speed and the right motor will be set to some value slightly over. This should correct the motor speeds such that the vehicle is now traveling straight.

A couple of notes -

  1. Now you have a means to steer the vehicle. If you set steeringRef to a positive value the vehicle will turn left, and if you set it negative it will turn right.
  2. The code I wrote above just uses (unmodified) proportional error to drive the steering. This will probably give less-than-satisfactory results; consider instead using a PID controller:


steeringError = steeringRef - steeringFbk;
steeringAdjustment = PID(steeringError,kP,kI,kD);    
setMotorSpeed(leftMotor, vehicleSpeed + steeringAdjustment);
setMotorSpeed(rightMotor, vehicleSpeed - steeringAdjustment);

Now, with PID gains, you can tune the system for the desired response time, overshoot, etc.

  • $\begingroup$ Afterthought - this of course needs to be run in a loop, but you could also run it on an interrupt setup to check and correct speed as often as your experience tells you that you need to. $\endgroup$
    – Chuck
    Commented Feb 10, 2016 at 14:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.