Tutorial

Short Tutorial for Dynamism with Python

This section contains all the basic functionality you need to control Junior platform. It contains basic building blocks needed for establishing a connection, sending specific signals, creation and retrieval of entries in the database, read and write operations on these entries, and update of the database on the robot side.

Note that the main philosophy is more or less the same for C and MatLab; you can use this tutorial for developing code in these languages, too. Alternatively, you can have a look at one of the following sources:

For the rest of this short tutorial, we will be using three different type of pointers. In Python, we will not explicitly declare these pointers; the functions we call will return them for us.

  • DyHost: Pointer to a copy of the database held by a (possibly) remote host. We will be using host to refer to a DyHost pointer.
  • DyDataSet: Pointer to a set of entities in the local copy of the database. In our case, it points to the path for all the entities belonging to a specific robot. We will be using ds to refer to a DyDataSet pointer.
  • DyData: Pointer for an entity in the local copy of the database. We will be using d to refer to a DyData pointer.

Data Handling

Registering New Entities

Dynamism lets us register single entities as well as arrays and strings. Dynamism supports the following types:

dy.DY_INT8 
dy.DY_UINT8 
dy.DY_INT16 
dy.DY_UINT16
dy.DY_INT32
dy.DY_UINT32
dy.DY_INT64
dy.DY_UINT64
dy.DY_FLOAT
dy.DY_DOUBLE

Let us, now, register a new single entity in the database that will store a float:

d = dy.data.create(dy.DY_FLOAT,'junior1.data1')

Alternatively, if we already have a DyDataSet pointer ds for Junior1, we can have the following line:

d = dy.data.create_at(ds,dy.DY_FLOAT,'data1')

In a similar fashion, let us, now, register a one dimensional float array with six elements to store the leg positions. Since there will be other entities having per-leg values, it is wise to create a nested structure as follows:

d_array = dy.data.create_array(dy.DY_FLOAT,1,[6],'junior1.leg.pos')

Dynamism lets us create multidimensional arrays with the use of a shape list. Here, we, first, give the size of the shape list, and then, pass the list representing the shape.

Alternatively, if we already have a DyDataSet pointer ds for Junior1, we can have the following line:

d_array = dy.data.create_array_at(ds,dy.DY_FLOAT,1,[6],'leg.pos')

Dynamism has a method for registering strings. It is, indeed, a special case for registering arrays. By default, the variable type is dy.DY_CHAR, and the shape has a single element. As the result, we can register a string buffer with 256 characters as follows:

d_string = dy.data.create_string(256,'junior1.string1')

Alternatively, if we already have a DyDataSet pointer ds for Junior1, we can have the following line:

d_string = dy.data.create_string_at(ds,256,'string1')

Retrieval of Pointers

For retrieving a pointer to a data entity, we use one of the following (depending on whether we have a DyDataSet pointer):

d = dy.data.retrieve('junior1.data1')
d = dy.data.retrieve_at(ds,'data1')

At this point, it is advised not to use the functions above since create method implicitly calls the retrieve method if the entity is already present in the database.

To retrieve a DyDataSet pointer, we use the following two functions:

ds = dy.data.path('junior1.leg')
ds2 = dy.data.path_at(ds,'leg')

Data Manipulation

Once we have the data pointers, we can easily perform ''reads from'' and ''writes to'' the database. One important detail is, get and set methods provided by Dynamism are type-specific; there does NOT exist a generic get or set method the user can call. So, the user needs to know the variable type, in advance, to perform successful reads and writes.

Let us start with reading a single entity pointed by d:

var1 = dy.data.get_float(d)

Similarly, to write a value to this entity:
dy.data.set_float(d,1.0)

which will set junior1.data1 to 1.0.

For the manipulation of arrays, we have two options. We can perform get and set on a specific element by using the two methods above with an array index:

pos5 = dy.data.get_float(d_array,5) 
dy.data.set_float(d_array,1.0,5)

Alternatively, we can use array specific methods to read the whole array or assign values to the whole array at once:

pos = dy.data.get_float_array(d_array)
dy.data.set_float_array(d_array,pos)

Network Synchronization

Dynamism makes it really easy and fast to develop various behaviors on the OCU side by providing an easy-to-use network interface between the robot and the OCU.

Establishing a Connection

Any OCU side code requires to establish a network connection to the host run at the robot side as the first step:

host = dy.network.connect(hostname,8650)

In the code snippet given above, hostname should be a valid name defined in /etc/hosts file. For more information, you may refer to Running Your Code. And, 8650 is just a TCP/UDP port number that is available.

Synchronization

Modifications performed in the local copy of the database does NOT affect the remote copies unless the specific part of the local copy is pushed. This push can be broadcasted or peer-to-peer as well as it can be a one time operation or a periodic task that can be initiated with or without a period set by the user:

dy.network.push('%s.data1' % hostname)
dy.network.push_to(host, '%s.data1' % hostname)
dy.network.start_send('%s.data1' % hostname)
dy.network.start_send_to(host, '%s.data1' % hostname)
dy.network.start_send_every(timestep,'%s.data1' % hostname)
dy.network.start_send_to_every(host, timestep, '%s.data1' % hostname)
dy.network.stop_send('%s.data1' % hostname)
dy.network.stop_send_to(host,'%s.data1' % hostname)

Similarly remote copies can be pulled to update the local copy:
dy.network.pull('%s.data1' % hostname)
dy.network.pull_from(host, '%s.data1' % hostname)
dy.network.start_receive('%s.data1' % hostname)
dy.network.start_receive_from(host, '%s.data1' % hostname)
dy.network.start_receive_every(timestep,'%s.data1' % hostname)
dy.network.start_receive_from_every(host, timestep, '%s.data1' % hostname)
dy.network.stop_receive('%s.data1' % hostname)
dy.network.stop_receive_from(host,'%s.data1' % hostname)

Signals: A Handy Shortcut

As long as a callback function is defined in the remote host, we are able to send strings to initiate anything defined in the callback method. A list of available signals can be found in Signals.