Introduction:iRobot Create/Roomba and Gumstix

From The Robotics Primer Workbook

Hardware

The robot you will be using for each exercise consists of a Create mobile base, Gumstix computer, Robostix microcontroller, and wifistix wireless communications board as shown in the images below. All of these separate components fit together to make a complete programmable robot. The Gumstix computer will act as the brains of the robot; all of you code will run on the Gumstix. The Robostix microcontroller board attached to the bottom of the Gumstix computer, and provides a hardware connection between the Gumstix and the Create. This board not only allows the Gumstix and Create to communicate, but also allows a wide variety of sensors and actuators to be attached to the Gumstix. Finally, the Wifistix attaches to the top of the Gumstix and provides wireless (802.11g) communications.

Roomba
Create
Gumstix Connex
Robostix
Wifistix

Constructing the Gumstix

Each of the three Gumstix boards (Gumstix Connex, Robostix, Wifistix) connect together via the two sockets located on either side of the Gumstix Connex board. These sockets are different in size. The 60-pin socket connects to the Robostix, and the 92-pin socket connects to the Wifistix. Attach these together now, and the result should look like the image below.

Gumstix

Test and Setup the Gumstix

At this point your Gumstix stack is fully assembled and almost ready for action. By default the Wifistix is disabled, so you need to log into the Gumstix and configure the Wifistix properly. The following HowTo will describe the process of setting up a serial terminal connection to the Gumstix, logging into the Gumstix, and enabling the Wifistix.

Howto: Gumstix and Wifi Setup

Attaching the Gumstix to the Create

The easiest method of securing the Gumstix to the Create is with standard tape. Just use a little tape to attach the Gumstix to the inside of the Create's payload bay.

Connecting the Gumstix to the Create

This section describes how to connect the Gumstix stack to the Roomba. The connection is a serial link between a 4-pin header on the Robostix and the mini-DIN port located on the side of the Roomba.

Using Custom Cable

A custom cable allows you to bypass a complex setup of peripheral devices. The cable is relatively easy to make if you are comfortable using wire cutters, and a soldering iron.

Howto: Build a Mini-DIN to 4-pin TTL Serial Cable

Using Off the shelf parts

This option requires no manual construction, but costs quite a bit more than make your own custom cable using the directions above.

Howto: Buy a Mini-DIN to 4-pin Serial Cable

Software

Each major hardware component (Roomba, Gumstix, and desktop PC) run different software programs. The Roomba has embedded code that we do not have access to, accept through the Roomba API. The Gumstix is a x86 computer running the Linux operating system (OS). This OS allows us to use Player robot control software. Player is able to control the Roomba's motors and read data from its sensors. It acts as a server by responding to commands sent to it via a client program. The code you will write is the client program. Think of Player as an abstract interface to robot hardware. Finally, your desktop PC also runs Linux and can interface with Player. This feature allows for easy visualization of sensor data, teleoperation (remote-control), and running client code remotely.

All this sounds daunting, but fortunately the hard work has been taken care of for you. In each exercise you will control the iRobot Create using a convient Client interface which conceals most of the nitty-gritty details. Fortunately, all the software is open-source, so if you're feeling adventerous feel free to inspect and fiddle with it.

Exercise Code Example

We will now walk through a very simple example of how to control the Roomba using the Client interface. This exercise is meant to demonstrate what the rest of the workbook exercises will look like, and provide examples how one might go about accomplishing each one.

The code for this exercise is found in the exercises/intro directory. Let's open a terminal window and navigate there.

  • Click on the Terminal icon found on the desktop.
  • You will be presented with command prompt represented as a dollar sign: $
  • Enter the following command, which will change directory (cd) to intro.
 $ cd exercises/intro
  • Now take a look at the files in this directory using the list command.
 $ ls
  • Here is a brief description of each file:
    • SConstruct: contains Python code describing how to build (make and executable) from the intro code. The scons program reads this file and produces the executable.
    • client.xml: configuration data used by your program. There are a few parameters that must exist which instruct the Client program where the Player server is running. You are also free to add in your own data, which we will demonstrate shortly.
    • exercise.cc: Your code goes here. In this file you will write your C code to control the Roomba.
    • main.cc: This contains C code that intializes the Client, runs an update loop, and closes the Client.

Exercise Code

Now take a look at the exercise.cc file using your favorite editor (vim, emacs, nano, etc). Nano is intuitive and easy to use right away. Emacs has more bells and whistles, but still fairly easy to understand. Vim has a bit of a learning curve, but if you patient and dedicated you can learn to edit files very quickly and efficiently.

 $ vim exercise.cc
 or
 $ emacs exercise.cc
 or
 $ nano exercise.cc

Here is a listing of what you should see:

// Overview: 
// This is the introduction exercise code. It's purpose is to
// demonstrate how to use the exercise functions, control the roomba, read
// data from the sensors, and output information to the terminal. The code
// within the functions are examples only, and designed for tampering. So
// play with the values, and experiment to get a better understanding of how
// the roomba works and reacts.

