Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / artificial-intelligence / machine-learning

Configuring Robot Peripherals

5.00/5 (1 vote)
27 Apr 2012CPOL9 min read 19K  
A chapter excerpt from Programming Robots
Programming Robots

By Paul J. Perrone

By simply laying down a few configuration files and a minimal amount of custom code, robot components, their interconnections, and their execution can be rapidly configured with MAX and Java. In this article based on chapter 3 of Programming Robots, author Paul Perrone explains how most of the brilliance and specific behaviors of your bot will be buried inside of the conduct, sensor, and actuator components themselves.

You may also be interested in...

Sensors and actuators are devices that connect to your robot and interface with the physical world. In the case of sensors, we’re generally sensing information from the physical world. In the case of actuators, we’re generally affecting the physical world based on informational commands from your robot. There is a commonality across sensors and actuators to realize this physical interface with the world and we leverage that fact using the peripheral abstractions illustrated in figure 1.

Here we see that a peripheral ultimately derives from the component and system abstractions. Additionally, a peripheral is considered a type of hardware component and hence why it has a hardware abstraction as its immediate parent abstraction. In the MAX library, there are interfaces for peripheral and hardware and associated generic class realizations called PeripheralGeneric and HardwareGeneric.

Figure 1 Robot peripheral structure

Peripheral Interfaces

Since a peripheral is an external interface with your robot, there must be some means to communicate and interact with this external device. That is, if your peripheral is a GPS sensor, you may, for example, interact with this GPS device through a serial port interface. Alternately, you may also have an Ethernet interface to such a device. The range of physical interfaces to and from your robot and different peripheral devices may vary widely. Be it serial ports, Ethernet, digital I/O, analog I/O, or some other physical connection, your peripheral will have some physical interface to your robot. Thus, as illustrated in figure 1, a peripheral abstraction has a relationship with an interface object. The peripheral may serve as a software representation of an external device for your robot, but the interface represents the physical interface this peripheral has with the external device. This relationship is managed underneath the hood by your peripheral via an InterfaceManager. The InterfaceManager can manage one or more physical interfaces for your peripheral. However, it is most commonly used to simply manage a single primary interface. It manages when the interface is opened, when it is closed, how information is written to the interface, and how information is propagated from the interface.

This degree of abstraction aids in building interface-independent robot applications. Therefore, for example, if you build an application that talks to a GPS sensor over a serial port and then later change to a different GPS device that leverages an Ethernet interface or perhaps leverages a serial-to-Ethernet converter, you can change the interface type without changing the GPS class and code. This is just one form of abstraction built into MAX that helps isolate change and provides for a tremendous degree of flexibility in coding portable and extensible robot applications. As illustrated in figure 2, an InterfaceGeneric class is extended by a wide variety of concrete interface types in MAX and also provides a hook to more rapidly build and integrate your own physical interfaces if you so choose.

Figure 2 Robot interface examples

Configuring Actuator Peripherals

With this background on peripherals in mind, let’s go to our Hello World sample. Listing 1 shows the configuration for our sample actuator. We pulled this configuration and its interface configuration directly from the [templates-config]/actuators/standardoutput directory over to our [src-config]HelloWorld/actuators directory. Here, we’re configuring a generic actuator specifying the class ActuatorGeneric. Common to all MAX objects, we can indicate how this object will be referenced by other objects via a ReferencePolicy configuration specification. Our Actuator instance is shared by any object referencing this object. These are the common reference policy types:

  • Dedicated— Indicates that each instance of this object referenced by other objects in the process is uniquely instantiated. That is, when referenced, a new instance of the object is returned. This is the default configuration.
  • Shared—Indicates that this object configuration instance is shared by all objects referencing this object. Thus, a single instance of the object is created and that same instance is returned to all referencing objects.
  • Pooled—Indicates that this object configuration creates a pool of objects. Thus, referencing objects get unique handles as managed by a pool of objects. Objects returned to the pool are released for other objects to reference.

Listing 1 Configuring an actuator peripheral

XML
<?xml version="1.0"?>
<!-- The configuration for a robot actuator -->
<hashtable id="Actuator">
	<!-- A sample template for MAX actuators -->
	<string id="ClassName">
com.perronerobotics.actuator.ActuatorGeneric
</string>
	
	<!-- Specifies the reference policy of the object 
		(i.e. Dedicated (default), Shared, Pooled) -->
	<id id="ReferencePolicy">Shared</id>	

	<!-- Specify the base and object specific configuration -->
	<hashtable id="Configuration">
		<!-- If true, automatically start interfaces (open them) at
			the tail end of configuration -->
  		<boolean id="AutoStart">true</boolean>

  		<!-- Specify the Object ID of a primary singular interface -->
		<id id="Interface">./StandardOutputInterface</id>
		
	</hashtable>
</hashtable>

We’re also configuring our Actuator to AutoStart. This is a configuration parameter part and parcel of this base HardwareGeneric class with behavior further refined in the PeripheralGeneric class. Setting this value to true induces the peripheral to call openInterfaces() on its InterfaceManager at the tail end of the peripheral’s configuration. This induces the InterfaceManager to call open() on each of the peripheral’s configured interfaces. Thus, for example, if the interface is a serial port, the port may be opened at this point automatically. Otherwise, a client object to the Peripheral would have to explicitly induce an open of its underlying interfaces.

In this sample, as indicated in listing 1, the actuator peripheral indicates that its configured interface has an ID labeled "./StandardOutputInterface". We saw earlier that the Robot’s configuration specified that one of its components had an ID of actuators.Actuator. In the directory [src-config]/HelloWorld/actuators, there is the Actuator.xml file listed in listing 1. In the case of this actuator, it is indicating that its interface is in the same context as itself using the "./" notation. Thus, the fully qualified name of the interface is actuators.StandardOutputInterface and you’ll find a StandardOutputInterface.xml file in [src-config]/HelloWorld/actuators.

This StandardOutputInterface.xml configuration is shown in listing 2. As we see here, this interface is a StandardIOInterface class (in the MAX library). This class extends the InterfaceGeneric class and provides a simple interface to standard input and output. In this case, the class is configured with its default configuration. When induced by the peripheral to write information to its output, it simply writes to standard output. This provides us with a simple way to see how an actuator plugs into an application. This class simply dumps its information to standard output but other actuators may have interfaces which write commands out to computer ports or directly control an output via a discrete digital, pulse width modulated, or analog output interface.

Listing 2 Configuring An Actuator Interface

XML
<?xml version="1.0"?>
<!-- The configuration for a robot peripheral interface -->
<hashtable id="StandardOutputInterface">
	<!-- A sample template for an interface to standard I/O (output) -->
	<string id="ClassName">
com.perronetech.comm.stdio.StandardIOInterface
</string>
</hashtable>

As you can see, configuring a Peripheral, and, in the above case, an actuator peripheral, is rather straightforward. If we’re able to leverage generic classes such as ActuatorGeneric or more concrete classes in the MAX library such as StandardIOInterface, writing to an actuator may be as simple as dropping a few configuration files into a project directory. Naturally there are more complicated scenarios to consider such as mapping application information to/from low level protocol information going to or coming from a specific peripheral device and interface. It may also be the case that you desire to leverage some of the generic features of peripherals and interfaces and extend their services with concrete classes of your own making. Thus, you might define your own concrete extension of ActuatorGeneric or InterfaceGeneric.

Configuring Sensor Peripherals

The other peripheral leveraged by our sample Robot is a sensor. Listing 3 provides configuration information for a Sensor object located within the sensors.Sensor context and [src-config]/HelloWorld/sensors/Sensor.xml file, which we pulled from the [templates-config]/sensors/standardinput directory. You should begin to detect a pattern here by now. You’ll see that we have a SensorGeneric class defined, with a Shared reference policy, configured to AutoStart its interfaces, and defining its interface. Here, the interface is a StandardInputInterface object stored in the sensor’s same context (in sensors.StandardInputInterface).

