Ultrasonic Sensor

 

In my opinion, this is the coolest part about building this robot. It is here that we give our robot some very elementary autonomous capability with an ultrasonic distance sensor. This is an amazing little device that will quickly and accurately report the distance an object is away from out robot. With this we program our robot to have some basic collision avoidance.

this sensor is sorta kinda like a little miniature radar. It works by emitting a sound pulse, and measuring how long it takes for the pulse to reflect back ( humans cannot hear the sound, hence the name ultrasonic). Velocity = distance / time ( i.e. mile per hour ). So then distance = velocity * time, the ultrasonic sensor will report the time it takes the pulse to reflect, we actually want half that amount, since the pulse going there and back is actually twice the distance to the object. Then we just need the velocity, which for us is the speed of sound in air.

To demonstrate this and get started with the sensor, lets hook up the sensor to the Arduino, and write a simple program that displays the distance measured to the Serial Monitor. There are three pins on the sensor, Vcc and Gnd, which supply power, and SIG . Connect the SIG pin to port 11.


 

I found the following code online, you can find it, and a good description of it here.


const int pingPin = 11;
unsigned int duration, inches;

void setup() {
  Serial.begin(9600);
}

void loop() {
  pinMode(pingPin, OUTPUT);          // Set pin to OUTPUT
  digitalWrite(pingPin, LOW);        // Ensure pin is low
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);       // Start ranging
  delayMicroseconds(5);              //   with 5 microsecond burst
  digitalWrite(pingPin, LOW);        // End ranging
  pinMode(pingPin, INPUT);           // Set pin to INPUT
  duration = pulseIn(pingPin, HIGH); // Read echo pulse
  inches = duration / 74 / 2;        // Convert to inches
  Serial.println(inches);            // Display result
  delay(200);		             // Short delay
}

An very good explanation and example calculation is provided at the link I referenced for this code. The key part is that the distance to the object in front of the sensor is equal to the time reported divided by 74, divided by 2.

I got this to work simply using my hand.

 

There is an interesting little quirk about using the ultrasonic distance sensor, it sometimes won’t work, and the way to get it to work is to disconnect and then reconnect the PWR wire, with the others still connected. Put another way you should hook up the PWR wire last.

Now that we know how to use the ultrasonic sensor, lets incorporate it into our robot. All we need to do for the hardware is connect 3 wires (PWR, GND, SIG) SIG is connected to port 11. We also need to add some code to make use of the sensor. This is an area where we could get pretty sophisticated trying to add Artificial Intelligence, and make our robot find its way around. Lets keep it simple for now and just have tracky stop, backup, and turn left when an obstacle is encountered. Here is the code to do it.

const int pingPin = 6;

   // test for obstacle
   int duration, inches=3;
   pinMode(pingPin, OUTPUT);          // Set pin to OUTPUT
   digitalWrite(pingPin, LOW);        // Ensure pin is low
   delayMicroseconds(2);
   digitalWrite(pingPin, HIGH);       // Start ranging
   delayMicroseconds(5);              // with 5 microsecond burst
   digitalWrite(pingPin, LOW);        // End ranging
   pinMode(pingPin, INPUT);           // Set pin to INPUT
   duration = pulseIn(pingPin, HIGH); // Read echo pulse
   inches = duration / 74 / 2;        // Convert to inches
   Serial.println(inches);            // Display result
   delay(200);		             // Short delay

   if( inches < 3 && inches > 0)
     {
       Serial.println("obstacle detected");
       tracky.Stop();
       tracky.DriveBackward();
       delay(1000); // go backwards briefly
       tracky.TurnLeft();
       tracky.Stop();
       tracky.DriveForward();
     } 
    delay(200);

And finally here is the full code implementing both remote control and the ultrasonic sensor!

// adds second motor and 2 button control
#include <IRremote.h>

// pin assignments
const int pingPin = 6; // need to set these
const int RECV_PIN = 4;
const int directionPinA = 12;
const int directionPinB = 13;
const int motorPinA = 3;
const int motorPinB = 11;
const int brakePinA = 9;
const int brakePinB = 8;

// hex code assigned to a button press
const long forward_button = 0xFD807F;  // uses 'VOL+' button 
const long stop_button = 0xFDA05F;     // uses 'Play' button
const long reverse_button = 0xFD906F;  // uses 'VOL-' button
const long left_button = 0xFD20DF;     // uses 'prev' button
const long right_button = 0xFD609F;    // uses 'next' button
const long repeat = 0xFFFFFFFF;

// global vars
const int AFORWARD = LOW;
const int BFORWARD = HIGH;
IRrecv irrecv(RECV_PIN);
decode_results results;
long current_command = 0;
long previous_command = 0;

// speed is used globally for motion and steering
const int MAX_SPEED = 255; // use speed 255  

// main class to represent our robot
class Robot
{
  private:
    int _lts; // left track speed
    int _rts; // right track speed 
    int _ltd; // left track direction
    int _rtd; // right track direction
    void drive(int lts, int rts, int ltd, int rtd);

  public:
    Robot(int lts, int rts, int ltd, int rtd);
    void Stop(); // engage both brakes    
    void DriveForward(); // both forward 
    void DriveBackward(); // both backward 
    void TurnLeft(); // opposite directions 
    void TurnRight(); // opposite directions
};

// create a new robot
Robot tracky(0, 0, AFORWARD, BFORWARD); // our robot is named tracky

