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.





Monday, September 9, 2013

Line Follower


Tasked to build a robot, using a Mega 2560 Arduino board, that followed about a half inch thick black line. I came up with the specimen in the gif above. A total of about 8 hours was spent wiring, coding, and debuging (4 hours of this was spent frustratingly examining/tweaking my not-working code only to find out that the robot hadn't been connected to ground, thereby negating any powerflow).

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. Left Outside Line Follower sensor is in PWM port 2, Left Inside Line Follower sensor is in PWM port 3, Right Inside Line Follower sensor is in port 4, and Right Outside Line Follower sensor is in port 5. A better view of the connections between Arduino board and sensors can be seen below. The pushbutton sensor (opted for this as the flip switch did not fit in the breadboard) is in PWM port 8.


Here we see the better angle of the wires going between the sensors and the Arduino board. Also note that there is a 10kOhm resistor connected to the ground of the push button in order to enable positive logic, pulling the button naturally towards 0, or off.


It is also important to note here that the Line Follower sensors are wired differently that one might intuitively assume. In most circuits, red stands for the "hot" wire in which voltage flow is considered to go through to get to the "ground" wire, black. However, in these sensors the white is used for the "hot" and black is reserved for "ground," while the red is used for data acquisition. Plugging the inputs in the wrong areas could result in a broken sensor, so this is something to be wary of.


Code:

#include <Servo.h>

Servo rightServo;
Servo leftServo;

int leftOutside = 2; //assigns left outside sensor as 2 for easy pinmoding
int leftInside = 3; //assigns left inside sensor as pin 3
int rightInside = 4; //assigns right inside sensor as pin 4
int rightOutside = 5; //assigns right outside sensor as pin 5
int movePos = 180; //value makes motors go
int stopPos = 90; //value makes motors stop
int color = 15; //arbitrary value above determined highest received value for white
int buttonPin = 8; //assigns button as pin 8 for easy pinmoding
int buttonValue = 0; //establishes a button value as 0

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

void leftTurn()  //this function makes the robot turn left

  rightServo.write(-movePos);
  leftServo.write(-movePos);
}

void rightTurn()  //this function makes the robot turn right

  rightServo.write(movePos);
  leftServo.write(movePos);
}

void stopRobot()  //this function stops the robot
{
  rightServo.write(stopPos);//90 is the servo stop point
  leftServo.write(stopPos);
  
}

void setup() {
  Serial.begin(115200);
  rightServo.attach(10);
  leftServo.attach(9);
  delay(10);
  pinMode(buttonPin, INPUT);
}

void loop() 
{
  stopRobot();
  
  buttonValue = digitalRead(buttonPin);
  
  while(buttonValue == 1)
  { 
    while(true)
    {
      Serial.print("Button value is: ");            
      Serial.println(buttonValue);                  //shows button value
      
      Serial.print("Left inside value: ");
      Serial.println(RCTime(leftInside));    //shows left inside follower value
  
      Serial.print("Right inside value: ");
      Serial.println(RCTime(rightInside));          //shows right inside follower value
  
      Serial.print("Left outside value: ");
      Serial.println(RCTime(leftOutside));    //shows left outside follower value
      
      Serial.print("Right outside value: ");
      Serial.println(RCTime(rightOutside));         //shows right outside follower value
      
      Serial.println("___________________");        //prints line to separate data values
      
      delay(10);    // Wait 10 ms
  
     if (RCTime(rightInside) > color || RCTime(leftInside) > color && RCTime(leftOutside) < color && RCTime(rightOutside) < color)  //goes straight
     {
        forward();
     }
     
     if (RCTime(rightInside) < color && RCTime(leftInside) < color && RCTime(leftOutside) > color)  //corrects left
     {
        leftTurn();
     }
     
     if (RCTime(rightInside) < color && RCTime(leftInside) < color && RCTime(rightOutside) > color)  //corrects right
     {
        rightTurn();
     }
    } 
  }
}

long RCTime(int sensorIn)         //Copied this function from the arduino website
 {
   long duration = 0;
   pinMode(sensorIn, OUTPUT);     // Make pin OUTPUT
   digitalWrite(sensorIn, HIGH);  // Pin HIGH (discharge capacitor)
   delay(1);                      // Wait 1ms
   pinMode(sensorIn, INPUT);      // Make pin INPUT
   digitalWrite(sensorIn, LOW);   // Turn off internal pullups
   while(digitalRead(sensorIn))
   {  // Wait for pin to go LOW
      duration++;
   }
   return duration;

 }

