SMM2
Published © GPL3+

Elliot the Line Follower Robot

A PID controlled line follower robot, named Elliot.

IntermediateShowcase (no instructions)20,171
Elliot the Line Follower Robot

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Dual H-Bridge motor drivers L298
SparkFun Dual H-Bridge motor drivers L298
×1
9V battery (generic)
9V battery (generic)
×1
9V Battery Clip
9V Battery Clip
×1
6V NiMh 2000mAh rechargeable battery
×1
Solderless Breadboard Half Size
Solderless Breadboard Half Size
×1
Jumper wires (generic)
Jumper wires (generic)
×1
IR Sensors
I used 5 of these
×1
Angle Bracket
×1
Painter's stick
×1
DC motor (generic)
×1
Robot Chassis
I got this on Amazon.com, it also included two geared DC motors.
×1
Caster wheel
×1
Electrical tape
A whole bunch of this...
×1

Story

Read more

Schematics

PID Line Follower Robot Schematic

Sorry if this is not the best diagram/schematic, and if you have any questions about the IR sensor wiring I'd be happy to help. The reason for this is I had trouble finding IR sensor modules on Fritzing.

Code

PID Line Follower Robot Code

C/C++
float pTerm, iTerm, dTerm;
int error;
int previousError;
float kp = 11; //11
float ki = 0;
float kd = 11; //11
float output;
int integral, derivative;
int irSensors[] = {13, 12, 11, 8, 7}; //IR sensor pins
int irReadings[5];
int motor1Forward = A0;
int motor1Backward = A1;
int motor1pwmPin = 5;
int motor2Forward = A3;
int motor2Backward = A2;
int motor2pwmPin = 3;
int motor1newSpeed;
int motor2newSpeed;
int motor2Speed = 70; //Default 70
int motor1Speed = 120; //Default 120

void setup() {
  //Declare all IR sensors as inputs
  for (int pin = 0; pin < 5; pin++) {
    int pinNum = irSensors[pin];
    pinMode(pinNum, INPUT);
  }
  pinMode(motor1Forward, OUTPUT);
  pinMode(motor1Backward, OUTPUT);
  pinMode(motor1pwmPin, OUTPUT);
  pinMode(motor2Forward, OUTPUT);
  pinMode(motor2Backward, OUTPUT);
  pinMode(motor2pwmPin, OUTPUT);
}

void loop() {
  //Put all of our functions here
  readIRSensors();
  calculateError();
  pidCalculations();
  changeMotorSpeed();
}

void readIRSensors() {
  //Read the IR sensors and put the readings in irReadings array
  for (int pin = 0; pin < 5; pin++) {
    int pinNum = irSensors[pin];
    irReadings[pin] = digitalRead(pinNum);
  }
}

void calculateError() {
  //Determine an error based on the readings
  if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 0) && (irReadings[3] == 0) && (irReadings[4] == 1)) {
    error = 4;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 0) && (irReadings[3] == 1) && (irReadings[4] == 1)) {
    error = 3;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 0) && (irReadings[3] == 1) && (irReadings[4] == 0)) {
    error = 2;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 1) && (irReadings[3] == 1) && (irReadings[4] == 0)) {
    error = 1;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 1) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    error = 0;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 1) && (irReadings[2] == 1) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    error = -1;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 1) && (irReadings[2] == 0) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    error = -2;
  } else if ((irReadings[0] == 1) && (irReadings[1] == 1) && (irReadings[2] == 0) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    error = -3;
  } else if ((irReadings[0] == 1) && (irReadings[1] == 0) && (irReadings[2] == 0) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    error = -4;
  } else if ((irReadings[0] == 0) && (irReadings[1] == 0) && (irReadings[2] == 0) && (irReadings[3] == 0) && (irReadings[4] == 0)) {
    if (previousError == -4) {
      error = -5;
    } else {
      error = 5;
    }
  } else if ((irReadings[0] == 1) && (irReadings[1] == 1) && (irReadings[2] == 1) && (irReadings[3] == 1) && (irReadings[4] == 1)) {
    error = 0;
  }
}

void pidCalculations() {
  pTerm = kp * error;
  integral += error;
  iTerm = ki * integral;
  derivative = error - previousError;
  dTerm = kd * derivative;
  output = pTerm + iTerm + dTerm;
  previousError = error;
}

void changeMotorSpeed() {
  //Change motor speed of both motors accordingly
  motor2newSpeed = motor2Speed + output;
  motor1newSpeed = motor1Speed - output;
  //Constrain the new speed of motors to be between the range 0-255
  constrain(motor2newSpeed, 0, 255);
  constrain(motor1newSpeed, 0, 255);
  //Set new speed, and run motors in forward direction
  analogWrite(motor2pwmPin, motor2newSpeed);
  analogWrite(motor1pwmPin, motor1newSpeed);
  digitalWrite(motor2Forward, HIGH);
  digitalWrite(motor2Backward, LOW);
  digitalWrite(motor1Forward, HIGH);
  digitalWrite(motor1Backward, LOW);
}

Credits

SMM2

SMM2

2 projects • 16 followers
I'm 15 and have much interest in Robotics, and open- source electronics like the Arduino platform.

Comments