4 Wheel Drive Line Follower Robot

by maker_ATOM in Circuits > Robots

13670 Views, 73 Favorites, 0 Comments

4 Wheel Drive Line Follower Robot

20211103_115835.jpg
4 Wheel Drive Line Follower Robot | Demonstration
20211103_113904.jpg
20211103_114811.jpg
20211103_114529.jpg

Line follower robot are one of the classic project for a robotic enthusiast with self balancing and obstacle avoidance robots. It helps to get acquainted with IR sensors, motor drivers, conditional statements and PID controllers.

So let's build a line follower robot giving it a spicy touch by making the robot more advance and including 4 wheel drive.

The Idea

1.PNG
3.PNG
2.PNG
4.PNG
5.PNG

The basic idea is to make the build look more like a F1 car with as possible as low ground clearance.

The chassis

The chassis will be made up of two major parts - one rear and other front. Both of them will be connected in the middle portion using nuts and bolts. A rear wing will be attached to give the build a final touch.

IR sensors

For the robot to know it's position on the track we will use IR sensors. The more IR sensors we have the more precisely we can know the position. Keeping this in mind we will use QTR-8RC sensor - a array of 8 IR sensors.

The QTR sensor will be installed to the front of the build resembling front wing of an F1 car.

Motor and it's Driver

As of motor we will be using N20 gear motor 1000rpm 12V - small and robust.

To driver the motors, L293d IC in DIP package is the perfect match.

Wheels

We will be 3D printing the wheels so that we can have custom diameter to fulfill the low ground clearance parameter.

Micro-controller

Arduino Nano is perfect for this build, able to handle PID controller and also not being an overkill.

Power House

3 li-ion batteries in series will be used as power house for the motor as well as micro-controller with voltage stepped down using a buck converter.

Breadboard

2 breadboards will be used to connect everything electrically...Wondering why breadboard and not PCB... Well because breadboard are super cheap than PCBs, no need of permanent connections and can be made look more nicer using jumper routing.

A Bit of Theory

20211101_190334.jpg
20211101_190421.jpg
20211101_190403.jpg

A line follower robot works by sensing the darkness of the track and follows it.

To sense the darkness of the track the robot uses an IR sensor.

The sensor has a IR LED and a IR receiver in pair. When the sensor is over black line all the light from IR LED is absorb and the IR receiver receives none and hence outputs digital low. And when the sensor is over white area it outputs digital high.

Note: Whether to output low or high on black line depends on the sensor construction, for sensor we are going to use follows above mentioned way.

We need at least 2 sensors to detect the direction of movement but we can use more sensors to improve the precision and get more data about the position of the robot on the track.

Supplies

Electronic Components:

  • Arduino Nano x 1_________________ Link
  • QTR 8-RC module x 1 _____________Link
  • Breadboard x 2 __________________ Link
  • L293d x 2_______________________ Link
  • N20 12V 1000rpm gear motor x 4____ Link
  • 18650 li ion battery x 3 ____________ Link
  • LM2596 buck converter module x 1 __ Link

Supplies:

  • 18650 Li-ion 3S cell holder x 1 ______Link
  • Male - Female jumpers ____________Link
  • Male pin headers_________________Link
  • Single strand wire for jumpers_______Link
  • N20 motor brackets x 4____________Link
  • M2 - 10mm countersunk bolts x 20___Link
  • M2 nuts x 20 ____________________Link
  • Rubber band x 8 _________________Link

Tools:

  • 3D printer/ 3D printing service
  • Screw diver (matching with bolts)
  • Multimeter
  • Hack saw/ household cutter
  • super glue
  • Tweezzer
  • Double tape
  • Solder iron

Secondary

  • Black electrical tape
  • chart paper A1 size

Printing 3D Parts

chassis_p1.PNG
chassis_p2.PNG
chassis_p3.PNG
Fwheel.PNG
Rwheel.PNG
Rwing_p1.PNG
Rwing_p2.PNG
Rwing_p2_mirror.PNG

I have printed the parts in PLA and so you can with 0.4mm nozzle, 0.2mm layer height and 20% infill without any custom settings.

As of color the wheels are printed in black and for the chassis you can go with any color you like.

The parts were designed in Fusion 360.

Preparing QTR-8RC Sensor

IMG_20211008_222755.jpg
IMG_20211008_222729.jpg
IMG20211005212141.jpg