Issues:
The most notable issue with this was getting the sensors to read properly. The causation of this was my own inattentiveness in not providing proper power flow. After about 4 hours of head scratching, forum browsing, and reprogramming, I found that I had neglected to connect a ground. After this was remedied the next biggest problem was that my robot was jittering, sweeping for a value. I found that the issue that caused this was the statement: 

  if (RCTime(rightInside) > color && RCTime(leftInside) > color && RCTime(leftOutside) < color && RCTime(rightOutside) < color)  //goes straight
     {
        forward();
     }

Which was later remedied and works as such,

  if (RCTime(rightInside) > color || RCTime(leftInside) > color && RCTime(leftOutside) < color && RCTime(rightOutside) < color)  //goes straight
     {
        forward();
     }

in the program above. After this, the robot was able to complete the course with realistic reliability, however it would still sometimes go off course. The irregularity of its path, I then found, was caused by it wiggling the paper out of the sensors' reading area. This problem, however, cannot be corrected outside of reinforcing the paper. 


Sunday, September 1, 2013

Simple Movements



Tasked to build a robot, using a Mega 2560 Arduino board, that went forwards, backwards, turned left, turned right, stopped, and made an led blink after the program has run its course. I came up with the specimen in the gif above. A total of about 3 hours was spent wiring, coding, and debuging.

Wiring:


This photo is a tad misleading but what was done was the black wire goes to the ground buss of the breadboard while the red wire goes to the hot buss of the bread board. One of the blue wires (PWM 2) goes to the positive end of the LED (to allow for programming/voltage control) while the other two (PWM 12 for the left servo and PWM 13 for the right servo) go to the white leads of the servos (one per servo). The ground leads for the servos are in the same row and then jumped to the ground buss of the breadboard to allow for wiring simplicity. This mentality also applies to the hot leads of the servos. 


This photo is also a bit misleading but the blue wire which seems to disappear underneath the battery is connected to one of the ends of the resistor. The resistor then spans to the positive end of the green LED (programmed to flash 5 times at the end of the program, noted it only does 4 times in the gif) which is hooked to the ground buss of the breadboard.


Code:


#include <Servo.h>


Servo rightServo;
Servo leftServo;


int pos = 180; //sets a turn value
int led = 2;  //initializes led variable to make it assignment easier
int counter = 0;  //initializes an integer for the ledBlink counter loop

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);
}

void leftTurn()  //this function makes the robot turn left
  rightServo.write(-pos);
  leftServo.write(-pos);
}

void rightTurn()  //this function makes the robot turn right
{ 98
  rightServo.write(pos);
  leftServo.write(pos);
}

void stopRobot()  //this function stops the robot
{
  rightServo.write(90);//90 is the servo stop point
  leftServo.write(90);
}

void ledBlink()  //this function makes the led blink 5 times
{
   while(counter != 5)
 {
   counter = counter + 1;
   digitalWrite(led, HIGH); //turns led on
   delay(500);
   digitalWrite(led, LOW);//turns led off
   delay(500);
 }
}

void setup()
{
  rightServo.attach(13);
  leftServo.attach(12);
  pinMode (led, OUTPUT);// this sets pin 2 (as assigned via led = 2) as an output pin

  forward();
  delay(1500);
  stopRobot();
  delay(1500);
  leftTurn();
  delay(1500);
  stopRobot();
  delay(1500);
  rightTurn();
  delay(1500);
  stopRobot();
  delay(1500);
  backward();
  delay(1500);
  stopRobot();
  delay(1500);
  ledBlink();   
}

void loop() //nothing here because we don't want it to loop
{
}

Issues:

It was quite difficult trying to get the thing to move properly. I found often during the troubleshooting phase that having a negative (pos) value would stop the servo's movement altogether. It wasn't until I looped a run-stop program in the void loop() and was able to physically configure the servos to move during the run section and stop during the stop sections that the robot then began to perform as initially intended. Also, I had absolutely no clue how to do an LED pulse so I needed to use reference materials for that, the source for which I cannot find any longer (will make a note to keep track of sources for future use/reference of others). Mounting all the necessary parts was also a pain, but I have found my current configuration is the best for now.