United Kingdom
Asked — Edited

Ping Roam V1.1.0

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 code


# 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).


ARC Pro

Upgrade to ARC Pro

Experience early access to the latest features and updates. You'll have everything that is needed to unleash your robot's potential.

#1  

That's allot of code :), I'll check this out. Thanks for sharing!

#2  

Bookmarked. Boxbot's upgrade to treads should be done this weekend, and prior to the treads, getting boxed in was a major issue, so i will definitely be trying this out.

Alan

United Kingdom
#3  

@Derrick it's only 477 lines... a third are comments and a third are blank so it's not that long really:) It looks bigger than it is. Not forgetting each GetPing has been expanded to 5 lines rather than 1 line since it has the "testmode" option (my way of being able to work on it and test it without it being connected to a robot).

It should be pretty easy to adjust now it has the comments for pretty much every command. There are two reasons for that, the first one is to help me debug it and solve the return problem I was getting for around a week before I realised my mistake. The second is to make it easy to understand, follow and modify. I will need to modify it to use it in Melvin since he will be using IR sensors and won't have a sweep servo but run 3 sensors in fixed positions. The logic and principles behind it will be the same though.

And the labels and gotos have been used so additional features can easily be thrown into it, and added as options with variables in the config section at the top. Or at least additional features could be added if I could think of any:) Hopefully this evolves into a complex yet easily customisable autonomous roaming/navigation script.

#4  

i like the comments,it makes it so much easer down the road

United Kingdom
#5  

The comments come in very handy when writing it over a few weeks. I'd get back to it and have to follow it all through again to see where I got to, why things were like they are etc. They also come in very handy when debugging it (and will come in handy when ironing out any bugs that may have gone un-noticed).

They will also come in handy when new features need adding in. If you can think when the feature needs to be executed you can find the place to throw in the goto really easily :)

And most of all, hopefully it further explains and demonstrates to people how scripts are made and work.

#6  

@rich, i have tried out the script. My setup on my platform is 1 motor with gearbox connected to an h bridge, 1 servo for left and right, and 1 ultrasonic sensor with servo. I changed the ports for my setup and merged my custom movement control to your script. Im kinda scratching my head because when i start your script everything seams fine, it sweeps and gets ping then movers forward. When it comes close to its first obstacle, it runs into it, then trys to move left and right, and then it just starts backing up forever. I don't know if its just my setup or what.my robot has issues.... Lol. I did not change anything besides the sensor ping, echo and servo sweep ie d10 trigger d11 echo and d8 sweep. Also i tried changing the max distance and turn amount. No luck....

#7  

send back a pic of the variable values when it gets stuck on a wall again.

#8  

I think my Robie may be cursed.

I've been anxious to give this code a try since @Rich posted the update. I added a few parameters for the head tilt since my Ping sensor is in my robot's head.

I loaded the code, made my change, set up a quick test course in my house, set Robie on the floor and hit start. He moved 6 inches and disconnected. I forgot to charge the batteries. (Doh!)

Once they were charged up, I set Robie on the floor and pressed start. He traveled a foot, then stopped. ARC locked up.

Back to the work bench and force closed ARC. Relaunched the software, ran a few minor tests. Everything looked fine.

Set Robie on the floor, hit start, and he started moving forward. Sweep motion worked great...and kept working like a champ as he drove right into the first obsticle and didn't stop. Stop script didn't stop him either, but I finally stopped him with the motion panel. No damage to the robot, but my ego took a thumping.

Back to the work bench and it appears my Ping sensor is goofed. It's reading a constant "255" and I'm not hearing that "ticking" sound it makes when active. By the time I checked the ports and swapped out two servo extentions, my free time was consumed, so I haven't had a chance to fully Scooby-Doo the problem. I'm probably going to have to crack open the head and check the solder points on the sensor itself...which will suck.

Still, I love the code and think it's going to work great for my little Robie!

United Kingdom
#9  