We will utilize almost every pin on the module except IR which is used to turn on and off the IR LEDs if necessary. The pin is pull high internally so even if we don't connect it will be ok.

  • Solder male pin headers to module.
  • Ensure the long legs are on the side of PCB where no component is present and the solder joint are soldered on the side where components are present.

Assembly 1 - Front Motor Bolts

IMG20211008092743.jpg
IMG20211008093113.jpg
IMG20211008095056.jpg
IMG20211008095225.jpg
IMG20211008093247.jpg
IMG20211008095311.jpg
IMG20211008100844.jpg
IMG20211008100904.jpg
IMG20211008100924.jpg

Removing Stringing

The best way to remove stringing post 3D printing is to use a pointed tip solder iron.

  • Ensure solder iron is hot enough.
  • Insert it though the holes so as stringing plastic melts of and gives room for bolts to go through.

With this we can also enlarge the holes if necessary.

Inserting bolts

  • Insert the bolt from bottom part of the chassis using a screw driver.

As the head of the bolt is bigger than the bolt body and so the holes are made bigger on the bottom side.

  • After inserting the bolt through holes, temporarily fic them in place using nuts.

Similarly insert and temporarily fix the other 3 bolts.

Assembly 2 - Front Bumper

IMG20211008092655.jpg
IMG20211008101229.jpg
IMG20211008101241.jpg
IMG20211008101351.jpg
IMG20211008101415.jpg
IMG20211008101454.jpg
IMG20211008101546.jpg
IMG20211008101814.jpg
IMG20211008101844.jpg
  • To add the support structure to holds the line sensor, first remove all the stringing using a solder iron.
  • Enlarge the curved parts of the support so that QTR sensor fits perfectly.
  • Insert the bolt from inside the chassis part and nut down the bolt.

This way the the support structure is firmly attached to the chassis.

If you observe there are no holes on support structure but slots for bolts to go.

They are made so that we can raise or lower the sensor so that we can have custom distance from the ground as the range of detection of sensor is low - from 3mm to 9mm.

Assembly 3 - Line Array Sensor

IMG20211008102000.jpg
IMG20211008102012.jpg
IMG20211008102152.jpg
IMG20211008102109.jpg
IMG20211008102422.jpg
IMG20211008102439.jpg
IMG20211008102512.jpg
  • Bolt the QTR module to the support structure.
  • Make sure the IR sensor face downwards.

The module can be paced either above the print or below as the print itself can move up or down but eventually the sensor was placed below the print.

Assembly 4 - Front Motor Brackets

IMG20211008102619.jpg
IMG20211008102711.jpg
IMG20211008102807.jpg
IMG20211008102932.jpg
IMG20211008103025.jpg
IMG20211008103215.jpg

Time to assemble brackets for the front motors.

  • Do insert nuts in brackets.
  • First insert the screwdriver and hold the bolt in place.
  • Then remove the nut we fixed temporarily.
  • Now fix the one end of bracket by tightening the bolt.

Follow the same process to fix both brackets.

Assembly 5 - Motors and Breadboards

IMG20211008103405.jpg
IMG20211008103432.jpg
IMG20211008103536.jpg
IMG20211008103718.jpg
IMG20211008103746.jpg
IMG20211008103801.jpg
IMG20211008103826.jpg
IMG20211008103857.jpg
  • Before we insert motors first trim off the male part of breadboard which is used to cascade with other breadboard.

It can be done with hacksaw or even a household cutter.

  • Now to fix the motors, unscrew the bolts a little and slide the motors and then tighten the bolts.
  • And now slide the breadboard into the profile for it.

Assembly 6 - Rear Wing

IMG20211008115154.jpg
IMG20211008115221.jpg
IMG20211008115338.jpg
IMG20211008115542.jpg
IMG20211008115647.jpg
IMG20211008115817.jpg
IMG20211008120143.jpg
IMG20211008120158.jpg
IMG20211008120209.jpg

At first it was intended that the rear wing will be installed using nut and bolt at this stage of build, but as I went on further with the build the rear wing hindered the process of wiring so I eventually I removed the wings and then latter installed them when the wiring was complete.

So I recommend not to install the wing at this stage. You might see the wing in few further steps, just ignore them.

Assembly 7 - Battery Holder

