Main Content

Line Follower Robot

An autonomous high speed line follower robot based on PID control.

I wanted to make a line follower robot for a competition for amateurs students, but I struggled to find a tutorial that explains exactly the line following process or that explains the principles by which it works. After 4 - 5 months of research, I managed to make an acceptable model that can take curves at a relatively high speed without getting off the track. At the end, it costed me 130 euro (pcb, 3d printing and all the components).

1. Making the line follower model - hardware

First of all, I made this robot for a line tracker competition, so speed and control are the most important factors, but there are also some requirements ( for instance, the robot mustn’t have the dimensions higher than 30x30 cm or the curve radius of the track must be at least 7.5 cm). So, I designed it as a “racing car”, with 2 motors in the back and a ball caster in the front. I put the QTR-8RC sensor array in the front of the robot, so that the ball caster will always be on the line.

I made this track with A3 papers and PVC tape

As I said before, the track has certain rules related to the curve radius. Keep in mind that the minimum curve radius the robot can take is the length from one of the wheels to the ball caster (in case when the motors only spin in one direction and take a value from 0 to 255). If you make a mistake (like I did), and the length is greater than the curve radius and the robot can’t take small curves, then you can spin the motors in reverse, meaning the robot will rotate around the center of the base. By doing so, you can burn and damage the motors.

The first prototype - doesn’t take the curves easily

As a development board I use an Arduino Pro Mini 5V. But the problem is that the motors require 6V, so I used a 5V step-down voltage regulator and a motor driver. For the battery I didn’t have too many options, so I choose the 7.4V li-po. The battery powers the motor driver and the voltage regulator with 7.4V, the motor driver has a little power loss and can power the motors from 0V to 7.4V (arduino PWM control). With the PWM control, Arduino can feed the motors exactly 6V, without damaging them. Next, the voltage regulator powers the arduino board and the other electric parts (sensors and HC-05) with exactly 5V.

This is the final model, after a lot of testing - I can still make it faster

!!!If you buy a Li-po battery, make sure you buy a charger as well.

2. Motors

For a high-speed robot, a small gear ratio of the motor will be better, because it provides a higher RPM but the torque will be lower. At a very low torque/ very high RPM, the line follower might not be able to take the curves and slip off the track. For more details: https://www.pololu.com/category/60/micro-metal-gearmotors.

Wiring the motors was a little challenging

3. Sensors

To use the QTR-8RC reflectance sensor array within an Arduino project, you must first install the specific library. You can search in “Manage Libraries” for “QTRSensors”, or, if it doesn’t work, open this link: https://www.pololu.com/docs/0J19/all. It provides the steps how to install the library and a documentation about how the sensor works.

Once installed the library, there are a few things needs to be mentioned:

you can either calibrate the robot and then read the values of the sensors which depend on the initial values from the calibration or read the raw values of the sensors. The first case will be more accurate. If you search in File > Examples > QTRSensors , you will find an example for both cases.

uint16_t position = qtr.readLineBlack(sensorValues);

with this line of code, the sensor array will return the position of the black line. It can be between 0 and 7000. If the position is 3500, it means the sensor array is on the center of the line

for (uint8_t i = 0; i < SensorCount; i++) { Serial.print(sensorValues[i]); Serial.print(‘\t’); }

if you want to access a particular sensor from the sensor array, you can call a loop function or simply call sensorValues[anumberfrom0to7] . It won’t work if you didn’t call first the qtr.readLineBlack(sensorValues);

in my final program, I didn’t make the calibration automatic. So, at the beginning of the program, during this phase, you should expose each reflectance sensor to the lightest and darkest readings they will encounter. For example, if you are making a line follower, you should slide the sensors across the line during the calibration phase so that each sensor can get a reading of how dark the line is and how light the ground is. Improper calibration will result in poor readings.

4. PCB and 3D printing

In this project I wanted to do something different and try not to use breadboard and wires in making the robot. So I mounted all the components on a PCB, to save space and not have problems with the connections. Designing this wasn’t so hard. First I made the schematic circuit with EasyEDA. Then, this software has a feature that can convert the schematic into a PCB, so making the connections between the components will be more simple. I only had to make the outline of the PCB, place the components inside the outline and then wire them (you can do it manually or automatic with auto router). I ordered 5 pieces directly from their website (the PCB stores in my country asked me to pay four times the normal price for them) and the delivery was in 3 weeks. Then I soldered some of the components directly on the PCB and the other components with a female header on the PCB - the HC-05 and the wires from the sensor array (so that way I could reuse and remove them).

