pyrobot overview

Introduction

The goal of the pyrobot project is to provide a programming environment for easily exploring advanced topics in artificial intelligence and robotics without having to worry about the low-level details of the underlying hardware.

One unique characteristic of pyrobot is the ability to write controllers using robot abstractions that enable the same controller to operate robots with vastly different morphologies. That is, a controller program written for a Khepera robot (hockey puck-sized, with infrared sensors) could work equally well for a Pioneer robot (medium suitcase-sized, with sonar sensors).

All of the source code for pyrobot is located at: /usr/local/pyrobot/

For example, the simulator worlds that we will be using are defined in: /usr/local/pyrobot/plugins/worlds/Pyrobot/

Invoking and exiting pyrobot

To invoke pyrobot do:

$ pyrobot

Then use the mouse to choose a server (PyrobotSimulator), choose a world (Tutorial.py), and choose a robot (PyrobotRobot60000.py). You can move the robot around in the world by left clicking on it. You can adjust its heading by pressing the CTRL key and left clicking.

To exit, go to the Robot menu at the top and choose Unload robot. Then go to the the File menu at the top and choose Exit.

Because pyrobot uses unix ports to connect to simulated and real robots, if it can't release these ports it sometimes hangs when you try to exit it. Do a CTRL-Z to suspend it, and then force quit it like this:

$ killall -9 pyrobot

When invoking pyrobotot you can also select the sever, world, and robot at the command line like this:

$ pyrobot -s PyrobotSimulator -w Tutorial.py -r PyrobotRobot60000.py

Actions in pyrobot

The basic actuators assumed in pyrobot are motors that propel a robot. We assume that every robot is capable of two kinds of motion:

All robot's in pyrobot have a move method which takes a translation amount and a rotation amount. Once the move method is called the robot will continually do this action until given another action. Use the command line of pyrobot to try these commands:

robot.move(1,0)      #translate forward with no rotation
robot.move(-1,0)     #translate backward with no rotation
robot.stop()
robot.move(0, 1)     #turn left in place 
robot.move(0,-1)     #turn right in place
robot.move(0.3,0.5)  #move forward and left at the same time
robot.stop()

Sonar sensors

The simulated robot in the Tutorial.py world is based on a real robot called the Pioneer. The sonar sensors on the Pioneer robot are numbered 0-15 starting at the front left. The gray lines emanating from the robot represent the simulated sonar values.

Some robots have multiple rings of sonar sensors. So each ring has an index. When there is only a single ring its index is 0. robot.sonar[0] returns a sonar device, which you can then index further to get individual values. Use the command line of pyrobot to try these commands:

robot.sonar[0][0].value
robot.sonar[0][1].value

Notice that if you repeat the same command without the robot moving, the returned values are different, this is due to added noise. The default units for these values are robot units (based on the diameter of the robot).

Pyrobot includes the concept of sensor groups. Read about it in this section of the documentation, and then try these commands:

#returns a list of sonar sensors in the front group
robot.sonar[0]["front"]  

# to see value of each sensor in the group
for s in robot.sonar[0]["front"]: print s.value

#use list comprehension to create a list of all front sonar values
[s.value for s in robot.sonar[0]["front"]]

#find the lowest front sonar value
min([s.value for s in robot.sonar[0]["front"]])

Light sensors

The world Tutorial.py does not contain any light emitters, and the robot does not contain any light sensors. Exit from pyrobot (remember to first unload the robot), and restart pyrobot using the world Braitenberg.py.

In the pyrobot simulator window, under the View menu select Light. Two orange lines will appear showing you the light sensors on the front of the robot. Similar to the sonar sensors, robots can have multiple sets of light sensors each with a unique index. robot.light[0] returns a light device which you can index further to get individual values. Use the command line of pyrobot to try these commands:

robot.light[0][0].value
robot.light[0][1].value

#use list comprehension to get a list of light values
[l.value for l in robot.light[0]]

Camera

The Tutorial.py world includes several colored objects and a robot equipped with a camera. An easy way to experiment with various image processing tools is to use the menus in the pyrobot window. Go to the Devices section, select camera[0], and then press the View button. This will open a camera window.

