February 1, 2016

Autonomous Arduino Vehicle

This was my first Arduino project. The brain in this vehicle is an Arduino Uno. The logic is pretty simple - it drives forward until it detects a wall or object. It then works out whether to go left or right and then continues on.

It uses an HC-SR04 ultrasonic distance sensor to measure distance several times a second. When it detects an object within 20cm it stops.

The blue servo (9G) rotates the sensor left and right, measuring the distance on either side. It then picks the greatest distance (or left if equal), and turns the vehicle in that direction. The process repeats.

The motors on the chassis are controlled by an L298N motor controller. The servo and the Arduino use separate battery packs. The current required for the motors exceeds what should pass through an Arduino.

It works well in an area without too much furniture. The ultrasonic sensors are quite focused. This means that low objects can be missed. Unfortunately I forgot to make a video of it and have since taken it apart to build other things from the parts.

The code was cobbled together and could easily be improved. The delays are a bit hit and miss. The aim is to allow the vehicle to turn approximately 90° when turning left or right.

Further improvements would be to replace the sleeps with a timing/sequencing library to manage motors and measurement.

Full code is available  here on github.

#include <Servo.h> //include Servo libraryconst 

int dangerThresh = 10; //threshold for obstacles (in cm)
int leftDistance, rightDistance; //distances on either side
Servo panMotor;
  
long duration; //time it takes to recieve PING signal

#define trigPin 13
#define echoPin 12

// Motor 1
int dir1PinA = 2;
int dir2PinA = 3;
int speedPinA = 9; // Needs to be a PWM pin to be able to control motor speed

// Motor 2
int dir1PinB = 4;
int dir2PinB = 5;
int speedPinB = 10; // Needs to be a PWM pin to be able to control motor speed

void setup() 
{  
  Serial.begin(9600);  //Define L298N Dual H-Bridge Motor Controller Pins
  pinMode(dir1PinA,OUTPUT);
  pinMode(dir2PinA,OUTPUT);
  pinMode(speedPinA,OUTPUT);
  pinMode(dir1PinB,OUTPUT);
  pinMode(dir2PinB,OUTPUT);
  pinMode(speedPinB,OUTPUT);
  panMotor.attach(6); //attach motors to proper pins
  panMotor.write(90); //set PING pan to center

  setup_edm();
}

void setup_edm()
{
  // distance
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);  
  Motor1(1);
  Motor2(1);
}

void loop()
{
  int distanceFwd = Ping();
  if (distanceFwd == -1 || distanceFwd > dangerThresh) //if path is clear
  {
    //move forward
    Motor1(1);
    Motor2(1);
  }
  else //if path is blocked
  {
    // stop
    Motor1(0);
    Motor2(0); 
    panMotor.write(0); 
    delay(500);
    rightDistance = Ping(); //scan to the right
    delay(500);
    panMotor.write(180);
    delay(700);
    leftDistance = Ping(); //scan to the left
    delay(500);
    panMotor.write(90); //return to center
    delay(100);
    compareDistance();
  }
}

void compareDistance()
{
  if (leftDistance > rightDistance) //if left is less obstructed 
  {
    // turn left
    Motor1(-1);
    Motor2(1);
    delay(500); 
  }
  else if (rightDistance>leftDistance) //if right is less obstructed
  {
    // turn right
    Motor1(1);
    Motor2(-1);
    delay(500);
  }
   else //if they are equally obstructed
  {
    // turn 180
    Motor1(1);
    Motor2(-1);
    delay(1000);
  }
}

void Motor1(int dir)
{
  switch(dir)
  {
    case 1: // Motor 1 Forward
      analogWrite(speedPinA, 255);
      digitalWrite(dir1PinA, LOW);
      digitalWrite(dir2PinA, HIGH);
      Serial.println("Motor 1 Forward");
      Serial.println("   ");
      break;    case 0: // Motor 1 Stop (Freespin)
      analogWrite(speedPinA, 0);
      digitalWrite(dir1PinA, LOW);
      digitalWrite(dir2PinA, LOW);
      Serial.println("Motor 1 Stop");
      Serial.println("   ");
      break;    case -1: // Motor 1 Reverse
      analogWrite(speedPinA, 255);
      digitalWrite(dir1PinA, HIGH);
      digitalWrite(dir2PinA, LOW);
      Serial.println("Motor 1 Reverse");
      Serial.println("   ");
      break;
  }
}

void Motor2(int dir)
{
  switch(dir)
  {
    case 1: // Motor 2 Forward
      analogWrite(speedPinB, 255);
      digitalWrite(dir1PinB, LOW);
      digitalWrite(dir2PinB, HIGH);
      Serial.println("Motor 2 Forward");
      Serial.println("   ");
      break;    case 0: // Motor 1 Stop (Freespin)
      analogWrite(speedPinB, 0);
      digitalWrite(dir1PinB, LOW);
      digitalWrite(dir2PinB, LOW);
      Serial.println("Motor 2 Stop");
      Serial.println("   ");
      break;    case -1: // Motor 2 Reverse
      analogWrite(speedPinB, 255);
      digitalWrite(dir1PinB, HIGH);
      digitalWrite(dir2PinB, LOW);
      Serial.println("Motor 2 Reverse");
      Serial.println("   ");
      break;
  }
}

long Ping()
{
  long duration, distance, returnValue;  digitalWrite(trigPin, LOW);
  delayMicroseconds(2); // Added this line
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin, LOW);  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;  if (distance > 200) {
    returnValue = -1;
  }
  else {
    returnValue = distance;
  }
  Serial.print(returnValue);  
  Serial.println(" cm");  
  return returnValue;
}