Reading errors between two mbed+xbee

30 Nov 2011

Hello everyone, I'm trying to communicate between two robots each is equipped with an mbed and a connected xbee. the systems are completely symmetrical. my Xbee module is 4214-XBEE, flat antenna

This is the code for the sending robot

sending

#include "mbed.h"

Serial xbee(p28, p27);
DigitalOut rst1(p26);

int main() {
    m3pi.cls();
    rst1 = 0;
    wait_ms(1);
    rst1 = 1;
    wait_ms(1);

    while (1) {
        xbee.printf("%s\n","abc");
    }
}

Here is the code for the reading robot

Reading

#include "mbed.h"

Serial xbee(p28, p27);  
DigitalOut rst1(p26); 
DigitalOut myled(LED1);

int main() {
    m3pi.cls();
    rst1 = 0;
    wait_ms(1);
    rst1 = 1;
    wait_ms(1);
    char str[10]={10};
    
    while (1) {
        wait(0.1);
        if (xbee.readable()) {
            xbee.scanf("%s/n", str);
            printf("is %s",str);
        } else {
            printf("Nothing");
        }
    }
}

My output is supposed to be abc. but it is only sometimes such. I'm getting: abbc, abcbc... etc Why am I getting so many errors? Is there anything wrong with my code? Is there any way to remove the errors?

30 Nov 2011

I'm afraid you are sending data far far to fast for the serial interface to keep up with, the first place the data goes is a very small buffer before being transmitted at the baud rate you've selected, to see if there is any room in this buffer to send more data you would use

    while (1) {
        if(xbee.writeable()){
           xbee.printf("%s\n","abc");
        }
    }

but this would only check if there was 1 byte free not the 4 you need,

using MODSERIAL would help as it allows for much larger buffers, but you would still need to limit your transmissions to the baud rate of the connection. quite a bit less probably.

you have also got to allow for data loss/corruption from the wireless connection, nothings perfect even in close proximity.

01 Dec 2011

Thank you for the timely replay. Do you think that I could use int instead to use only 1 byte? I only need 4 digits numbers up to 5533, I think I'll still need 2 bytes, right? I could manage with some errors. But I did a small calculation to check my error ratio and had a ratio of correct reads / all reads to something less than 0.001... I can't work with that.

I'll also check tomorrow this code and the MODSERIAL. Thank you very much.

01 Dec 2011

The error rate you are getting is because of the buffer overflows due to how much data your trying to send, it should be almost nothing once you fix that.

To send a max value of 5533 you would indeed need a 16bit value to send it as binary, although depending on your update rate and to simplify the packet detection you could just use printf and scanf like you are, sending as binary you would have to create a packet with at least 3 bytes of overhead, it really depends on if your going to send more then just the one short,

Example transmition code

#include "mbed.h"

Serial xbee(p28, p27);
Timer serial_update_timer;

int main() {
    uint16_t value = 1234;
    serial_update_timer.start();

    while (1) {
        if(serial_update_timer.read_ms() > 100 && xbee.writeable()){ // 10hz update rate
            serial_update_timer.reset();                             
            xbee.printf("%d\n",value);
        }
    }
}

unbuffered Serial should handle 10hz easily, and xbee modules are quite good at error detection, they do buffer a set amount or wait a short time before they send a wireless packet, not sure how it will effect your application

01 Dec 2011

you can avoid transmit-to-XBee buffer overflow by your own software send/receive protocol scheme, and/or you can use hardware flow control. For the latter, you wire CTS from the XBee to the microprocessor's UART input of that name and most UARTs will stop sending when the XBee takes CTS false due to buffer-full. If the UART lacks a CTS, you can wire CTS to an input port pin and have your sofwtare look at CTS before sending EACH byte. As I recall, you have to config the XBee to use CTS handshaking flow control.