Next, point the robot so that it is facing the blue box in the upper-left hand corner of Tutorial.py world. In the camera window, left click the mouse on the blue color; this will turn all the blue color to red. Notice in the pyrobot window that you've just added a match filter, which takes three parameters for RGB values. Next in the camera window, select Filter, then Blobify, and then Red. To see all the filters you've created, in the camera window, select Filter and then List filters. The current filters will be displayed in the pyrobot window. If you were doing these steps in a program, you could use these filter commands directly and would only need to do them once at the start of the program.

The filter results will be numbered in the order that you added them. In this example, the match filter will be 0 and the blobify filter will be 1. You can access the camera filter results by doing:

robot.camera[0].filterResults[filterNum]
The blobify filter returns a list of lists. Each sublist represents the information on one blob. The sublists are ordered from largest to smallest blob. Typically we only focus on the sublist numbered 0, representing the biggest blob in view. To get the largest blob's data do:
robot.camera[0].filterResults[1][0]
This will return a list of five values representing the bounding box of the blob and its area: (x1, y1, x2, y2, area).

Gripper

The CamWorld.py world includes a robot with a gripper and some small pucks that can be picked up and moved around. You can see a list of all the gripper commands by going to the Device area of the pyrobot window and selecting gripper[0]. Then press the View button. You can invoke the gripper commands by pressing the buttons in the menu or at the pyrobot command line.

Notice that the gripper has two break beam sensors that allow it to sense when something is between the gripper arms. Try moving the robot with the mouse so that one (or both) of these break beam sensors is triggered. Next try picking up a puck, storing it, moving the robot to a new location and then deploying the puck there.

Simulation (using setPos and getPos)

Being able to find and move entities within the simulator is very useful when doing experiments.

Through the simulation device you can find out and set the locations of various entities in the simulation such as robots and pucks. In order to access an entity in the simulation you need to know its name, as designated in the world file. For example, in the CamWorld.py world, the robot is named "Pioneer1". To find out the robot's location do:

robot.simulation[0].getPose("Pioneer1")
This will return a list of three values representing its x, y location and heading in radians. To move the robot to a particular location do:
robot.simulation[0].setPose("Pioneer1", x, y, heading)
where x and y are within the bounds of the world and heading is in radians. The heading is in the range 0 to 2pi: 0 (and 2pi) is north, pi/2 is west, pi is south, and 3pi/2 is east.

Try finding and moving the pucks around in CamWorld.py. In order to do this you'll need to know the names of the pucks. You can find out by looking at the source code for this world, which is located in the directory given in the introductory section above.

Creating, testing, and modifying pyrobot brains

Below is the template for a brain to control a robot in pyrobot.

from pyrobot.brain import Brain  
   
class BasicBrain(Brain):
   def setup(self):
      """
      This method is optional.  It will be called once when the
      brain is instantiated, prior to the first call to the step
      method. 
      """
      pass
      
   def step(self):
      """
      This method must be defined and will be called automatically
      every time step. 
      """
      self.robot.move(0.5,0) 

def INIT(engine):
   return BasicBrain("BasicBrain", engine)

Every brain must have a step method that is run every time step (approximately 10 times per second). A brain may also have an setup method that will be run once when an instance of the class is contstructed.

Using an editor, insert the code for the basic brain given above and save it as BasicBrain.py Now invoke pyrobot and specify the brain at the command line like this:

pyrobot -s PyrobotSimulator -w Tutorial.py -r PyrobotRobot60000.py -b BasicBrain.py

To start the brain, press the Run button. This brain moves the robot forward. When an obstacle is encountered the robot will be stalled in front of it, though it is still trying to move forward. To see that this is the case, use the mouse to drag the robot back away from an obstacle. You can see that it is still constantly moving forward.

To stop the brain, press the Stop button. Let's modify this brain, so that instead of constantly moving forward it will try instead to avoid obstacles. Use an if statement to check the minimum of all of the front sonar values. When the minimum is below 0.5 the robot should turn right, otherwise the robot should move forward.

Save your file and then press the Reload Brain button. This will replace the old version of the brain with the new one. Press Run button to test out the new brain. Keep modifying the brain until you it successfully avoids obstacles.