Project tutorial
Artificial Intelligence (AI) Based Line Following Robot

Artificial Intelligence (AI) Based Line Following Robot © LGPL

Artificial Intelligence (AI) based line Following robot is a robot that a sense of detecting the correct path for its route.

  • 2,996 views
  • 5 comments
  • 21 respects

Components and supplies

Apps and online services

About this project

After developing the Arduino based Pick & Place Robot the idea was to develop an Artificial Intelligent AI-based line following robot. Developing a simple line following robot was good for the beginner just what it needed to add some sort of infrared sensors instead of servo motors in my recent project. "The idea was to test my skills at advanced level".

Although it was a difficult task some sort of online research helped me a lot.

Why there is a need for AI-Based line following robot?

When comes to AI it's the recent technology that has the potential to change the world environment thus effective human life.A dream that can come true by putting intelligence to our robots to understand real-life problems and solve it accordingly, that dream can be only come true through Artificial Intelligence that's why everyone is talking about it.

  • It can be used in the assembly/production line.
  • Passenger pickup buses.

Although my prototype robot can be a bit of intelligence it's just a beginning for me to move my projects toward AI. Thus here I will try to explain step by step development of line following robot using Artificial Intelligence in quite a simple language. Due to a lack of resources, I will not build a robot but I can explain very well that how can you build it by doing some sort of research.I will try to provide accurate codes that will work on your Arduino IDE, So that you can develop your first AI robot quite easily.

You can support me on Patreon from Here: http://bit.ly/31NfQ6A

"You can find the cheapest rates apparatus in the USA on the description of this video just click on the video."

Now let's come to the project "An AI-based Line Following Robot ! ".

USE OF INFRARED SENSORS

Our project includes 7 infrared sensors as shown in the diagram.

  • 5 for PID Control
  • 1 for left detection
  • another one for right side detection.

5 PID Control Sensors Role: These 5 sensors will be used to generate digital output either high or low (1, 0) respectively.

The sensor centered with relation to the black line only that sensor will produce HIGH(1).The similarly possible outcome from that sensor could be:-

  • 10000
  • 11000
  • 01000
  • 01100
  • 00100
  • 00110
  • 00010
  • 00011
  • 00001
  • 00000
  • 11111

Now come other two sensors for left and right possible outcomes are

Far-left Sensor: analog output high or low

Far-left Sensor: analog output high or low

To store the value of 5 sensors lets create an array variable.

in LFSensor[5]={1,1,1,1,1};

To store the value of the left and right sensors we will use integer

int farleft_sensor=0;

As we know we have 5 sensors that can be used to store the left and the right path is taken by robot in an array. So

LFSensor[0] = digitalRead(lineFollowSensor0);
LFSensor[1] = digitalRead(lineFollowSensor1);
LFSensor[2] = digitalRead(lineFollowSensor2);
LFSensor[3] = digitalRead(lineFollowSensor3);
LFSensor[4] = digitalRead(lineFollowSensor4);
farRightSensor = analogRead(farRightSensorPin);
farLeftSensor = analogRead(farLeftSensorPin);

MAZE LEFT-HAND RULE :

watch this video to understand the maze left-hand rule

In short, the Left-Hand Rule can be described as:

  • Place your left hand on the wall.
  • Begin walking forward
  • At every intersection, and throughout the maze, keep your left hand touching the wall on your left.
  • Eventually, you will reach the end of the maze. You will probably not go the shortest and most direct way, but you will get there.

So, the key here is to identify the intersections, defining what course to take based on the above rules. Specifically, in our kind of 2D Maze, we can find 8 different types of intersections (see the first picture above):

Looking at the picture, we can realize that the possible actions at intersections are:

At a "Cross"

  • Go to Left, or
  • Go to Right, or
  • Go Straight
  • At a "Cross"Go to Left, orGo to Right, orGo Straight

At a "T":

  • Go to Left, or
  • Go to Right
  • At a "T":Go to Left, orGo to Right

At a "Right Only":

  • Go to Right
  • At a "Right Only":Go to Right

At a "Left Only":

  • Go to Left
  • At a "Left Only":Go to Left

At "Straight or Left":

  • Go to Left, or
  • Go Straight
  • At "Straight or Left":Go to Left, orGo Straight