void setup()
{

  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  // setup channels A
  pinMode(motorPinA, OUTPUT); //Initiates Motor Channel A pin
  pinMode(brakePinA, OUTPUT); //Initiates Brake Channel A pin

  // setup Channel B
  pinMode(motorPinB, OUTPUT); //Initiates Motor Channel B pin
  pinMode(brakePinB, OUTPUT);  //Initiates Brake Channel B pin

  digitalWrite(brakePinA, LOW);   // disengage the Brake for channel A
  digitalWrite(brakePinB, LOW);   // disengage the brake for channel B

  // setup ports for ultrasonic sensor
  pinMode(pingPin, OUTPUT);
}

void loop() 
{
   // test for obstacle
   int duration, inches=3;
   pinMode(pingPin, OUTPUT);          // Set pin to OUTPUT
   digitalWrite(pingPin, LOW);        // Ensure pin is low
   delayMicroseconds(2);
   digitalWrite(pingPin, HIGH);       // Start ranging
   delayMicroseconds(5);              //   with 5 microsecond burst
   digitalWrite(pingPin, LOW);        // End ranging
   pinMode(pingPin, INPUT);           // Set pin to INPUT
   duration = pulseIn(pingPin, HIGH); // Read echo pulse
   inches = duration / 74 / 2;        // Convert to inches
   Serial.println(inches);            // Display result
   delay(200);		             // Short delay

   if( inches < 3 && inches > 0)
     {
       Serial.println("obstacle detected");
       tracky.Stop();
       tracky.DriveBackward();
       delay(1000); // go backwards briefly
       tracky.TurnLeft();
       tracky.Stop();
       tracky.DriveForward();
     } 
    delay(200);

  if (irrecv.decode(&results)) {   // results is an instance of a decode_results class, decode() returns an int
    Serial.println(results.value, HEX);

    if( results.value == repeat )
     {
       current_command = previous_command;
     }
    else
     {
       current_command = results.value;
       previous_command = current_command;
     }

    // channel A is the left motor as viewed from a "driver" viewpoint"
    // channel B is the right motor as viewed from a "driver" viewpoint"  
    switch (current_command) 
      {
       //Serial.println("in switch statement");
       case forward_button:
            tracky.DriveForward();
            break;
       case stop_button: 
            tracky.Stop();
            break;
       case reverse_button:
            tracky.DriveBackward();
            break;
       case left_button:
            tracky.TurnLeft();
            break;
       case right_button:
            tracky.TurnRight(); 
            break;
      }   
     irrecv.resume(); // Receive the next value
  }
}

Robot::Robot(int lts, int rts, int ltd, int rtd)
{
  _lts = lts;
  _rts = rts;
  _ltd = ltd;
  _rtd = rtd;
}

void Robot::drive(int lts, int rts, int ltd, int rtd)
{
  //Serial.println(lts);
  digitalWrite(directionPinA, ltd); // Establishes direction of Channel A
  //digitalWrite(brakePinA, LOW);   // Disengage the Brake for Channel A
  analogWrite(motorPinA, lts);    // Spins the motor on Channel A

  //Serial.println(rts);
  digitalWrite(directionPinB, rtd); // Establishes direction of Channel B
  //digitalWrite(brakePinB, LOW);   // Disengage the Brake for Channel B
  analogWrite(motorPinB, rts);   // Spins the motor on Channel B at full speed 
}

void Robot::Stop()
{
  //Serial.println("Stop");
  //digitalWrite(brakePinA, HIGH);   // engage the Brake for channel A
  //digitalWrite(brakePinB, HIGH);   // engage the brake for channel B
  _lts = 0;
  _rts = 0;
  drive(_lts, _rts, _ltd, _rtd);

}    

void Robot::DriveForward()
{
  //Serial.println("Forward");
  _lts = MAX_SPEED;
  _rts = MAX_SPEED;
  _ltd = AFORWARD;
  _rtd = BFORWARD;
  drive(_lts, _rts, _ltd, _rtd);
}

void Robot::DriveBackward()
{
  //Serial.println("Backwards");
  _lts = MAX_SPEED;
  _rts = MAX_SPEED;
  _ltd = !AFORWARD;
  _rtd = !BFORWARD;
  drive(_lts, _rts, _ltd, _rtd);
}

void Robot::TurnLeft()
{
  //Serial.println("Turn Left");
  Serial.println(_lts);
  Serial.println(_rts);
  // the robot does not have to be moving to turn, we will spin in place
  drive(MAX_SPEED, MAX_SPEED, !AFORWARD, BFORWARD); // drive the left track in the opposite direction  
  delay(750);
  drive(_lts, _rts, _ltd, _rtd); // resume whatever we were doing when this function was called
 }

void Robot::TurnRight()
{
  //Serial.println("Turn Right");
  // the robot does not have to be moving to turn, we will spin in place
  drive(MAX_SPEED, MAX_SPEED, AFORWARD, !BFORWARD); // drive the left track in the opposite direction  
  delay(500);
  drive(_lts, _rts, _ltd, _rtd); // resume whatever we were doing when this function was called
}

Here is a short little video of the ultrasonic sensor in action!

 

 

I hope you made it this far, and found the tutorial useful, if so I hope you don’t stop here, your next step can be in one of many directions. Head over to the Final Testing section to discuss how we can improve tracky and add some capabilities.

 

Intro->SOS->Chassis Assembly->Motors & Drive-train->Arduino-Remote Control->Assembly->Ultrasonic Sensor->Final Testing

 Posted by at 3:51 pm

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)


Time limit is exhausted. Please reload CAPTCHA.