So I finally connected together a few things that arrived in the mail.
This incredibly-sloppily wired-up robot is my first attempt to make something useful, eg. that will one day deliver a can of beer to my hands.
Right now it's a prototype.
It consists of a Dagu 5 chassis which I bought from here:
http://www.robotgear.com.au/Product.aspx/Details/554
(There are suppliers overseas too).
I also got their controller board which supports up to 4 motors and encoders.
At this stage the encoders are not used (although you may spot the wiring for them on the top). There is interrupt-driven code in the sketch to detect one of the encoders.
To help others get started, here is how I wired it up:

The battery is actually 6 x 1.5 NiMh batteries taped to the side.
This is the sketch:
// Dagu 5 Chassis example.
// Author: Nick Gammon
// Date: 11th December 2011
volatile int rotaryCount = 0;
#define PINA 8
#define PINB 9
#define INTERRUPT 0 // that is, pin 2
#define DIRECTIONA 4
#define MOTORA 5
#define DIRECTIONB 7
#define MOTORB 6
#define TIME_FORWARDS 10000
#define TIME_BACKWARDS 10000
#define TIME_TURN 1200
// Interrupt Service Routine for a change to encoder pin A
void isr ()
{
boolean up;
if (digitalRead (PINA))
up = digitalRead (PINB);
else
up = !digitalRead (PINB);
if (up)
rotaryCount++;
else
rotaryCount--;
} // end of isr
void setup ()
{
attachInterrupt (INTERRUPT, isr, CHANGE); // interrupt 0 is pin 2, interrupt 1 is pin 3
pinMode (MOTORA, OUTPUT);
pinMode (DIRECTIONA, OUTPUT);
pinMode (MOTORB, OUTPUT);
pinMode (DIRECTIONB, OUTPUT);
} // end of setup
byte phase;
unsigned long start;
int time_to_go;
void loop ()
{
analogWrite (MOTORA, 200);
analogWrite (MOTORB, 200);
start = millis ();
// check current drain
while (millis () - start < time_to_go)
{
if (analogRead (0) > 325) // > 1.46 amps
break;
}
switch (phase++ & 3)
{
case 0:
digitalWrite (DIRECTIONA, 1);
digitalWrite (DIRECTIONB, 1);
time_to_go = TIME_FORWARDS;
break;
case 1:
// turn
digitalWrite (DIRECTIONA, 1);
digitalWrite (DIRECTIONB, 0);
time_to_go = TIME_TURN;
break;
case 2:
digitalWrite (DIRECTIONA, 0);
digitalWrite (DIRECTIONB, 0);
time_to_go = TIME_BACKWARDS;
break;
case 3:
digitalWrite (DIRECTIONA, 0);
digitalWrite (DIRECTIONB, 1);
time_to_go = TIME_TURN;
break;
} // end of switch
analogWrite (MOTORA, 0);
analogWrite (MOTORB, 0);
delay (500);
} // end of loop
And this is the robot banging into walls (52 seconds):
The code is designed to drive the robot forwards or backwards for 10 seconds. Then it attempts to turn by driving the wheels in opposite directions for 1.2 seconds.
The current-sense circuit is used to detect too much load on the motors, if that happens the code immediately skips to the next phase.
There are quite a few improvements that could be made. For one thing, it needs a beer carrier.
It also could use a sensor to detect nearby obstacles. And a smarter algorithm would help it get out of being stuck in tight places. Oh, and it needs a sensor to stop it turning upside-down and spilling its guts.
This photo, taken after I neatened up the wiring with a my wire-wrapping tool, shows the connections between the motor board and the Arduino:
