Introduction: High Performance Line Follower Robot

Hi! I'll try to introduce you to the world of line follower robots. Many of us have ever heard about this kind of weird bots,that exist in a wide variety of versions from really slow and heavy ones,that usually can work even with only discrete electronic components, to the Japanese extreme ones that are almost professional approaches.

I'll show my approach that I think is pretty cool. As I used this robot in some local line follower competitions I've needed to adapt the robot to their standards; what means the robot is not bigger than a 12x20cm square. There are three important parts in the development of this robot: The electronic circuitry, the 3d design and printing, and the programming configurations and adjustments.

Step 1: Finding Motors

To make the robot you'll need both wheels and motors. There are plenty different types of these, but if you're a beginner I recommend using the ones pololu sells to you. Pololu is a website from Nevada-US that offers different kind of robots accessories, even entire robots (but normally line follower competitions forbid using them). Pololu Motors

Here comes the most important decision that is which motors and which wheels to use. Pololu offers us four kind of motors, low-power, medium-power, high-power, and long-life-high-power (all of them work at 6v and have the same physical dimensions). Which is the difference? The lower-power ones consume less power, but this means a worse motor because we'll have less speed or less force. I particularly don't recommend using this kind of motors that are made for other proposes rather that high performance competitions. I only used the high-power motors, and high-power-long life and I can tell you they don't consume too much.

