Ping)))Dar "1 Scan Only, Please"
Hello,
I've gotten the Ping)))Dar program to run (on my Boe-Bot) as described but am still having a few issues.
How do I modify the code so the Ping)))Dar only scans once and then moves forward toward object.
My boebot goes through the scanning sequence, identifyies object, then moves forward maybe several inches. It then stops, goes through the scanning process again, moves forward another couple of inches, stops, scans again, etc.
Again, I want it to accept the initial scan and move forward to infinity.
Here's the code:
I've gotten the Ping)))Dar program to run (on my Boe-Bot) as described but am still having a few issues.
How do I modify the code so the Ping)))Dar only scans once and then moves forward toward object.
My boebot goes through the scanning sequence, identifyies object, then moves forward maybe several inches. It then stops, goes through the scanning process again, moves forward another couple of inches, stops, scans again, etc.
Again, I want it to accept the initial scan and move forward to infinity.
Here's the code:
' -----[ Title ]--------------------------------------------------------------
' Smart Sensors and Applications - GoToClosestObject.bs2
' Sweep Ping))) Ultrasonic Rangefinder across 180-degrees and find the closest
' object. Then calculate and execute the turn required to face the object.
' Travel forward until the object is less than or equal to 5 cm from the front
' of the rangefinder.
' IMPORTANT: This program has several constants that have to be tuned before
' it will work right. Follow the instructions in Smart Sensors
' and Applications, Chapter 8, Activity #4 and #5 before you run
' this program!
' {$STAMP BS2} ' Target device = BASIC Stamp 2
' {$PBASIC 2.5} ' Language = PBASIC 2.5
' -----[ I/O Definitions ]----------------------------------------------------
' Ping))) Ultrasonc Rangefinder and Mounting Bracket
PingServo PIN 14 ' Servo that directs Ping))) snsr
Ping PIN 1 ' Ping))) sensor signal pin
' Boe-Bot servo pins (Left and right are from driver's seat perspective.)
BotServoLeft PIN 13 ' Left drive servo
BotServoRight PIN 12 ' Right drive servo
StartLED PIN 0 ' display start delay
' -----[ Constants ]----------------------------------------------------------
' Ping))) mounting bracket constants
LimitLeft CON 1189 ' Bracket 90-degrees Left
LimitRight CON 286 ' Bracket 90-degrees Right
Limits CON LimitLeft + limitRight 'this added from Forum
Center CON 750 ' Center/0-degree pulse duration
Increment CON 15 ' Increment for pulse sweeping
MinSweep CON 40 ' Pulses -> 90-degree right
' Boe-Bot continuous rotation servo control constants
FwdLeftFast CON 817 ' Fast settings - straight ahead
FwdRightFast CON 650
RotateRight CON 763 ' Boe-Bot rotate right pulse
RotateLeft CON 740 ' Boe-Bot rotate left pulse
BtwnPulses CON 20 ' ms between servo pulses
' Ping))) Ultrasonic Rangefinder constants
CmConstant CON 2260 ' Echo time -> cm with **
SinCosTo256 CON 517 ' For */ -127..127 -> -256..256
Ms20 CON 330 ' 20 ms worth of cm
' MSB sign (twos complement)
Negative CON 1 ' Negative sign (bit-15)
Positive CON 0 ' Positive sign (bit-15)
' Ping and turning axis geometry
PingDirToAngle CON 8454 ' Servo pulse to angle ** con
PingAxleOffset CON 7 ' 7 cm between ping))) and axis
' -----[ Variables ]----------------------------------------------------------
time VAR Word ' Ping))) echo time
pingDir VAR Word ' Pulse duration -> direction
pingRev VAR Word ' Pulse duration -> direction for reversed servo
' added from Forum
x VAR Word ' x coordinate
y VAR Word ' y coordinate
distance VAR Time ' Object centimeter distance
markDir VAR y ' Pulse points to closest object
rightMark VAR x ' Pulse to object's right side
leftMark VAR pingDir ' Pulse to object's left side
pulses VAR x ' +/- brads to turn toward object
PrevDist VAR Byte ' Previous distance measurement
angle VAR Byte ' Servo angle from right in brads
counter VAR angle ' Loop counter
minDist VAR angle ' Minimum distance measurement
sweepInc VAR Nib ' Increment for servo sweep
sweepDir VAR Bit ' Increment/decrement pingDir
xSign VAR Bit ' Stores sign of x variable
ySign VAR xSign ' Stores sign of x variable
pSign VAR Bit ' Sign of pulses variable
edgesFound VAR Bit ' Navigation flag
temp VAR Byte
' -----[ Initialization ]-----------------------------------------------------
' -----[ EEPROM Data ]-----------------------------------------------------
RunStatus DATA $00 ' run status
' -----[ Initialization ]--------------------------------------------------
Reset:
READ RunStatus, temp ' read current status
temp = ~temp ' invert status
WRITE RunStatus, temp ' save for next reset
IF (temp > 0) THEN END ' run now?
Start_Delay:
HIGH StartLED ' show active
PAUSE 5000 ' start delay
LOW StartLED ' LED off
' following from Forum
pingDir = LimitRight ' Start servo at 0-degrees
FOR counter = 1 TO 40 ' Initialize servo position
'PULSOUT PingServo, pingDir ' Forum: removed & replaced by next 2 lines
pingRev = Limits - pingDir
PULSOUT PingServo, pingRev
PAUSE 20
NEXT
sweepInc = Increment ' Set the sweep increment
' -----[ Main Routine ]-------------------------------------------------------
GOSUB Get_Ping_Cm ' First distance measurement
DO UNTIL distance <= 5 ' Repeat until distance <= 5 cm
edgesFound = 0 ' Clear edges found flag
DO UNTIL edgesFound = 1 ' Repeat until edges found = 1
GOSUB Face_Closest_Object ' Find & face closest object
LOOP
GOSUB Get_Ping_Cm ' Get current distance
DO UNTIL distance <= 5 ' Drive toward object
prevDist = distance MAX 255 ' Current distance -> previous
GOSUB Get_Ping_Cm ' Get new distance
PULSOUT BotServoLeft, FwdLeftFast ' Boe-Bot forward
PULSOUT BotServoRight, FwdRightFast
PAUSE BtwnPulses - (distance / Ms20) ' 20 ms pause between pulses
IF distance >= prevDist + 5 THEN EXIT ' Exit if distance increasing
LOOP
LOOP ' Main routine's outermost loop
END
' -----[ Subroutines - BoeBot_Turn_Brads ]-----------------------------------
' Boe-Bot turns a certain number of binary radians to face an object.
BoeBot_Turn_Brads:
IF pSign = Positive THEN
FOR counter = 0 TO ABS(pulses)
PULSOUT BotServoLeft, RotateRight
PULSOUT BotServoRight, RotateRight
PAUSE BtwnPulses - (distance / Ms20)
NEXT
ELSE
FOR counter = 0 TO ABS(pulses)
PULSOUT BotServoLeft, RotateLeft
PULSOUT BotServoRight, RotateLeft
PAUSE BtwnPulses - (distance / Ms20)
NEXT
ENDIF
RETURN
' -----[ Subroutines - Face_Closest_Object ]----------------------------------
' Scan for closest object using a Ping))) rangefinder mounted on a standard
' servo. Locate the middle fo the object, and turn Boe-Bot to face it.
Face_Closest_Object:
' Initialize sweep increment.
sweepInc = Increment
' Start Servo rotated to the far right.
pingDir = LimitRight
GOSUB Point_At_PingDir
' Make minDist large and sweepDir positive (0). Single_Sweep sweeps
' left -> right while measuring object distances and stores the direction
' of the closest object in markDir.
minDist = 65535
sweepDir = Positive
GOSUB Single_Sweep
' Point the servo in the direction of the closest distance measurement.
pingDir = markDir
GOSUB Point_At_PingDir
' Scan to find object's right side.
GOSUB Find_Right_Side
IF edgesFound = 0 THEN RETURN
' Point the servo in the direction of the closest distance measurement.
pingDir = markDir
GOSUB Point_At_PingDir
' Scan to find object's right side.
GOSUB Find_Left_Side
IF edgesFound = 0 THEN RETURN
' Average the angles to the object's left and right sides. That's the
' middle of the object. Point rangefinder in that direction.
pingDir = leftMark + rightMark / 2
GOSUB Point_At_PingDir
' At this point, the Ping))) should be pointing directly at the closest
' object.
' Calculate the angle to the object's angle in brads, and turn the
' Boe-Bot to face that angle.
GOSUB Turn_Angle_Adjust
GOSUB BoeBot_Turn_Brads
' Face Ping))) rangefinder straight ahead.
pingDir = Center
GOSUB Point_At_PingDir
RETURN
' -----[ Subroutines - Find_Left_Side ]---------------------------------------
' Scan left until the measured distance is 10 cm beyond the closest distance,
' which is assumed to mean the object's side has been found.
' If the object's side has been found within the 180-degree field of vision,
' set edgesFound = 1 and store the pulse duration (pingDir) at which the
' object was found in the leftMark variable.
' If the side was not found by the 180-degree point in the scan, rotate the
' Boe-Bot until the edge is found, and then set edgesFound to 0 signifying
' that the scan will have to be repeated because the Boe-Bot rotated
' to find the side, which would otherwise cause the markDir variable to
' store an incorrect value.
Find_Left_Side:
sweepDir = Positive
distance = minDist
sweepInc = 1
DO UNTIL distance > minDist + 10
GOSUB Sweep_Increment
GOSUB Get_Ping_Cm
IF pingDir >= LimitLeft - 10 THEN
pingDir = LimitLeft - 50
GOSUB Point_At_PingDir
DO UNTIL distance > minDist + 10
PULSOUT BotServoLeft, RotateLeft
PULSOUT BotServoRight, RotateLeft
GOSUB Get_Ping_Cm
PAUSE 20
LOOP
edgesFound = 0
RETURN
ENDIF
LOOP
leftMark = pingDir
edgesFound = 1
RETURN
' -----[ Subroutines - Find_Right_Side ]--------------------------------------
' Mirror image of Find_Left_Side.
Find_Right_Side:
sweepDir = Negative
distance = minDist
sweepInc = 1
DO UNTIL distance > minDist + 10
GOSUB Sweep_Increment
GOSUB Get_Ping_Cm
IF pingDir <= LimitRight + 10 THEN
pingDir = LimitRight + 50
GOSUB Point_At_PingDir
DO UNTIL distance > minDist + 10
PULSOUT BotServoLeft, RotateRight
PULSOUT BotServoRight, RotateRight
GOSUB Get_Ping_Cm
PAUSE 20
LOOP
edgesFound = 0
RETURN
ENDIF
LOOP
rightMark = pingDir
edgesFound = 1
RETURN
' -----[ Subroutine - Get_Ping_Cm ]-------------------------------------------
' Gets Ping))) rangefinder measurement and converts time to centimeters.
' Distance may be declared as time to save variable space.
Get_Ping_Cm:
PULSOUT Ping, 5
PULSIN Ping, 1, time
distance = time ** CmConstant
RETURN
' -----[ Subroutines - Point_At_PingDir ]-------------------------------------
' Points servo mounted Ping))) rangefinder at an angle determined by the
' value of the pingDir variable.
Point_At_PingDir:
FOR counter = 0 TO MinSweep
' PULSOUT PingServo, pingDir ' Forum: removed & replaced by next 2 lines
pingRev = Limits - pingDir
PULSOUT PingServo, pingRev
PAUSE BtwnPulses
NEXT
RETURN
' -----[ Subroutine - Polar_To_Cartesian ]------------------------------------
' Calculates x and y (Cartesian coordinates) given distance and angle
' (polar coordinates).
Polar_To_Cartesian:
' Calculate left/right component.
x = COS angle ' Polar to Cartesian
xSign = x.BIT15 ' Store sign bit
x = ABS(x) */ SinCOsTo256 ' Polar to Cartesian continued
x = distance */ x
IF xSign = negative THEN x = -x ' Correct sign with sign bit
' Calculate straight ahead component.
y = SIN angle ' Polar to Cartesian
ySign = y.BIT15 ' Store sign bit
y = ABS(y) */ SinCOsTo256 ' Polar to Cartesian continued
y = distance */ y
IF ySign = negative THEN y = -y ' Correct sign with sign bit
RETURN
' -----[ Subroutines - Single_Sweep ]-----------------------------------------
' Do one sweep, and find the closest distance measurement and the
' pulse value that points the servo in that direction.
Single_Sweep:
DO UNTIL pingDir >= LimitLeft
GOSUB Sweep_Increment
GOSUB Get_Ping_Cm
IF distance < minDist THEN
minDist = distance
markDir = pingDir
ENDIF
LOOP
RETURN
' -----[ Subroutine - Sweep_Increment ]---------------------------------------
' Increment/decrement the position of the servo that directs the Ping)))
' rangefinder. When pingDir goes outside either LimitRight or LimitLeft,
' the sweep direction toggles.
Sweep_Increment:
' Change sweepDir for adding/subtracting increment if at rotation limit.
IF pingDir <= LimitRight THEN
sweepDir = Positive
ELSEIF pingDir >= LimitLeft THEN
sweepDir = Negative
ENDIF
' Add/subtract increment to/from pingDir.
IF sweepDir = negative THEN
pingDir = pingDir - sweepInc
ELSEIF sweepDir = Positive THEN
pingDir = pingDir + sweepInc
ENDIF
' Send positioning pulse to Ping))) Mounting Bracket servo.
' PULSOUT PingServo, pingDir ' Forum: removed & replaced by next 2 lines
pingRev = Limits - pingDir
PULSOUT PingServo, pingRev
RETURN
' -----[ Subroutines - Turn_Angle_Adjust ]------------------------------------
' Adjusts required turn angle based on 7 mm offset of Ping))) rangefinder from
' Boe-Bot's turning axis.
Turn_Angle_Adjust:
' Get the object's distance at its center.
GOSUB Get_Ping_Cm
' Position servo & calculate angle from far-right in brads.
angle = pingDir - 250 ** PingDirToAngle
GOSUB Polar_To_Cartesian
' Add distance between Ping))) and center of Boe-Bot axis.
y = y + PingAxleOffset
' Recalculate the turning angle with respect to Boe-Bot's turning axis.
angle = x ATN y
pulses = 64 - angle
pSign = pulses.BIT15
RETURN
Comments
I would suggest making sure your batteries are fresh. The servos can draw a significant amount of current causing the BOE to reset, restarting the program. I had a similar problem with Ping roaming and it took me a bit to determine the batteries were weak.
Try replacing the batteries and if the issue persists, we have another problem to sort out.
Good Luck!
Amanda
Change this section:
DO UNTIL distance <= 5 ' Drive toward object prevDist = distance MAX 255 ' Current distance -> previous GOSUB Get_Ping_Cm ' Get new distance PULSOUT BotServoLeft, FwdLeftFast ' Boe-Bot forward PULSOUT BotServoRight, FwdRightFast PAUSE BtwnPulses - (distance / Ms20) ' 20 ms pause between pulses IF distance >= prevDist + 5 THEN EXIT ' Exit if distance increasing LOOP
To this:
DO PULSOUT BotServoLeft, FwdLeftFast ' Boe-Bot forward PULSOUT BotServoRight, FwdRightFast PAUSE 20 LOOP
I just removed all the distance checks and calculations once the robot starts moving toward the target. The robot will just keep going without looking where it's going anymore.