IMG20211008120609.jpg
IMG20211008120633.jpg
IMG20211008120652.jpg
IMG20211008120856.jpg
IMG20211008120937.jpg
IMG20211008121036.jpg

To fix the battery pack place it below the rear chassis and insert the bolt from below and nut down from above.

It doesn't really matter if the red wire is to the left or right of rear wing as the holder is symmetric.

Assembly 8 - Rear Motor Brackets

IMG20211008121320.jpg
IMG20211008121442.jpg
IMG20211008121509.jpg
IMG20211008121713.jpg

To install brackets for rear motors, bolt the brackets over the place intended for them on the rear part.

Do place the nuts in the brackets.

Assembly 9 - Joining the Front and Rear Part

IMG20211008092713.jpg
IMG20211011152620.jpg
IMG20211011152737.jpg
IMG20211011154545.jpg
IMG20211011154601.jpg
IMG20211011154914.jpg
IMG20211011155236.jpg
IMG20211011155306.jpg
IMG20211011155614.jpg
IMG20211011155628.jpg

The front part of chassis and rear part are ready to be attached together.

Both part sandwich into each other with the help of dedicated profile.

  • To join them permanently we'll use nut bolts.
  • First flip the build on its side profile.
  • Now using a tweezer hold a nut inside the cavity.
  • Take a bolt and fix into the nut using screw driver.

Go for the inner holes first then for outer ones.

Assembly 10 - Installing Rear Motors

IMG20211011155732.jpg
IMG20211011155805.jpg
IMG20211011155818.jpg
IMG20211011160037.jpg
IMG20211011160308.jpg

To install the rear motors same as front motors, loosen the bolts a little, slide the motor and then tighten the bolts again.

Assembly 11 - Installing Breadboard

IMG20211011160343.jpg
IMG20211011160411.jpg
IMG20211011160404.jpg
IMG20211011160540.jpg
IMG20211011160616.jpg

To install the breadboard on rear part remove the double tape cover and place it on the center of the chassis. The breadboard being symmetric can be placed any how with the longer side parallel to the axle.

Assembly 13 - Attaching Wheels

IMG20211011190526.jpg
IMG20211011223145.jpg
IMG20211011223156.jpg

Insert the wheels into the motor shaft where the hollow part faces outwards.

The wheels were designed with a tight tolerance so the wheels need a bit of force to go through the shaft. There might be chance that wheel wont go through the shaft due to printer setting in that case use a solder iron to expand the hole.

If by chance the hole gets more bigger than required use hot glue or super glue to fix it.

Ground Clearance

IMG20211011191621.jpg
IMG20211011191818.jpg
IMG20211011223714.jpg
IMG20211011224510.jpg
IMG20211011224610.jpg
IMG20211011224648.jpg

The ground clearance should be 3mm as of design but considering the weight of batteries and other components, the chassis does bend a little reducing the ground clearance and chance are there where the chassis might hit track.

So to increase the ground clearance a small piece or paper or cardboard can be inserted into the gap where the front and the rear parts meet on the upper side.

This increase the ground clearance on the middle portion but alters the distance of QTR sensor from the track as the contact point of front wheels act as a pivot.

This distance of sensor can be adjusted by moving the support structure up and down as its has slots in it. It doesnt really matter if sensor is placed above the support structure or below.

Assembly 14 - Installing Buck Converter

IMG20211011225303.jpg
IMG20211011225325.jpg
IMG20211011225902.jpg
IMG20211011230406.jpg
IMG20211011230536.jpg
IMG20211011230731.jpg

The buck converter will be placed on the mounting brackets of rear motor using double tape.

  • Cut out 2 pieces of double tape with size same as top of mounting bracket of motor.
  • Peal off and stick the double tape on the mounting bracket.
  • Now peal the other coating and place the buck over it.

Orientation: The power IN terminals should be towards you when the QTR sensor faces to left.

Cut out the floating wires of battery pack to appropriate length and solder them to power in terminals.

Red goes to +IN and black to -IN on buck converter.

Setting the Buck Converter to 5V

IMG20211012084657.jpg
IMG20211012084739.jpg

The buck converter reduces the voltage from battery pack to 5V efficiently which is the optimal working voltage of Arduino Nano, QTR sensor.

  • Insert the batteries in battery pack with proper orientation.
  • Test the battery pack voltage using a multimeter, it should be between 9.6V to 12V
  • To set the buck converter rotate the potentiometer so as to get 5V on multimeter.