The difference between thehigh-power and high-power-long life is that the long life have a longer lifetime but they can't bear giving them more than 6v and heavy stalling, while the high-power motors can deal with these conditions better. I actually used the high-power motors for this robot because I don't want to risk breaking my motors.They can work for several hours of continued usage without breaking though (some old robots with these kind of motors have worked for 3 years and more, and still hasn't broken)

Which gear ratio should you choose? A higher gear ratio means lower-speed but higher torque what involves higher acceleration, even instant acceleration with even heavy robots. I don't recommend using nothing more than 30:1 gear ratio because you won't be able to do a fast robot that is our objective (however, you need to make your robot weight less than 250 gr), and nothing less than 10:1, because they could be incredible fast motors but they are not able to deal with curves (because of the weight of the motors themselves and the inertia that this generates). So the decision is between 30:1 or 10:1, I particularly used four 10:1 motors, because using four motors means the robot can handle curves better ,but, a robot with only two 30:1 motors can work also although you'll need maybe to give them more than 6v to achieve higher speeds. With four 10:1 motors the robot can go really fast with no more than 6.5v. What about only two 1:10 motors? This can work too, but the robot takes more time to accelerate, what is bad itself but doesn't make it a bad idea.

Step 2: Finding Wheels

Which wheels should you use? I particularly used the pololu wheels because they are prepared specially for this motors. There are three important factors that define how a wheel is

  • The wheel circumference: as the motor speed is measured in rounds per minute, a higher circumference involves a higher distance traveled in the same minute, but a higher effort the motor need to take. The wheel diameter I used is of32 mm ( approximately 100 mm circumference
  • The wheel traction: This means how can the rubber of the wheel stick to the surface. A higher traction means we can go though curves better without falling away of the track.
  • The wheel weight: This is really important because a high traction wheel that weight 15 gr would mean a 60 gr heavier robot, which is pretty bad because we'll have a higher inertia, and the robot'll need a good traction to handle the curves that depends of the wheel rubber and the floor material. This wheels weight 3.2 gr each one.

For more information about torque and force you can go to the pololu website tutorial

You are free to select the wheels you want, but take care of the fact you need to make their shaft compatible with your motors.

Step 3: Finding Battery

I strongly recommend you to use the LiPo batteries because of it's long duration compared to their tiny size, and because of the fact they are rechargeable batteries

You can buy them for example on amazon.com or dx.com. I particulary used 7.4 two cell LiPo battery like this, with 850 mah. The miliampere-hour metric says how long hour battery will last. Lower mah means lower duration but a smaller and lighter battery while higher mah means higher duration but probably a bigger and heavier battery.

You can use other technology rather than the LiPo batteries, but if you want a high-performance robot you'll need to use this kind of batteries.

To charge LiPo batteries you'll need to use a LiPo charger

Step 4: Ball Caster

In order to put the robot black line detectors as far as possible from the motors (so the robot will get more time to react in curves), and because of the fact we can't make parts of the robot touch the floor directly as this will probably scratch the floor, a ball caster, in this case in fact, two ball casters, are needed in order to make the robot stable.

According to your design you'll need this accessory or not, but in order to be stable, a robot always needs tree or more contact points. If you have four motors, as the example shown, by default you wouldn't need more contact points, but, if the top part of the robot is long and heavier than the back, as this case, you'll need it. Also using a ball caster in the line detector arrays means we guarantee that the sensors will always be at the same distance to the floor which can't vary.

We used pololu ball caster that is ideal for this case. You must take care of not choosing a ball caster that is too heavy or too big.

Also, remember that if you use more than three contact points, you'll need to make them to bealigned.

Step 5: The Robot Structure

This is maybe the most important part of the building process of the robot. There are several ways to build the robot structure, the part that gathers all the components that make the robot. The more traditional way is to carefully cut and drill polystyrene (plastic), but, in this case we designed two 3d models using google sketch up (you can download my model), and printed them with a 20x20 3D Printer. We used screws and nuts to attach the motors and the printed circuit boards. (screws of 2mm for pololu motors and ball casters, and 3mm for the printed circuit boards).

Also, we added the pololu motor brackets (black edition), to make easier the motor placement. This piece can be 3d printed also because its' model is avaialable on thingiverse

To print in 3d you should use Cura or any similar program to export the stl model file, you can find plenty of tutorials on how to do that in the inernet.

Step 6: The Line Detector Circuitry

Well, now we'll start to build the robot's circuits. We'll start building the sensors that detect the floor colors (from white to black). We have attached two ball casters to the robot's base to make sure all the sensors are always at the same distance from floor. Which components do you need? We actually used 9 cny70 sensors (I am sure 7 or 5 can be fine), 9 220 ohm resistors, and 9 56k pull-down resistors. You can find all these components on http://www.digikey.com/ or any electronic supplier. I have attached an image of the circuit for a single cny70 sensor and also the printed circuit board pdf (if you want to use my circuit), and the proteus model (if you want to modify it, but you'll need proteus 8.2 that is not free software).

The objective of this circuit board is to get the analog sensing value of each cny70 that goes from 0 to 5v, where 0v means black, and 5v means totally white. The cny70 gives a precision of 0-1024, so when we'll read this information to the micro controller we'll get an integer between 0 and 1024 that will inform us the color being read by this sensor.

There are 11 male pins going out from the circuit. Two of them are the ground reference and the 5v power source, and the other 9 are the senors analog output (1 from each). This is not a complex circuit, just copying nine times the schematic circuit from the image. Be careful soldering all the sensors on the right side.

Note: If you want you can use other alternatives rather than the cny70 sensor, there are some of them with the same pinout (that are, for example, smaller).

Also I used different amounts of cny70 sensors during the development of the robot

  • First I used 7 sensors with 1 extra sensor in the border to detect a white sign (that is given in some competitions. It is like this) <- The program I'll explain will use this version, but it is possible to adapt it to make it more simpler or more complex
  • Then I started to use just 5 sensors for line following proposes (that still is enough), and leave without usage two of the sensors while I actually started to use the 2 extra sensors on the border to detect two white signs (one on each side)

Step 7: Main Circuitry

We have reached the most important part of the robot maybe, the main circuit where we have a programmable micro controller that is like the brain of our robot. Can an arduino board be used? Sure, but in this case we decided to use a micro controller (more precisely a pic18f4550), because it occupy less space than an arduino and in some competitions using arduino is forbidden. Also to program the microchip you'll need a pic programmer. You can buy one (which is more expensive) or order a cheap third party programmer (that for our proposes there is no difference). Here are some cheap pickit 2 programmers (which is needed to program a pic18f4550. (option - option).

Which other components you'll need?

  • A single pic18f4550: the micro controller.
  • A 20 mhz crystal for the pic18f4550
  • 3-6 leds (the pcb itself only uses 3 because 6 '5mm' leds doesn't fit)
  • 3 220 resistors to use for the leds
  • 2 ceramic 10nf capacitors for the 7805 circit
  • 2 ceramic 18pf capacitors for the crystal
  • an l293d or sn7544 (maybe not a bad idea buying some to have a backup), we use them to commute the motors
  • a switch
  • pins (to connect the battery, and the pcb boards one to each other)
  • three buttons (we recommend this ones), to configure and debugthe robot
  • a 7805 (to get 5v for the microcontroller and the cny70 sensors)

All these components can be found on digitkey.com or any other electronics website. You can get here also the schematic if you want to make your own pcb. The circuit is really simple itself.

Step 8: Starting to Program

Now we have arrived to the most important part of the robot, that between top quality robots is what defines who's better: The robot programming. We'll use the mplab xc8 compiler (you can download and install it for free) and sublime text as ide (which also is free). You are free to use mplab x ide or the classic mplab ide if you want. I will not explain how to install it because there are already plenty of tutorials on how to do that (only I will submit the sublime text command to build and run xc8, but you'll need to configure xc8 path and to install pk2cmd it case you use sublime text).

The code of the project is all on a single file (rayito.c) because that way it's easier to share it.

We'll start to explain some parts of the source code in the next step. Probably you won't be able to make the robot work magically if you don't understand the basics of how this program works, because the program itself has lots of details and calibration values that probably won't work on a different robot with different properties.

Step 9: Calibrating the Line Detectors

This is maybe a simple step, but using this simple algorithm will make the robot follow the line in the same way in different tracks that has different light conditions. Why we need to calibrate the cny70 sensors? Because although I said previously this sensor gives a 0 for black and a 1024 for white, actually we don't get almost never a round 0-1024 because there is no track where their white reflects 100% of the light and their black 0%. In the real world we'll probably get a value, we can just call it A for the darkest dark of the track, and another value, call it B, for the brightest white. It's true to say 0<=A<=B<=1024. How do we calibrate the robot? Before the robot starts following the line we will need to move the line follow sensor array to make them all read fully the black and the white part of the track.

This is the code for the calibration read (It is called for the 5 seconds calibration time)

void initLED(){ ///We initialize the read variables (this is called one time when the program starts)    
    int x;
    for (x = 0;x < 8;x++){
        amax[x] = 0; ///Amax is the value called B in the tutorial
        amin[x] = 1024; ///Amin is the value called A in the tutorial
    }
}
void CalRead(){ ///We read calibration values (this is called in the 5 seconds calibration period
L_ROJO = T1000 < 500*6; ///We make the red led to blink
    int x;
    for (x = 0;x < 7;x++){  //For the first 7 line follower detectors
        /***Attention: We use T(x) because it is defined in the first part of the program and makes the line follower
        detectors to be in the right order 0 to 7 ***/
        amax[x] = max(amax[x],T(x)); ///if we store a value higher than the last stored we replace it
        amin[x] = min(amin[x],T(x)); ///if we store a value lower than the last stored we replace it
    }
    ///The seventh sensor can not be acceded by using T(7). 
    ///We don't use this sensor to use the line, we use it to read the sign that
    ///is given in some competitions to make the robot know there is a curve. Ignore it if you don't need it.
    
    amax[7] = max(amax[7],J(7));  
    amin[7] = min(amin[7],J(7));
}

So when the calibration time ends, we'll get the 7 values read by the sensor into the C array. each sensor has its amin (A) and its amax (B) value. Then in the program we just convert the value read (A-B) to the range (0-1024) using simple math. If it occurs we read a value less than A then we consider we read A, and if it ocurrs we read a value higher than B then we consider we read B.

///This is just pseudo-code, does not work directly, only with learning proposes.
///In the real program I shared amax[x] is B and amin[x] is A
int w = W[x]; ///W[x] goes from 0 to 1024
w = min(w,B); //If w is higher than B, then w is B
w = max(w,A); //If w is lower than A, then w is A
w -= A; ///We make w logically go from 0 to B-A
w *= 1024; ///Now w will go from 0 to (B-A)*1024
w /= (B-A); ///And now we make w to go from 0 to 1024

Step 10: The Weighted Average

This is one of the most important algorithms we'll use to make the high performance line follower as good as possible. The Weighted Average (you can search about it on Wikipedia) is an average where each part of their terms has a different importance weight. The members of the average with higher value influence more the result of the equation, while the ones with lower value influence it only slightly. Why we need to use this kind of average? Because we won't make a simple line follower with something as simple as this

if (S1 see black){
	Left();
}else if (S2 see black){
	Right();
}else{
	Front();
}

We're making a high performance robot, so we need to calculate a precise estimation of where is the center of the line we are following. How do we calculate it? With the weighted average. We'll get the 5 center cny70 values on each programming cycle, (each of these values goes from 0-Black to 1024-White), and we'll need to transform these 5 values to a single value that says where is the center of the line we're following. To get to our objective we'll assign a position value to each sensor. This position value is defined as the value the formula would give if the center of the line is exactly focused on the center of the sensor. Of course this is theoretical but each sensor will try to make the position value be near its value. If a sensor reads more white than other, then the formula result will be more near its position value than the other.

So, of the 5 sensors, the firsts sensor will be assigned 0 while the fifth 4000. This means the position value we'll read is going to be in the range 0-4000. 2000 means the line is exactly in the center of the sensor array. If the robot detect we have just lost the track then the position value will be set to 0 or 4000 accordingly to the last value read. In this case we called the first sensor -2000 and the fifth sensor 2000 and then we reduced the range from -2000,2000 to -200,200

void Ponderado(){    sum = 0;
    division = 0;
    nove = 0;
    char center;
    for (x = 0;x <= 6;x++){

**This MACRO makes

if(T(x)>amax[x]){
	w=amax[x];
}else if(T(x) < amin[x]){
	w=amin[x];
}else{
	w=T(x);
}***/

	w = ran(T(x),amin[x],amax[x]);
        w -= amin[x];
        w *= (ll)1000;
        w /= (amax[x]-amin[x]);
        if (w > TH){
            nove = 1;
        }
        if (x == 3){
            if (w > TH){ center = 1; }else{ center = 0; } ///We store here if the center sensor reads 0 or 1000
        }
        ///A is the weight
        ///B is the position
        if (x == 0 or x == 6){ continue; } ///We ignore the sensors 0 and 6
	v = (1000) * (x-3);///This variable will be -2000,-1000,0,1000,2000 in each cycle
        sum += (w*v); 
        division += (w);
    }
   if (nove == 0){ ///if we don't see the line        POSICION = POSICION > 0 ? 200 : - 200; ///Now we set the value accordingly the last value set. if posicion is > to 0 then posicion equals 200, if not it equals -200
        
    }else{
        POSICION = (ll)(sum) / (ll)(division); ///We get the weighted average result
        POSICION /= 10; ///We change the scale from -2000,2000 to -200,200
    }
}

Step 11: The PD Algorithm

So now we've reached the heart of the project. Almost every good like follower robot needs this algorithm to make sure we'll follow the line optimally. The robot has two or four motors. Which say we'll control the direction that the robot follow giving more power to a motor or the other. We can control the speed of the motors by the usage of the pulse-width-modulation, that is integrated in the robot code, and allow us to use a function, MotorsSpeed(a,b) to set the speed of the motor A from -1000 to 1000 and the speed of the motor B from -1000 to 1000. We'll quote it but it doesn't make sense to explain here how it works. (But I promise it does!)

void MotorsSpeed(int A,int B){
///If mode equals alfa then we invert the motors voltage
    MotorASpeed(MODE == ALFA ? A : B); 
    MotorBSpeed(MODE == BETA ? A : B);
}
void MotorASpeed(int S){
	S = min(S,1000); 
	S = max(S,-1000);
    
    ADIR = S > 0 ? 0 : 1;
    S = S > 0 ? S : 1000 + S; 
    
    CCP1CONbits.DC1B1 = S % 4;
    CCPR1L = S / 4;
}
void MotorBSpeed(int S){
    S = min(S,1000);
    S = max(S,-1000);
    
    BDIR = S > 0 ? 0 : 1;
    S = S > 0 ? S : 1000 + S;
    
    CCP2CONbits.DC2B = S % 4;
    CCPR2L = S / 4;
}

So now we'll implement the PD algorithm whose objective will be to decide how much react (how much more power given to one motor than the other) when the line is far from the center of the sensor array according to two terms:

  • Proportional: This term is proportional to how far is the sensor array center from the line center
  • Derivative: The value of this term is according to how much the sensor array center has moved from the last time (its change speed). Adding this term to formula will make the robot to "predict" were the line will be in the next iteration which causes (if we use it correctly) a huge decrease of oscillations.

There are two constants, that are KP, and KD that says how much each term affects the robot's behavior. Testing to get these to the best values is part of the development of the robot. The result of the formula will be proportional to how much power is given to a motor than the other. If the result is positive, probably motor A will have more power than B, in the other case, motor B will have more power than A.

I have added in the robot a third term KR, that makes that if the motor speed is negative (which means it goes in reverse way), then the speed is multiplied by a factor. This is not necessary but because of the characteristics of my motors I'd needed to add it.

Now take a look of the PID algorithm (that has the KR thing, but you can ignore it)

void LineFollow(){
    double kp,kd,kr,speed;
	///POSICION has the value of the center of the line previously calculated
    kp = KP[speedMode];
    kd = KD[speedMode];
    kr = KR[speedMode]; 
    DER = POSICION - LP; ///We calculate how much the line has moved from the last iteration
    PIDf = (POSICION* kp + DER * kd);
 
        if (PIDf > 0){
            MotorsSpeed(Mr(speed-PIDf,kr) , speed); ///Mr makes the value to multiply by KR if it is negative. You can delete it        
	}else{
            MotorsSpeed(speed , Mr(speed+PIDf,kr) ); ///Mr makes the value to multiply by KR if it is negative. You can delete it
        }
    LP = POSICION;  ///We store the last line position
}

Step 12: Summary

If I had time I would be able to write 10 or 20 more pages about how to build a cool line follower robot. You can improve the robot methods in several ways for example making a robot that learns the track, and then in the second lap accelerates on the straight lines, or by buying better (but more expensive) motors. However I have given to you a cool description on how this kind of robot can be built. I hope you liked the tutorial and I attach a video of a competition race of the robot (it lost 2-1!). Have no doubt in asking me about the programming or anything else. The code is complex (900+) lines but I have explained to you the key parts so you are able to play with it or make your own code based on it.

Initial testing Video:

Good Luck!