Go Down

Topic: processing2arduino - parsing serial stream (Read 1 time) previous topic - next topic

C5

Hello everyone,

I built an application to control a servo motor with moue movements. I mapped X coords to angle of servo motor. Now I want to add Y coords to control another servo motor, and I need a way to parse the serial stream on arduino, in order to distingush what is what.

Any pointer will do....
thanks

C5

mem

#1
Jan 08, 2008, 06:55 pm Last Edit: Jan 08, 2008, 07:08 pm by mem Reason: 1
There are lots of ways do to what you want. I assume your x and y values are 16 bit integers. The app I am currently working sends and receives binary packets, so I have distilled the following which may be useful.  
Usage: if(SerialInput() == 'x')
               // do something with xValue;

Code: [Select]

// the routine below expect 3 bytes:
// tag - 'x' or 'y' to indicate the meaning of the following value
// msb - the most significant byte of the value
// lsb - lsb of the value
//
// you can define other tags if other more data needs to be sent, but the code below //always expects  exactly two bytes after each tag.

int xValue;
int yValue;


char SerialInput() {
 // returns 'x' if x value received, 'y' if y value, or 0 if nothing

  if(Serial.available() >= 3 ){
         uint8_t      tag = Serial.read();  
         uint8_t      msb = Serial.read();
         uint8_t      lsb = Serial.read();
         unsigned int value = lsb + (msb <<8);
         
         switch(tag) {
            case 'x' : xValue = value; break;         // save the value in the global variable
            case 'y' : yValue = value; break;
            default  : tag = 0;   //not a valid tag
         }
         return tag;  
  }
  return 0;
}


I haven't used processing, but would think the sending code would look something like the following.
Example usage: SendMessage('x', 300);
Code: [Select]

void SendMessage(char tag, int value) {
  Serial.write(tag,byte);
  Serial.write(value >>8 ,byte);
  Serial.write( (byte)value) ;  
}

C5

#2
Jan 09, 2008, 11:57 am Last Edit: Jan 09, 2008, 11:58 am by C5 Reason: 1
Thanks for your reply mem,

I tryed to use your code on arduine, and just to fetch data from serial send command integrated in arduino, and then to print teh results, but I couldn't manage to do it.
Can you help on this one?

This is what is on arduino:

Code:

int xValue;
int yValue;


void setup() {
Serial.begin(9600);
}

void loop() {

 SerialInput();

 }

char SerialInput() {
 // returns 'x' if x value received, 'y' if y value, or 0 if nothing

  if(Serial.available() >= 3 ){
         uint8_t      tag = Serial.read();  
         uint8_t      msb = Serial.read();
         uint8_t      lsb = Serial.read();
         unsigned int value = lsb + (msb <<8);
         
         switch(tag) {
            case 'x' : xValue = value; break;         // save the value in the global variable
            case 'y' : yValue = value; break;
            default  : tag = 0;   //not a valid tag
         }
         return tag;  
        Serial.println(xValue);
        Serial.println(yValue);
  }
  return 0;
}



mem

#3
Jan 09, 2008, 01:40 pm Last Edit: Jan 09, 2008, 01:49 pm by mem Reason: 1
The routine returns just before you print the values so they are never sent.

You can fix it as follows:
   Before the if(Serial.available() >= 3 ){ statement, add the statment: tag=0 ;
   move the return tag; statement to the end of the routine in place of the return 0;

The posted code would also work if you put the return tag statement after the print statements but the above is clearer.  

When I posted I was thinking that your code would do something like

loop() {
  if(SerialInput() ) {
       Serial.println(xValue);
       Serial.println(yValue);
  }  
}

C5

Hello mem,

I can say that something is going on, but it is not clear what.

I'm still trying to control my servo from the arduino serial monitor send command.

The data that arduino is expecting are from 0 to 1023 for x and from 0 to 255 for y, in command like this SendComm("x"+mouseXcoords+"y"+mouseYcoord+/n);
Where I will have for example if the cursor is in the middle,
stream = x512y128
and so on...

To achive this, should I modify your code to do something like this:
if SerialInput == x
read the stream untill SerialInput == y
this input = xValue
else if SerialInput == y
read the stream until /n
this input = yValue

Or do you have any other clue regarding the data types, and teh protocol...

Thanks

C5

mem

#5
Jan 09, 2008, 05:12 pm Last Edit: Jan 09, 2008, 05:30 pm by mem Reason: 1
if you are sending the x and y data together then you can simplify the code.  The following assumes 'x' as a header and then both x and y as 16 bit values using two bytes each.  The msb of y will always be zero for now but if your mouse hardware changes you won't have to change the protocol

Code: [Select]
int xValue,yValue;

boolean SerialInput() {
 // returns true if valid data received, global x & y variables are updated
 // packets start with the char 'x' and include x and y co-ords
// protocol consists of 5 bytes  'x', xmsb, xlsb, ymsb, ylsb

  boolean result = false ;                // default return code if we dont get a valid packet
  if(Serial.available() >= 5 ){  
        if( Serial.read() == 'x'){  // if true this the start of a packet???                  
           uint8_t      msb = Serial.read();   // get the x data
           uint8_t      lsb = Serial.read();
           xValue = lsb + (msb <<8);           // save the x data
           msb = Serial.read();               // get the y data  
           lsb = Serial.read();
           yValue = lsb + (msb <<8);
           result = true;                      // we have a packet and have updated the global variables
        }
  }    
  return result;
}


I am assuming you are using processing and that write(byte) will send a raw byte,

Assuming X and Y are the integer values of the mouse, the protocol assumes  something like:

send('x');
send ((byte)(X / 256));
send ((byte)(X % 256));    //  X mod 256
send((byte)(Y/ 256));
send ((byte)(Y % 256));

If you are using Processing and that doesn't send raw data then we may need a whole new protocol.
BTW, I think Processing needs those casts so it knows that the data is a byte, but I have not actually used Processing myself so am not really sure.

C5

mem,

It works, thanks A LOT.

it still needs some fine tuning, but it works. I don't know whay I was complicating it here......

anyway, i'm glad we finished it...I owe you a beer...minimum ;)


C5

mem

Good to hear its working. Have fun. Post the results when you have it finished

Oh, and thanks for the beer  :)

