sending 3 values from processing to arduino ?

hello guys

i have a project in mind, its simply an RGB led that simulate the color of any pixels in a specefic image.

it goas as folowing :

1 - picking the color of any pixel in an image by processing

2 - send the RGB values to arduino.

3 - receiving the values by arduino and apply it to the RGB led using analogWrite .

but iam having a problem in sending and receving the values

the problems :

1 - the RGB values that been send via the serial port are wrong and some in minus sign (i checked it
with println)

2 - the RGB doesn't seem to light any color but the greenish ones and also the wrong green
no bluish no redish.

the processing code :

import processing.serial.*;
Serial port;


PImage img;

void setup() {
  size(580, 695);
  port = new Serial(this, Serial.list()[1], 9600);
  img = loadImage("lizard.jpg");
}

void draw() {
  image(img, 0, 0);
  img.loadPixels();
  color c = get(mouseX, mouseY);
  float r  = red(c);
  float g  = green(c);
  float b  = blue(c);
  byte out[] = new byte[3];
  out[0] = byte(r);
  out[1] = byte(g);
  out[2] = byte(b);
  port.write(out);

  println(out);

  fill(r, g, b);
  noStroke();

  rect(20, 20, 50, 50);
  fill(255);
  text(r, 20, 250);

  text(g, 20, 270);

  text(b, 20, 290);
}

the arduino code :

int curvalue = 0;
int val[] = {0,0,0} ;
int r = 6;
int g = 5;
int b = 3;


void setup() {
  Serial.begin(9600);
  pinMode(r,OUTPUT);
  pinMode(g,OUTPUT);
  pinMode(b,OUTPUT);

 
}

void loop() {

  if (Serial.available() > 0){
    int incomingvalue = Serial.read();
    val[curvalue] = incomingvalue;
    curvalue++;
   
      analogWrite(r,val[0]);
      
      analogWrite(g,val[1]);
    
      analogWrite(b,val[2]);
     
      curvalue = 0;
      
     
    }
  }

}

Robin2's serial input basics thread may help you format data packets that can be received reliably.

groundFungus:
Robin2's serial input basics thread may help you format data packets that can be received reliably.

thanks,groundFungus

i tryied example 2 with some modification but still the same problem the RGB led light with just greenish
look no blush nothing .

the processing part has also some problems (the values are not acurrate and minus signs )
any help with that ?

Send your three values like this <123, 45, 678> and use the third example and the parse example.

If you can't get it to work post your Arduino program.

...R

One problem is that the red(c), green(c) and blue(c) functions (in the Processing sketch) return floats and when you try to send them as bytes the data gets messed up. Look in the Processing reference at the color data type. There is shown a way to get the color values using bit shifting that returns ints (much easier to send). Then you can send the ints (r, g, b) via port.write, in the format suggested by Robin2 with:

port.write("<" + r + "," + g + "," + b + ">");

Using the parse example in the serial input basics, recover the numbers as shown in the parse example for parsing ints (atoi).

thanks guys for helping ,

i tryied example 5 in serial basics with parsing with some modification to receive 3 floats
but didnt work (this time the led is just off) , the code :

// Example 5 - Receive with start- and end-markers combined with parsing

const byte numChars = 3;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int r = 3;
int g = 5;
int b = 6;

float value1 = 0;
float value2 = 0;
float value3 = 0;
//float floatFromPC = 0.0;

boolean newData = false;

//============

void setup() {
    Serial.begin(9600);
    pinMode(r,OUTPUT);
  pinMode(g,OUTPUT);
  pinMode(b,OUTPUT);
    /*Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
    Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
    Serial.println();
    */
}

//============

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

   /* strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 */
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    int1 = atof(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    int2 = atof(strtokIndx);     // convert this part to a float

     strtokIndx = strtok(NULL, ",");
    int3 = atof(strtokIndx); 
}

//============

void showParsedData() {
  
    
    analogWrite(r,value1);
     analogWrite(g,value2);
      analogWrite(b,value3);
    
}

and the processing code :

import processing.serial.*;
Serial port;


PImage img;

void setup() {
  size(580, 695);
  port = new Serial(this, Serial.list()[1], 9600);
  img = loadImage("gog.jpg");
}