#include <iostream>
#include <roomba/Client.hh>
#include <roomba/Clock.hh>
#include <roomba/XMLConfig.hh>

// Pointer to the roomba client. This provides us access to sensor data, and
// allows us to command the roomba
extern Client *client;

// Global Parameters
double linearVelocity;
double angularVelocity;
double duration;
Clock myClock;

////////////////////////////////////////////////////////////////////////////////
// exerciseLoad: This function is called first for loading of  any information
// necessary for the exercise. The return boolean value indicates whether to 
// continue, or stop the program (true=continue, false=stop).
bool exerciseLoad(XMLConfigNode *node)
{
  // Here we can load in values from the config file specified on the
  // command line.

  // The default client.xml file contains a <roomba:motorControl> block. We
  // will read in these values, and store them for future use.

  // Find the child of the root node that contains the motorControl block
  XMLConfigNode *motorControlNode = node->GetChild("motorControl");

  // Only read the data if the block was found
  if (motorControlNode)
  {
    // Read the double value associated with the "linearVelocity" name
    linearVelocity = motorControlNode->GetDouble("linearVelocity",0.0,0);

    // Read the double value associated with the "angularVelocity" name
    angularVelocity = motorControlNode->GetDouble("angularVelocity",0.0,0);

    // Read the double value associated with the "duration" name
    duration = motorControlNode->GetDouble("duration",0.0,0);
  }


  // Return value indicate whether the program should quit.
  // false = quit, true = continue
  return true;
}


////////////////////////////////////////////////////////////////////////////////
// exerciseInit: This function is called second for initialization of any 
// information necessary for the exercise. The return boolean value indicates 
// whether to continue, or stop the program (true=continue, false=stop).
bool exerciseInit()
{

  // Here we can initialize anything else that is required during the update
  // cycles.
  myClock.Reset();

  client->SetSpeed(linearVelocity, angularVelocity);

  // Return value indicate whether the program should quit.
  // false = quit, true = continue
  return true;
}



////////////////////////////////////////////////////////////////////////////////
// exerciseUpdate: This function is called every update cycle. The code
// within this function should implement the solution to the current
// exercise. The return boolean value indicates whether to continue the
// update cycles, or stop the program (true=continue, false=stop).
bool exerciseUpdate()
{
  Pose2d<double> robotPose;
  double currLinearSpeed, currAngularSpeed;
  bool result;

  // Here we put all the code to monitor and control the roomba. This code
  // will be called repeatidly until we return a false value.

  // Set the result to false if the clock has expired.
  result = !myClock.Expired(Time(duration));

  robotPose = client->GetPose();

  // Display the robot's pose
  std::cout << "Pose[" << robotPose << "]\n";

  // Return value indicates whether the program should quit.
  // false = quit, true = continue
  return result;
}


Let's step through this code.

These comments give an overview description of the exercise.

// Overview: 
// This is the introduction exercise code. It's purpose is to
// demonstrate how to use the exercise functions, control the roomba, read
// data from the sensors, and output information to the terminal. The code
// within the functions are examples only, and designed for tampering. So
// play with the values, and experiment to get a better understanding of how
// the roomba works and reacts.

Any necessary include files this exercise may need. Feel free to add more depending on your needs

#include <iostream>
#include <roomba/Client.hh>
#include <roomba/Clock.hh>
#include <roomba/XMLConfig.hh>

This defines the pointer to the Client, which provides the abstract interface to the Roomba and Gumstix. A few global variables are also defined here. Add more global variables as you see fit.

// Pointer to the roomba client. This provides us access to sensor data, and
// allows us to command the roomba
extern Client *client;

// Global Parameters
double linearVelocity;
double angularVelocity;
double duration;
Clock myClock;

This is the first function called when the program is executed. The XMLConfigNode parameter of this function provides us with access to the contents of the client.xml file. In this example we read a linear and angular velocity to drive the robot, and a duration in seconds for the robot to run. Compare this code to the contents of the client.xml file.

////////////////////////////////////////////////////////////////////////////////
// exerciseLoad: This function is called first for loading of  any information
// necessary for the exercise. The return boolean value indicates whether to 
// continue, or stop the program (true=continue, false=stop).
bool exerciseLoad(XMLConfigNode *node)
{
  // Here we can load in values from the config file specified on the
  // command line.

  // The default client.xml file contains a <roomba:motorControl> block. We
  // will read in these values, and store them for future use.

  // Find the child of the root node that contains the motorControl block
  XMLConfigNode *motorControlNode = node->GetChild("motorControl");

  // Only read the data if the block was found
  if (motorControlNode)
  {
    // Read the double value associated with the "linearVelocity" name
    linearVelocity = motorControlNode->GetDouble("linearVelocity",0.0,0);

    // Read the double value associated with the "angularVelocity" name
    angularVelocity = motorControlNode->GetDouble("angularVelocity",0.0,0);

    // Read the double value associated with the "duration" name
    duration = motorControlNode->GetDouble("duration",0.0,0);
  }


  // Return value indicate whether the program should quit.
  // false = quit, true = continue
  return true;
}

