Line Follower Robot
One of the most basic autonomous robot you can build is a line following robot(LFR). This type of robot is run over a white surface which has an arbitrary path drawn over it by using back paint. The task of the robot is to run exactly along this painted path. You may note that the surface may also be black(or any other dark colour), in that case the path is a light colour like white. Please watch the following video for a LFR in action.

Designing an LFR

At minimum our LFR design require the following components.
  • A sensor to detect the line on the surface.(It can be a simple IR Reflectance Sensor or an high end camera!). We will use a simple IR based sensor, it is cheap and easy to build and use. This article describe how to make a line sensor array.
  • A microprocessor to run the code that takes inputs from the sensor and control the motion of robot. We will use a cheap single chip computer called anmicrocontroller (MCU). A popular family of microcontroller is AVR series fromAtmel. A member of the popular family is ATmega8. ATmega8 is chosen because it has just the required amount of resources and is very low cost.
  • The MCU cannot drive the motors (used to actually make the robot run) directly, so a motor driver is used. A motor driver in our case is a simple 16pin chip calledL293D. It can drive 2 DC motors. We use a technique called PWM to vary the speed of motor digitally from the MCU. The drive mechanism is a differential drive in which we do not require to turn the front wheel for changing direction of heading. Only two rear powered wheel is enough for motion and turning. This is different from the way cars and bikes are turned, in these the front wheel is turned to turn the vehicle. More information on differential drive is give in this article.
  • Wheels that are connected to motors shaft the motor.
  • Battery to power the whole thing.
  • chassis to hold everything.

The Mechanical Construction of Robot.

line following robot

Final Assembled LFR

The robot is build using common and low cost parts easily available online.
Mechanical Construct is described in detail here.

Electronics for the Robot.

The electronics for the robot is kept as simple as possible. The electronics board is split into to parts.
  • The main board that has the MCU, basic MCU support circuit, motor driver and indicator LEDs.
  • The line sensor board that is connected at the bottom part of the robot.
These two units are neatly connected using a FRC cable(see this).
line follower board diagram

Main Board Schematic.

The schematic for line sensor array is given in this article.
Purchase
You can purchase both the circuit boards made using high quality PCBs and parts. Simply follow the link. Our store accept online payment using debit cards, ATM cards and Net Banking. The products will be delivered to you door steps within 3-5 days any where in India using quality courier service.
other wise you can build the circuits on a general purpose PCB or breadboard. But those are lot messy, bulky and does not fit well in the chassis. Beginners should avoid using them. You can save lots of time and pay more attention in the program part that is more important.

The program for LFR.

The LFR Program needs help from three libraries :-
  1. LED lib (to turn on/off five indicator LEDs)
  2. Motor lib (to control the speed and direction of rotation of motor)
  3. ADC lib (to configure and use the analog to digital converter of ATmega8)
The code is written using the C language so you need to be comfortable with the following.
  • Syntax of C language.
  • Concept of libraries.
  • Source File, Header File etc.
  • Preprocessor, Compiler and Linker, what they are and what they do and how to use them.
The IDE (Integrated Development Environment) that is a software suite that let you enter, edit, compile,debug project and manage files in project. The IDE that we are using is the latest Atmel Studio 6. Introduction to AS6 is here.
A new project is created as described in above tutorial and configured then the library files LED,Motor and ADC needed to be added to the project. Adding a library to current AS6 project is described in libraries manual.

/*
 * LFRM8.c
 *
 * Created: 5/26/2012 7:59:45 PM
 *  Author: Avinash Gupta
 */

#include <avr/io.h>
#include <util/delay.h>

#include "lib/adc/adc.h"
#include "lib/motor/motor.h"
#include "lib/led/led.h"

#define SENSOR_THRES 800

//Map Sensor Number to ADC Channel
#define SENSOR1 0
#define SENSOR2 1
#define SENSOR3 2
#define SENSOR4 3
#define SENSOR5 4

//Gloabal varriables
float pGain = 200;   //Proportional Gain
float iGain =  0.2;  //Integral Gain
float dGain =  120;  //Differential Gain
int delay = 10;

int32_t eInteg = 0;  //Integral accumulator
int32_t ePrev  =0;      //Previous Error