Now the buck converter is all set to deliver 5V.

Placing Motor Driver and Micro Controller

IMG20211012085000.jpg
IMG20211012085006.jpg
IMG20211012085029.jpg

Place L293d IC on lower breadboard where the notch of the IC points to the front of the robot.

As of Arduino Nano place it on upper breadboard with the USB facing to the front when the QTR sensor faces to right.

Note: The orientation as described and shown in picture are different as it was changed latter in the build.

Connecting Front Motors

1.PNG
IMG20211013082938.jpg
IMG20211013084918.jpg
IMG20211013090418.jpg
IMG20211013090437.jpg
IMG20211013090930.jpg
IMG20211013090957.jpg

To connect the motors,

  • First cut out 4 pieces of single strand wire 2 of different color each.
  • Strip off the insulation of wire just so that the wire goes all into the breadboard.
  • Now bend one side of the wire so that it gets inserted into the hole on the motor.
  • Now insert the wire on breadboard this should connect one motor to pin 3 and 6 and other motor to pin 11 and 14.
  • Insert the bend part into hole of motor and solder them.

Powering Micro Controller

2.PNG
IMG20211013092552.jpg
IMG20211013093250.jpg
IMG20211013093437.jpg
IMG20211013093613.jpg

Arduino Nano will be powered using buck converter and as the the voltage is step down by buck converter we will connect its output to 5V pin of Nano rather than Vin of Nano.

  • Take a single strand wire and cut to appropriate length
  • Then solder the one end to buck converter and bend other end and insert in breadboard.

Connections:

____Buck converter__Arduino Nano__

  • ___OUT+_________ 5V________
  • ___OUT-_________ GND ______

Connecting Front Motor Drivers

3.PNG
IMG20211013100915.jpg
IMG20211013100934.jpg
IMG20211014082720.jpg
IMG20211014082740_01.jpg
IMG20211014082757.jpg
IMG20211014082848.jpg
IMG20211014083126.jpg
IMG20211014083157.jpg

All the connections were made using single strand wire except the power for motors to save red color wire for future use.

Note: The connections illustrated above and mentioned below are ones to be followed and not the ones shown in picture as they were changed to ease out the code in latter of the build.

Connections:

L293d-1 is the one closest to front motors

____Nano___L293d-1___L293d-2____

  • _ 5V____pin 16_____ pin 16_____
  • _GND___pin 4_____ pin 4-12____ (pin 4,5,12,13 of L293d are connected to each other internally)
  • _ D2___ pin 1, 9____ pin 1, 9____
  • _D12 ___pin 7________________
  • _D11 ___pin 2________________
  • _D10___pin 10 _______________
  • _D5____pin 15 _______________
  • _______pin 8______pin 8 ____to + of battery pack taken through IN+ of buck converter

Connecting Rear Motors

4.PNG
IMG_20211014_121531.jpg
IMG20211014120113.jpg
IMG20211014120137.jpg
IMG20211014120307.jpg
IMG20211014120657.jpg
IMG20211014120749.jpg
IMG20211014121108.jpg
IMG20211014121136.jpg
IMG20211014121307.jpg

The connection for rear motor were also made using single strand wires.

Connections:

____Nano____L293d-1____L293d-2___

  • _D9_________________pin 2 ____
  • _D8_________________pin 7 ____
  • _D7_________________pin 10 ___
  • _D6_________________pin 15 ___
  • pin 3 to closet pin to arduino of left motor when seen from behind
  • pin 6 to farthest pin to arduino of left motor
  • pin 11 to closer pin to arduino of right motor
  • pin 14 to farthest in to arduino of right motor

Still confused?

No worries head on to next step it will help in debugging.

Testing Motor Connections

20211104_180513.gif

Insert the batteries in the battery holder and upload the following sketch in Nano.

#define motorEnable 2

#define AmotorPow 11
#define AmotorDir 12
#define BmotorPow 10
#define BmotorDir 5
#define CmotorPow 9
#define CmotorDir 8
#define DmotorPow 6
#define DmotorDir 7