This is the second function called during execution. Place any initialization code here. In this exercise we have initialized a clock to keep track of the time, and instructed the Client to drive the robot with the linear and angular velocities.

////////////////////////////////////////////////////////////////////////////////
// exerciseInit: This function is called second for initialization of any 
// information necessary for the exercise. The return boolean value indicates 
// whether to continue, or stop the program (true=continue, false=stop).
bool exerciseInit()
{

  // Here we can initialize anything else that is required during the update
  // cycles.
  myClock.Reset();

  client->SetSpeed(linearVelocity, angularVelocity);

  // Return value indicate whether the program should quit.
  // false = quit, true = continue
  return true;
}


This function is the third to be called. It is also called during every update cycle, until a value of false is returned. This function will contain the meat of the exercise, and commonly queries the Client for new sensor data (update the state info) and sends commands based on this data. Here we check the clock, if it has expired then we tell the program to terminate by returning a false. We also get the current pose (x, y, theta) of the robot and display this information on the command line.

////////////////////////////////////////////////////////////////////////////////
// exerciseUpdate: This function is called every update cycle. The code
// within this function should implement the solution to the current
// exercise. The return boolean value indicates whether to continue the
// update cycles, or stop the program (true=continue, false=stop).
bool exerciseUpdate()
{
  Pose2d<double> robotPose;
  double currLinearSpeed, currAngularSpeed;
  bool result;

  // Here we put all the code to monitor and control the roomba. This code
  // will be called repeatidly until we return a false value.

  // Set the result to false if the clock has expired.
  result = !myClock.Expired(Time(duration));

  robotPose = client->GetPose();

  // Display the robot's pose
  std::cout << "Pose[" << robotPose << "]\n";

  // Return value indicates whether the program should quit.
  // false = quit, true = continue
  return result;
}

When this program is executed, the Client will connect to the Player server based on the information withing the client.xml file. The velocities and duration will be read from the client file, the clock initialized, and the velocities sent to the Client. Then every iteration of the update cycle will cause the current robot pose to be displayed on the terminal.

GUI

The default behavior of exercise will cause a graphical interface to pop-up. This interface provides a convient means to view the state of the robot as well as send commands. Below is an image of what the GUI looks like.

Graphical Interface Example

TODO: Describe the GUI. Not writing it up now, because it will change in the near future.

XML Config File

The XML configuration file contains a few setup parameters for the Client as well as any data your exercise program requires.As the name implies, the format of this file is in XML (eXtensible Markup Language). You can read all about XML at the W3C site.

So let's take a look at the client.xml file for this exercise, and focus on just the important parts.

<?xml version='1.0'?>

<client xmlns:player='http://www.roombadev.com/xmlschema/psg/#player'
        xmlns:roomba='http://www.roombadev.com/xmlschema/psg/#roomba'>

  <!-- Parameters for the connection to the Player server -->
  <player:params>

    <!-- Hostname or IP-address of the machine running the Player server -->
    <host>192.168.0.240</host>

    <!-- Port on which Player is listening -->
    <port>6665</port>

  </player:params>


  <!--******************************-->
  <!-- Add custom attributes below. -->
  <!--******************************-->

  <!-- Example input for the exerciseLoad function -->
  <roomba:motorControl>
    <linearVelocity>0.01</linearVelocity>
    <angularVelocity>0.0</angularVelocity>
    <duration>2.0</duration>
  </roomba:motorControl>

</client>

This section contains the parameters for connecting to the Player server. The <host>...</host> attribute tells the client where the Player server is running. The <port>...</port> specifies which port the Player server is running on. Most of the time you will not need to change the port attribute. In this example, the Player server is running on the machine (Gumstix) with an IP address of 192.168.0.240.

  <!-- Parameters for the connection to the Player server -->
  <player:params>

    <!-- Hostname or IP-address of the machine running the Player server -->
    <host>192.168.0.240</host>

    <!-- Port on which Player is listening -->
    <port>6665</port>

  </player:params>

This section contains our custom attributes. There is no limit to the number, type, or format of the attributes as long as they obey the XML constraints. Here we have defined a <roomba:motorControl> block that contains our parameters for controlling the speed of the motors and how long they should run for. The first attribute in this block, <linearVelocity>...</linearVelocity> is the linear speed at which the robot should move. Similarly, the <angularVelocity>...</angularVelocity> will be used to control how fast the robot should turn. Finally, <duration>...</duration> will control how long the robot will run.

<!-- Example input for the exerciseLoad function -->
<roomba:motorControl>
  <linearVelocity>0.01</linearVelocity>
  <angularVelocity>0.0</angularVelocity>
  <duration>2.0</duration>
</roomba:motorControl>

</blockquote>

Adjust these parameters and observe the effects they have on the robot's behavior.