Build an Arduino Line Following Robot
by David Kirk

Instructional YouTube Video:  https://youtu.be/vlrOqIcTcHc

    
click pictures to enlarge





Below is a list of parts needed.  Most parts can also be found on Amazon.

Item Price Supplier
Arduino Mega 2560 $11 Ebay
LN298 Motor Controller $4 Ebay
NeoPixel 8 LED Strip $7 Ebay
Dupont jumper wires (male to female) $4 Ebay
Arduino gear motors (wheels included) $6 Ebay
Arduino push button $2 Ebay
DC-168 12V battery & charger $10 Ebay
QTR-8RC $10 Pololu
Caster with 1/2" plastic ball $2 Pololu

Notes
1.  I like making the platform out of thin plywood.  Acrylic can be used but may crack easier.
2.  Many parts can be hot glued to the platform.  I recommend using the supplied bolts for mounting the caster.  The Arduino can be hot glued but I attached mine with bolts since there's sideways pressure on it when you plug in the data cable.
3.  The floor needs to be a non-reflective surface such as dull carpet.  For the line, I'm using 1" red 3M duct tape that's shiny (reflective).  If you can find 2" then cut it down the middle to have 1" width lines.
4.  The threshold values will need to be changed depending on the floor, reflective tape, and lighting. 
5.  If you use different motors such as ones from Pololu, make sure to get one with a higher gear ratio (higher torque).
6.  You can use an Arduino Uno, but can only connect 6 of the 8 sensors on the QTR-8C - leave the middle two disconnected.
7.  The QTR-8C will need to be soldered to the wires.  Also, wires need to be soldered to the motors and pushbutton.  Here's how to install the QTRSensor library for Arduino.
8.  The NeoPixel 8 LED Strip is not absolutely necessary, but definitely helps so you can see what the sensors see.  Here's how to install the NeoPixel library.
8.  I bought a female DC power connector to plug into the DC-168 battery, however, you could cut the battery's 12v output wires (male connector) and plug directly into the motor controller.
9.  The robot in the pictures above also has a speaker to make beeps or to play a victory song.
10.  Check out another robot I built:  Kirk BB-8
 

Sample Line Following Robot Code

// you made need to install the old version (3.0) of QTRSensors.h library in Arduino IDE
#include <QTRSensors.h>
#include <Adafruit_NeoPixel.h>

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(8, 10); // NumPixels, Pin

// Arduino Mega - connect QTR wires to Analog pins 0 - 7
QTRSensorsRC qtr((unsigned char[]) {54, 55, 56, 57, 58, 59, 60, 61}, 8);  // Mega code

// Arduino Uno - connect QTR wires to Analog pins 0 - 5
// QTRSensorsRC qtr((unsigned char[]) {14, 15, 16, 17, 18, 19}, 6); // Uno code

unsigned int sensor[8];  // used to store the value each sensor reads

// change these to set the the threshold for each sensor to detect a line
int Threshold[8] = {700, 700, 700, 700, 700, 700, 700, 700};

// connect motor controller pins to Arduino digital pins
int enA = 2; int in1 = 3; int in2 = 4;   // motor 1
int in3 = 5; int in4 = 6; int enB = 7;   // motor 2


void Stop()   // stop robot
{
   digitalWrite(in1, LOW);
   digitalWrite(in2, LOW);
   digitalWrite(in3, LOW);
   digitalWrite(in4, LOW);
}

void Forward (int LeftSpeed, int RightSpeed) // range 0 - 255
{
   digitalWrite(in1, HIGH); // turn on left motor to forward
   digitalWrite(in2, LOW);
   analogWrite(enA, LeftSpeed);
   digitalWrite(in3, HIGH); // turn on right motor to forward
   digitalWrite(in4, LOW);
   analogWrite(enB, RightSpeed);
}

void Reverse (int LeftSpeed, int RightSpeed) // range 0-255
{
   digitalWrite(in1, LOW); // turn on left motor to forward
   digitalWrite(in2, HIGH);
   analogWrite(enA, LeftSpeed);
   digitalWrite(in3, LOW); // turn on right motor to forward
   digitalWrite(in4, HIGH);
   analogWrite(enB, RightSpeed);
}

void SetPixelsToSensors()  // turn on NeoPixels that are less than threshold value
{
   for (int n=0; n<=7; n++)
   {
      if (sensor[n] < Threshold[n])
         pixels.setPixelColor(7-n, pixels.Color(40,40,40));
      else
         pixels.setPixelColor(7-n, pixels.Color(0,0,0));
      pixels.show();
   }
}

void setup()
{
   // set all the motor control pins to outputs
   pinMode(enA, OUTPUT);
   pinMode(enB, OUTPUT);
   pinMode(in1, OUTPUT);
   pinMode(in2, OUTPUT);
   pinMode(in3, OUTPUT);
   pinMode(in4, OUTPUT);
  
   Serial.begin(9600); // used to write to serial monitor
   pixels.begin();     // initialize NeoPixels

   // set up pushbutton
   pinMode(53,INPUT_PULLUP);

   while (digitalRead(53) != LOW) // loop until pushbutton is pressed
   {
      //for testing QTR, print the sensor values to Serial Monitor
      qtr.read(sensor);
      SetPixelsToSensors();
      Serial.print(sensor[0]); Serial.print(" "); Serial.print(sensor[1]); Serial.print(" ");
      Serial.print(sensor[2]); Serial.print(" "); Serial.print(sensor[3]); Serial.print(" ");
      Serial.print(sensor[4]); Serial.print(" "); Serial.print(sensor[5]); Serial.print(" ");
      Serial.print(sensor[6]); Serial.print(" "); Serial.print(sensor[7]); Serial.print("\n");
      delay(500);
   }
   Forward(50,50);
}

void loop()
{
   qtr.read(sensor);
   SetPixelsToSensors();

   if (sensor[0] < Threshold[0])
   {
      Forward(10,60);
   }
   else if (sensor[7] < Threshold[7])
   {
      Forward(60,10);
   }
   else if (sensor[1] < Threshold[1])
   {
      Forward(25,60);
   }
   else if (sensor[6] < Threshold[6])
   {
      Forward(60,25);
   }
   else if (sensor[5] < Threshold[5])
   {
      Forward(60,40);
   }
   else if (sensor[2] < Threshold[2])
   {
      Forward(40,60);
   }
   else if (sensor[3] < Threshold[3] || sensor[4] < Threshold[4])
   {
      Forward(60,60);
   }
   else if (sensor[5] < Threshold[5])
   {
      Forward(60,40);
   }
   else
      Forward(60,60);

   delay(10);
}