void draw() {
  image(img, 0, 0);
  img.loadPixels();
  color c = get(mouseX, mouseY);
  float r  = red(c);
  float g  = green(c);
  float b  = blue(c);
 /* byte out[] = new byte[3];
  out[0] = byte(r);
  out[1] = byte(g);
  out[2] = byte(b);
  */
port.write("<" + r + "," + g + "," + b + ">");


 println(r);

  


  fill(r, g, b);
  noStroke();

  rect(20, 20, 50, 50);
  fill(255);
  text(r, 20, 250);

  text(g, 20, 270);

  text(b, 20, 290);
}

i have a little hard time understanding bit shifting value >> n what the n represent ?!
is it the seperation distance between the values or what ?

the example in the processing page is not so clear to me

int m = 8 >> 3; // In binary: 1000 to 1
println(m); // Prints "1"
int n = 256 >> 6; // In binary: 100000000 to 100
println(n); // Prints "4"

I can't imagine why you decided to use the name int1 for a floating point variable - but the compiler won't care.

What the compiler will care about is the fact that you have not declared the variable int1 before trying to use it

 int1 = atof(strtokIndx);

You need to add this at the top of the program

float int1;
float int2;
float int3;

But it would make your program more understandable if you had

float redValue;
float blueValue;
float greenValue;

And it would be more practical if you change your Processing program so that it sends integer values as that is what will be needed by the Arduino. And in that case the best solution would be

int redValue;
int blueValue;
int greenValue;

and then you parse code would use atoi() rather than atof()

...R

Here is the Processing code modified to use the bit shift and sending integers in packet format.

void draw() {
  image(img, 0, 0);
  img.loadPixels();

  color c = get(mouseX, mouseY);
  int r = (c >> 16) & 0xFF;  // Faster way of getting red(c)
  int g = (c >> 8) & 0xFF;   // Faster way of getting green(c)
  int b = c & 0xFF;          // Faster way of getting blue(c)

  port.write("<" + r + "," + g + "," + b + ">");


  println("red " + r + " green " + g + " blue " + b);

  fill(r, g, b);
  noStroke();

  rect(20, 20, 50, 50);
  fill(255);
  text(r, 20, 250);

  text(g, 20, 270);

  text(b, 20, 290);
  delay(200);  //  added so as not to flood the serial port.
}[code]

[/code]

Robin2:
I can't imagine why you decided to use the name int1 for a floating point variable - but the compiler won't care.

What the compiler will care about is the fact that you have not declared the variable int1 before trying to use it

 int1 = atof(strtokIndx);

You need to add this at the top of the program

float int1;

float int2;
float int3;




But it would make your program more understandable if you had


float redValue;
float blueValue;
float greenValue;






And it would be more practical if you change your Processing program so that it sends integer values as that is what will be needed by the Arduino. And in that case the best solution would be


int redValue;
int blueValue;
int greenValue;



and then you parse code would use atoi() rather than atof()

...R

thanks Robin2 , i acttualy had declared the ints(1,2,3) (the float variables ! ) i just used the first very short names came up to my mind :slight_smile: didnt have time , put i changed it to glopal variables values(1,2,3) just to post it in the fourm so it doesnt look stupid,

and forgot to change it in the void function so all that was just a typing mistake .sorry about that

i will change the parse code to atoi , and test it ...

groundFungus:
Here is the Processing code modified to use the bit shift and sending integers in packet format.

void draw() {

image(img, 0, 0);
  img.loadPixels();

color c = get(mouseX, mouseY);
  int r = (c >> 16) & 0xFF;  // Faster way of getting red(c)
  int g = (c >> 8) & 0xFF;  // Faster way of getting green(c)
  int b = c & 0xFF;          // Faster way of getting blue(c)

port.write("<" + r + "," + g + "," + b + ">");

println("red " + r + " green " + g + " blue " + b);

fill(r, g, b);
  noStroke();

rect(20, 20, 50, 50);
  fill(255);
  text(r, 20, 250);

text(g, 20, 270);

text(b, 20, 290);
  delay(200);  //  added so as not to flood the serial port.
}[code]


[/code]

thank you groundFungus ,

it seems to work well in processing , it geting the right value over the serial port.

but when i tested it with the arduino code in previos comment (example 5)
the RGB dont light up at all , nothing !

Can you post your receiver code again? The modified example 5 you showed in reply 5 has some obvious errors such as the parser updates different variables to the ones you use in showData().

Can you also show an example of the serial data it actually gets?

Yes, please post your latest Arduino code.

MorganS:
Can you post your receiver code again? The modified example 5 you showed in reply 5 has some obvious errors such as the parser updates different variables to the ones you use in showData().

