User loginNavigation
Who's onlineThere are currently 0 users and 1 guest online.
|
$50 Robot - Sonar UpgradeSubmitted by pomprocker on July 17, 2008 - 3:54pm.
![]() Introduction
I chose to go with the Parallax Ping Ultrasonic Sensor for this upgrade to the $50 Robot. Though only tested on an ATmega8, 168, and 128 this should port over to any AVR 8-bit RISC microcontroller. The reason I chose this sensor is because it is readily available at some local electronics locations instead of having to order online. Most notably, this sensor can be picked up at your local Radio Shack. The datasheet can be found on the Parallax website here (.pdf), please download yourself a copy. You also need to make sure that you have Procyon AVRlib installed. Theory
The section were most interested in on the datasheet is the 'Communication Protocol' section on page 2.
Construction
First you need to create a cable to wire it to the $50 Robot MCU. I recommend about a foot long, since you're going to be braiding it which makes it shorter. Please follow the tutorial written by our admin on that: Wire Connector Tutorial
Then you have to follow this tutorial for fabricating a mount for your Ping Sensor: Mounting a Sensor Your mount will differ depending on if you want to mount it directly to the chassis or to a servo. For now this tutorial only covers mounting it to the chassis and using it as a touchless bumper.
Coding
Timer -
We are going to use a basic timer in order to record the time that the Ping sensor brings the pin high. Which in turn we can use to calculate the distance away and object is. In SoR_Utils.h, you need to include the timer header file depending on which mcu you're using.
#include "timer.h" or #include "timerx8.h"
We also need to add this simple function to SoR_Utils.h
//**************RESET TIMER**************
void reset_timer_0(void) {
//restart timer count
TCNT0=0x00;//clear timer
//clear timer0's overflow counter.
timer0ClearOverflowCount();
}
//***************************************
While you're in the file, go ahead and add this to the servo function area:
void robot_go_back(void)
{
servo_left(352);
servo_right(200);
}
In the Initialize function of SoR_Utils.h add this line:
timer0Init(); // initialize the timer system
Registers -
Image of an ATmega8/ATmega168 with ports:
Port registers allow for lower-level and faster manipulation of the i/o pins on the microcontroller. The ATmega8 and ATmega168 have three ports: B, C, and D.
DDRB - The Port B Data Direction Register PORTB – The Port B Data Register
Macros -
There is a header file called sfr_defs.h which is included in io.h, which is included in SoR_Utils.h. SFR stands for special functions register and the file contains a few useful macros which we can use:
#define bit_is_clear (sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit))) Test whether bit bit in IO register sfr is clear. This will return non-zero if the bit is clear, and a 0 if the bit is set. #define bit_is_set (sfr, bit) (_SFR_BYTE(sfr) & _BV(bit)) Test whether bit bit in IO register sfr is set. This will return a 0 if the bit is clear, and non-zero if the bit is set. #define loop_until_bit_is_clear (sfr, bit) do { } while (bit_is_set(sfr, bit))
Wait until bit bit in IO register sfr is clear. #define loop_until_bit_is_set(sfr, bit) do { } while (bit_is_clear(sfr, bit))
Wait until bit bit in IO register sfr is set.
These macros associate simple commands with complicated bitwise operators. You can see examples of these macros in action in the code below.
#define PORT_ON( port_letter, number ) port_letter |= (1<<number) #define PORT_OFF( port_letter, number ) port_letter &= ~(1<<number) #define PORT_ALL_ON( port_letter, number ) port_letter |= (number) #define PORT_ALL_OFF( port_letter, number ) port_letter &= ~(number) #define FLIP_PORT( port_letter, number ) port_letter ^= (1<<number) #define PORT_IS_ON( port_letter, number ) ( port_letter & (1<<number) ) #define PORT_IS_OFF( port_letter, number ) !( port_letter & (1<<number) #define PINGPIN 2 // assign a pin to the Ping Sensor #define DDR DDRC #define PORT PORTC #define PIN PINC
Function:
void ping(void) {
PORT_ON(DDR, PINGPIN); // Switch PingPin to OUPUT
// ------Trigger Pulse--------------
PORT_OFF(PORT, PINGPIN); // Bring PingPin low before starting trigger pulse
delay_us(2); // Wait for 2 microseconds
PORT_ON(PORT, PINGPIN); // Bring PingPin High for 5us according to spec sheet.
delay_us(5); // Wait for 5 microseconds
PORT_OFF(PORT, PINGPIN);; // Bring PingPin Low and standby
//--------End Trigger Pulse---------------------
FLIP_PORT(DDR, PINGPIN); // Switch PingPin to INPUT
loop_until_bit_is_set(PIN, PINGPIN); // Loop until the the PingPin goes high (macro found in sfr_def.h)
//clears timer, reset overflow counter
reset_timer_0(); //reset timer 0
loop_until_bit_is_clear(PIN, PINGPIN); // Loop until the the PingPin goes low (macro found in sfr_def.h)
//read timer0's overflow counter
//255 is count before overflow, dependent on clock
int elapsed_time=timer0GetOverflowCount()*255+TCNT0;
PingVal = elapsed_time * 2.068965517;t
} // end ping function
// All the values are based on running at 8MHz. You can see in the comments, I multiplied the original 1MHz values by 8.
while(1) {
scan();
ping();
//Object Avoider
if (PingVal > 8) {
// object detected
if (sharp_IR_reading > scan_thresh) {
//240 far right, 400 center, 448 far left
//object on left
if(scan_angle > 380)
while (sharp_IR_reading > scan_thresh) {
robot_turn_right();
sharp_IR_reading=a2dConvert8bit(3);
} // end while
//object on right
else if(scan_angle < 360) // 41 * 8
while (sharp_IR_reading > scan_thresh) {
robot_turn_left();
sharp_IR_reading=a2dConvert8bit(3);
} // end while
} // end if
// object not detected
else
robot_go_straight();
} // end if
else {
while (PingVal < 16) {
robot_go_back();
ping();
} // end while
for (int i = 0; i > 5; i++)
robot_turn_right();
} // end else
delay_cycles(3200);//a small delay to prevent crazy oscillations -> 400 * 8
} // end while loop
( categories: )
|
|