
Over the past few years, I've received emails from various students at universities around the world, wanting to find out how to write software for their Garcia Robot. The product is made by Acroname, Inc. and comes with a wide variety of options. Most of what I focus on here is the software aspect of the system, which requires an embedded computing platform. Acroname ships the Garcia with a Stargate board, sold by Crossbow Solutions, equipped with a USB port, a PCMCIA slot for wireless networking, two serial ports for interfacing with sensors/actuators, and an ARMv5-based Intel XScale CPU.
Besides the main computer described above, the Garcia also includes a micro-controller board, called the Brainstem, that provides a serial interface for controlling 2 wheel motors and accessing data from infra-red sensors and the ledge detector. Knowing the various ways of interfacing with the Brainstem is key to being able to write complex programs to control every aspect of the robot's behavior.
The Stargate platform runs a provided distribution of Linux. It is therefore possible to develop applications using the system call APIs (ie, read()/write()) in order to receive and send data over a serial port to the Brainstem. This is a cumbersome but useful way to gain precise control over all of the operations of the Brainstem, but is usually only a good option if predictability is needed for timeliness experiments. Also, this method requires the developer to understand many details about the Brainstem architecture and configuration.
Included with the software is a cross-compiler toolchain. Various toolchains for ARM-based platforms can be downloaded from the web, but they all provide an assembler, compiler, linker and other tools for generating ARM binaries using an x86-based pc for the development environment. Once a program is compiled, it can be uploaded to the Stargate via a wireless network, and subsequently executed.
Brainstem Commands
A Brainstem command is a variable-length sequence of bytes, with the following format:

The module field specifies the address of one of the two available modules on the Brainstem: the GP and the MOTO. The MOTO controls the motors and some of the infra-red sensors, and the GP controls the rest of the sensors. Refer to manuals on Acroname's website for details on which module is associated with each of the sensors/actuators. By default, the module address of the GP is 2, and the MOTO is configured at address 4.
Following the module address, the second byte of the command specifies the length in bytes of the command packet, not including the first two bytes for the module and length. Next, the command field specifies one of the many possible commands to execute. Acroname maintains a list of these commands and their argument formats in their Brainstem reference. Each command has a different number of arguments with varying semantics, so following the command field there are zero or more argument bytes.
The following is an example of a command packet that tells the Brainstem to set the velocity of one of the motors to the value 10: 4 4 62 0 0 10. Here, the first byte of value 4 specifies that this packet is for the MOTO module. The third byte of value 62, specifies the command number that sets the motor velocity, and the following bytes are the command's arguments, which specify to set the motor with index 0 to a velocity of 10 units. The command and its arguments have a combined size of 4 bytes, thus 4 is specified as the length field in the second byte of the packet.
In many cases, after a command is sent to the Brainstem, a reply will be sent back through the serial port in the form a debug packet. For example, after informing the GP module to do an infra-red sensor reading, a debug packet containing the value read from the sensor can be obtained via a read() call on the serial port's file descriptor.
An Example Program
The code for a simple console program is listed below, as an example of how to send Brainstem commands over the Stargate's serial port. The code uses standard APIs and assumes that the serial port device file is located at /dev/cua0. This code is intended for illustrative purposes only, and may need to be tweaked for use in practice. The values for the command bytes are read from the standard input and sent in binary format using the write() system call on the file descriptor of the serial port.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#define MAX_COMMAND_BYTES 50
#define SERIAL_PORT "/dev/cua0"
main()
{
int i;
int fd;
size_t bytes_written;
char command_bytes[MAX_COMMAND_BYTES];
// Open the serial port for writing
fd = open(SERIAL_PORT, O_RDWR | O_SYNC);
if(fd < 0)
{
printf("Failed to open serial port\n");
exit(1);
}
while(1)
{
// Collect command byte values from user
printf("Enter Command >> ");
scanf("%d %d", &command_bytes[0], &command_bytes[1]);
for(i = 0; i < command_bytes[1]; i++)
scanf("%d", &command_bytes[i+2]);
// Send command packet to serial port
bytes_written = 0;
do
{
bytes_written = write(fd, (void *)(command_bytes + bytes_written),
(size_t)(command_bytes[1] + 2) - bytes_written);
if(bytes_written < 0)
{
printf("Error writing to serial port: %d\n", bytes_written);
exit(1);
}
} while(bytes_written < (size_t)(command_bytes[1] + 2));
printf("Sent command to module %d, length %d:", command_bytes[0],
command_bytes[1]);
for(i = 2; i < (command_bytes[1] + 2); i++)
printf(" %d", command_bytes[i]);
printf("\n");
}
}
References
- Acroname, Inc.: http://www.acroname.com
- Crossbow Solutions XScale Platform: http://blog.xbow.com/xblog/stargate_xscale_platform/
- Stargate Resources: http://platformx.sourceforge.net/Links/resource.html
0 comments:
Post a Comment