But brain-dead simple is to simply limit the send-data packets rate per second as suggested above, and use no flow control, software or hardware. (But you'll not get info on transmit success either). Be sure that the XBee option for MAC layer ACK is configured - else there will be no error correcting retransmissions done by the XBee.

01 Dec 2011

I've tried the MODSERIAL, and it does it's just terrifically, up to a point. My code scans for a transmission every 0.1 seconds. after about 5 seconds (that would consist about 50 scans.) I start getting errors again, and then I go back to getting consistent errors (as in, I can barely get the original correct transmission through). Why is that? I did not specify a buffer for the MODSERIAL, so it goes directly to 256. If I specify a larger buffer the errors start at a later period (> 10 seconds). So I'm guessing someone reached the end of it's buffer. My money is on both. How do I safely clear the buffer? I tried using GetCount and when it's larger than X flush, but it always introduces additional problems. Also, BufferFull introduces issues of it's own, like sometimes killing the transmission mid which makes the receiving end get stuck. In that 5 seconds range I get 50 good solid reads. and that's mighty fine. I can work with that, but I wonder if there is any way to handle the end of Buffer thing.

Thanks a lot, Uriel

EDIT: I've worked around with the MODSERIAL and it is great. Actually, great cannot describe what I'm feeling right now. but... I'm a bit weak on my C++ side. I'm using this serial interrupt (thanks to MODSERIAL)

Interrupt

void rxCallback(MODSERIAL_IRQ_INFO *q) {
    myled2=!myled2;
    read = true;
}

int main() {
    xbee.attach(&rxCallback, MODSERIAL::RxIrq);

It seems to run a few times and then refuse to run again. I'm not sure I understand how this works. I know that the digital interrupt will activate whenever the condition is met (change from 0 to 1). And if I got it right, the serial interrupt (the Rx one) should activate whenever something enters the Rx buffer, I think that this should work as long as another robot is transmitting. So why does the interrupt stops working after a few runs? (maybe once the buffer is full the only way to empty it is BufferFlush?)

Also, a totally nub question, is there any way to stop an interrupt from acting at all? (In certain parts of it's operation cycle the robot won't be using the Xbee, I'd like to shut down the interrupt from working because other mbeds might still be transmitting.)

01 Dec 2011

I'm glad your getting things moving along, you should never have to clear the buffer, as long as your processing the data your receiving, whenever you read what you have received its removed from the rx buffer, also you shouldn't have to stop the rx interrupt, in fact unless you want to scan data as you receive it you shouldn't have to use it, mbed are fast, they can process much more data then serial can throw at them and still leave you plenty of cycles to do what you want,

I'm not sure why your rx interrupts stops firing, it shouldn't, is the mbed still running? not crashed, same goes for the transmitting unit,

in my SimpleSerialPacket library, (very alpha, not documented) I decided to leave everything I could out of interrupts so the flow of the program is predictable, the library is overkill for your situation and the overhead of the packets with checksums would be more then the data your sending or I would have mentioned it earlier, using the library I can read a serial data stream and decode it in about 10us, ofc the more data you through at it the longer it takes, but it never drops below 20,000 cycles a second and this is reading all 3 serial ports, (in my system gps, ahrs, and the control system)

what you need to do in your main loop is check if there is more than 5 bytes (4 digit ascii number and newline) in the MODSERIAL buffer, and read them, therefore clearing the buffer for more data, this could be accomplished with:

char str[10]={0,0,0,0,0,0,0,0,0,0};
while(1){
    if(xbee.rxBufferGetCount() > 5)
        xbee.scanf("%s/n", str);
    }
}

you would need to send the data as 4 bytes and an /n so 0001/n ect,

the better solution would be to use example 2 in the MODSERIAL library, using autoDetectChar('/n') and the autodetect callback, MODSERIAL Example 2 although, again suitability all depends on the complexity of your protocol

05 Dec 2011

I think I know why the interrupt stops working. I stop reading the data from the serial port at some points, but robots are still transmitting. The buffer becoms full and nothing new enters it, thus the condition of the interrupt in the MODSERIAL stops being "true".

But that's it. I think I got it. Thank you very very much Chris!