Thanks for sharing this. You inspire me and i also made a similar solution during this weekend.
But I have a problem. Maybe you could answer or someone from the forum.
I can not wake up my vacuum (roomba 620) from the state of "suspension" to whose passes automatically after 5 minutes. (all diodes off). Complete code is on end of post.
From old documentation "Roomba_SCI_Spec_Manual.pdf" wake up should looks like this
ser.setRTS (0)
time.sleep (0.1)
ser.setRTS (1)
time.sleep (2)
I can do it "hardware". It means when my yellow cabel from "DD" during insertion into arduino pinMode(D3, OUTPUT) ... roomba weak up all times.
But when cable is connect to D3 permanently and try send few times signals like this.
digitalWrite(D3, LOW); delay(10);
digitalWrite(D3, HIGHT); delay(2);
It didnt work.
Of course it wake up when i push button "clean" by finger. Did you have similar problem
My full code is little more complicate and right now looks like this:
#define MY_BAUD_RATE 115200
// Enable debug prints to serial monitor
#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
// Enable repeater functionality for this node
//#define MY_REPEATER_FEATURE
#define MY_RF24_CHANNEL 76 // brama - kuchnia
#define CHILD_ID_BATT_TEMP 100 // Id of the 2nd msg1_3
#define CHILD_ID_BATT_PROC 101 // Id of the 2nd msg1_4
#define CHILD_ID_BATT_VOLT 102 // Id of the 2nd msg1_2
#define CHILD_ID_BATT_AH 103 // Id of the 2nd msg2_5
#define CHILD_ID_BATT_CHARGE_TYPE 104 // Id of the 2nd msg1_1
#define CHILD_ID_BATT_CHARGE_SOURCE 105 // Id of the 2nd msg2_2
#include <SoftwareSerial.h>
#include <MySensors.h>
#define NUMBER_OF_FUNCTION 7
#define NUMBER_OF_SENSORS 6
int ddPin = 3;
int rxPin = 6;
int txPin = 7;
SoftwareSerial roomba(rxPin, txPin);
const char SWITCH_NAMES[NUMBER_OF_FUNCTION][14] = { "Roomba-Stop","Roomba-Dock","Roomba-Clean","Roomba-Spot","Roomba-Max","Roomba-Power","Roomba-Play" };
const char SENSORS_NAMES[NUMBER_OF_SENSORS][24] = { "Roomba-Batt-Temp","Roomba-Batt-Proc","Roomba-Batt-Volt", "Roomba-Batt-mAH" , "Roomba-Batt-CHt" , "Roomba-Batt-CHs" };
//for sensorgetting
#define ROOMBA_READ_TIMEOUT 300
#define ROOMBA_WAKE_COUNT 10
uint8_t buf[52];
boolean lowBattery = true; // Acts as a debounce
long battery_Current_mAh = 0;
long battery_Total_mAh = 0;
long battery_percent = 0;
boolean DeadBattery = false;
boolean FullBattery = true;
unsigned long chargingState = 0;
long voltage = 0;
long temp = 0;
long OiMode = 0;
long ChargeSource = 0;
long sensorfrequency = 60000; // frequency the sensors are read
long lastsensorread = 0; // when were the sensors read the last time
unsigned long lastsensorssend = 0;
const char ChargeTypes[6][34] = { "Not charging","Reconditioning Charging","Full Charging","Trickle Charging","Waiting","Charging Fault Condition" };
const char OiTypes[4][14] = { "Off","Passive","Safe","Full" };
int packetSizes[58] = {
0,0,0,0,0,0, //1-6
1,1,1,1,1,1,1,1,1,1,1,1, //7-18
2,2, //19-20
1, //21
2,2, //22-23
1, //24
2,2,2,2,2,2,2, //25-31
1, //32
2, //33
1,1,1,1,1, //34-38
2,2,2,2,2,2, //39-44
1, //45
2,2,2,2,2,2, //46-51
1,1, //52-53
2,2,2,2, //54-57
1 //58
};
// Initialize messages
MyMessage msg1_3(CHILD_ID_BATT_TEMP, V_TEMP); //status of Temperature
MyMessage msg1_4(CHILD_ID_BATT_PROC, V_PH); //status of Charge [%]
MyMessage msg1_2(CHILD_ID_BATT_VOLT, V_VOLTAGE); //status of Voltage
MyMessage msg2_5(CHILD_ID_BATT_AH, V_CURRENT); //status of mAH
MyMessage msg1_1(CHILD_ID_BATT_CHARGE_TYPE, V_TEXT); //status of charget type
MyMessage msg2_2(CHILD_ID_BATT_CHARGE_SOURCE, V_TEXT); //status of charger source
void setup() {
pinMode(ddPin, OUTPUT);
digitalWrite(ddPin, LOW);
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
roomba.begin(115200);
//Serial.println("Sending start command...");
//delay(1000);
//// set up ROI to receive commands
defsongs();
delay(500);
rstop();
Serial.println("Ready to go!");
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Roomba", "1.2");
for (int sensor = 0; sensor < NUMBER_OF_FUNCTION; sensor++) {
// Register all sensors to gw (they will be created as child devices)
present(sensor, S_BINARY, SWITCH_NAMES[sensor]);
delay(100);
}
present(CHILD_ID_BATT_TEMP, S_TEMP, SENSORS_NAMES[0]); delay(100);
present(CHILD_ID_BATT_PROC, S_WATER_QUALITY, SENSORS_NAMES[1]); delay(100);
present(CHILD_ID_BATT_VOLT, S_MULTIMETER, SENSORS_NAMES[2]); delay(100);
present(CHILD_ID_BATT_AH, S_MULTIMETER, SENSORS_NAMES[3]); delay(100);
present(CHILD_ID_BATT_CHARGE_TYPE, S_INFO, SENSORS_NAMES[4]); delay(100);
present(CHILD_ID_BATT_CHARGE_SOURCE, S_INFO, SENSORS_NAMES[5]); delay(100);
}
void loop() {
unsigned long now = millis();
if (now > lastsensorssend + sensorfrequency)
{
readsensors();
lastsensorssend = now;
}
}
void receive(const MyMessage &message) {
// We only expect one type of message from controller. But we better check anyway.
if (message.type == V_LIGHT) {
int mySensor = message.sensor;
int myComand = message.getBool();
//Serial.print(message.sensor);
if (myComand == 1) {
switch (mySensor) {
case 0:
Serial.println("Stop");
rstop();
break;
case 1:
Serial.println("Dock");
rcommand(143);
break;
case 2:
Serial.println("Clean");
rcommand(135);
break;
case 3:
Serial.println("Spot");
rcommand(134);
break;
case 4:
Serial.println("Max");
rcommand(136);
break;
case 5:
Serial.println("Power-Off");
rcommand(133);
break;
case 6:
Serial.println("Song");
rcommand(141);
rsong(0);
break;
}
}
}
}
void rstop() {
if (rwakeup()) {
roomba.write(128); delay(100);
roomba.write(131); delay(100);
roomba.write(137); delay(100);
byte j = 0x00;
roomba.write(j); delay(100);
roomba.write(j); delay(100);
roomba.write(j); delay(100);
roomba.write(j); delay(100);
roomba.write(128);
}
}
void rsong(int b) {
roomba.write(b); delay(100);
}
void rcommand(int command) {
if (rwakeup()) {
roomba.write(128); delay(100);
roomba.write(131); delay(100);
roomba.write(command);
}
}
void play(char note, int rlong) {
roomba.write(rnote(note)); delay(10); roomba.write(64 / rlong); delay(10);
}
bool rwakeup() {
bool ret = getSensors(6, buf, 52);
Serial.print("wekup: ");
Serial.print(ret);
if (!ret) {
for (int ii = 1; ii < ROOMBA_WAKE_COUNT; ii++)
{
for (int jj = 0; jj < 3; jj++) {
digitalWrite(ddPin, HIGH); delay(10);
digitalWrite(ddPin, LOW); delay(2);
}
delay(100);
roomba.write(128);
if (getSensors(6, buf, 52)) {
ret = true;
break;
}
Serial.print("-");
}
}
Serial.println(ret);
return ret;
}
bool getSensors(uint8_t packetID, uint8_t* dest, uint8_t len) {
roomba.write(142);
delay(100);
roomba.write(packetID);
delay(100);
return getData(dest, len);
}
bool getData(uint8_t* dest, uint8_t len)
{
while (len-- > 0)
{
unsigned long startTime = millis();
while (!roomba.available())
{
// Look for a timeout
if (millis() > startTime + ROOMBA_READ_TIMEOUT)
return false; // Timed out
}
*dest++ = roomba.read();
}
return true;
}
//for sensorgetting
int getPacketSize(int p) {
return packetSizes[p - 1];
}
int getPacketOffset(int p) {
int i = 0;
for (int s = 1; s < p; s++) {
i += getPacketSize(s);
}
return i;
}
//read sensors
void readsensors()
{
if (getSensors(6, buf, 52)) {
int off = 0;
// Battery Checks
off = getPacketOffset(21);
chargingState = buf[off + 0];
voltage = buf[off + 2] + 256 * buf[off + 1];
temp = buf[off + 5];
battery_Current_mAh = buf[off + 7] + 256 * buf[off + 6];
battery_Total_mAh = buf[off + 9] + 256 * buf[off + 8];
if (battery_Total_mAh == 0) battery_Total_mAh = 1;
int nBatPcent = battery_Current_mAh * 100 / battery_Total_mAh;
battery_percent = nBatPcent;
//Oi Mode
off = getPacketOffset(35);
OiMode = buf[off + 0];
//ChargeSource
off = getPacketOffset(34);
ChargeSource = buf[off + 0];
send(msg1_3.set(temp)); delay(100);
send(msg1_4.set(battery_percent)); delay(100);
send(msg1_2.set(round(voltage / 10), 1)); delay(100);
send(msg2_5.set(battery_Current_mAh)); delay(100);
send(msg1_1.set(ChargeTypes[chargingState])); delay(100);
send(msg2_2.set(ChargeSource)); delay(100);
//send(msg2_5.set(chargingState)); // Send info value to gw
//send(msg2_5.set("charging state")); // Send info value to gw
//send(msg2_5.set(battery_Total_mAh)); // Send info value to gw
//send(msg2_1.set(OiTypes[OiMode])); // Send info value to gw
lastsensorread = millis();
}
else { send(msg1_1.set("roomba is off")); } // Send info value to gw
}
void defsongs() {
uint8_t zero = 0;
roomba.write(128); delay(100); roomba.write(131); delay(100); //[128 131](Start the command stream and change roomba mode to "Safe" mode)
roomba.write(140); delay(100); roomba.write(zero); delay(100); //[140 0](Start song definition and define the first song, song number 0)
roomba.write(25); //[16](16 notes will be sent for song number 0)
play('E', 4); //[76 16](play Mi sound for 1 / 4 seconds) // E
play('E', 4);
play('E', 2);
play('E', 4);
play('E', 4);
play('E', 2); //[76 32](play Mi sound for 1 / 2 seconds)
play('E', 4);
play('G', 4);
play('C', 4);
play('D', 4);
play('E', 1);
play('F', 4);
play('F', 4);
play('F', 2);
play('F', 4);
play('E', 4);
play('E', 2);
play('E', 4);
play('D', 4);
play('D', 4);
play('E', 4);
play('D', 1);
delay(100);
roomba.write(128);
}
int rnote(char note) {
int command = 31;
switch (note) {
case 'C': command = 72; break;
case 'D': command = 74; break;
case 'E': command = 76; break;
case 'F': command = 77; break;
case 'G': command = 79; break;
}
return command;
}