Pages: [1]   Go Down
Author Topic: best way to process data received via XBEE?  (Read 1194 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi there
i've been working on basics, intermediate applications using XBEE devices, and got good results (turning on leds with remote or controller on pC for example )
now i'm working on controlling an uav, or anykind of robot via the same configuration, that is:

____ PC  - Processing ( for the controller or remote) + XBEE on Explorer sending data
____ ARduino - XBEE recieving data

i only use essential XBEE PINS:   1 = Vcc, 10 = Gnd; 2 (data in) = Rx ( i use Main serial on board, ATMEGA 2560 )

i'm thinking of the best method to process the incoming data ( i got good results, but sometimes for example, my actionned motor doesn't stop, or maybe not as quick as i would like to etc.. i also would like to get the more advanced commands, for example turning the robot of the exact angle sent by the sticks etc.. )

this is an example of code i came with:

______
PC + processing:
_______

// key A is pressed
XBEE.write ('A'); // this works well, acurate and fast

// a stick is used
XBEE.write('Y');  // tells the arduino its gonna be an Y axis
XBEE.write ( ValY ) ;   // valY is the value i get using processing code like:  ValY = Y.getValue ();
// this works well too
// my processing sketch works well and responds well


_____
arduino + xbee receiving data
_______

void setup(){
Serial.begin (9600);  // exact same BD as XBEE receiver
}

void loop (){
processData () ; // i think its better processing data out of the loop, may be wrong or useless
}

processData (){
char c = Serial.read ();   // RX0 reads the incoming data from XBEE

// and now what i do is this kind of method:
if ( c == 'A' ){
// action for A

}

if ( c== 'Y') {         // an Y axis has been pressed
int i = Serial.read ();   // i want to get the data coming right after that, in order to use it for a proportionnal answer:
// action for Y for example:
myMotorRight.write ( i );
myServo.write(i); // etc..
}

} // end processData


So, what do you think of my method?
the main problems i get are:
motors turn on well ( for example i can turn a specific motor only) but sometimes wont stop;
right now, i'm not able to get a motor answering to the integer i= serial.read () right after my char c= serial.read() indicating an Y has been pressed; may be a problem of delays; using only integers might be a solution

i tryed to replace the "if's" by "while's" but once i get a keyPressed or a stick actionned, the answering action is done but does not stop anymore
do you think i should insert some Serial.available or some serial.flush() ?? ( i tried but didnt change anything )
do you think sending only integers ( and not char then integer ) would be more efficient?


