VRPN 06.04

VRPN main page

Obtaining VRPN

VRPN Support

Installing and Testing

Compiling and Modifying

Client code

Server code

Troubleshooting

Connections

Logging and Playback

Shared Objects

Sound

Clock Synchronization

Text Messages

Doxygen documentation

VRPN on PDAs

Coming attractions & suggestions

UNC-specific information

Servers

There is a generic server, whose source code lives in server_src/vrpn.C. There is a Makefile and a Visual Studio project file to compile it into vrpn_server. This server reads instructions about which devices to open from a configuration file (default is vrpn.cfg in the directory where it is run, the -f flag lets you specify another file). This configuration file contains one line for each device that is to be opened. A complete sample configuration file with example declarations for each type of server object that can be run by the generic server can be found here. Example lines for this file to configure trackers are:

vrpn_Tracker_Fastrak          Tracker0    /dev/ttyS0     115200
vrpn_Tracker_Dyna             Tracker0 1   /dev/ttyS0    19200
vrpn_Tracker_Flock           Tracker0 4   /dev/ttyC4    115200
vrpn_Tracker_Flock_Parallel  Tracker0 4  /dev/ttyC4    115200 /dev/ttyC0 /dev/ttyC1 /dev/ttyC2 /dev/ttyC3

Each of the lines lists the type of tracker, followed by parameters specific to that type. The first argument to each is the name of the device as it will be known to VRPN (in this case Tracker0, you would put different names if the trackers were all going on the same server; you might want a more descriptive name anyway). If this server is run on a machine named foobar, you would open the tracker as "Tracker0@foobar" in each case. The next argument for all but vrpn_Tracker_Fastrak is the number of sensors (the Fastrak driver opens all available sensors). The next argument is the name of the serial port to open, then the baud rate for that port. The vrpn_Flock_Parallel driver is made for the case where each sensor on the driver has its own serial connection; the port names for the sensor connections follow the baud rate. The controller is plugged into the initial port (/dev/ttyC4 in the example) for control signals; just as in the case where all reports come from the same port.

Example lines for other UNC-specific devices are:

vrpn_Button_Python     Button0   2
vrpn_Linux_Sound       Sound0

The vrpn_Button_Python is a device that plugs directly into a parallel port (numbered from 1, listed on the line) and uses the 5 input control lines to sense the state of up to 5 buttons. It's pretty easy to make a "dongle" that lets you plug buttons in; David Harrison has these and the devices.

The server for a Phantom haptic device is in phantom.C, and has a windows-NT project to build it.

The server for the UNC ceiling tracker is maintained by the tracker group and is not distributed with the library.

The vrpn_Linux_Sound was a sound server that runs under Linux. It is no longer compilable.

Building your own server

The name of all objects all begin with vrpn_. The base class for the object (from which both client and server objects are derived) will look something like vrpn_Tracker or vrpn_Button. Client objects should have the name _Remote at the end. Server objects have names specific to the device or class of devices that they serve (for example, _Fastrak for a certain kind of tracker). Objects to be used by the server (and which drive specific devices) will therefore look like vrpn_Tracker_3Space or vrpn_Tracker_Fastrak. The base class and _Remote device must be defined in the header file that is part of the library (vrpn_Tracker.h, for example). Specific server classes derived from the base class can be in separate header and source files, since they do not need to be compiled except on the architecture and machine where they run. This is the case for the 3Space tracker driver.

The base class for an object should handle the registration of message types and sender names with the connection that the object uses. It should also contain all routines for packing and unpacking the messages that are sent across the connection. This keeps all of the encoding and decoding in one class, and ensures that all derived classes use the same methods to do this.

A VRPN server will create a vrpn_Connection in a listening state and then create one of more device-specific server objects, each connected to this connection. It then cycles through each object, calling the mainloop() methods on the device objects and then on the connection object (to send messages generated by the local objects and to receive messages from the remote objects.

Example servers

A somewhat sophisticated server would read the names and parameters of its devices from a configuration file and start the objects based on these parameters. This would allow changing names, parameters and devices without recompiling the code.

An even more complicated server is the generic server that is found in server_src/vrpn.C.

An example of a server and client running in the same process can be found in client_and_server.C in the server directory. Another example that verifies that you can delete remote objects can be found in test_vrpn.C in the same directory.

A simple example server is shown here. This server creates a tracker and button object, then runs forever.

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "vrpn_Connection.h"
#include "vrpn_Button.h"
#include "vrpn_Tracker.h"
#include "vrpn_Tracker_Fastrak.h"


main (unsigned argc, char *argv[])
{
	int	bail_on_error = 1;

        vrpn_Synchronized_Connection connection;
	vrpn_Tracker	*tracker;
	vrpn_Button	*button;

	//Open a 3Space tracker
	if ( (tracker =
	     new vrpn_Tracker_Fastrak("Tracker0", &connection, "/dev/ttyS1", 19200)) == NULL){
	  fprintf(stderr,"Can't create new vrpn_Tracker_Fastrak\n");
	  return -1;
	}

	//Open a Python Button box on parallel port 1
	if ( (button =
	     new vrpn_Button_Python("Button0", &connection, 1)) == NULL){
	  fprintf(stderr,"Can't create new vrpn_Button_Python\n");
	  return -1;
	}

	// Loop forever calling the mainloop()s for all devices and the connection
	while (1) {
		int	i;

		// Let all the buttons generate reports
		button->mainloop();

		// Let all the trackers generate reports
		tracker->mainloop();
		}
		// Send and receive all messages
		connection.mainloop();
	}
}