V1.1.2 available on page 3
Taking on board some of the comments made recently regarding autonomous roaming, plus a few improvements I wanted to make I have updated the Ping Roam script (which if I knew it would be so popular I would have made more of an effort the first time around).
I've done some quick testing with it however my testbot runs on 4 modified servos with wheels on which isn't the best method of driving it so it may still have some bugs in... that's where you come in Let me know if there are any bugs, anything that doesn't work quite like it should, any further improvements you want...
I did have a bug in the escape routine, which I think I have now solved. Where it has a loop in the routine to continue turning until the sensor reading is above the setpoint I think that was throwing off the return at the end of the routine, not returning to where it came from but returning to when it was told to loop. Solved with additional labels and it seems to be working now...
Changes
# Boxed In check added
# Escape from Boxed In added
# Avoidance of left/right/left/right loops
# Automatic calculation of sweep servo center position
# Tidied up code
# More comments added
# Almost completely made with labels and gotos
And, here is the codeCode:
# Ping Object Avoidance
# Using Ultra Sonic Ping Sensor on servo for avoidance
# Version 1.1.0
# Configuration Settings
# Adjust values below for port configuration
$pingport = D0 # Change for Ping Port
$echoport = D1 # Change for Echo Port
$sweepservo = D2 # Change for sweep servo port
# Adjust values below for movement control
$reverseturn = 1 # Reverse before turn? 0 = no, 1 = yes
$maxdistance = 30 # Change for maximum distance from object before avoiding in units
$boxedindistance = 20 # Change for maximum distance for boxed in detection
$turnamount = 500 # Change for how long to turn for in ms
$reverseamount = 500 # Change for how long to reverse for in ms (if applicable)
$movementspeed = 255 # Change for movement speed
$slowturn = 127 # Change for slow turn speed
# Adjust values below for sweep configuration
$sweepmin = 10 # Change for min limit
$sweepmax = 90 # Change for max limit
$sweepservodelay = 500 # Change for delay between sweep servo movements and readings
# Testing Options
$testmode = 0 # Change to 1 if testing without PING sensor
# Do not adjust these values
$sweepcenter = $sweepmin+$sweepmax
$sweepcenter = $sweepcenter/2
$sweepcenter = Round($sweepcenter,0)
$sweepprevious = $sweepmax # Do not change
$sweepcurrent = $sweepcenter # Do not change
$SweepErrorFlag = 0 # Do not change
$BoxedInErrorFlag = 0 # Do not change
$BoxedInRun = 0 # Do not change
$SweepCenterRun = 0 # Do not change
$EscapeRun = 0 # Do not change
$ScriptErrorFlag = 0 # Do not change
$isboxedin = 0 # Do not change
$penultimatemove = "none"
$lastmove = "none"
# ------- The Script --------
# Set the start point for any loops
:begin
# Center the sweep servo
Servo($sweepservo, $sweepcenter)
# Start moving forwards
FORWARD()
# Start the detection
Goto(detect) # This line is redundant
# Detection code
# Set a label for loops and gotos
:detect
# Use random numbers if in test mode
IF ($testmode=0)
$currentdistance = GetPing($pingport, $echoport)
ELSE
$currentdistance = GetRandom(0,255)
ENDIF
# Check the current distance against the max allowed distance
IF ($currentdistance <= $maxdistance)
# If the current distance is below the max distance start avoiding
GOTO(avoid)
# Set label for avoid return to avoid return errors
:avoidreturn
ENDIF
# Run the sweeping servo code
GOTO(sweep)
# Wait
SLEEP ($sweepservodelay)
# Loop back to the start of detection
GOTO(detect)
# Avoidance code
# Set a label for loops and gotos
:avoid
# First check if boxed in
Goto(boxedin)
# If the robot is boxed in run the escape code
IF ($isboxedin = 1)
Goto(escape)
# Avoid return error after escape loop by setting a label for a goto
:escapereturn
ENDIF
# Check to see if to reverse before turning
IF ($reverseturn = 1)
# If the option of reverse before turning is set reverse
Reverse($movementspeed,$reverseamount)
ENDIF
# Check the servo position
# Check if it's to the left
IF ($sweepcurrent = $sweepmin)
# If the servo is in the lowst position (left) move right
Goto(moveright)
# Continue moving forwards
FORWARD()
# Else check if it's to the right
ELSEIF ($sweepcurrent = $sweepmax)
# If the servo is in the highest position (right) move left
Goto(moveleft)
# Continue moving forwards
FORWARD()
# Else assume it's in the middle
ELSE
# If the servo is in the center position check which side is closest to the object and move the other way
# Move and check the left side
Servo($sweepservo,$sweepmin)
# Use random numbers if in test mode
IF ($testmode=0)
$pingmin = GetPing($pingport, $echoport)
ELSE
$pingmin = GetRandom(0,255)
ENDIF
# Wait
Sleep(400)
# Move and check the right side
Servo($sweepservo,$sweepmax)
# Use random numbers if in test mode
IF ($testmode=0)
$pingmax = GetPing($pingport, $echoport)
ELSE
$pingmax = GetRandom(0,255)
ENDIF
# Wait
Sleep(400)
# Move and check the center
Servo($sweepservo,$sweepcenter)
IF ($pingmin > $pingmax)
Goto(moveright)
FORWARD()
ELSE
Goto(moveleft)
FORWARD()
ENDIF
ENDIF
# Return to the main code
Goto(avoidreturn)
# The sweep code
# Set a label for loops and gotos
:sweep
# Move in the correct direction and store previous position
# Check what the current position is
# Check if left
IF ($sweepcurrent = $sweepmin)
# Save the current position as the previous
$sweepprevious = $sweepcurrent
# Move to the next position
Servo($sweepservo, $sweepcenter)
# Save the current position
$sweepcurrent = GetServo($sweepservo)
# Else check if its center and where it was before
# If it is center and was left before
ELSEIF ($sweepcurrent = $sweepcenter and $sweepprevious = $sweepmin)
# Save the current position as the previous
$sweepprevious = $sweepcurrent
# Move to the next position
Servo($sweepservo, $sweepmax)
# Save the current position
$sweepcurrent = GetServo($sweepservo)
# If it is center and was right before
ELSEIF ($sweepcurrent = $sweepcenter and $sweepprevious = $sweepmax)
# Save the current position as the previous
$sweepprevious = $sweepcurrent
# Move to the next position
Servo($sweepservo, $sweepmin)
# Save the current position
$sweepcurrent = GetServo($sweepservo)
# Else check if right
ELSEIF ($sweepcurrent = $sweepmax)
# Save the current position as the previous
$sweepprevious = $sweepcurrent
# Move to the next position
Servo($sweepservo, $sweepcenter)
# Save the current position
$sweepcurrent = GetServo($sweepservo)
# Else something has gone wrong
ELSE
# Set an error flag for debugging purposes
$SweepErrorFlag = 1
ENDIF
# Return back to the main script
Return()
# The sweep center code
# Set a label for loops and gotos
:sweepcenter
# Set a flag so we know it has run for debugging purposes
$SweepCenterRun = 1
# Move the servo to the left position
Servo($sweepservo,$sweepmin)
# Use random numbers if in test mode
IF ($testmode=0)
$pingmin = GetPing($pingport, $echoport)
ELSE
$pingmin = GetRandom(0,255)
ENDIF
# Wait
Sleep(200)
# Move the servo to the right
Servo($sweepservo,$sweepmax)
# Use random numbers if in test mode
IF ($testmode=0)
$pingmax = GetPing($pingport, $echoport)
ELSE
$pingmax = GetRandom(0,255)
ENDIF
# Wait
Sleep(200)
# Move the servo back to the center
Servo($sweepservo,$sweepcenter)
# Check which side has the closest object
# If the object to the left is further away than the object to the right
IF ($pingmin > $pingmax)
# Move to the right
RIGHT($movementspeed,$turnamount)
# Move forwards again
FORWARD()
# Else if the object to the right is further away than the object to the left
ELSEIF ($pingmin < $pingmax)
# Move to the left
LEFT($movementspeed,$turnamount)
# Move forwards again
FORWARD()
# Else they are both the same
ELSE
# So move left - this can be customised
LEFT($movementspeed,$turnamount)
# And move forwards again
FORWARD()
ENDIF
# Retyrn to the main code
Return()
# The boxed in code
# Set a label for loops and gotos
:boxedin
# Set a flag so we know it has run for debugging
$BoxedInRun = 1
# Get distance to the side
# Move the servo to the left
Servo($sweepservo,$sweepmin)
# Use random numbers if in test mode
IF ($testmode=0)
$side1scan = GetPing($pingport,$echoport)
ELSE
$side1scan = GetRandom(0,255)
ENDIF
# Get distance to the other side
# Move the servo to the right
Servo($sweepservo,$sweepmax)
# Use random numbers if in test mode
IF ($testmode=0)
$side2scan = GetPing($pingport,$echoport)
ELSE
$side2scan = GetRandom(0,255)
ENDIF
# Get distance to the front
# Move the servo to the center
Servo($sweepservo,$sweepcenter)
# Use random numbers if in test mode
IF ($testmode=0)
$centerscan = GetPing($pingport,$echoport)
ELSE
$centerscan = GetRandom(0,255)
ENDIF
# Check if boxed in by compairing the results against a fixed boxed in distance
IF ($side1scan < $boxedindistance and $side2scan < $boxedindistance and $centerscan < $boxedindistance)
# If any are true set the boxed in flag
$isboxedin = 1
ENDIF
# Return to the main script
Return()
# The escape code
# Set a label for loops and gotos
:escape
# Set a flag so we know it has run for debugging
$EscapeRun = 1
# Reset the boxed in flag
$isboxedin = 0
# Center the sweep servo
Servo($sweepservo,$sweepcenter)
# Turn slowly
Left($slowturn)
# Set up a loop
:escapeloop
# Scan until clear
# Use random numbers if in test mode
IF ($testmode=0)
$escapescan = GetPing($pingport,$echoport)
ELSE
$escapescan = GetRandom(0,255)
ENDIF
# If the scan result is below the boxed in distance loop
IF ($escapescan < $BoxedInDistance)
# Go back to the start of the escape loop
Goto(escapeloop)
ENDIF
# Continue forwards
FORWARD()
# Return to the main script
Goto(escapereturn)
# Move Right code
# Set a label for loops and gotos
:moveright
# Check the last 2 moves to avoid left right left right loops
IF ($lastmove = "left" and $penultimatemove = "right")
# If it has been right then left dont move right again but escape from a loop
Goto(escape)
# Reset the last move
$lastmove = "none"
# Else just move right
ELSE
RIGHT($movementspeed,$turnamount)
# Save the penultimate move
$penultimatemove = $lastmove
# Save the last move
$lastmove = "right"
ENDIF
# Go back to the main script
Return()
# Move left code
# Set a label for loops and gotos
:moveleft
# Check the last 2 moves to avoid left right left right loops
IF ($lastmove = "right" and $penultimatemove = "left")
# If it has been left then right dont move left afain but escape from a loop
Goto(escape)
# Reset the last move
$lastmove = "none"
# Else just move left
ELSE
LEFT($movementspeed,$turnamount)
# Save the penultimate move
$penultimatemove = $lastmove
# Save the last move
$lastmove= "left"
ENDIF
# Go back to the main script
Return()
# End of scripts
It's also on the cloud PingAvoidanceV1.1.0
And for ease of copying and pasting (in case the forums decide to add in some emoticons) it's also on pastebin
Any and all feedback is greatly appreciated no matter how trivial. Feel free to make your own improvements and modifications (let me know what they are too - believe it or not I'm still learning too).
Asked
— Edited
Copy & Paste it from the Paste Bin to avoid the forum formatting taking over
Thank you for the script.
Could you please make one that uses IR sensors?
Manuel
Although, if you wanted a go at adapting this one for IR it's pretty simple.
Replace all GetPing() commands for GetADC(ADC Port)
Swap around all less than < and greater than > conditions in the IFs (IR work backwards to ultrasonic, as in Ultrasonic measures distance, the higher the number the further away the object. IR measures proximity, the higher the number the closer the object)
And voilà.
I'll do an IR version of Ping Roam 1.1.2 when I get chance though. I have been working on an IR roam script using 3 IR sensors, which is on my PasteBin but is an untested, old alpha version. It's here if anyone is interested in seeing where it's at right now (untested, unfinished, probably doesn't work very well).
It's untested, in fact I haven't even tried it in ARC so there could be some syntax errors... But for now (since I don't know when I'll find the time to test it properly and make the EZ-Cloud projects etc.) give it a try and see what happens.
right, center, left, center, right center, and so forth.
Would you mind if I trouble you for more scripts?
I just ran it, my sweep servo moved the other way to what I had thought it did so I needed to make code changes (very simple, just change MoveLeft and MoveRight labels around should do it - I did it the long way since I was trying to video it) but once they were made it ran almost perfectly (ping sensor isn't the best, neither is the sweep in my opinion).
Video of it on Jarvis Mk 0.25 coming when I get chance to edit it and stuff. I'll leave the crashes in to demonstrate the drawbacks to this method too though.
It's still uploading and processing as I write this but keep checking back if it says unavailable as it will eventually become available.
I give you Ping Roam V1.1.2
You can see the problems with ultrasonic sensors (I think mine is playing up a little) and the accuracy when using a sweeping servo over multiple sensors. But it works
Would like to test my battery longevity.
Code:
That should move forwards for 3 seconds, turn left (you may need to adjust the 500 to suit your turn time), forwards, left etc.
Alternately, just hit left or right on the Movement Panel and watch it spin
Thanks,
mel
Personally I find it's not the best way to do things as there are blind spots and bumps still happen but if you are short on space or free ports then it does a good enough job.
Thanks!
An update is also in the works which will use smart avoidance which will use sensor based turning rather than time based turning although I need to build a robot to test this before I'm confident enough that it'll work.
If you wanted to alter it for fixed sensors it is a pretty simple alteration. Basically all that would be needed is for the code to be changed whenever the sweep servo is moved and the GetPing() command run, rather than move the servo just change the GetPing() ports to the relevant sensor.
So, for example if you had 3 sensors on D0 and D1, D2 and D3 and D4 and D5, you can omit the sweep code and just use
Code:
And adjust the If for the collision detection
Code:
to
Code:
The sweep centre sub routine could be pretty much eliminated too and replaced with an If to check which sensor (out of the left and right) is closest...
Code:
Hopefully that makes enough sense (if not I will be posting the whole code at some point but right now I'm struggling with the flu so my brain hurts a lot!)