@McJeff0125, That's the problem with a lot of the ping sensors, the one in Melvin often reports back 255 when it isn't. That's the main reason I use IR sensors and am rewriting the above script to use 3 IR sensors in fixed positions rather than 1 ping on a servo. I have read that the voltage and current to a sensor is crucial and can have negative effects if not just right.

@derrick that sounds odd, I'll take another look at the code just in case but the reversing part shouldn't get stuck in a loop. If you open the script up and run it with the script showing it'll show you down the right hand side what's happening, and why it's getting stuck in a reverse loop - but doing this does mean no access to the Movement Panel to stop the robot so be aware of that.

#10  

my batterys were going dead, after a full charge the script seems to work well!.....lol :)

#11  

LOT of times using a sonar is the material,thats the reason for bad reading,same with IR can only detect certain materials.

For a good design you need both,and sometimes thats not enough.

Plus orientation of the sensor,plus size of the cone detection.

United Kingdom
#12  

I just trying this with my BV4113 H bridge and it works then for some reason like @Derrick says it can get stuck reversing forever. Also it would be good if the robot stopped like it was thinking and then reversed

Certainly shows the power of ARC that we can simply mod a few parameters and then run it on completly different platforms

I'm getting odd issues though like the laptop connects and I can control the robot except any movement with my movement panel

#13  

I noticed my ping sensor would randomly spike to 255 when i charged the battery it went away.low voltage to the ping sensor, so i think the script would start looping...?

United Kingdom
#14  

I'll look into it all. I just set testbot going again and it had the constant reverse problem (something that hadn't happened before). In fact, it seems it's just doing a few things not quite as it should... things that hadn't happened first time around. I'm not sure if it's connected to the fact my PC is currently bogged down by other processes too, very possibly. I will have a dedicated EZ-Robot PC sometime in the next week or so which will eliminate that.

@winstn60 is it just this project/script that is giving you the Movement Panel problems or is it a general problem you are having?

I've added in some stops in the V1.1.1 code but need to check the reversing problem, it shouldn't reverse without turning afterwards although it may be running the escape code which then doesn't get chance to run if the sensor reports > the minimum distance, so if a spurious 255 pops in it'll exit the escape and go on forwards.

