Writing a Player interface

From The Player Project

Revision as of 11:26, 14 February 2011 by Georgeshu (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

A interface is a specification of how to interact with a certain class of robotic sensor, actuator, or algorithm. The interface defines the syntax and semantics of all messages that can be exchanged with entities in the same class.

How to add an interface for a new kind of device.

There are two ways to add an interface to Player:

  • Static interfaces are part of the Player distribution and are defined in libplayerinterface. These interfaces handle most of the default messages in Player.
  • Plugin interfaces are built as shared objects and loaded at runtime. Plugin interfaces are recommended for custom and experimental applications.

Plugin interfaces have several advantages over their static counterparts:

  • They allow for custom applications
  • They allow for rapid development and changes; libplayerinterface doesn't need to be regenerated each time the interface definition is changed
  • They are portable: Plugin interface definitions can be kept in separate repositories with their companion drivers.


Plugin Interfaces

Example Plugin Interface

Sample code for a rudimentary plugin interface is included in the examples directory; for a default install, this will be:


This directory example contains three objects: an interface plugin, a driver plugin for the new interface, and a client program that uses the new interface in conjunction with the plugin driver.

To start, copy the files in this directory into a new folder. Enter the folder, and try building the examples:

$ mkdir build
$ cd build
$ cmake ..
$ make

This produces several outputs:

  • A new plugin interface: defined in example_interface.h and contained in example.so
  • A plugin driver, libexample_driver.so that uses the example interface. For more information on writing a plugin driver, see Writing a Player driver.
  • A sample playerc client program, example_client, that accesses data from the new interface from playerc.

You can test the example interface using the included configuration file:

$ player ./example.cfg

The config file contains a new interface block that specifies the name, code and path of the plugin interface:

  name "example"
  code 128
  plugin "libexample"

Writing your own plugin interface

The first step in creating a new interface is to decide on the messages that the interface needs to handle. Player supports three different messagetypes: commands, data, and requests. Interfaces may one or more of these messagetypes as necessary. For example, the gps interface supports only a single message: a data message that contains GPS related state information (latitude, longitude, etc.) On the other hand, the position2d interface has a large number of requests, data, and command messages. The messages the plugin interface implements depend on what the interface needs to accomplish.

To create a new interface, you must first create an interface definition file which contains the interface specifications (messages, structures, etc.) Then you can create plugin drivers and playerc functions that implement the interface. We will now describe the steps in detail.

The interface definition

Interfaces start with an interface definition file. Interfaces all have a unique number, so a plugin interface needs a new number. Player's builtin interfaces are numbered up to the 60's, so it's safest to create a number starting in the 100's to make sure the plugin interface does not conflict with any of the Player interfaces. Once you choose a number, create an interface definition file named ##_interfacename.def

The first part of the interface definition file is the description block. The description block contains a summary of your interface, and can be useful for documenting the purpose of the interface.

* Interface information goes here

The next section of the interface definition file contains the messages the interface will contain.

/** Example data */
message { DATA, EXAMPLE, 1, player_eginterf_data_t };
/** Example Request */
message { REQ, EXAMPLE, 1, player_eginterf_req_t };
/* Another example request */
message { REQ, ANOTHEREXAMPLE, 2, player_eginterf_req2_t };
/** Example Command */
message { CMD, EXAMPLE, 1, player_eginterf_cmd_t };

The first field in the message block is the message type. This must be either a CMD (command), REQ (request), or DATA (data) message.

The second field is the message subtype. Subtypes can have any name, and depend on the functionality of the interface. For example, most interfaces have a DATA message called STATE, which is used to hold data that is published often by a class of device. The convention is to capitalize the subtypes, as they will be expanded into define statements. For example, the data message above will be expanded into PLAYER_EXAMPLE_DATA_EXAMPLE.

The third field is a unique identifier for the message type and subtype. If your interface will contain multiple messages of the same type, they must have unique identifiers. In the above example, there are two REQ type messages, each with separate identifiers.

The last field is the structure that is to be associated with the message. In general, each message passed through the Player server has some kind of message payload. A command will contain a data structure that will hold command data, and a request may contain information about what data is being requested. These structures are also part of the interface definition, as described below.

The final part of the interface definition file is the structures that will be used by each message. These structures are defined as standard c structs, and may contain any arbitraty variables deemed appropriate by the user. The example interface defines the following:

typedef struct player_eginterf_data
	uint32_t stuff_count;
	double *stuff;
} player_eginterf_data_t;

typedef struct player_eginterf_req
	int value;
} player_eginterf_req_t;

typedef struct player_eginterf_cmd
	char doStuff;
} player_eginterf_cmd_t;

Generally, the structures will be named in some way that corresponds with the message types they go with. The names of the structures are usually in the form of "player_interfacename_structname"

Building the interface

The example interface includes a CMakeLists.txt file that builds the interface shared objects. The process for building the plugin interface using CMake is a lot like the process for building and installing Player. From within the example interface source directory, try:

$ mkdir build
$ cd build
$ cmake ..
$ make

The build directory should now contain the shared objects for the plugin interface, and the header files that generated from the interface definition file. For more information on building plugin interfaces, see the section on Compiling plugin interfaces

Static Interfaces

Static interfaces are the interfaces that ship with the Player source distribution. These interfaces

Adding a static interface to Player

In some situations, it may be desirable to add a static interface directly to Player. To add a new interface create a new file in player-source/libplayerinterface/interfaces directory. The file name should be

<interface number>_<interface name>.def

for example:


The interface number should be padded to three digits to aid sorting. New interfaces should use the next free interface code rather than filling in gaps. This is to avoid confusion with old removed interfaces.

In the file you should have:

  • a description block that contains a description of the interface for the documentation
  • a set of message blocks that define the interfaces messages these are structured as message { TYPE, SUBTYPE, SUBTYPE_CODE, DATA_TYPE };
  • the data types for your interface in standard C code

The best bet is to have a look at some of the other interfaces and copy what they have done.

When modifying an interface try to avoid renumbering the subtype codes. If you remove a subtype just leave a gap, this will aid in version compatibility.

Personal tools