11.1 - Definition of a Player Device Driver

A device driver, or just driver, is defined in the Player documentation as

A piece of software (usually written in C++) that talks to a robotic sensor, actuator,
or algorithm, and translates its inputs and outputs to conform to one or more interfaces.
The driver's job is hide the specifics of any given entity by making it appear to
be the same as any other entity in its class.

The driver is a vendor specific and it actually accesses the device hardware. However, it uses Player interfaces an proxies to abstract the vendor specifics details from the client controller software. The Player documentation gives and example of a laser range finder. A driver is an implementation of a specific laser model of a specific vendor, such as SICK LMS200. However, the Player programmer uses RangerProxy to access a generic laser ranger. The specific laser running on the robot is informed in the cfg file.

11.2 - The Architecture of a Player Device Driver

A Player driver source codes are located in the server\drivers dir, where the robot drivers are located under server\drivers\mixed dir. The drivers opaque and speech are probably the simplest ones, so they are recommended to start understanding the driver architecture.

There are example drivers located at examples\plugins\exampledriver

This section explains the driver architecture using an example of a new Player driver for the audio library called LibSoX. The existing audio resources in Player are quite complicated, motivating the creation of a simpler and modern audio interface for robots.

The source code and compilation scripts for the soxplayer driver are located at <source_code>/Ch11.1/. As can be seem in <source_code>/Ch11.1/soxplayer.h, a Player driver is an extension of the class ThreadedDriver. This class has virtual methods that must be defined in the new driver, such as:

  • virtual int ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr, void * data); It deals with messages coming from the clients
  • virtual int MainSetup(); Set up the device when a client connects to the driver
  • virtual void MainQuit(); Shutdown the device when the client is shutdown
  • virtual void Main(); Main function for device thread

It is also mandatory to have a constructor which parses the cfg file, such as:

  • Soxplayer(ConfigFile* cf, int section);

The driver must also have a device address attribute, declared as

  • player_devaddr_t sound_addr;

The most important method is the ProcessMessage, where the incoming messages are checked and processed. PLAYER_PLAYSOUND_CMD_VALUES and player_playsound_cmd_t must match with the interface used by the driver, in this case, the playsound interface, defined in Chapter 10. The MatchMessage compares the incoming message header (hdr) with the expected interface header. If they match, then the incoming data (data) is typecasted to data interface type (player_playsound_cmd_t) and executed accordingly.

The Play method actually deals with the lib SoX details such as, open/read the audio file, apply effects, and send it to audio device driver at the OS level, in this case, alsa.

The SoxPlayer driver is a fairly simple driver dealing with a single interface, but a driver can be more complex and dealing with multiple interfaces. It is highly recommended after doing this tutorial to experiment with more complex existing drivers in the server\drivers dir.

11.2 - Compiling the Player Device Driver

You can compile the driver as a stand-alone library or integrated to the Player source code distribution. Usually, you would start with the stand-alone compilation until the driver is fully tested. Once it is stable, documented, and it useful for other people, you can submit it as a patch for the Player maintainer, as explained next.

11.2.1 - Driver Depedencies

The soxplayer driver depends on the LibSoX. So, now it is the time to install this library with the following command:

> sudo apt-get install -y libsox-dev

11.2.2 - Compiling the Player Device Driver as a Stand-Alone driver

Initially, while you are still developing and testing your new driver, it is better to compile it separately from Player. This section shows you how to compile like this. The environment variables CMAKE_MODULE_PATH and PKG_CONFIG_PATH are very important in this step. Please check the Section 1.1 - A Note on Installing Player/Stage to see how to set these variables. Details of CMake and PKGConfig are beyond the scope of this manual, but it is highly recommended subject of study if you plan to be a serious Player/stage developer or Linux software developer.

> cd <source_code>/Ch11.1/
> mkdir -p build
> cd build/
> cmake ../
> make

The driver library will be created in the current dir (Ch11.1/build). For convenience, there is a compile.sh script that does the same thing with a single command. Alternatively, there is a the Ch11.1/Mafefile, which uses PKGConfig definitions instead of CMake. Both scripts can be used as a template to compile other drivers.

11.2.3 - Compiling the Player Device Driver as part of Player distribution

If you really think that your driver can be useful for other people, it is highly recommended to include it into the Player source code distribution. Here were are assuming a git version system is used for Player.

Download a new, clean, and updated Player source code it from www.github/playerproject/player and follow these steps to add the soxplayer source code and scripts. For this step, you cannot reuse an existing local copy because it might have your local changes.

> git clone https://github.com/playerproject/player.git
> cd  player/server/drivers
> mkdir sox
> cd sox
> cp <source_code>/Ch11.1/soxplayer.cc .
> cp <source_code>/Ch11.1/soxplayer.h .
> cp <source_code>/Ch11.2/soxplayer.cfg .
> cp <source_code>/Ch11.2/soxplayer-test.cc .
> cp <source_code>/Ch11.3/CMakeLists.txt .

Change the player/server/drivers/CMakeLists.txt file from

ADD_SUBDIRECTORY (sonar)
ADD_SUBDIRECTORY (speech)

to

ADD_SUBDIRECTORY (sonar)
ADD_SUBDIRECTORY (sox)
ADD_SUBDIRECTORY (speech)

Now it is time to recompile Player with its new driver

> cd  player/
> mkdir build
> ccmake ..
check the option soxplayer if it is ON or OFF
> cmake ..
> make -j 8

If it is ok, then create a patch file and submitted it to the https://github.com/playerproject/player

> cd  player/
> git diff --cached > soxplayer_driver.patch

TO DO - this step gives this error.

CMakeFiles/playerdrivers.dir/__/drivers/sox/soxplayer.o: In function `player_driver_init':
soxplayer.cc:(.text+0x7d): multiple definition of `player_driver_init'
CMakeFiles/playerdrivers.dir/__/drivers/position/snd/snd.o:snd.cc:(.text+0x82): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [server/libplayerdrivers/libplayerdrivers.so.3.1.1-dev] Error 1
make[2]: Leaving directory `/home/osboxes/repos/player-new/build'
make[1]: *** [server/libplayerdrivers/CMakeFiles/playerdrivers.dir/all] Error 2
make[1]: Leaving directory `/home/osboxes/repos/player-new/build'

11.3 - TRY IT OUT

This test will fully test not only the soxplayer driver, but also the playsound interface developed in Chapter 10. The example is located at <source_code>/Ch11.2.

The CFG file defines the soxplayer driver, without any parameter:

It assumes that the driver library is located in the same directory or its path is defined in the LD_LIBRARY_PATH environment variable.

C++ client controller:

It defines the PlaySoundProxy and it executes the filename sound.play(argv[1]) passed as argument.

Launch Player:

and finally, on another terminal, compile and run the controller software.

It will play the R2D2 sound file and the client side terminal will show the following message.

$ ./soxplayer-test R2D2.mp3
playerc warning   : warning : [Player v.3.1.1-dev] connected on [localhost:6665] with sock 3

closing Player client
img

img