Pyro - Python Tutorial
This tutorial will introduce you to the Pyro-Python interface. This tutorial assumes that you are familiar with Pyro and the PyroTutorial.
To get this to work outside of the Pyro interface, you need to set two environment variables. If you are using bash as your shell, you can insert these two lines in your .bashrc file:
export PYROBOT=/usr/local/pyrobot export PYTHONPATH=/usr/local:$PYTHONPATH
Then you should re-execute the file by doing source .bashrc. If you are using another shell, then add these environment variables in the appropriate format. Next time you log in, they will automatically be set and you don't have to do this again.
Notice that PYROBOT should be set to wherever you installed Pyro, and PYTHONPATH should be set to the directory right above that. You can use these variables at the shell prompt by preceeding the name with a dollar sign (e.g., cd $PYROBOT).
Since Pyro is built on top of Python, and Python is an interpreted language, you can interactively build up pieces of Pyro code. For example, let's explore a robot interface. First, let's start up a Pioneer simulator: either SRIsim, or pioneer. You saw how you could do that via the Pyro interface in the PyroTutorial, and in the PyroUsersManual. But because the simulators are actually outside of Pyro, you can also do that at the shell:
% $PYROBOT/plugins/simulators/SRIsim local & OR % $PYROBOT/plugins/simulators/pioneer &
NOTE: The % sign represents a command shell prompt, and the & says to run the command in the "background" (which means that you get your prompt back to type in other commands). The simulator should start up in another window.
Now, let's start Python:
% python2.1 Python 2.1.1 (#1, Aug 13 2001, 19:37:40) [GCC 2.96 20000731 (Red Hat Linux 7.1 2.96-96)] on linux2 Type "copyright", "credits" or "license" for more information. >>>
The >>> is the prompt for Python. You can enter in any Python expression at the prompt and it will evaluate it and print it out. For example, let's add 4 and 3 together, and divide by 2:
>>> 4 + 3 / 2 5 >>>
and it returns the answer. Hey! Seven divided by two is 3.5, not 5. What's going on? Well, first of all, you need to put parens around (4 + 3). But you also need to make one of the values be a floating point value if you want a floating point answer. Otherwise, it will leave the answer as an integer. Here are some different methods of doing that:
>>> (4 + 3) / 2.0 3.5 >>> float(4 + 3) / 2 3.5 >>>
You can see a Python Tutorial at:
How to think like a computer scientist: Learning with python.
Ok, now that we can start and use Python, let's create a robot. First, we import the approriate library that defines our robot type, and create an instance:
>>> from pyrobot.robot.saphira import *
>>> s = SaphiraRobot("PioneerSimulated", 1)
Here, we first import the code to define a SaphiraRobot, and then create a robot instance named "s". The parameters to the function SaphiraRobot() constructor are the name, followed by a 1 if we want to connect to a simulator, and 0 to connect to a real Pioneer.
Now, let's see what we have defined. We'll use the dir() function:
THIS IS OLD AND NEEDS TO BE UPDATED!
>>> dir(s) ['controls', 'data', 'dev', 'drawableName', 'drivers', 'name', 'needToRedraw', 'options', 'senses', 'type']
Here, we type enter the command "dir(s)" which lists the methods and fields of the variable "s". We see that there are 10 items listed. If we were insterested in the senses that this robot has, we can display them by just evaluating the name of the dictionary:
>>> s.senses
{'robot': {'th': <built-in function Saphira_getThr>, 'type': <function <lambda> at 0x8119e6c>,
'z': <built-in function Saphira_getZ>, 'x': <built-in function Saphira_getX>, 'y': <built-in function Saphira_getY>, 'simulator': <function <lambda> at 0x81bceac>, 'th': <built-in function Saphira_getTh>,
'name': <function <lambda> at 0x81c62e4>, 'stall': <built-in function Saphira_IsStall>},
'sonar': {'type': <function <lambda> at 0x81c9c5c>, 'z': <function <lambda> at 0x81bd164>,
'x': <built-in function Saphira_getSonarXCoord>, 'y': <built-in function Saphira_getSonarYCoord>,
'ox': <built-in function Saphira_sonar_x>, 'th': <built-in function Saphira_sonar_th>,
'oz': <function <lambda> at 0x81226cc>, 'arc': <function <lambda> at 0x8122704>,
'flag': <built-in function Saphira_getSonarFlag>, 'value': <built-in function Saphira_getSonarRange>,
'oy': <built-in function Saphira_sonar_y>, 'count': <function <lambda> at 0x81bd12c>}}
This shows that s.senses is a dictionary (indicated by the curly braces). In fact, you see that there are dictionaries inside the dictionary. Let's display that information in a slightly different way. Let's look at just the keys of the dictionaries, with a brief description of what each item is:
robot - dictionary of robot senses thr - theta, angle of direction, given in radians th - theta, angle of direction, given in degrees type - type of robot (saphira, khepera, etc.) z - z-coord of robot location x - x-coord of robot location y - y-ooord of robot location simulator - yes or no (1 or 0) name - arbitary name given by creator stall - is the robot stalled? 0 = no, >1 = yes (different ways of being stalled; robot specific) sonar - dictionary of sonar readings type - range, etc. z - z-coord of hit x - x-coord of hit y - y-coord of hit ox - x-coord of origin of sensor th - angle of sensor, in radians oz - z-coord of origin of sensor arc - width of sensor, in radians flag - new reading? value - reading (distance) oy - y-coord of origin of sensor count - how many of this type of sensor (sonar in this case)
So, it turns out that the Pioneer robot is really of type saphira. The Saphira-type robot can actually be one of many kinds (Pioneer2AT, Pioneer2DX, etc.)
If we wished to read some other sense data, try this:
>>> s.update() >>> s.sonar[0][0].value
First, we tell the robot, s, to update its readings.
The sonars on the Pioneer are numbered as follows. Standing behind the robot looking at it:
0 - 90 degree to LEFT side, front 1 - angled LEFT side, front 2 - front far LEFT 3 - front LEFT 4 - front RIGHT 5 - front far RIGHT 6 - angled RIGHT side, front 7 - 90 degree to RIGHT side, front 8 - 90 degree to RIGHT side, back 9 - angled RIGHT side, back 10 - back far RIGHT 11 - back RIGHT 12 - back LEFT 13 - back far LEFT 14 - angled LEFT side, back 15 - 90 degree to LEFT side, back
Other data is stored as a field of the robot instance "s". If we wanted to see the robot's name, we simply type:
>>> s.name 'PioneerSimulated'
Which is the name we gave it initially when we created it. When you are done using the Python interface, you must close up the connection with the simulator.
>>> s.disconnect()
Let's try some experimenting. Put the robot in a position so that it has a wall exactly 1 meter to its left. Recall the instructions for moving the simulated robot in PyroTutorial.
Now, get a reading from one of the sensors facing the wall. How far off is the reading? How much noise is in a simulated reading?
Python Global Variables
It can be difficult to have globals between two modules, or between a user program and a module. Here is a trick:
There is an empty file in pyrobot/syste/share.py. Then in a module, you can create a program, say test.py:
import pyrobot.system.share as share # the empty file
def function():
print share.someGlobalVar
In a brain, or some other program, you can:
import pyrobot.system.share as share from test import * share.someGlobalVar = 1000 function()
and that will print 1000. This can be difficult to do any other way.
Related topics:
- DevelopmentalRoboticsSummer2002 . . . . 1 match