At "Straight or Right":

  • Go to Right, or
  • Go Straight
  • At "Straight or Right":Go to Right, orGo Straight

At a "Dead End":

  • Go back ("U turn")
  • At a "Dead End":Go back ("U turn")

At "End of Maze":

  • Stop
  • At "End of Maze":Stop

But, applying the "Left-Hand Rule", the actions will be reduced to one option each:

  • At a "Cross": Go to Left
  • At a "T": Go to Left
  • At a "Right Only": Go to Right
  • At a "Left Only": Go to Left
  • At a "Straight or Left": Go to Left
  • At a "Straight or Right": Go Straight
  • At a "Dead End": Go back ("U turn")
  • At the "End of Maze": Stop

We are almost there! "Be calm!"

When the robot reaches a "Dead End" or the "End of a Maze", it is easy to identify them, because theydo not exist ambiguous situations (we have already implemented those actions on the Line Follower Robot, remember?). The problem is when the robot finds a "LINE" for example because a line can be a "Cross" (1) or a "T" (2). Also when it reaches a "LEFT or RIGHT TURN", those can be a simple turn (options 3 or 4) or options to go straight (5 or 6). To discover exactly what type of intersection the robot is, an additional step must be taken: the robot must run an "extra inch" and see what is next (see the second picture above, as an example).

So, in terms of flow, the possible actions can be now described as:

At a "DEAD END":

  • Go back ("U turn")
  • At a "DEAD END":Go back ("U turn")

At a "LINE":

  • Run an extra inch
  • If there is a line: It is a "Cross" ==> Go to LEFT
  • If there is no line: it is a "T" ==> Go to LEFT
  • If there is another line: it is the "End of Maze" ==> STOP
  • At a "LINE":Run an extra inchIf there is a line: It is a "Cross" ==> Go to LEFTIf there is no line: it is a "T" ==> Go to LEFTIf there is another line: it is the "End of Maze" ==> STOP

At a "RIGHT TURN":

  • Run an extra inch
  • if there is a line: It is a Straight or Right ==> Go STRAIGHT
  • If there is no line: it is a Right Only ==> Go to RIGHT
  • At a "RIGHT TURN":Run an extra inchif there is a line: It is a Straight or Right ==> Go STRAIGHTIf there is no line: it is a Right Only ==> Go to RIGHT

At a "LEFT TURN":

  • Run an extra inch
  • if there is a line: It is a Straight or LEFT ==> Go to LEFT
  • If there is no line: it is a LEFT Only ==> Go to LEFT
  • At a "LEFT TURN":Run an extra inchif there is a line: It is a Straight or LEFT ==> Go to LEFTIf there is no line: it is a LEFT Only ==> Go to LEFT

Note that in fact, In case of a "LEFT TURN", you can skip the test, because you will take LEFT anyway. I left the explanation more generic only for clarity. At the real code, I will skip this test.

Here are some issues that may come while making this project.

Related Topic

Arduino DRIVER ISSUE RESOLVING

watch this video to solve Arduino driver issue :


Code

RoBot_Maze_Solve_2C/C++
/*------------------------------------------------------------------
7 sensors Smart Robot - Maze Solver and Line Follower with programable PID controller via BT
==> Basic movement based on Nano Mouse Robot, developed by Michael Backus (http://www.akrobotnerd.com/ )
==> Line follow based on http://samvrit.tk/tutorials/pid-control-arduino-line-follower-robot/?ckattempt=1
==> CREDIT to Patrick McCabe for the path Solving Code, visit patrickmccabemakes.com!!
Marcelo Jose Rovai - 23 April, 2016 - Visit: http://mjrobot.org
-------------------------------------------------------------------*/

#include <Servo.h>
#include "robotDefines.h"

String command;
String device;

// BT Module
#include <SoftwareSerial.h>
SoftwareSerial BT1(10, 11); // El pin 10 es Rx y el pin 11 es Tx