void  DelayMs(uint8_t ms);
float ReadSensors();
float PID(float cur_value,float req_value);


float control;
float s;

int main(void)
{
   //Initialize Motors subsystem.
   MotorInit();

   //Initialize LED subsystem
   LEDInit();

   //Initialize Analog to Digital Converter (ADC)
   InitADC();


    while(1)
    {
      //Previous Sensor Reading
      float sprev;

      //Take current sensor reading
      //return value is between 0 to 5
      //When the line is towards right of center then value tends to 5
      //When the line is towards left of center then value tends to 1
      //When line is in the exact center the the valeue is 3
        s=ReadSensors();

      //If line is not found beneath any sensor, use last sensor value. 
      if(s==0xFF)
      {
         s=sprev;
      }

      //PID Algorithm generates a control variable from the current value
      //and the required value. Since the aim is to keep the line always
      //beneath the center sensor so the required value is 3 (second parameter)
      //The first argument is the current sensor reading.
      //The more the difference between the two greater is the control variable.
      //This control variable is used to produce turning in the robot.
      //When current value is close to required value is close to 0.
      control = PID(s,3.0);

      //Limit the control
      if(control > 510)
         control = 510;
      if(control < -510)
         control = -510;

      if(control > 0.0)//the left sensor sees the line so we must turn right
      {
         if(control>255)
            MotorA(MOTOR_CW,control-255);
         else
            MotorA(MOTOR_CCW,255-control);

         MotorB(MOTOR_CW,255);
      }
      if(control <= 0.0)//the right sensor sees the line so we must turn left
      {
         if(control<-255)
            MotorB(MOTOR_CCW,-(control+255));
         else
            MotorB(MOTOR_CW,255+control);

         MotorA(MOTOR_CCW,255);
      }

      //Delay     
      DelayMs(delay);

      sprev=s;
    }
}

void DelayMs(uint8_t ms)
{
   uint8_t i;
   for(i=0;i<ms;i++)
   {
      _delay_ms(1);
   }
}

//Implements PID control
float PID(float cur_value,float req_value)
{
  float pid;
  float error;

  error = req_value - cur_value;
  pid = (pGain * error)  + (iGain * eInteg) + (dGain * (error - ePrev));

  eInteg += error;                  // integral is simply a summation over time
  ePrev = error;                    // save previous for derivative

  return pid;
}

float ReadSensors()
{
   uint16_t eright,right,middle,left,eleft;
   uint8_t     sensor1,sensor2, sensor3, sensor4,sensor5;

   float avgSensor = 0.0;

   eright=ReadADC(SENSOR5);
   if(eright>SENSOR_THRES)//Right black line sensor
   {
      sensor5 = 1;
      LEDOn(5);
   }
   else
   {
      sensor5 = 0;
      LEDOff(5);
   }

   // Read analog inputs
   right=ReadADC(SENSOR4);
   if(right>SENSOR_THRES)//Right black line sensor
   {
      sensor4 = 1;
      LEDOn(4);
   }
   else
   {
      sensor4 = 0;
      LEDOff(4);
   }

   middle=ReadADC(SENSOR3);
   if(middle>SENSOR_THRES)// Middle black line sensor
   {
      sensor3 = 1;
      LEDOn(3);
   }
   else
   {
      sensor3 = 0;
      LEDOff(3);
   }

   left=ReadADC(SENSOR2);
   if(left>SENSOR_THRES)// Left black line sensor
   {
      sensor2 = 1;
      LEDOn(2);
   }
   else
   {
      sensor2 = 0;
      LEDOff(2);
   }

   eleft=ReadADC(SENSOR1);
   if(eleft>SENSOR_THRES)// Left black line sensor
   {
      sensor1 = 1;
      LEDOn(1);
   }
   else
   {
      sensor1 = 0;
      LEDOff(1);
   }


   if(sensor1==0 && sensor2==0 && sensor3==0 && sensor4==0 && sensor5==0)
   {
      return 0xFF;
   }

   // Calculate weighted mean
   avgSensor = (float) sensor1*1 + sensor2*2 + sensor3*3 + sensor4*4 + sensor5*5 ;
   avgSensor = (float) avgSensor / (sensor1 + sensor2 + sensor3 + sensor4 + sensor5);

   return avgSensor;
}