The low voltage/ping sensor issue is good to know and also exactly the reason why I need to get testbot off of the box and AA batteries and on to a decent platform with the 2S LiPo (which should eliminate any voltage issues since I don't let them run below 6v)

All good things to know so thanks for testing it out. Any more problems please post about them, I'm sure there are other things that could be made better or that don't run quite right.

United Kingdom
#15  

Hi Rich its a general problem which I never had before. I have to reboot the EZ-B board to get control back on the movement panel. But if I get your script running it works well fror a few seconds then ARC locks up or the robot goes into permanent reverse I just floormap error InvalidOperationException: Object is currently in use elswhere. Very frustrating

Are you on Skype btw I'm neil.winstanley st albans if you want a chat

United Kingdom
#16  

I received that error for the first time tonight, never had it before and didn't pop up when it was in test mode running from random numbers with no EZ-B connected either.

No I don't have skype anymore, the latest update sent my PC a little nuts, failed to install so decided to remove it completely since I barely use it.

United Kingdom
#17  

ahh glad its not just me,

Just thought I could show you on Skype what your project does with my bot.

Email?

United Kingdom
#18  

rich@richpyke.net

United Kingdom
#19  

I forgot to mention that v1.1.1 is on the cloud.

A couple of changes so far (although still working on it when I find the time);

  1. Modified code so it doesn't reverse after escaping from boxing in or avoiding a left/right/left/right loop.
  2. Added in a stop and a sleep before all forward and reverse movements.
  3. Added an emergency stop script which stops the roam script and stops any movement that's currently happening.

I just ran it again to check it out and had no errors this time. I suspect it may have been down to the computer running slowly when I last tried it, but also sounds like low battery levels and inaccurate ping readings may also cause strange behaviour. I'm thinking of ways around that, something like taking 3 readings each time rather than 1, and using ands in the ifs to only be true if all 3 readings are below the threshold... but I've not had chance to do that yet.

United Kingdom
#20  

The inspiration needed to complete version 1.1.2 of the Ping Roam script came tonight.

Changes

  1. Changed escape return to use else therefore avoiding reversing and turning after an escape.
  2. Added in stop and sleep before any forward or reverse movements.
  3. Added emergency stop script.
  4. All ports are now constants, use ports specified in the head of the code or port summary or adjust the code to suit your ports.

Plenty of comments so you can follow and customise the script where necessary.


# Ping Object Avoidance
# Using Ultra Sonic Ping Sensor on servo for avoidance
# Version 1.1.2


# Configuration Settings
# This script assumes the following ports;
#
# Trig Port = D0
# Echo Port = D1
# Sweep servo = D2

# 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
# Calculate the centre position for the sweeping servo
# Minimum position plus maximum position divided by 2
# Round to 0 decimal places
$sweepcenter = Round((($sweepmin+$sweepmax)/2),0)
# Set the previous position to the max position for initial movement
$sweepprevious = $sweepmax # Do not change
# Set the current position to the centre position for initial movement
$sweepcurrent = $sweepcenter # Do not change
# Set some flags for testing - to be removed in final release
$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
# Set last and penultimate moves.
$penultimatemove = "none"
$lastmove = "none"



# ------- The Script --------

# Set the start point for any loops
:begin

# Center the sweep servo
Servo(D2, $sweepcenter)

# Start moving forwards
FORWARD()

# Start the detection
Goto(detect) # This line is redundant but left for educational purposes



# Detection code

# Set a label for loops and gotos
:detect

# Use random numbers if in test mode - to be removed in final release
IF ($testmode=0)
  $currentdistance = GetPing(D0, D1)
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
  
# Change to else to avoid reversing and turning after an escape - dont forget the endif at the bottom
ELSE 
  
  # Check to see if to reverse before turning
  IF ($reverseturn = 1)
    # If the option of reverse before turning is set stop then reverse
    # Add in a stop and sleep before movement
    Stop()
    Sleep(200)
    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
    # Add in a stop and sleep before movement
    Stop()
    Sleep(200)
    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
    # Add in a stop and sleep before movement
    Stop()
    Sleep(200)
    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(D2,$sweepmin)
    # Use random numbers if in test mode
    IF ($testmode=0)
      $pingmin = GetPing(D0, D1)
    ELSE 
      $pingmin = GetRandom(0,255)
    ENDIF 
      
    # Wait
    Sleep(400)
    
    # Move and check the right side
    Servo(D2,$sweepmax)
    # Use random numbers if in test mode
    IF ($testmode=0)
      $pingmax = GetPing(D0, D1)
    ELSE 
      $pingmax = GetRandom(0,255)
    ENDIF 
      
    # Wait
    Sleep(400)
    
    # Move and check the center
    Servo(D2,$sweepcenter)
    IF ($pingmin > $pingmax)
      Goto(moveright)
      # Add in a stop and sleep before movement
      Stop()
      Sleep(200)
      FORWARD()
    ELSE 
      Goto(moveleft)
      # Add in a stop and sleep before movement
      Stop()
      Sleep(200)
      FORWARD()
    ENDIF 
  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(D2, $sweepcenter)
  
  # Save the current position
  $sweepcurrent = GetServo(D2)
  
# 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(D2, $sweepmax)
  
  # Save the current position
  $sweepcurrent = GetServo(D2)
  
# 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(D2, $sweepmin)
  
  # Save the current position
  $sweepcurrent = GetServo(D2)
  
# Else check if right
ELSEIF ($sweepcurrent = $sweepmax)
  
  # Save the current position as the previous
  $sweepprevious = $sweepcurrent
  
  # Move to the next position
  Servo(D2, $sweepcenter)
  
  # Save the current position
  $sweepcurrent = GetServo(D2)
  
# Else something has gone wrong
ELSE 
  # Set an error flag for debugging purposes - to be removed for final release
  $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(D2,$sweepmin)

# Use random numbers if in test mode
IF ($testmode=0)
  $pingmin = GetPing(D0, D1)
ELSE 
  $pingmin = GetRandom(0,255)
ENDIF 
  
# Wait
Sleep(200)

# Move the servo to the right
Servo(D2,$sweepmax)

# Use random numbers if in test mode
IF ($testmode=0)
  $pingmax = GetPing(D0, D1)
ELSE 
  $pingmax = GetRandom(0,255)
ENDIF 
  
# Wait
Sleep(200)

# Move the servo back to the center
Servo(D2,$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
  # Add in a stop and sleep before movement
  Stop()
  Sleep(200)
  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
  # Add in a stop and sleep before movement
  Stop()
  Sleep(200)
  FORWARD()
  
# Else they are both the same
ELSE 
  
  # So move left - this can be customised
  LEFT($movementspeed,$turnamount)
  
  # And move forwards again
  # Add in a stop and sleep before movement
  Stop()
  Sleep(200)
  FORWARD()
ENDIF 
  
# Return 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 - to be removed for final release
$BoxedInRun = 1

# Get distance to the side
# Move the servo to the left
Servo(D2,$sweepmin)

# Use random numbers if in test mode - to be removed for final release
IF ($testmode=0)
  $side1scan = GetPing(D0, D1)
ELSE 
  $side1scan = GetRandom(0,255)
ENDIF 
  
# Get distance to the other side
# Move the servo to the right
Servo(D2,$sweepmax)

# Use random numbers if in test mode
IF ($testmode=0)
  $side2scan = GetPing(D0, D1)
ELSE 
  $side2scan = GetRandom(0,255)
ENDIF 
  
# Get distance to the front
# Move the servo to the center
Servo(D2,$sweepcenter)

# Use random numbers if in test mode
IF ($testmode=0)
  $centerscan = GetPing(D0, D1)
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(D2,$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(D0, D1)
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
# Add in a stop and sleep before movement
Stop()
Sleep(200)
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)
  Sleep(200)
  
  # 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)
  Sleep(200)
  
  # Save the penultimate move
  $penultimatemove = $lastmove
  
  # Save the last move
  $lastmove= "left"
  
ENDIF 
  
# Go back to the main script
Return()

# End of scripts

This script has not been real world tested - Testbot has been re-purposed to become Jarvis. As a result I am currently unable to run any real world tests on the code. I will be temporarily adding the sweeping servo and ping sensor to Jarvis as soon as I possibly can however in the mean time any comments on it's success or failure would be very much appreciated.

The project is on the EZ-Cloud under Public Library, Examples, Ping Roam V1.1.2 or you can Download here

Also available for copy and paste on pastebin here

United Kingdom
#21  

Any improvements are welcomed also. For instance, one question I often think about when I am writing this script is Would it be better written to use 3 Ping Sensors rather than a sweeping servo? What is more commonly used, Ping or IR? What do the people want it to do?

So hit it up with suggestions, requests, whatever:) I have no problem writing a bunch of these for the different methods either, I'm not afraid of a little coding!..

#22  

Rich,

Can you send us a video? I would love to see how it behaves.

Very elaborate and well commented code!

Bill

United Kingdom
#23  

I will do when I have a robot that is capable of running the code (Jarvis is being temporarily repurposed but the adaptation is taking a little longer than I planned).

#24  

@Rich, I'd like to try this using a modified Roomba with the Ping sensor centrally located at the front of the body. Using the two H-bridges built into the Roomba PCB. Each H-bridge has a forward and reverse PWM lead. What EZ-B control would best suit this trial ?

United Kingdom
#25  

@RobotDoc 2 H-Bridges, probably going to need the custom Movement Panel with scripts for the movement (i.e. Set() each port as required) Is each H-Bridge driving one wheel in either forward or reverse? If so you could use the 4 Wire H-Bridge control and set up one H-Bridge as the Left trigger A & B and the other H-Bridge as the right Trigger A & B.

I just did a quick run on modified Jarvis but it needs setting up and I found out that both Melvin and Jarvis need to have a lot re-written to work with the new syntax of using variables. Busy weekend coming up too so it may be a while before I get to do a proper test (it seemed to work but I needed to use my hand to simulate an object). When I do a proper test with it all set up I will pop a video up.

That said, Testbot was videoed, it's been improved with a boxed in escape routine and avoidance of getting stuck in left/right/left/right loops but the general movement/detection is the same.

#26  

Having trouble with the GOTO(detect)

United Kingdom
#27  

Did you copy from here? The label gets reformatted by the forum to :Detect, check your script to see if its messed up.

#28  

Yes I did Copy it from here, I am new to scripting, been piggy backing from your examples trying to learn the syntax.

United Kingdom
#29  

That's great, that's why I put in so many comments. I'd love to see what other people can do to improve on the scripts I post.

Copy & Paste it from the Paste Bin to avoid the forum formatting taking over:) (There are a few smiley faces in there too which will throw back errors)

