Tuesday, September 17, 2013

Basic Obstacle Avoidance

Tasked to build a robot, using a Mega 2560 Arduino board, that turned in response to obstacles presented to it. I came up with the specimen in the gifs below. A total of about 6 hours was spent wiring, coding, and debugging.



Left Turn

In this gif, the the robot executes a left turn when presented with an object in front of it.

Right Turn


In this gif, the robot executes a right turn when presented with an object to its front and left.

Turning Around


In this gif, the robot executes a backwards movement and a 180 degree turn when presented with an object to its front, left, and right.

Wiring:


In this photo we can observe the physical connections to the Arduino Mega 2560. The servos, left and right, go into PWM ports 9 and 10, respectively. The servo that turns the Parallax Ping Sensor is in PWM port 7 while the actual Parallax Ping Sensor is in PWM port 6.


In this photo the Servo's mounting is displayed. Two arms protrude from the Boebot allowing for its mounting and proper clearance for the Parallax Ping Sensor.

Code:

/*   In this program the robot will demonstrate obstacle avoidance using an ultrasonic sensor.
     This robot will continue along a path until an object is spotted, stop, turn the sensor 
     left, if the path is clear it will turn the robot left and continue, if not it will then
     turn the sensor to the right, check to see if it is clear and continue, and, finally, if no
     clear path is read it will turn around and go forward.
  
     Program written by Korbin Barker on 9/16/2013
     
     Robotic Platform:  Boebot
     Microcontroller:    Arduino MEGA 2560
     Servos:                2 Parallax Continuous Rotation Servos
                                1 Parallax Standard Servo
     Sensors:              1 Parallax Ping Sensor
                                1 Vex Bumper Switch
                                4  Parallax QTI Line Follower Sensors (disabled for this build)
*/

#include <SoftwareSerial.h>
#include <Servo.h>

/* initializes the servos */
Servo rightServo;
Servo leftServo;
Servo sweepServo;

/* initializes all necessary data values and inputs for the ultrasonic sensing */
const int pingPort = 6;
long pongValue = 0;
int distance = 0;
const int leftPos = 180;
const int middlePos = 90;
const int rightPos = 0;

/* initializes all necessary data values and inputs for movement */
const int pos = 180; //sets a turn value
const int stopPos = 90;
const int time = 600;

/* Ping Sensor movement for sensing */

void sweepLeft()  //looks for a leftward barrier, senses to see if path is blocked
{
  sweepServo.write(leftPos);
  delay(1000);
}

void sweepRight() //looks for a rightward barrier, senses to see if path is blocked
{
  sweepServo.write(rightPos);
  delay(1000);
}

void sweepMiddle() /*looks for a frontal barrier, senses to see if path is blocked (MOST IMPORTANT FUNCTION  
                               IN THE SENSING PROGRAM SET AS ALL OTHER FUNCTIONS BASE 
                               THEMSELVES OFF THIS RESPONSE) */
                     
  sweepServo.write(middlePos);
  delay(1000);
}

void sensDistance()//senses, calculates, and prints distances
{
  pinMode(pingPort, OUTPUT);    //sets pingPort as an OUTPUT
  
  digitalWrite(pingPort, LOW);  //sets pingPort LOW to not produce a sound
  delayMicroseconds(2);
  
  digitalWrite(pingPort, HIGH); //sets pingPort HIGH to produce a sound
  delayMicroseconds(5);
  
  digitalWrite(pingPort, LOW);  //sets pingPort LOW to  stop producing a sound
  delayMicroseconds(2);         
  
  pinMode(pingPort, INPUT);     //sets pingPort as an INPUT to read pongValue
  
  pongValue = pulseIn(pingPort, HIGH, 2800); //reads for the HIGH pongValue
  
  if(pongValue == 0)
  {
    Serial.println("Nothing received"); // if no signal is returned, "Nothing received" is printed in the serial monitor
  }
  
  else  //for everything else the distance is printed using the calculation contained in this else
  {
    distance = pongValue/2/74;
    
    Serial.print("Distance:");
    Serial.println(distance);
  }
  delay(1);
}

/* functions for controlling movement of robot */

void forward()  //this function makes the robot go forward
{
  rightServo.write(-pos);
  leftServo.write(pos);
}

void backward()  //this function makes the robot go backward
{
  rightServo.write(pos);
  leftServo.write(-pos);
  delay(2*time);
}

void turnAround()  //turns robot around (~180 degrees)
{
  rightServo.write(-pos);
  leftServo.write(-pos);
  delay(2*time);
}

void turnLeft()  //this function makes the robot turn left 90 degrees
  rightServo.write(-pos);
  leftServo.write(-pos);
  delay(time);
}

void turnRight()  //this function makes the robot turn right 90 degrees
  rightServo.write(pos);
  leftServo.write(pos);
  delay(time);
}

void stopRobot()  //this function stops the robot's movement
{
  rightServo.write(stopPos);//90 is the servo stop point
  leftServo.write(stopPos);
}
/*=======================SETUP STEP=========================*/

void setup()
{
  rightServo.attach(10);
  leftServo.attach(9);
  sweepServo.attach(7);
  
  Serial.begin(9600);
}

/*========================LOOP STEP=========================*/

void loop()
{
  if(pongValue == 0 || distance > 6) //reads value, if true the robot continues forward, if false program progresses
  {
    forward();
    sweepMiddle();
    sensDistance();
  }
  
  else
  {
    stopRobot();
    sweepLeft();
    sensDistance();
    
    if(distance > 6 || pongValue == 0) /* reads value after turning the Ping Sensor to sense for a leftward barrier
                                                        if true, robot turns left and kicks out to the first if statement, if false
                                                        program progresses */
    {
      turnLeft();
      stopRobot();
      sweepMiddle();
    }
    
    else
    {
      stopRobot();
      sweepRight();
      sensDistance();
      
      if(distance > 6 || pongValue == 0) /* reads value after turning the Ping Sensor to sense for a rightward barrier
                                                          if true, robot turns right and kicks out to the first if statement, if false
                                                          program progresses */
      {
        turnRight();
        stopRobot();
        sweepMiddle();
      }
      
      else                              /* if all other conditions above have proved false, then this triggers and the robot
                                             moves backwards, then turns around
                                             the logic behind it is that if there is a barrier left, that condition is false
                                             if a barrier is right, that condition is false, and the frontal barrier has to be
                                             present in order for the other two to happen so the robot would then turn 
                                             around and go the other way */
      {
        sweepMiddle();
        backward();
        stopRobot();
        turnAround();
        stopRobot();
        sensDistance();
      }
    }
  }
}

Issues:

One of the most important issues I had was getting the proper tiering to work with the functions and condition statements. There was literally no steps taken to solving this in any regard. What basically happened was at around 1:30 a.m. I decided to give the coding one more go, rewrote everything in the void loop() step and it worked. From there I just had to tweak values. Also, another main issue that I encountered was some kind of power issue. There were many times where the robot would shut off or only do a command for a fraction of its intended time. Based on some debugging, (i.e. jiggling the cable that goes to power the robot) I found that it was either an issue with the battery (not retaining a charge), the charger (being faulty and telling me the battery is charged when it isn't), or the cable going from battery to arduino board. Nothing conclusive has otherwise been drawn from this.





No comments:

Post a Comment