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 -
- 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.
- 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.