The Ultrasonic Sensor
-
Upload
adalberto-sharpley -
Category
Documents
-
view
23 -
download
0
description
Transcript of The Ultrasonic Sensor
The 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
}