The LFR Code Walkthrough.

The main program begins by Initializing three subsystems namely MotorLED and ADC(for sensor input). The code is as follows.
 //Initialize Motors subsystem.
 MotorInit();
 
 //Initialize LED subsystem
 LEDInit();
 
 //Initialize Analog to Digital Converter (ADC)
 InitADC();
Then program enters into a infinite loop ( while(1) { //Main LFR Loop } ), this infinite loop keeps the robot follow line as long as it has power.
In the loop first thing we do is to read the sensor using the ReadSensors() we get a value between 1 to 5 as follows.
  • When the line is towards right of center then value tends to 5
  • When the line is towards left of center then value tends to 1
  • When line is in the exact center the the value is 3
  • Returns 0xFF if no line is detected.
  • Return value may be fractional also, like it is 2.5 when line is beneath sensor 2 and sensor 3.
In case a line is NOT found we below any sensor we used value we got last time. This is done by storing the current line position in a variable sprev just before the end of main loop. This sprev is used as previous line position for the next loop.
Code:
 s=ReadSensors();
 //If line is not found beneath any sensor, use last sensor value. 
 if(s==0xFF)
 {
  s=sprev;
 }
Now a PID algorithm is used to find out the control variable from the current positionand required position.
Current Position it is the position of line as read by the sensors.
Required Position is 3 (to keep the line on the middle sensor whose number is 3)
Code:
control = PID(s,3.0);
Then we make the control variable come within a range of -510 to +510
Code:
 //Limit the control
 if(control > 510)
 control = 510;
 if(control < -510)
 control = -510;
When the control variable is more than 0 that means line is towards the left, so we need to take right turn to correct the error and bring the robot back to track. To do a right turn we need to make the right motor go slow by the amount of control (if control is less than 255).
Code:
MotorA(MOTOR_CCW,255-control);
if control is more than 255 then we need to make the right motor go in opposite direction by the amount of control.
This will create a much faster right turning.
MotorA(MOTOR_CW,control-255);
Similarly if control variable is less than 0 that means line is towards the right, so we need to take left turn to correct the error and bring the robot back to track. The whole code looks like this.
  if(control > 0.0)//the left sensor sees the line so we must turn right
  {
   if(control>255)
    MotorA(MOTOR_CW,control-255);
   else
    MotorA(MOTOR_CCW,255-control);
   
   MotorB(MOTOR_CW,255);
  }
  if(control <= 0.0)//the right sensor sees the line so we must turn left
  { 
   if(control<-255)
    MotorB(MOTOR_CCW,-(control+255));
   else
    MotorB(MOTOR_CW,255+control);
    
   MotorA(MOTOR_CCW,255);
  } 
For more information turning the robot please see differential drive mechanism.
Finally we delay a bit for next cycle and store the current line position (s) to variablesprev for used in next cycle.
 //Delay 
 DelayMs(delay);
 
 sprev=s;

Programming the LFR Hex code to MCU.

Configuring the MCU

The MCUs fuse bits must be set as follows.
  • LOW Fuse = 0xFF
  • HIGH Fuse = 0xC9
Setting AVR Fuse Byte

Fig.: Setting the Fuse bytes.

Running the Robot.

Put batteries in your robot and place it in the flex sheet which has a line printed on it using black colour. Place the robot over the line. Switch on the robot and see the action.

Trouble Shooting.

If you are not lucky enough to get this working in the first try, don't be much unhappy! First try to do every thing exactly as I told. Make sure you should not use any type of replacement parts like a 200 RPM motor because every thing need to be in harmony. Using a battery with higher voltage or high speed motor will make the robot go too fast to catch the line. Similarly using another surface than a flex will have different reflectance so the sensor will not be able to "see" the line.
If you are using exactly 100% same steps and parts and still not able to get the robot working. Leave a comment in a proper manner with sufficient details so that we can help you. And never use SMS language while leaving a comment. If you don't have time to write then others also don't have time to read!
Best of luck ! I am here to help all !

Downloads.