For a sensor and, for that matter, for any Peripheral receiving input, we need to define some way to read information from the sensor. In this case, we’ve configured an AsynchronousPolicy, which instructs the peripheral to automatically listen for events on its interface. Thus, when information is available at the interface driver level, it will be received and pushed to the Peripheral’s InterfaceManager. That gets information from the Interface to the InterfaceManager automatically as it is received on the interface. To further automatically push information from the InterfaceManager to the Peripheral object itself, we configured a ListenForInterfaceUpdates variable. This gets information automatically routed from the InterfaceManager to the peripheral no matter what type of information is received. Since one Interface object may actually feed one or more peripheral objects, this filtering will come in handy.

XML
<?xml version="1.0"?>
<!-- The configuration for a robot actuator -->
<hashtable id="Actuator">
	<!-- A sample template for MAX actuators -->
	<string id="ClassName">
com.perronerobotics.actuator.ActuatorGeneric
</string>
	
	<!-- Specifies the reference policy of the object 
		(i.e. Dedicated (default), Shared, Pooled) -->
	<id id="ReferencePolicy">Shared</id>	

	<!-- Specify the base and object specific configuration -->
	<hashtable id="Configuration">
		<!-- If true, automatically start interfaces (open them) at
			the tail end of configuration -->
  		<boolean id="AutoStart">true</boolean>

  		<!-- Specify the Object ID of a primary singular interface -->
		<id id="Interface">./StandardOutputInterface</id>
		
	</hashtable>
</hashtable>

We have information propagated from this sensor peripheral’s interface all the way to the sensor peripheral object itself. It is possible to subclass and further configure the SensorGeneric class and do some preprocessing on the information it receives from the external world. But in our HelloWorld sensor configuration, we simply pass the information own downstream to a conduct.Plan object. We do achieve this by adding an entry to the TriggerAlwaysObjectIDs configuration section in the template. For our prebuilt HelloWorld example in listing 3, this value is already added. The TriggerAlwaysObjectIDs configuration is built into the SystemGeneric class (a parent class for SensorGeneric) and automatically propagates events received to objects listed in its configuration. Here, we configure our application to push events to our custom Plan object that has been configured as a sub-component of our sample Robot.

Our Sensor object is configured with the interface whose configuration is listed in listing 4. Here we see that our HelloWorld sensor’s interface is simply an instantiation of the same StandardIOInterface class used for the actuator. The difference here is that we’ve defined this interface object to ListenOnConsole, which means that it will listen on standard input for input information. This is our simple way to illustrate how a sensor interface may be configured. You act as the external sensor and enter integer values on the command line when running this sample. The numbers you input are read by the StandardIOInterface, propagate to the Sensor’s InterfaceManager, to the sensor itself, and then to the Plan object.

Listing 4 Configuring a Sensor Interface

XML
<?xml version="1.0"?>
<!-- The configuration for a robot peripheral interface -->
<hashtable id="StandardInputInterface">
	<!-- A sample template for an interface to standard I/O (input) -->
	<string id="ClassName">
com.perronetech.comm.stdio.StandardIOInterface
</string>

	<!-- Specify the base and object specific configuration -->
	<hashtable id="Configuration">
		<!-- Configure this standard I/O interface to listen on 
			its stdin console -->
		<boolean id="ListenOnConsole">true</boolean>
	</hashtable>
</hashtable>

Summary

Peripherals, be they sensors or actuators, are key components of any robot system. As we’ve just seen in our basic sample, it is very easy to configure a basic sensor and actuator for use in our robots using the technique shown here. Peripheral interfaces are also easily configured and in such a way that a decoupling between peripheral objects and their physical interfaces may be achieved.

Here are some other Manning titles you might be interested in:

Arduino in Action
Martin Evans, Joshua Noble, Mark Sproul, and Jordan Hochenbaum

The Well-Grounded Java Developer
Benjamin J. Evans and Martijn Verburg

Machine Learning in Action
Peter Harrington

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)