Project 2 - Code
// Define pins for H-bridge
#define enA 6
#define enB 9
#define IN1 2
#define IN2 3
#define IN3 4
#define IN4 5
// Define pins for ultrasonic sensor
#define trigPin 7
#define echoPin 8
// Define pins for IR sensors
#define IRSensorR 10
#define IRSensorRM 11
#define IRSensorLM 12
#define IRSensorL 13
int IRSensorValues; // Integer value to store the values of the sensors as bits in 1 value
// Booleans to indicate if a sharp right or sharp left turn is detected
bool sharpright = false;
bool sharpleft = false;
bool turnAround = false; // Boolean to indicate if the robot is turning around to be able to disable the collision detection
static unsigned long startTime; // Variable to store the startTime of the timer, which is used for the sharp turns and for turning at the end of the line
// Variables to store the information of the ultrasonic sensor
long duration;
int distance;
int obstacleDistance = 10; //in cm
// To compensate the deviation of the motors(motor B is driving faster than motor A), we limited the maximum speed of motor B
float maxSpeedMotorA = 255;
float maxSpeedMotorB = 190;
float motorSpeed = 0.6; // Variable to control the total speed of the robot
// Variables to store the actual speed per motor
float speedMotorA;
float speedMotorB;
void setup() {
// The 4 pins for the IR sensors are set to input
pinMode(IRSensorR,INPUT);
pinMode(IRSensorRM,INPUT);
pinMode(IRSensorLM,INPUT);
pinMode(IRSensorL,INPUT);
// The 6 pins for the H-bridge are set to output
// To control the speed and the direction of motor 1
pinMode(enA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
// To control the speed and the direction of motor 2
pinMode(enB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// The 2 pins for the input and output are set for the ultrasonic sensor
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Calculate the speed per motor motor according to the max speed per motor and the total speed of the motors
speedMotorA = maxSpeedMotorA * motorSpeed;
speedMotorB = maxSpeedMotorB * motorSpeed;
delay(5000); //startup delay so the robot doesn't drive immediately after uploading the code
}
void loop() {
delay(50); // Small delay to be sure the robot can process the sensor values completely
// When the ultrasonic sensor detects an obstacle and the robot is not turning around, the robot needs to stop
// otherwise, the robot needs to follow the line
if(collisionDetected() && !turnAround){
wheels(0,0);
} else{
lineDetection();
}
}
void lineDetection(){
// Put the 4 values of the IR sensors in 1 integer to be able to use the switch case statement and make it more readable
// High sensor value means line detected, low sensor value means no line detected
IRSensorValues = B00000000;
IRSensorValues += B1 * digitalRead(IRSensorR);
IRSensorValues += B10 * digitalRead(IRSensorRM);
IRSensorValues += B100 * digitalRead(IRSensorLM);
IRSensorValues += B1000 * digitalRead(IRSensorL);
// Switch case to determine direction of the motors according to the sensor values
switch (IRSensorValues){
case B0110:
wheels(1,1);
resetBools(); // The sensors detect a straight line, so booleans for sharpturns needs to be resetted
break;
case B1111:
wheels(1,1);
break;
case B1110:
// There is a sharp left turn coming, so the boolean needs to be true if there wasn't already a sharp right turn detected
if(!sharpright){
sharpleft = true;
}
wheels(0.5,1);
break;
case B0111:
// There is a sharp right turn coming, so the boolean needs to be true if there wasn't already a sharp left turn detected
if(!sharpleft){
sharpright = true;
}
wheels(1,0.5);
break;
case B1000:
wheels(-1,1);
break;
case B1100:
wheels(0.5,1);
break;
case B0100:
wheels(0,1);
break;
case B0010:
wheels(1,0);
break;
case B0011:
wheels(1,0.5);
break;
case B0001:
wheels(1,-1);
break;
case B0000:
// When there is no line detected anymore, drive forward until the time has passed in 1 of the 3 cases
wheels(1,1);
// When a sharp left turn was detected, turn left after 500 ms
if(sharpleft){
if(millis() - startTime > 500){
wheels(-1,1);
}
}
// When a sharp right turn was detected, turn right after 500 ms
else if(sharpright){
if(millis() - startTime > 500){
wheels(1,-1);
}
} else{
// When no sharp turn was detected, stop after 1500 ms and turn around after 2000 ms
if(millis() - startTime > 1500){
if(millis() - startTime < 2000){
wheels(0,0);
} else{
wheels(1,-1);
turnAround = true; // Set the turnAround boolean to true so the ultrasonic sensor is disabled during turning
}
}
}
break;
default: // When sensor input is not known/possible, stop the motors
wheels(0,0);
break;
}
// When the line is detected by at least 1 of the sensors, reset the timer and set the turnAround boolean to false
// so the robots will conitinue following the line
if(IRSensorValues != B0000){
startTime = millis();
turnAround = false;
}
}
// Function to reset the bools to be sure the robot is not turning when it doesn't need to
void resetBools(){
sharpleft = false;
sharpright = false;
}
// Function to set a boolean value whether an obstacle is detected or not
bool collisionDetected(){
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance = duration*0.034/2;
// When an object is closer than the specified obstacle distance, return true, otherwise return false
return (distance < obstacleDistance);
}
// Function to control the wheels, positive value means forward, negative value means backward and 0 means stop
// Values between 0 and 1 can be used to control the speed per motor. 0.5 means that the motor is running on half power
void wheels(int directionLeft, int directionRight){
// Right Motor(A)
if(directionRight > 0){ // Forward
analogWrite(enA, directionRight*speedMotorA);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
} else if(directionRight < 0){ // Reverse
analogWrite(enA, -directionRight*speedMotorA);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
} else{ // Stop
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
}
// Left Motor(B)
if(directionLeft > 0){ // Forward
analogWrite(enB, directionLeft*speedMotorB);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
} else if(directionLeft < 0){ // Reverse
analogWrite(enB, -directionLeft*speedMotorB);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
} else{ // Stop
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
}
}