C5

Hello mem,

its been awhile and i forgot to post my code.

here is for future reference, the code works really good, and its super fast.
i implemented some stuff if for example you turn off the system i want my camera calibrated, and some more that i forgot, go tru the code and see for yourself, the messge expected is "X123" if you want X axix and 123 value

cheers

thanks

int servoPinX = 2;     // control pin for X servo motor
int minPulseX = 500;   // minimum servo position
int maxPulseX = 2500;  // maximum servo position
int pulseX = 0;        // amount to pulse the servo

int inputX = 0;
int inputY = 0;

long lastPulseX = 0;    // the time in milliseconds of the last pulse
int refreshTimeX = 20; // the time needed in between pulses

int analogValueX = 0;

int servoPinY = 3;     // control pin for Y servo motor
int minPulseY = 500;   // minimum servo position
int maxPulseY = 2500;  // maximum servo position
int pulseY = 0;        // amount to pulse the servo


long lastPulseY = 0;    // the time in milliseconds of the last pulse
int refreshTimeY = 20; // the time needed in between pulses

int analogValueY = 0;

int xValue = 128;
int yValue = 64;

int input = 0;

void setup() {
   pinMode(servoPinX, OUTPUT); // Set X servo pin as an output pin
   pinMode(servoPinY, OUTPUT); // Set Y servo pin as an output pin
   pulseX = minPulseX; // Set the X motor position value to the minimum
   pulseY = minPulseY; // Set the Y motor position value to the minimum

   Serial.begin(9600); //begin serial communication

}

void loop() {

   char in = SerialInput();

   if(in == 'x'){ //if X received...
       inputX = xValue;

       analogValueX = (inputX*4);      // read the analog input
       pulseX = (analogValueX * 19) / 10 + minPulseX;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseX >= refreshTimeX) {
           digitalWrite(servoPinX, HIGH);   // turn the motor on
           delayMicroseconds(pulseX);       // length of the pulse sets the motor position
           digitalWrite(servoPinX, LOW);    // turn the motor off
           lastPulseX = millis();           // save the time of the last pulse
       }
   }
   else if(in == 'y'){
       inputY = yValue;

       analogValueY = (inputY*4);      // read the analog input
       pulseY = (analogValueY * 19) / 10 + minPulseY;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseY >= refreshTimeY) {
           digitalWrite(servoPinY, HIGH);   // turn the motor on
           delayMicroseconds(pulseY);       // length of the pulse sets the motor position
           digitalWrite(servoPinY, LOW);    // turn the motor off
           lastPulseY = millis();           // save the time of the last pulse
       }
   }
   else if(in == '0'){
       int inX = 128;

       analogValueX = (inX*4);      // read the analog input
       pulseX = (analogValueX * 19) / 10 + minPulseX;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseX >= refreshTimeX) {
           digitalWrite(servoPinX, HIGH);   // turn the motor on
           delayMicroseconds(pulseX);       // length of the pulse sets the motor position
           digitalWrite(servoPinX, LOW);    // turn the motor off
           lastPulseX = millis();           // save the time of the last pulse
       }

       int inY = 64;

       analogValueY = (inY*4);      // read the analog input
       pulseY = (analogValueY * 19) / 10 + minPulseY;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseY >= refreshTimeY) {
           digitalWrite(servoPinY, HIGH);   // turn the motor on
           delayMicroseconds(pulseY);       // length of the pulse sets the motor position
           digitalWrite(servoPinY, LOW);    // turn the motor off
           lastPulseY = millis();           // save the time of the last pulse
       }

   }
   else if(! Serial.available()){
       inputX = xValue;

       analogValueX = (inputX*4);      // read the analog input
       pulseX = (analogValueX * 19) / 10 + minPulseX;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseX >= refreshTimeX) {
           digitalWrite(servoPinX, HIGH);   // turn the motor on
           delayMicroseconds(pulseX);       // length of the pulse sets the motor position
           digitalWrite(servoPinX, LOW);    // turn the motor off
           lastPulseX = millis();           // save the time of the last pulse
       }
       inputY = yValue;

       analogValueY = (inputY*4);      // read the analog input
       pulseY = (analogValueY * 19) / 10 + minPulseY;    // convert the analog value
       // to a range between minPulse
       // and maxPulse.

       // pulse the servo again if rhe refresh time (20 ms) have passed:
       if (millis() - lastPulseY >= refres

mem


Go Up