_____
i also sometimes get other kind of weird trouble:
for example yesterday afternoon i've been testing my protocols for turning the UAV, landing,lifting ( that is simply actionnate a certain motor and not another, throttle on a certain motor and brake on another etc.. ) and i managed to get some results with problems mentionned above.
and today as i turn everything back on power, cannot manage to recieve a single data via the XBEEs ( i got a lot of them, i often test them, they detect each other, the "sending data" xbee is working, but it seems sometimes the receiving one doesn't...
 smiley-roll-blue  smiley-roll-blue

i need some new ideas coming from efficient brains   smiley-eek-blue




_______ double POST PB, delete one please
Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 988
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This code will read the serial port even if there aren't characters waiting to be read:
Code:
processData (){
char c = Serial.read ();   // RX0 reads the incoming data from XBEE
You need to wait for Serial.available() to be >0 (really, >= the number of characters you expect), before reading data from the serial port, or all you will get is the -1 that Serial.read() returns when there is no serial data waiting to be read.

Same for the Serial.read() below if (c == 'Y').

This might explain some of the funky behavior you're seeing.

-br

Edit: fix typo.
« Last Edit: February 23, 2013, 07:04:26 am by billroy » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok thanks for your help i think this is exactly what i need
so to make sure:

if i type :  if ( Serial.available > 0 ) {
//do something
}
this action will take place if Serial receives anything

if i type: if ( Serial.available > 3 ) {
// do something
}
this action will only occur if i've received at least 4 data?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49092
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
so to make sure:
Yes and yes.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

THANKS to your advice i managed getting the very exact result i wanted; that is controlling any kind of robot with my processing code.

I still have a little trouble which i didn't expect:

on the processing side i got things like that:    XBEESerial.write ( data ) ;       // data is the converted value (*100) i get from my sticks
and data ranges from 0 to 999.

on the arduino side i got this:        int data = Serial.read() ; println ( data );

so i expected to see integers come out, but what is weird is that data i get ( after processing sending and xbee reception) only ranges from 0 to 258
which is cool but as not relevant as i want it to be. Because on the processing side i managed to write something coverting the data to an accurate range, and expected to use it on the arduino.

Any ideas? ( i tried coding   " long data = Serial.read();"  but still got the same pb  smiley-roll )

thanks for your help,  i still almost succeeded to my first very cool application  smiley-mr-green
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49092
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
on the processing side i got things like that:    XBEESerial.write ( data ) ;       // data is the converted value (*100) i get from my sticks
and data ranges from 0 to 999.
So, the Processing side is sending "0" or "135" or "999".

Quote
on the arduino side i got this:        int data = Serial.read() ; println ( data );
And you are reading one of the characters that Processing sent, in the cases where it sent more than one. In no case is the Processing application sending any kind of separator between the values.

In the serial buffer, you might find "1458328543". Does that represent 14, 583, 28, 543 or does it represent 145, 83, 285, 43? Or, does it represent some other set of values?

Quote
i tried coding   " long data = Serial.read();"  but still got the same pb
Of course, because a byte fit in an int. There was no reason to use a bigger moving van to hold the marble.
« Last Edit: February 25, 2013, 01:45:15 pm by PaulS » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry but it may not be  difficult on a technical side, but we need to be accurate on words:

In the serial buffer, you might find "1458328543". Does that represent 14, 583, 28, 543 or does it represent 145, 83, 285, 43? Or, does it represent some other set of values?
Of course, because a byte fit in an int. There was no reason to use a bigger moving van to hold the marble.

ok so if i got your right, the serial buffer has every data comming from processing without any space in between.
so i need to find a solution, using functions like  serial.ReadBytesUntil() or anything else.

The first idea i come with is: 
i set a little Timeout on the arduino serial side, so that it does not search in the buffer for too long, and i try to be very accurate on both side ( processing/arduino concerning the timing)
on the arduino serial again, i use  serial.ReadBytesUntil(character, buffer, length)    (character to find, length will be "3" as i want integer like 100,999, am i right? ; still don't see how i have to declare the "buffer" )

*****on my processing sketch****
( the problem only concerns sending data depending of the sticks, as i would like to use this to have a proportionnal answer )
everytime a stick is pressed i write to the xbee something like ('Y') for instance

 if ((FloatToInt ( ValYLeft ) < - 150 )){                 Val Y left is the value got from the Y Stick, and 150 is the value of security so that i do not
   println( FloatToInt( -ValYLeft ));                      continously send this value.  "FloatToInt" is my converting program for the serial process
   XBeeSerial.write ('y');                       // by writing an y i indicate the next data concerns an Y axis
   delay(10);
   XBeeSerial.write('p');          // that's the only way i found to indicate it's gonna be a positive Y axis, which means on the arduino side, we will
   delay(10);                        // have to wait again for another char
   XBeeSerial.write ( FloatToInt ( -ValYLeft ) ) ;    // this is the value coresponding to the pressed stick i would like to read on the arduino
   delay(50);
 }


***on the arduino side***

if ( c == 'y' ){                      //remember  char c = Serial.read();
    Serial.println("y stick");            // this works everytime
    delay(10);
    c = Serial.read();   

   
    if ( c == 'p'){                       // it's gonna be a positive y axis
        data = Serial.read ();       
        Serial.println( " Y Up: "+data);      //this does not work
        // do something
       }
     
       
     if ( c == 'n' )  {                         // a negative one
        data = Serial.read ();
        Serial.println("Y Down: "+data );        //this does not work
        // do something
       }
     } // end of process for Y axis
   

To solve it i thought adding another char 's'  that would represent the end of processing-xbee sending data
for instance:

 if ((FloatToInt ( ValYLeft ) < - 150 )){                 
   println( FloatToInt( -ValYLeft ));                     
   XBeeSerial.write ('y');                       
   delay(10);
   XBeeSerial.write('p');         
   delay(10);                       
   XBeeSerial.write ( FloatToInt ( -ValYLeft ) ) ;
  delay(10);
  XBeeSerial.write('s');  // i'm adding this so the arduino can see where it ends
  delay(50);
 }

and on the arduino side i use ReadBytesUnil ( s , buffer , 3 ) ; 's' is the char causing the stop; 3 is the length ( integers from 150 to 999 );
but still don't see how you would declare buffer
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 611
Posts: 49092
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
ok so if i got your right, the serial buffer has every data comming from processing without any space in between.
Technically, it is "without any delimiter in between". The delimiter can be a space, a comma, a carriage return, or any other non-digit character that you want to use.

Quote
so i need to find a solution, using functions like  serial.ReadBytesUntil() or anything else.
You need to find a solution. It does not need to involve a blocking method like readBytesUntil().

It could be code like below that reads and stores data, starting when a start marker (<) arrives, and triggering the use of the data only when the end marker (>) arrives:
                                                                                                                   
Code:
#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Where it says "Process the packet", you could use strtok() and atoi() to do the processing, if you use a delimiter between the values that is different from the delimiter(s) between the packets.

Quote
The first idea i come with is:
i set a little Timeout on the arduino serial side, so that it does not search in the buffer for too long
Not necessary, as you can see above.

Quote
on the arduino serial again, i use  serial.ReadBytesUntil(character, buffer, length)    (character to find, length will be "3" as i want integer like 100,999, am i right? ; still don't see how i have to declare the "buffer" )
Length will not be "3". It might me 3. Huge difference. You'd declare buffer just like declared inData above.

Comments can go before a block of code. It is not necessary to tell a story next to the code. In fact it is annoying to try to follow code AND comments that way. If a story is necessary, and I'm not arguing that you shouldn't tell a story (even if it is only to yourself), put it before the code.
Logged

Pages: [1]   Go Up
Jump to: