processing2arduino - parsing serial stream

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

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;

// 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);

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

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;
}

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); } }

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

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

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.

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

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

Oh, and thanks for the beer :)

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

Hi C5,

Thanks for sharing, have fun!