//---------------------------------------------
void setup() 
{
  
  Serial.begin(9600);
  BT1.begin(9600);
  
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  
  // line follow sensors
  pinMode(lineFollowSensor0, INPUT);
  pinMode(lineFollowSensor1, INPUT);
  pinMode(lineFollowSensor2, INPUT);
  pinMode(lineFollowSensor3, INPUT);
  pinMode(lineFollowSensor4, INPUT);
  
  // servos
  leftServo.attach(5);
  rightServo.attach(3);
  
  BT1.print("check the PID constants to be sent to Robot");
  Serial.print("check the PID constants to be sent to Robot");
  BT1.println('\n');
  
  while (digitalRead(buttonPin) && !mode)
  {  
    checkBTcmd();  // verify if a comand is received from BT remote control
    manualCmd ();    
    command = "";  
  }
  
  checkPIDvalues();
  mode = STOPPED;
  status = 0; // 1st pass
}

void loop() 
{
  ledBlink(1);
  BT1.println("Start First Pass");
  Serial.println("Start First Pass");
  readLFSsensors();  
  mazeSolve(); // First pass to solve the maze
  ledBlink(2);
  BT1.println("End First Pass"); 
  Serial.println("End First Pass"); 
  
   while (digitalRead(buttonPin) && !mode)
  {  
    checkBTcmd();  // verify if a comand is received from BT remote control
    manualCmd ();    
    command = "";  
  }
  
  BT1.println("Starting 2nd Pass"); 
  Serial.println("Starting 2nd Pass"); 
  pathIndex = 0;
  status = 0;
  mazeOptimization(); //run the maze as fast as possible
  ledBlink(3);
  BT1.println("End 2nd Pass"); 
  Serial.println("End 2nd Pass"); 
  
  while (digitalRead(buttonPin) && !mode)
  {  
    checkBTcmd();  // verify if a comand is received from BT remote control
    manualCmd ();    
    command = "";  
  }
  
  mode = STOPPED;
  status = 0; // 1st pass
  pathIndex = 0;
  pathLength = 0;
}
FunctionsC/C++
void mazeSolve(void)
{
    while (!status)
    {
        readLFSsensors();  
        switch (mode)
        {   
          case NO_LINE:  
            motorStop();
            goAndTurn (LEFT, 180);
            recIntersection('B');
            break;
          
          case CONT_LINE: 
            runExtraInch();
            readLFSsensors();
            if (mode != CONT_LINE) {goAndTurn (LEFT, 90); recIntersection('L');} // or it is a "T" or "Cross"). In both cases, goes to LEFT
            else mazeEnd(); 
            break;
            
         case RIGHT_TURN: 
            runExtraInch();
            readLFSsensors();
            if (mode == NO_LINE) {goAndTurn (RIGHT, 90); recIntersection('R');}
            else recIntersection('S');
            break;   
            
         case LEFT_TURN: 
            goAndTurn (LEFT, 90); 
            recIntersection('L');
            break;   
         
         case FOLLOWING_LINE: 
            followingLine();
            break;      
        
         }
    }
}

//---------------------------------------------
void recIntersection(char direction)
{
  path[pathLength] = direction; // Store the intersection in the path variable.
  pathLength ++;
  simplifyPath(); // Simplify the learned path.
}

//----------------------------------------------
void mazeEnd(void)
{
  motorStop();
  BT1.print("The End  ==> Path: ");
  for(int i=0;i<pathLength;i++)
    BT1.print(path[i]);
    //Serial.print(path[i]);
  BT1.println("");
  Serial.print("  pathLenght ==> ");
  Serial.println(pathLength);
  status = 1;
  mode = STOPPED;
}

//----------------------------------------------
void followingLine(void)
{
   //readLFSsensors(); 
   calculatePID();
   motorPIDcontrol();   
}

//------------------------------------------------------------------------------------------
// Path simplification.  The strategy is that whenever we encounter a
// sequence xBx, we can simplify it by cutting out the dead end.  For
// example, LBL -> S, because a single S bypasses the dead end
// represented by LBL.
void simplifyPath()
{
  // only simplify the path if the second-to-last turn was a 'B'
  if(pathLength < 3 || path[pathLength-2] != 'B')
    return;

  int totalAngle = 0;
  int i;
  for(i=1;i<=3;i++)
  {
    switch(path[pathLength-i])
    {
      case 'R':
        totalAngle += 90;
	break;
      case 'L':
	totalAngle += 270;
	break;
      case 'B':
	totalAngle += 180;
	break;
    }
  }

  // Get the angle as a number between 0 and 360 degrees.
  totalAngle = totalAngle % 360;

  // Replace all of those turns with a single one.
  switch(totalAngle)
  {
    case 0:
	path[pathLength - 3] = 'S';
	break;
    case 90:
	path[pathLength - 3] = 'R';
	break;
    case 180:
	path[pathLength - 3] = 'B';
	break;
    case 270:
	path[pathLength - 3] = 'L';
	break;
  }

  // The path is now two steps shorter.
  pathLength -= 2;
  
} 