Can you also show an example of the serial data it actually gets?

// Example 5 - Receive with start- and end-markers combined with parsing

const byte numChars = 3;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int r = 3;
int g = 5;
int b = 6;

int value1 = 0;
int value2 = 0;
int value3 = 0;
//float floatFromPC = 0.0;

boolean newData = false;

//============

void setup() {
    Serial.begin(9600);
    pinMode(r,OUTPUT);
  pinMode(g,OUTPUT);
  pinMode(b,OUTPUT);
    /*Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
    Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
    Serial.println();
    */
}

//============

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

   /* strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 */
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    value1 = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    value2 = atoi(strtokIndx);     // convert this part to a float

     strtokIndx = strtok(NULL, ",");
    value3 = atoi(strtokIndx); 
}

//============

void showParsedData() {
  
    
    analogWrite(r,value1);
     analogWrite(g,value2);
      analogWrite(b,value3);
    
}

how would i get the data that the arduino acttualy gets ? you mean the data that been sent by prcessing
by println ! .

or by the arduino serial monitor ! ( i cant open the serial monitor while the processing skech still on )

is there another way ?

const byte numChars = 3;

You are receiving more than 3 characters, <123,213,244> is like what you receive, so you need at least 14 (13 + one for NULL).

void parseData() // split the data into its parts
{
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
 
  //strtokIndx = strtok(NULL, ",");
  value1 = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  value2 = atoi(strtokIndx);     // convert this part to a float

  strtokIndx = strtok(NULL, ",");
  value3 = atoi(strtokIndx);
}

Here is the corrected parseData function. You had commented out the line that tells strtok where to look for the data (tempChars). compiles and works on my Uno.

const byte numChars = 3;

The examples, as written, have that set to 32 bytes. Why change it? Always have it a bit bigger than you need.

As a general rule, when working with example programs don't change anything unless the change is essential. When you have it working you can consider tidying things up.

...R

groundFungus:

const byte numChars = 3;

You are receiving more than 3 characters, <123,213,244> is like what you receive, so you need at least 14 (13 + one for NULL).

void parseData() // split the data into its parts

{
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars, ",");    // get the first part - the string

//strtokIndx = strtok(NULL, ",");
  value1 = atoi(strtokIndx);    // convert this part to an integer

strtokIndx = strtok(NULL, ",");
  value2 = atoi(strtokIndx);    // convert this part to a float

strtokIndx = strtok(NULL, ",");
  value3 = atoi(strtokIndx);
}




Here is the corrected parseData function. You had commented out the line that tells strtok where to look for the data (tempChars). compiles and works on my Uno.

thanks groundFungus , it worked but there is another little problem

the RGB dosent seem to match the color on the image , it seems very shifted and i dont think its a RGB led
fault !?

is there is a way to see the data received by the arduino ? i cant use serial monitor .

I used an LCD when testing with data coming from Processing. What you can do is: make sure that the processing program is not using the serial port so then you can use the serial monitor. Put serial prints where you want to check values. Type into the serial monitor send line the data that would be output form Processing (<r,g,b>) and send. See if the serial prints match what you entered. Before you run the Processing app again, comment or remove the serial prints.

This is my serial test code for illustration. My variable names are different so you can't just paste it.

void loop()
{
  recvWithStartEndMarkers();
  if (newData == true)
  {
    Serial.print("Received");
    Serial.println(receivedChars);
    strcpy(tempChars, receivedChars);
    parseData();
    showParsedData();
    newData = false;
    /*
      lcd.clear();
      lcd.print("R ");
      lcd.print(red);
      lcd.print(" G ");
      lcd.print(green);
      lcd.print(" B ");
      lcd.print(blue);
    */
  }
}


void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false)
  {
    rc = Serial.read();

    if (recvInProgress == true)
    {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars)
        {
          ndx = numChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

void parseData()
{
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars, ",");
  red =  atoi(strtokIndx);
  strtokIndx = strtok(NULL, ",");
  green = atoi(strtokIndx);
  strtokIndx = strtok(NULL, ",");
  blue = atoi(strtokIndx);
}

//============

void showParsedData()
{
  Serial.print("red ");
  Serial.println(red);
  Serial.print("green ");
  Serial.println(green);
  Serial.print("blue ");
  Serial.println(blue);

}

In addition to what @groundFungus has said it can be very useful to include in your PC program (the Processing program) th ability to view debug messages from the Arduino.

...R