void setup()
{
  pinMode(motorEnable, OUTPUT);

  pinMode(AmotorPow, OUTPUT);
  pinMode(AmotorDir, OUTPUT);
  pinMode(BmotorPow, OUTPUT);
  pinMode(BmotorDir, OUTPUT);
  pinMode(CmotorPow, OUTPUT);
  pinMode(CmotorDir, OUTPUT);
  pinMode(DmotorPow, OUTPUT);
  pinMode(DmotorDir, OUTPUT);

  digitalWrite(motorEnable, HIGH);

  delay(2000);
}

void loop()
{
  //move forward
  digitalWrite(AmotorDir, HIGH);
  analogWrite(AmotorPow, 0);
  digitalWrite(CmotorDir, HIGH);
  analogWrite(CmotorPow, 0);
  digitalWrite(BmotorDir, HIGH);
  analogWrite(BmotorPow, 0);
  digitalWrite(DmotorDir, HIGH);
  analogWrite(DmotorPow, 0);
  delay(2000);

  //stop
  digitalWrite(AmotorDir, LOW);
  analogWrite(AmotorPow, 0);
  digitalWrite(CmotorDir, LOW);
  analogWrite(CmotorPow, 0);
  digitalWrite(BmotorDir, LOW);
  analogWrite(BmotorPow, 0);
  digitalWrite(DmotorDir, LOW);
  analogWrite(DmotorPow, 0);
  delay(400);

  //rotate clockwise
  digitalWrite(AmotorDir, HIGH);
  analogWrite(AmotorPow, 0);
  digitalWrite(CmotorDir, HIGH);
  analogWrite(CmotorPow, 0);
  digitalWrite(BmotorDir, LOW);
  analogWrite(BmotorPow, 255);
  digitalWrite(DmotorDir, LOW);
  analogWrite(DmotorPow, 255);
  delay(500);

  //stop
  digitalWrite(AmotorDir, LOW);
  analogWrite(AmotorPow, 0);
  digitalWrite(CmotorDir, LOW);
  analogWrite(CmotorPow, 0);
  digitalWrite(BmotorDir, LOW);
  analogWrite(BmotorPow, 0);
  digitalWrite(DmotorDir, LOW);
  analogWrite(DmotorPow, 0);
  delay(400);
}

After 2 seconds of powering up the wheels should start rotating.

Place the robot on ground, if all the connections were made perfectly then the robot should move forward for about 2 seconds rotate clockwise and then again move forward in whichever direction it is pointing.

Points for debugging:

  • If the wheels rotate in the opposite direction than expected, flip the connections to the motors.

Connecting QTR Sensor

5.PNG
IMG20211015153539.jpg
IMG20211015154047.jpg
IMG20211015154209.jpg
IMG20211015155620.jpg
IMG20211015155734.jpg
IMG20211017102404.jpg
IMG20211017102422.jpg
IMG20211017102443.jpg
IMG20211017102455.jpg
IMG20211017102600.jpg

Note: The QTR sensor as depicted in the illustration and the one used are not same.

As the QTR sensor has male headers and the breadboard require female ones we need male to female jumper wire to connect QTR sensor to Nano but the length of the premade jumpers is not customizable, so I have cut the female part of jumper to required length and then soldered the open end to male pin headers.

Connections:

____QTR sensor____Nano__

  • _VCC__________5V ___
  • _GND________ GND___
  • _D1___________D3____
  • _D2___________D4____
  • _D3___________A5____
  • _D4___________A4____
  • _D5___________A3____
  • _D6___________A2____
  • _D7___________A1____
  • _D8___________A0____

There is no need to connect IR pin to any as the pin internally connected to VCC.

Adding Rear Wing

IMG20211029112352.jpg
IMG20211029112414.jpg
IMG20211029112426.jpg
IMG20211029112433.jpg

It was planned to install the rear wing using nut and bolts, but I did not wanted to remove the battery holder so eventually ended super gluing the rear wing.

  • First super glue the 2 supports and then glue the wing over them.

If the wires create a obstruction remove or bend them temporary.

Complete With the Assembly

20211103_115835.jpg

After Installing the rear wing we are complete with the assembly of the robot.

The only thing left is to build a track and to program the robot.

Required Libraries

qtr library.PNG
library for pid.PNG

Library for QTR sensor

To read the data from QTR sensor we will utilize library developed from pololu itself. It can be directly installed from Arduino IDE by searching QTR in the library manager.

Library for PID controller