//----------------------------------------------------------------------------------------------
void mazeOptimization (void)
{
  while (!status)
  {
    readLFSsensors();  
    switch (mode)
    {
      case FOLLOWING_LINE:
        followingLine();
        break;    
      case CONT_LINE:
        if (pathIndex >= pathLength) mazeEnd (); 
        else {mazeTurn (path[pathIndex]); pathIndex++;}
        break;  
      case LEFT_TURN:
        if (pathIndex >= pathLength) mazeEnd (); 
        else {mazeTurn (path[pathIndex]); pathIndex++;}
        break;  
      case RIGHT_TURN:
        if (pathIndex >= pathLength) mazeEnd (); 
        else {mazeTurn (path[pathIndex]); pathIndex++;}
        break;   
    }    
   }  
}

//-----------------------------------------------------
void mazeTurn (char dir) 
{
  switch(dir)
  {
    case 'L': // Turn Left
       goAndTurn (LEFT, 90);      
       break;   
    
    case 'R': // Turn Right
       goAndTurn (RIGHT, 90);     
       break;   
       
    case 'B': // Turn Back
       goAndTurn (RIGHT, 800);     
       break;   
       
    case 'S': // Go Straight
       runExtraInch(); 
       break;
  }
}
GeneralFunctions.C/C++
void ledBlink(int times)
{
   for (int i = 0; i<times; i++)
   { 
      digitalWrite (ledPin, HIGH);
      delay (500);
      digitalWrite (ledPin, LOW);
      delay (500);
   } 
}

//-----------------------------------------------------------------------------

 void checkBTcmd()  
 { 
   while (BT1.available())   //Check if there is an available byte to read
   {
     delay(10); //Delay added to make thing stable 
     char c = BT1.read(); //Conduct a serial read
     device += c; //build the string.
   }  
   if (device.length() > 0) 
   {
     Serial.print("Command received from BT ==> ");
     Serial.println(device); 
     command = device;
     device ="";  //Reset the variable
     BT1.flush();
    } 
}

//------------------------------------------------------------------------
void manualCmd()
{
  switch (command[0])
  {
    case 'g':
      mode = FOLLOWING_LINE;
      break;
    
    case 's': 
      motorStop(); //turn off both motors
      break;

    case 'f':  
      motorForward();  
      break;

    case 'r':     
      motorTurn(RIGHT, 30);
      motorStop();
      
      break;

   case 'l': 
      motorTurn(LEFT, 30);
      motorStop();
      break;
    
    case 'b':  
      motorBackward();
      break;
      
    case 'p':
      Kp = command[2];
      break;
    
    case 'i':
      Ki = command[2];
      break; 
    
    case 'd':
      Kd = command[2];
      break;
  }
}

//------------------------------------------------------------------------
void sendBTdata (int data) // send data to BT

{
    digitalWrite (ledPin, HIGH);
    BT1.print("Data from Arduino");
    BT1.print(data);
    BT1.print(" xx");
    BT1.println('\n');
    digitalWrite (ledPin, LOW);
}

//--------------------------------------------------------
void calculatePID()
{
  P = error;
  I = I + error;
  D = error-previousError;
  PIDvalue = (Kp*P) + (Ki*I) + (Kd*D);
  previousError = error;
}

//--------------------------------------------------------
void checkPIDvalues()
{
  
  BT1.print("PID: ");
  BT1.print(Kp);
  BT1.print(" - ");
  BT1.print(Ki);
  BT1.print(" - ");
  BT1.println(Kd);  
  
  Serial.print("PID: ");
  Serial.print(Kp);
  Serial.print(" - ");
  Serial.print(Ki);
  Serial.print(" - ");
  Serial.println(Kd);  
  
}

