Robot Raconteur Python
This document uses Python to demonstrate how Robot Raconteur works, and also serves as the reference for the Python Robot Raconteur library. The examples require that the Robot Raconteur Python library be installed.
For Windows and Mac OSX, use the ``pip`` command to install Robot Raconteur from PyPi:
pip install robotraconteur
Other packages are required to run the examples:
pip install pyserial pygame opencv
For Ubuntu, use the Robot Raconteur PPA:
sudo add-apt-repository ppa:robotraconteur/ppa
sudo apt update
Newer versions of Ubuntu may use Python pip packages.
Once the PPA is configured, install the Robot Raconteur packages:
sudo apt install python-robotraconteur python3-robotraconteur
Other packages are required to run examples:
sudo apt install python-pygame python-opencv python-pyserial
Ubuntu packages are available for 16.04 (Xenial), 18.04 (Bionic) and 20.20 (Focal).
When using Robot Raconteur in Python, the “thunk” code require to handle different service and data types is handled dynamically so there is no need to generate out extra source code. Instead, the client will receive an object that has all the correct members automatically on connect, and a service simply needs to have the correct functions and properties. How this is accomplished will be discussed through the rest of this document. Python uses “duck typing” so it is not necessary to worry about inheritance or interfaces, the functions and properties just need to exist. A significant advantage of Python’s dynamic typing is Robot Raconteur can generate client interface objects dynamically on connect so a client does not need any prior information about the service it is connecting to.
Python \(\leftrightarrow\) Robot Raconteur data type mapping
An important aspect to working with Robot Raconteur is understanding the mapping between Robot Raconteur types and the native types in the language using Robot Raconteur. For Python these are a little more complicated because Python does not have as strong a typing system as other languages. Robot Raconteur uses numpy arrays for all numeric arrays of all shapes.
Table 1 shows the mapping between Robot Raconteur and Python data types. For simple arrays, Robot Raconteur expects column NumPy arrays of the correct type. Multi-dim arrays are normal NumPy arrays of the correct type.
Structures are initialized using a special command in RobotRaconteurNode
called NewStructure
. The
NewStructure
command takes the fully qualified name of the structure, and an optional client object reference.
The function GetStructureType
returns the structure type that can be used as a constructor.
Pods are represented as numpy.array
using custom dtype
. These dtype
are initialized using the
GetPodDType
command in RobotRaconteurNode
. The GetPodDType
command takes the fully qualified name of the
structure, and an optional client object reference. The returned dtype
can be used as parameter with the
numpy.zeros(shape, dtype)
to initialize an array with the pod type. Note that pods are always stored in
numpy.array
. For a scalar, use numpy.zeros((1,),dtype)
. numpy.array
uses “array” style indexing
for fields. For example, to access the “y” field in a 2 dimensional array at index (1,3), use myarray[1][3]['y']
.
This can be used to get or set the value.
Namedarrays are represented as numpy.array
using custom dtype
. These dtype
are initialized using the
GetNamedArrayDType
command in RobotRaconteurNode
. The GetNamedArrayDType
command takes the fully qualified
name of the namedarray, and an optional client object reference. The returned dtype
can be used as parameter with the
numpy.zeros(shape, dtype)
to initialize an array with the pod type. Note that pods are always stored in
numpy.array
. For a scalar, use numpy.zeros((1,),dtype)
. “ namedarray can be converted to a normal numeric array
using the NamedArrayToArray
command in RobotRaconteurNode
. A normal numeric array can be converted to namedarray
using ArrayToNamedArray
command in RobotRaconteurNode
. The first dimension of the numeric array must
match the total number of numeric elements in a scalar namedarray. The normal numeric arrays will have one more
dimension than the namedarray. numpy.array
uses “array” style indexing for fields. For example, to access
the “y” field in a 2 dimensional array at index (1,3), use myarray[1][3]['y']
. This can be used to get or set the
value.
Maps are dict
in Python.
Lists are list
in Python.
Enums are stored as int
in Python.
Robot Raconteur Type |
Python Type |
Notes |
---|---|---|
double, single |
|
|
cdouble, csingle |
|
|
int8, uint8, int16, uint16, int32, uint32, int64, uint64 |
|
Depends on sys.maxint size |
double[] |
|
|
single[] |
|
|
int8[] |
|
|
uint8[] |
|
|
int16[] |
|
|
uint16[] |
|
|
int32[] |
|
|
uint32[] |
|
|
int64[] |
|
|
uint64[] |
|
|
cdouble[] |
|
|
csingle[] |
|
|
Multi-dim arrays |
|
Type maps same as array, more dimensions |
string |
|
|
Map (int32 key) |
|
All keys must be |
Map (string key) |
|
All keys must be |
List |
|
Standard list of expected type |
structure |
varies |
See text for more info |
pods |
|
See text for more info |
namedarrays |
|
See text for more info |
enums |
|
|
varvalue |
|
See text for more info |
Python Reference to Functions
Robot Raconteur frequently uses function references (called function handles or function pointers) to implement callbacks for events and other situations where the library needs to notify the software. In Python, this is accomplished using function references (also called function objecs depending on the author). Consider a simple module “MyModule” shown in the following example:
class myobj(object):
def hello1(name):
print "Hello " + name
def hello2(name):
print "Hello " + name
o=myobj()
ref1=o.hello1
ref2=hello2
ref1("John")
ref2("John")
This example demonstrates that a function reference can be easily made by referencing the function without the argument parenthesis. This method works for module and class functions.