Australia
#30  

Hi Rich,

Thank you for the script. Could you please make one that uses IR sensors?

Manuel

United Kingdom
#31  

Sure thing.

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).

United Kingdom
#32  

I needed a break from the boring tedious work I have to do today so... give this a go

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.

#33  

Great Script, just gave it a try, ran perfectly. I really like the servo Sweep,

right, center, left, center, right center, and so forth. Would you mind if I trouble you for more scripts?

United Kingdom
#34  

Give me ideas and I'll give it a go:) I welcome any ideas, or even challenges:D Provided I have a robot that can run it (although not necessarily required, I wrote Ping Roam without a robot).

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.

United Kingdom
#35  

I'm too tired, too hungry and too hot to mess around video editing on a PC that's as unstable as Jenga.

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 :)

#36  

Can you do a simple script that drive around in circle or box, square with an infinity loop? Would like to test my battery longevity.

United Kingdom
#37  

:start
Forward()
Sleep(3000)
Left()
Sleep(500)
Goto(start)

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 :)

#38  

@Rich, how many sensors do you have operating on this robot for navigation? Is it just one with a servo to sweep?

Thanks,

mel

United Kingdom
#39  

1 sensor, 1 servo to sweep it.

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.

#40  

I think I will have mine stationary. But, this would change the script dramatically. I plan to put two sonars in front and two IR units also. I used to have front,back,left,right, upper,lower,sonar,IR,PIR. It just slows down the operation. I like your idea of having fewer ones.