To implement PID control we use library developed by Brett Beauregard. It can also be installed directly from the Arduino IDE by searching PID in the library manager.

Building the Track

IMG_20211110_084414.jpg
IMG20211110081043.jpg

The shape of the track is totally customizable.

To build the track you can use chart paper (25 x 30 inch) and stick them together to form a bigger arena.

Use pencil to outline the track first and then use electrical tape to form the track.

Testing and Calibrating QTR Sensor

Screenshot (4).png
1.PNG
20211110_084705.gif

To test the QTR sensor upload the example sketch QTRRCExample available in the QTR library.

Change the following line of code as the default pins are not the ones we are using.

  qtr.setSensorPins((const uint8_t[]){ 3, 4, 19, 18, 17, 16, 15, 14}, SensorCount);

After uploading open the serial monitor.

The build-in LED indicates the status of calibration. When the LED turns on, it indicates that calibration has started. Move the robot to and fro on the track to calibrate it. Each IR sensor should sense the darkness and brightness at least once. As the calibration time ends the LED turns off and we can see some values on the serial monitor.

The first 8 vertical columns indicate the 8 IR sensors. If the sensor is on dark line then the sensor outputs is greater than 500 and if its on white area it outputs values less than 300.

The last column indicates the position of the robot on track. 3500 indicates the robot is perfectly centered. 0 indicated the bot is to extreme right and if the line position is 7000 it indicated the bot is at extreme left.

The Programs

There are multiple algorithms for the line follower robot to work of which the following 2 are most commonly used.

With conditional statements

In this algorithm we use conditional statements like if ... else statements to check the position of robot on the track using array of IR sensors (QTR sensor) and then accordingly we power the motors to turn left or right.

Overview of the code

First we define the necessary variables and macros.

Then in setup function we set all motors pins to output. Then we call few functions to set the QTR sensor. Then the calibration starts. Keep the robot on the track and move it to and fro for the IR sensors to detect darkness and brightness. The end of calibration is indicated by turning off the build-in LED. It waits for 2 seconds and moves to loop function.

In loop function it first checks the position of itself on the track using a function from the QTR library. Then we set the variables - turn direction and motor speed accordingly to the position of robot on the track and we gradually decrease or increase the motor speed so that the robots turns smoothly and then we set the motors to, based the turn direction and present motor speed.

//using conditional statements

#include<QTRSensors.h>

#define motorEnable 2
#define AmotorPow 11
#define AmotorDir 12
#define BmotorPow 10
#define BmotorDir 5
#define CmotorPow 9
#define CmotorDir 8
#define DmotorPow 6
#define DmotorDir 7

QTRSensors qtr;

const uint8_t SensorCount = 8;
uint16_t sensorValues[SensorCount];

int Input;

int motorPow = 0;
int neededmotorPow = 0;
int turnDirec = 0;

unsigned long currentTime = 0;
unsigned long prevTime = 0;
unsigned long elapsedTime = 0;

void setup()
{
  pinMode(motorEnable, OUTPUT);

  pinMode(AmotorPow, OUTPUT);
  pinMode(AmotorDir, OUTPUT);
  pinMode(BmotorPow, OUTPUT);
  pinMode(BmotorDir, OUTPUT);
  pinMode(CmotorPow, OUTPUT);
  pinMode(CmotorDir, OUTPUT);
  pinMode(DmotorPow, OUTPUT);
  pinMode(DmotorDir, OUTPUT);

  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]) {
    3, 4, 19, 18, 17, 16, 15, 14
  }, SensorCount);

  digitalWrite(motorEnable, LOW);

  //calibration
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t i = 0; i < 400; i++)
  {
    qtr.calibrate();
  }
  digitalWrite(LED_BUILTIN, LOW);
  delay(2000);

  digitalWrite(motorEnable, HIGH);

}

