I have been working on a project over the summer and I had to add functionality to Todd E. Kurt's (author of "Hacking Roomba") code; I added in functionality to include ALL the sensor readings, and (rudimentary, but effective) error checking for serial data packets.
Here's the code that handles all serial communication with the Roomba/Create:
char sensorbytes[10];
// Sensor Packet 1
#define BUMPRIGHT (sensorbytes[0] & 0x01)
#define BUMPLEFT ((sensorbytes[0] & (1<<1))>>1)
#define WHEELDROP_C ((sensorbytes[0] & (1<<4))>>4)
#define WHEELDROP_L ((sensorbytes[0] & (1<<3))>>3)
#define WHEELDROP_R ((sensorbytes[0] & (1<<2))>>2)
#define WALL (sensorbytes[1])
#define CLIFF_L (sensorbytes[2])
#define CLIFF_FL (sensorbytes[3])
#define CLIFF_FR (sensorbytes[4])
#define CLIFF_R (sensorbytes[5])
#define VWALL (sensorbytes[6])
#define MOTOROVER_L ((sensorbytes[7] & (1<<4))>>4)
#define MOTOROVER_R ((sensorbytes[7] & (1<<3))>>3)
#define DIRT_L (sensorbytes[8])
#define DIRT_R (sensorbytes[9])
// Sensor packet 2
#define REMOTE (sensorbytes[0])
#define BUTTON_CLEAN ((sensorbytes[1] & (1<<1))>>1)
#define BUTTON_SPOT ((sensorbytes[1] & (1<<2))>>2)
#define BUTTON_POWER ((sensorbytes[1] & (1<<3))>>3)
#define DISTANCE ((sensorbytes[2] << 8) + sensorbytes[3])
#define ANGLE ((360*((sensorbytes[4] << 8) + sensorbytes[5]))/(258*PI)) // Degrees
#define RADIANS ((2 * ((sensorbytes[4] << 8) + sensorbytes[5])) / 258) // Radians
// Sensor Packet 3
#define CHARGE_STATE (sensorbytes[0])
#define VOLTAGE ((sensorbytes[1] << 8) + sensorbytes[2])
#define CURRENT ((sensorbytes[3] << 8) + sensorbytes[4])
#define TEMP (sensorbytes[5])
#define CHARGE ((sensorbytes[6] << 8) + sensorbytes[7])
#define CAPACITY ((sensorbytes[8] << 8) + sensorbytes[9])
...
void updateSensors(byte packet) {
Serial.print(142, BYTE);
Serial.print(packet, BYTE);
delay(100); // wait for sensors
char i = 0;
while(Serial.available()) {
int c = Serial.read();
if( c==-1 ) {
SensorError();
}
sensorbytes[i++] = c;
}
if(i < 6) { // Size of smallest sensor packet is 6
SensorError();
}
}
void SensorError() {
for(byte i = 0; i < 10; i++) {
digitalWrite(ledPin, HIGH);
delay(25);
digitalWrite(ledPin, LOW);
delay(25);
}
delay(500);
}
void WakeUp() {
// wake up the robot
digitalWrite(ddPin, LOW);
delay(100);
digitalWrite(ddPin, HIGH);
delay(2000);
}
The '...' indicates I've left out all the other stuff (required loop(), setup(), etc). This is just the stuff you'll need in addition to your code.
In the void setup(){} function, you can put this to control the roomba:
WakeUp();
for(i = 0; i < 3; i++) { // Set baud rate to 19200bps
digitalWrite(ddPin, LOW);
delay(100);
digitalWrite(ddPin, HIGH);
delay(100);
}
Serial.begin(19200);
delay(100);
// set up ROI to receive commands
Serial.print(128, BYTE); // START (Now in PASSIVE Mode)
delay(50);
Serial.print(133, BYTE); // POWER; Turn off to see if we are plugged in
delay(100);
ChargeMonitor();
Serial.print(130, BYTE); // CONTROL (Now in SAFE Mode)
delay(50);
In the 'ChargeMonitor' routine, I added some code to use alongside an Emic TTS module to speak out charging/battery status, but the code doesn't seem to work (somehow I'm sending the data to it improperly...). I used the SoftSerial library to communicate with the Emic.
Also, a milestone that, according to my online searches, close to nobody knows:
In order to communicate to the roomba, the ATmegaxxx MUST be disconnected from the Tx/Rx pins of the FT232 USB-Serial chip. The FT232 seems to drop the voltage coming from the roomba/from the arduino to the roomba, and therefore voltage trigger thresholds (HI/LO) are out of whack for serial communication, and it almost always doesn't work.
Have fun!