United Kingdom
#41  

When I get back to my robots I will be having IR and Ultrasonic fixed stationary, I'll be using pretty much the same code but with changes to the reading of sensors and behaviour depending on the readings, it's only a few extra elseifs and a small change to the script so it doesn't need to move the sensors. When it's done I will be sharing but at the moment I have other things occupying my time so the robots have taken a back seat.

#42  

That sound incredibly good to me.

Thanks! :)

Canada
#43  

OMG this would be perfect . .....

#44  

there is a newer version I believe. 1.1.2 I think. check the ez-cloud.

United Kingdom
#45  

Yes 1.1.2 is the latest one, which is on page 3, the cloud and PasteBin

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

$sensor1 = GetPing(D0,D1)
$sensor2 = GetPing(D2,D3)
$sensor3 = GetPing(D4,D5)

And adjust the If for the collision detection

IF ($currentdistance &lt;= $maxdistance)

to

IF ($sensor1 &lt;= $maxdistance OR $sensor2 &lt;= $maxdistance OR $sensor3 &lt;= $maxdistance)

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...

IF($sensor1 &lt; $sensor3)
  Left($movementspeed,$turnamount)
Else
  Right($movementspeed,$turnamount)
EndIf

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!)

#46  

Get some R & R Rich hope you get to feeling better. A bottle of Vodka got me through the flu one year.

Canada
#47  

Yea. I just got over something too. And thanks. I have been reading all your posts and the getting started on scripting. Thanks get better soon.