void loop()
{
  currentTime = millis();
  elapsedTime = currentTime - prevTime;

  Input = qtr.readLineBlack(sensorValues);

  //case 1 extreme left
  if ((Input > 0) & (Input < 250))
  {
    neededmotorPow = 0;
    turnDirec = 0;
  }

  //case 2 left
  else if ((Input > 250) & (Input < 750))
  {
    neededmotorPow = 7;
    turnDirec = 0;
  }

  //case 3 left
  else if ((Input > 750) & (Input < 1250))
  {
    neededmotorPow = 14;
    turnDirec = 0;
  }

  //case 4 left
  else if ((Input > 1250) & (Input < 1750))
  {
    neededmotorPow = 21;
    turnDirec = 0;
  }

  //case 5 left
  else if ((Input > 1750) & (Input < 2250))
  {
    neededmotorPow = 28;

    turnDirec = 0;
  }

  //case 6 left
  else if ((Input > 2250) & (Input < 2750))
  {
    neededmotorPow = 35;
    turnDirec = 0;
  }

  //case 7 left
  else if ((Input > 2750) & (Input < 3250))
  {
    neededmotorPow = 42;
    turnDirec = 0;
  }

  //case 8 go straight
  else if ((Input > 3250) & (Input < 3750))
  {
    neededmotorPow = 47;
    turnDirec = 1;
  }

  //case 9 right
  else if ((Input > 3750) & (Input < 4250))
  {
    neededmotorPow = 42;
    turnDirec = 2;
  }

  //case 10 right
  else if ((Input > 4250) & (Input < 4750))
  {
    neededmotorPow = 35;
    turnDirec = 2;
  }

  //case 11 right
  else if ((Input > 4750) & (Input < 5250))
  {
    neededmotorPow = 28;
    turnDirec = 2;
  }

  //case 12 right
  else if ((Input > 5250) & (Input < 5750))
  {
    neededmotorPow = 21;
    turnDirec = 2;
  }

  //case 13 right
  else if ((Input > 5750) & (Input < 6250))
  {
    neededmotorPow = 14;
    turnDirec = 2;
  }

  //case 14 right
  else if ((Input > 6250) & (Input < 6750))
  {
    neededmotorPow = 7;
    turnDirec = 2;
  }

  //case 15 exterme right
  else if ((Input > 6750) & (Input < 7250))
  {
    neededmotorPow = 0;
    turnDirec = 2;
  }

  //stop
  else
  {
    neededmotorPow = 255;
    turnDirec = 1;
  }


  if (elapsedTime > 100)
  {
    if (motorPow > neededmotorPow)
    {
      motorPow--;
    }
    else if (motorPow < neededmotorPow)
    {
      motorPow++;
    }
    prevTime = currentTime;
  }

  //left
  if (turnDirec == 0)
  {
    digitalWrite(AmotorDir, HIGH);
    analogWrite(AmotorPow, motorPow);
    digitalWrite(CmotorDir, HIGH);
    analogWrite(CmotorPow, motorPow);
    digitalWrite(BmotorDir, LOW);
    analogWrite(BmotorPow, 255 - motorPow);
    digitalWrite(DmotorDir, LOW);
    analogWrite(DmotorPow, 255 - motorPow);
  }

  //straight
  if (turnDirec == 1)
  {
    digitalWrite(AmotorDir, HIGH);
    analogWrite(AmotorPow, motorPow);
    digitalWrite(CmotorDir, HIGH);
    analogWrite(CmotorPow, motorPow);
    digitalWrite(BmotorDir, HIGH);
    analogWrite(BmotorPow, motorPow);
    digitalWrite(DmotorDir, HIGH);
    analogWrite(DmotorPow, motorPow);
  }

  //right
  if (turnDirec == 2)
  {
    digitalWrite(AmotorDir, LOW);
    analogWrite(AmotorPow, 255 - motorPow);
    digitalWrite(CmotorDir, LOW);
    analogWrite(CmotorPow, 255 - motorPow);
    digitalWrite(BmotorDir, HIGH);
    analogWrite(BmotorPow, motorPow);
    digitalWrite(DmotorDir, HIGH);
    analogWrite(DmotorPow, motorPow);
  }
}

With PID Controller

The other code uses PID algorithm to set the motors according to position over the track.

As the input values are discrete the effect of D and I on the Output is fairly negligible. Hence the code only uses P controller.

The input parameter of P controller is the position of robot on the track and the Output of the P controller is the motor speed with turn direction indicated by sign of the motor speed.

The value of parameter P was figured manually.

//using only P of PID controller 

#include<PID_v1.h>
#include<QTRSensors.h>

#define motorEnable 2

#define AmotorPow 11
#define AmotorDir 12
#define BmotorPow 10
#define BmotorDir 5
#define CmotorPow 9
#define CmotorDir 8
#define DmotorPow 6
#define DmotorDir 7

