Close

Mooooor code

A project log for Old Roomba, new tricks

Add mapping & MQTT-interfacing with ESP8266 and an IMU

simon-jansenSimon Jansen 03/15/2022 at 08:370 Comments

The code is starting to come together. I wanted a way to check when the roomba is docked and charging. Of course I could use the datastream for this. It has a bit set for when it's docked at its home base and a byte for its charging state.

But when it's docked, the roomba also gives a message every second. Something like:

bat:   min 16  sec 35  mV 16198  mA 1102  tenths-deg-C 223  mAH 2496  state 5

 When it's docked, I don't need the high speed datastream. So I want to switch over to getting the info from this message instead. Then the ESP8266 has its processing power freed up to do ... Idunno ¯\_(ツ)_/¯

The docked message is in ASCII instead of bytes. I want the values to be interpreted AND to be throughput to MQTT (when debugging). 

You know what this means of course: 

IT'S HEADACHE-... I MEAN CHARACTER-ARRAY-TIME!

Some of the characteristics of the message we're dealing with:

I messed around with a few different ways to interpret the message. 

In the end I settled on the following: 

All is done in a separate function that gets passed an incoming character. It uses C string functions as strcmp(), strcpy() and strtok(). 

void Roomba632::CheckChargingMessage(char incommingChar){
    //Example:
    //"bat:   min 16  sec 35  mV 16198  mA 1102  tenths-deg-C 223  mAH 2496  state 5"
    static int chargingMessageState;
    char* pos;
    char buffer[7];
    static char j;
    static char chargingHeaderBuffer[10], chargingMessageBuffer[80];
    switch (chargingMessageState){
        case chargingMessageWaitingForHeader:
            if(incommingChar =='b'){
                chargingMessageState = chargingMessageReadingHeader;
                p_requestStopDatastreamFlag = true;
                j=0;
            }
        break;
        case chargingMessageReadingHeader:
            chargingHeaderBuffer[j] = incommingChar;
            j++;
            if (j==10){
                if (strncmp(chargingHeaderBuffer, "at:   min ",10)==0){ 
                    chargingMessageState = chargingMessageReadingMessage;
                }
                else{
                    chargingMessageState = chargingMessageWaitingForHeader;
                }
                j = 0;
            }
        break;
        case chargingMessageReadingMessage:
            chargingMessageBuffer[j] = incommingChar;
            j++;
            if (j==79){
                j=0;
                chargingMessageState = chargingMessageReadingHeader;
            }
            if (incommingChar == '\n'){
                pos = strtok(chargingMessageBuffer, " ");
                j = 1;
                
                while (pos != NULL){
                    if (j== 5){ //Voltage
                        strcpy(buffer, pos);
                        batteryVoltage = atol(buffer);
                    }
                    if (j== 7){
                        strcpy(buffer, pos);
                        current = atol(buffer);
                    }
                    if (j== 9){
                        strcpy(buffer, pos);
                        batteryTemp = atol(buffer)/10; //Decimals are dropped
                    }
                    if (j== 11){
                        strcpy(buffer, pos);
                        batteryCapacity = atol(buffer);
                    }
                    if (j== 13){
                        strcpy(buffer, pos);
                        chargingState = atoi(buffer);
                    }
                    j++;
                    pos = strtok(NULL, " ");
                }
                state = roombaHome;
                charging = true;
                docked = true;
                p_requestStopDatastreamFlag = true;                
                chargingMessageState = chargingMessageReadingHeader;
                j = 0;
            }
        break;
    }
}

 The states are all defined with a bunch of enumerations in the header file. The code is far from perfect, but it works quite nicely and is another element for my roomba class. 

Still some improvements: I'm setting states of other state machines outside of the state machines. This is a big no-no that I will try to solve when I tidy up everything.

Also, I'm quite charmed by the idea of a circular buffer with a rotating index and might try that too.

For now, it'll do. I'm getting ~23000 main loops every second. So maybe it has enough spare processing power to do my taxes or plot for world domination?? 

Discussions