//-----------------------------------------------
void testLineFollowSensors()
{
     int LFS0 = digitalRead(lineFollowSensor0);
     int LFS1 = digitalRead(lineFollowSensor1);
     int LFS2 = digitalRead(lineFollowSensor2);
     int LFS3 = digitalRead(lineFollowSensor3);
     int LFS4 = digitalRead(lineFollowSensor4);
     
     Serial.print ("LFS: L  0 1 2 3 4  R ==> "); 
     Serial.print (LFS0); 
     Serial.print (" ");
     Serial.print (LFS1); 
     Serial.print (" ");
     Serial.print (LFS2); 
     Serial.print (" ");
     Serial.print (LFS3); 
     Serial.print (" ");
     Serial.print (LFS4); 
     Serial.print ("  ==> ");
    
     Serial.print (" P: ");
     Serial.print (P);
     Serial.print (" I: ");
     Serial.print (I);
     Serial.print (" D: ");
     Serial.print (D);
     Serial.print (" PID: ");
     Serial.println (PIDvalue);
}
sensorFuntionsC/C++
//-------------------------------------------------------------
/* read line sensors values 

Sensor Array 	Error Value
0 0 0 0 1	 4              
0 0 0 1 1	 3              
0 0 0 1 0	 2              
0 0 1 1 0	 1              
0 0 1 0 0	 0              
0 1 1 0 0	-1              
0 1 0 0 0	-2              
1 1 0 0 0	-3              
1 0 0 0 0	-4              

1 1 1 1 1        0 Robot found continuous line - test if an intersection or end of maze
0 0 0 0 0        0 Robot found no line: turn 180o

*/
void readLFSsensors()
{
  LFSensor[0] = digitalRead(lineFollowSensor0);
  LFSensor[1] = digitalRead(lineFollowSensor1);
  LFSensor[2] = digitalRead(lineFollowSensor2);
  LFSensor[3] = digitalRead(lineFollowSensor3);
  LFSensor[4] = digitalRead(lineFollowSensor4);
  
  farRightSensor = analogRead(farRightSensorPin);
  farLeftSensor = analogRead(farLeftSensorPin);
  
  if     ((LFSensor[0]== 1 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 1 ))  {mode = CONT_LINE; error = 0;}
  else if((LFSensor[0]== 0 )&&                                                   (farRightSensor < THRESHOLD)) {mode = RIGHT_TURN; error = 0;}
  else if ((farLeftSensor <  THRESHOLD)                                                  &&(LFSensor[4]== 0 )) {mode = LEFT_TURN; error = 0;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = NO_LINE; error = 0;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 1 ))  {mode = FOLLOWING_LINE; error = 4;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 1 ))  {mode = FOLLOWING_LINE; error = 3;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = 2;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = 1;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = 0;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error =- 1;}
  else if((LFSensor[0]== 0 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = -2;}
  else if((LFSensor[0]== 1 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = -3;}
  else if((LFSensor[0]== 1 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 ))  {mode = FOLLOWING_LINE; error = -4;}
  
  Serial.print (farLeftSensor);
  Serial.print (" <== LEFT  RIGH==> ");
  Serial.print (farRightSensor);
  Serial.print ("  mode: ");
  Serial.print (mode);
  Serial.print ("  error:");
  Serial.println (error);
    
}

//-----------------------------------------------------------
void readLateralSensors(void)

{
  
}
RobotDefines.hC/C++
int mode = 0;

# define STOPPED 0
# define FOLLOWING_LINE 1
# define NO_LINE 2
# define CONT_LINE 3
# define POS_LINE 4
# define RIGHT_TURN 5
# define LEFT_TURN 6

const int power = 250;
const int iniMotorPower = 250;
const int adj = 0;
float adjTurn = 8;
int extraInch = 200;
int adjGoAndTurn = 800;

const int ledPin = 13;
const int buttonPin = 9;

// LFSensor more to the Left is "0"
const int lineFollowSensor0 = 12; 
const int lineFollowSensor1 = 18; 
const int lineFollowSensor2 = 17; 
const int lineFollowSensor3 = 16;
const int lineFollowSensor4 = 19;

const int farRightSensorPin = 0; //Analog Pin A0
const int farLeftSensorPin = 1; //Analog Pin A0
const int THRESHOLD = 150;
int farRightSensor = 0;
int farLeftSensor = 0;


int LFSensor[5]={0, 0, 0, 0, 0};

// PID controller
float Kp=50;
float Ki=0;
float Kd=0;

float error=0, P=0, I=0, D=0, PIDvalue=0;
float previousError=0, previousI=0;

#define RIGHT 1
#define LEFT -1

Servo leftServo;
Servo rightServo;

//-------------------------------------------------
//Specific Maze Phase 2 (optimization) definitions and variables 

unsigned char dir; 

// The path variable will store the path that the robot has taken:
//  'L' for left
//  'R' for right
//  'S' for straight (going straight through an intersection)
//  'B' for back (U-turn)

char path[100] = "";
unsigned char pathLength = 0; // the length of the path
int pathIndex = 0;
unsigned int status = 0; // solving = 0; reach end = 1
MotorFuntionsC/C++
void motorStop()
{
  leftServo.writeMicroseconds(1500);
  rightServo.writeMicroseconds(1500);
  delay(200);
}

//--------------------------------------------- 
void motorForward()
{
  leftServo.writeMicroseconds(1500 - (power+adj));
  rightServo.writeMicroseconds(1500 + power);
}

//---------------------------------------------
void motorBackward()
{
  leftServo.writeMicroseconds(1500 + power);
  rightServo.writeMicroseconds(1500 - power);
}

//---------------------------------------------
void motorFwTime (unsigned int time)
{
  motorForward();
  delay (time);
  motorStop();
}

//---------------------------------------------
void motorBwTime (unsigned int time)
{
  motorBackward();
  delay (time);
  motorStop();
}

//------------------------------------------------
void motorTurn(int direction, int degrees)
{
  leftServo.writeMicroseconds(1500 - (iniMotorPower+adj)*direction);
  rightServo.writeMicroseconds(1500 - iniMotorPower*direction);
  delay (round(adjTurn*degrees+20));
  motorStop();
}

//---------------------------------------------------
void motorPIDcontrol()
{
  
  int leftMotorSpeed = 1500 - (iniMotorPower+adj) - PIDvalue;
  int rightMotorSpeed = 1500 + iniMotorPower - PIDvalue;
  
  // The motor speed should not exceed the max PWM value
   constrain(leftMotorSpeed, 1000, 2000);
   constrain(rightMotorSpeed, 1000, 2000);
  
  leftServo.writeMicroseconds(leftMotorSpeed);
  rightServo.writeMicroseconds(rightMotorSpeed);
  
  //Serial.print (PIDvalue);
  //Serial.print (" ==> Left, Right:  ");
  //Serial.print (leftMotorSpeed);
  //Serial.print ("   ");
  //Serial.println (rightMotorSpeed);
}

//---------------------------------------------------
void runExtraInch(void)
{
  motorPIDcontrol();
  delay(extraInch);
  motorStop();
}

//---------------------------------------------------
void goAndTurn(int direction, int degrees)
{
  motorPIDcontrol();
  delay(adjGoAndTurn);
  motorTurn(direction, degrees);
}

Schematics

Circuit Diagram
Circuit diagram msmcir7yvw

Comments

Similar projects you might like

Maze Solver Robot, using Artificial Intelligence

Project tutorial by MJRoBot

  • 45,012 views
  • 11 comments
  • 79 respects

One Button Click Artificial Intelligence Based Home Monitor

Project tutorial by Geeve George

  • 8,210 views
  • 1 comment
  • 43 respects

TIA Weak Artificial Intelligence IoT Assistant

Project tutorial by Adam Milton-Barker

  • 4,681 views
  • 0 comments
  • 23 respects

WiFi Robot

Project tutorial by Kartik

  • 4,541 views
  • 1 comment
  • 12 respects

Amazing 6WD Off-Road Robot | Arduino RC Robot

Project tutorial by Jithin Sanal

  • 10,288 views
  • 0 comments
  • 56 respects

Joy Robot (Robô Da Alegria)

Project tutorial by Igor Fonseca Albuquerque

  • 4,646 views
  • 6 comments
  • 34 respects
Add projectSign up / Login