3PI Line Follower Too Bang-Bang

In electronics, anything that only goes full-left or full-right, (or full-on, full-off, etc.) is known as bang-bang. Usually this introduces unacceptable noise, vibration or erratic behavior in circuits or actuators.
When I see that the 3PI sample line follower code only uses

set_motors(0,100);
and
set_motors(100,0);
and
set_motors(100,100);

…I am immediately suspicious that this control can’t be fast or smooth. Shutting down a high speed motor abruptly and shifting from stop to a high speed often can’t be a great idea.
I’m going to try three refinements. I’ll let you know how they work.

First, instead of only two possible states, I’ll divide the possible speeds into five instead of two. I think this will give finer, smoother control.
So the source would look like:

while(1)
{
	unsigned int position = read_line(sensors,IR_EMITTERS_ON);
	if        (position < 1000)	set_motors(    0,100); // too far left
	else if(position < 1500) 	set_motors(  50,100); // a little to the left
	else if(position < 2500) 	set_motors(100,100); // well centered
	else if(position < 3000) 	set_motors(100,  50); // a little to the right
	else			set_motors(100,    0); // too far right
}

The second possibility is to divide the readings from zero to 4,000 into say 40 different increments so that the change in motor speed would be much less abrupt.

And thirdly, how about infinite control? Meaning, make the algorithm so that you just plug the 0 - 4,000 number into an equation that accurately adjusts both motors very finely.

My theory is that smaller, finer adjustments to motor speeds will allow the 3PI to react quicker and more smoothly to changes in sensor readings.

When this works, I’ll change the 100 to a constant so that I can gradually increase the constant until 3PI finds its maximum speed just under loss of control. Something like:

const int MAX = 100;
while(1)
{
unsigned int position = read_line(sensors,IR_EMITTERS_ON);
if        (position < 1000)	set_motors(        0,  MAX); // too far left
else if(position < 1500) 	set_motors(MAX/2,  MAX); // a little to the left
else if(position < 2500) 	set_motors(MAX,      MAX); // well centered
else if(position < 3000) 	set_motors(MAX,   MAX/2); // a little to the right
else			set_motors(MAX,           0); // too far right
}

…then by just changing MAX, I can experiment easily with higher speeds.

Hello.

The simple “three-zone” approach was actually originally a “two-zone” algorithm that made the robot turn left when right of the line and right when left of the line, but this was a little too jerky. Our goal with the simple line-following program was to show just how easy it can be to follow a line if you are willing to move slowly enough. You can see an example of this simplified line-following algorithm in this video produced by Make:

The resulting motion is so choppy that some people think they’re seeing an artificially sped-up/time-lapse video (check the youtube comments).

This is where our second line-following sample program comes in. It uses PID control to produce what you termed “infinite control”. The PID algorithm takes the line position as an argument and produces left and right motor speeds as outputs. The functions used are continuous, so you get smooth changes in motor speed as the line moves rather than discontinuous jerks as in the three-zone case. Once you get the PID constants right, it’s rather amazing just how well it works.

- Ben