double Setpoint = 3500;

double Input, Output;

double Kp = 0.017;
double Kd = 0;
double Ki = 0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

QTRSensors qtr;

const uint8_t SensorCount = 8;
uint16_t sensorValues[SensorCount];

int motorPow = 0;

void setup()
{
  pinMode(motorEnable, OUTPUT);

  pinMode(AmotorPow, OUTPUT);
  pinMode(AmotorDir, OUTPUT);
  pinMode(BmotorPow, OUTPUT);
  pinMode(BmotorDir, OUTPUT);
  pinMode(CmotorPow, OUTPUT);
  pinMode(CmotorDir, OUTPUT);
  pinMode(DmotorPow, OUTPUT);
  pinMode(DmotorDir, OUTPUT);

  digitalWrite(motorEnable, LOW);

  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255, 255);
  myPID.SetSampleTime(5);
  //myPID.SetControllerDirection(REVERSE);

  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]) {
    3, 4, 19, 18, 17, 16, 15, 14
  }, SensorCount);

  //calibrate
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t i = 0; i < 400; i++)
  {
    qtr.calibrate();
  }
  digitalWrite(LED_BUILTIN, LOW);
  delay(2000);

  digitalWrite(motorEnable, HIGH);
}

void loop()
{
  Input = qtr.readLineBlack(sensorValues);

  myPID.Compute();

  //straight
  if ((Output < 4) & (Output > -4))
  {
    motorPow = map(Output, -4, 4, 0, 4);
    digitalWrite(AmotorDir, HIGH);
    analogWrite(AmotorPow, motorPow);
    digitalWrite(CmotorDir, HIGH);
    analogWrite(CmotorPow, motorPow);
    digitalWrite(BmotorDir, HIGH);
    analogWrite(BmotorPow, motorPow);
    digitalWrite(DmotorDir, HIGH);
    analogWrite(DmotorPow, motorPow);
  }

  //right
  else if (Output > 4)
  {
    digitalWrite(BmotorDir, LOW);
    analogWrite(BmotorPow, 195 + Output);
    digitalWrite(DmotorDir, LOW);
    analogWrite(DmotorPow, 195 + Output);
    digitalWrite(AmotorDir, HIGH);
    analogWrite(AmotorPow, 60 - Output);
    digitalWrite(CmotorDir, HIGH);
    analogWrite(CmotorPow, 60 - Output);
  }

  //turn left
  else if (Output < -4)
  {
    digitalWrite(BmotorDir, HIGH);
    analogWrite(BmotorPow, 60 - abs(Output));
    digitalWrite(DmotorDir, HIGH);
    analogWrite(DmotorPow, 60 - abs(Output));
    digitalWrite(AmotorDir, LOW);
    analogWrite(AmotorPow, 195 + abs(Output));
    digitalWrite(CmotorDir, LOW);
    analogWrite(CmotorPow, 195 + abs(Output));
  }
}

Playing With the Robot

You can use any of the two programs to command the robot.

Place the batteries in the battery holder. As soon as the robot is powered the first thing it does is starts calibration. As mentioned move the robot to and fro to calibrate itself.

Calibration is performed every time the Nano is reset as the lighting conditions may change which affect the sensing of IR sensors.

Calibration last around 10 seconds. As the calibration ends indicated by build-in LED turning off it waits for 2 seconds and starts to follow the line.

Is Friction Enough?

IMG20211022112847.jpg
IMG20211022115943.jpg
IMG20211022121810.jpg
IMG20211022121818.jpg
IMG20211027142139.jpg
IMG20211027142210.jpg

As the wheels were printed in PLA material they might not perform well on paper so to improve the friction between the wheel and paper track we can wrap rubber bands over the wheels. Having two rubber bands on each side increases the stability of the wheels.

  • Use super glue to hold the rubber band in place.

Now you are all set to see the robot in action.

Insert the batteries, calibrate it and see the robot in action following the black line.

Final Thoughts

The build was not at all straight forward many things didn't go as planned so I had to revise some.

Few things I would like to improve in the next version is to use better material for the wheels, instead of having 2 chassis pieces joined together a complete chassis will be printed, and to to reduce the wobble by using more IR sensors with more efficient and better program.

Do follow me on Instagram.