This is the PCB I will use for the robot

The other components (the battery and sensor support) I made from 3D printed components. I used a CAD software (SketchUp) and then for each part I imported one as an STL file. After that I printed them at an electronics store. I had few problems with the screws, because the holes where too small or the 3d printed parts came over them. I used M3X16 screws for the motors brackets and the battery and sensor support, and M2X10 screws for the ball caster.

1 / 2 Prototype robot - you can see the lack of space and the chaotic wiring

1 / 4 The new robot, made with PCB (who replaces the wires and the breadboard) and with 3d printing.

!!You might want to review the STL of battery support because it might not be good for another battery. It can be bigger or the wires that connect the battery might not not fit in the hole made especially for them.

STL Line Follower

5. The line following algorithm and PID control

The line following algorithm is quite simple. If the position is higher or lower than 3500, then the robot must turn left or right.

1 - position 7000; 2 - position 3500; 3 - position 0.

But if we put this in a loop, the robot will oscillate until it eventually gets off the track. And this is where PID control comes in handy. In practical terms it automatically applies accurate and responsive correction to a control function (wikipedia). This means that the robot will no longer oscillate and will be able to take different types of curves at different curve radius without getting off the line. To make it easier to understand the program, we will use an integral called error. It can be both positive and negative.

int error = 3500 - position;

The distinguishing feature of the PID controller is the ability to use the three control terms of proportional, integral and derivative influence on the controller output to apply accurate and optimal control (wikipedia). But that’s not all. For each term, it corresponds to a constant, Kp, Ki and Kd, that must be adjusted so that the robot can follow a line without oscillating or slowing down or getting off the track.

Here, the proportional term is the error. It directly controls how to take the curves - if Kp is a small value he will take the curves easier (he will go almost straight); if it is a large value it will take the curves suddenly (either it will oscillate on a straight line, or it will take the curve too tight and it will leave the track).

int P = error;

The integral term accumulates all errors. The integral term seeks to eliminate the residual error by adding a control effect due to the historic cumulative value of the error. When the error is eliminated, the integral term will cease to grow. This will result in the proportional effect diminishing as the error decreases, but this is compensated for by the growing integral effect (wikipedia). In other words, it helps the robot stop oscillating. But at a Ki that is too high, it will do the opposite.

int I = I + error;

The derivative term makes the calculation between the current error and the last error. When the robot suddenly hits a tight curve, this value will be high and will force the robot to take the required curve. The more rapid the change, the greater the controlling or dampening effect (wikipedia). At a Kd too small, this value might not take place. At a Kd too high, it can give errors to the whole program and the robot can oscillate, run very slowly or take very narrow curves that don’t even exist.

int D = error - lastError; lastError = error;

In the end, the equation of speed that will be applied to the motors will be:

float motorspeed = PKp + IKi + D*Kd; int motorspeeda = basespeeda + motorspeed; int motorspeedb = basespeedb - motorspeed; //where basespeed is the speed of each motor when the robot goes in a straight line - 100 or 150

The whole point of this algorithm is finding the 3 constants. They can be anything. For example, for my robot Kp is 0.07, Ki is 0.0008 and Kd is 0.6. You can change their values every time in the program, or you can put a bluetooth module in which you can control these values directly from the phone.

6. Bluetooth control

In this project, I made my robot with a HC-05 bluetooth module to make it easier for me to find those values. I will give an arduino file where I did the control via bluetooth, as well as the apk file (located in the schematics part). The PCB schematic also contains the bluetooth module.

I used Mit App Inventor because I can make this type of apps fast. Although, it is not the best. First you design the look of the app and second you block-code it.

1 / 2 The designer part

The idea of how I made the connection between the Arduino (HC-05) and the phone is simple. Because I couldn’t send a value higher than 255 (I only could send one byte), I had to do it in such a way that for each instruction (for example the change of sliders) I first sent a number that represented the instruction (1 for Kp, 3 for Ki, 5 for Kd and 7 for the buttons). But that means that the constants will be between 0 and 255. And for example for my robot Ki is 0.0008. So I made a second value for each constant(multiP, multiI and multiD), that divides by a power of 10 the constants. For example, the Arduino receives the values 1, 55 and then 2, 2. That means the Kp is first 55, then multiP is 100. At the end Kp is 55 / 100 = 0.55. Because Ki is the smallest number and have 4 decimals, the slider of the multi takes a number between 0 and 5 (10^5 = 100000). The code who has in its name (+ Bluetooth communication) is made especially for phone communication.”

Link to article