Displayduino control via Serial

Hello, I am new to arduino and have some basic understanding of the language but have been running into some problems with the serial.read function.
I am using the Displayduino (http://mondomatrix.com/info/?page_id=311) to control a matrix of 80 RGB leds. The leds are connected to LEDmatrix boards (http://mondomatrix.com/info/?page_id=317) which are controlled by the Displayduino through an RS485 network. The Displayduino uses arduino programing to change individual rgb values for each led on each board of leds (changeLED(board,led,r,g,b). I am trying to communicate to the displayduino via usb serial to change the color values live using Max/Msp. Using this tutorial (Trossen Robotics Community Database Error) I have written my own function in arduino to take the values from serial and input them into the changeLED function and have run into some problems. If I try to send my values they don't get separated correctly. using the serial monitor if i send 1/1/0/0/255/255/255 (1/1 to call my function and board 0 led 0 r 255 g 255 b 255) it gets separated into a jumble of values like this-

1
1
0
0
2
25
255
2
25
255
2
25
255

I am looking for some help to get these values more organized and also help to get the old values cleared out as soon as new values come in because there are going to be 5 values constantly coming in for 80 leds. i made the poor choice of going with the displayduino and it's boards and now I'm stuck with them. The mondomatrix team has not been able to offer advice so any help would be appreciated.
here's my code

#include <MatrixNet.h>
unsigned long serialdata;
int inbyte;
int board;
int led;
int red;
int green;
int blue;
MatrixNet myMatrix;
void setup()
{
  myMatrix.begin();
  Serial.begin(115200);
 
}

void loop()
{
  getSerial();
  switch(serialdata)
  {
  case 1:
    {
      //analog digital write
      getSerial();
      switch(serialdata)
      {
      case 1:
        {
          //analog write
          getSerial();
          board = serialdata;
          
          getSerial();
          led = serialdata;
          
          getSerial();
          red = serialdata;
          
          getSerial();
          green = serialdata;
          
          getSerial();
          blue = serialdata;
          
          myMatrix.changeLED(board, led, red, green, blue);
         
          break;
         
         }
      
     }

      break;
    }
  }
}

long getSerial()
{
  serialdata = 0;
  while (inbyte != '/')
  {
    inbyte = Serial.read(); 
    if (inbyte > 0 && inbyte != '/')
    {
     
      serialdata = serialdata * 10 + inbyte - '0';
      Serial.println(serialdata);
      
     }

  }
  inbyte = 0;
  return serialdata;
 
}

I would say you should be sending:
001/001/000/000/255/255/255

instead of:
1/1/0/0/255/255/255

That should work more natively. You can always use the read and write instead of sending string. Also be sure to flush your buffers after reading.

-Alex

You're printing the value for every character received. Move the Serial.print outside the while loop.

get the old values cleared out

That's automatic, you're overwriting them in getSerial().

Note that this code is prone to getting out of sync if you miss a character or come in half way through a sequence.


Rob

thanks for the quick help! using three numbers for each value seems to work! i also had to add a / after the last number to signify the end of that number.
is there an easier way to do this? just curious. I am having trouble sending "/" through the serial object in max.
thanks again for the help.

If you're always sending 3 chars per number then technically there's no need for a delimiter, still no point changing things.

I'd replace

getSerial();
red = serialdata;

with

red = getSerial();

just looks neater but won't have any real affect on performance.

is there an easier way to do this?

There are other ways but I'm not sure in this case it's worth persuing them. For example you could just send 7 binary values plus a delimiter, that way you just have

byte data[5];

if (Serial.available()) {
   if (Serial.read() == 'x') // ignore data until the delimiter
      for (int i = 0, i < 5; i++)
         data[i] Serial.read();
}

switch (data[0]) { // switch on the board #
// etc etc
// it's not clear what you are doing with the data
}

The only thing here is selecting the delimiter value as (presumably) all values are valid data. Maybe use 255 and limit the colours to 0-254. Or don't bother with a delimiter but then you can get out of phase if you miss a character.


Rob

graynomad thank you for the help but the serial object in max/msp just doesnt cut it for me. i am now trying to use processing to communicate with the displayduino via serial. are you familiar with processing? I want to capture video at a resolution of 8x10 and get the rgb value for each pixel and be able to send it out of processing to the displayduino. the format would have to be (ledboard, lednumber, r, g, b). i am having trouble with turning the "pixels" array into my lednumber. if you are familiar with processing i can post the sketchy code i have come up with.

if you are familiar with processing i can post the sketchy code i have come up with.

Others of us are. Post your code.

i am having trouble with turning the "pixels" array into my lednumber.

You can't turn an array into a number. The index into the pixels array is related to the led number. The pixels array is a 2D array, though, so the relationship is not linear.

sorry paul, just new to the forum posting thing, forgot anyone can read this.
i am using the Jmyron library here.

////processing code/////
import JMyron.*;

JMyron theMov;
import processing.serial.*;
Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port 

void setup() {
  size(8, 10);

  
  theMov = new JMyron();
  theMov.start(width, height);
  theMov.findGlobs(0);


noStroke();
 //Serial ports for transmission to Arduino 
 String portName = Serial.list()[0];
 myPort = new Serial(this, portName, 115200);
}


void draw() {
  theMov.update();
  int[] currFrame = theMov.image();

  // draw each pixel to the screen
  loadPixels();
  for (int i = 0; i < width*height; i++) {
    float r = red(currFrame[i]);
    float g = green(currFrame[i]);
    float b = blue(currFrame[i]);

    pixels[i] = color(r,g,b);
  setRGB(red(currFrame[0]),blue(currFrame[0]),green(currFrame[0]));  //to set the rgb values for the first led in my grid?
  }
  updatePixels();

}
void setRGB (float r, float g, float b)  {
 myPort.write('D');      //board
 myPort.write(int(0));
 myPort.write('L');      //led 
 myPort.write(int(0));
 myPort.write('R');      //red
 myPort.write(int(r));
 myPort.write('G');      //green
 myPort.write(int(g));
 myPort.write('B');      //blue
 myPort.write(int(b));
 
 
 }
public void stop() {
  theMov.stop();
  super.stop();
}

///arduino code///
#include <MatrixNet.h>
char processing;          // Variable to store data received from serial port via processing
int board;
int led;
int red;
int green;
int blue; // Variables to store 

MatrixNet myMatrix;
void setup() 
{  myMatrix.begin();
 Serial.begin(115200); // Start serial communication at 115200 bps
} 

void loop() 
{ 

 if (Serial.available()>0) { 
  // If data is available to read,
   processing = Serial.read();    // read it and store it in processing variable

    if (processing == 'D') board=Serial.read();
    if (processing == 'L') led=Serial.read();
    if (processing == 'R') red=Serial.read();
    if (processing == 'G') green=Serial.read();
    if (processing == 'B') blue=Serial.read();
     
    myMatrix.changeLED(int(board),int(led),int(red),int(blue),int(green)); //the final command to change each led
 }

}

i am new to processing so any help would be appreciated

  setRGB(red(currFrame[0]),blue(currFrame[0]),green(currFrame[0]));  //to set the rgb values for the first led in my grid?

Why are you calling this width * height times, in the loop?

If you call this in the loop, the value in the [] should be i, and i should be passed as an argument, too. It defines which LED to light up.

i am not sure why i am calling that in the loop. so if I change the 0 to i in that setRGB part and plug in

myPort.write(int(i));
myPort.write('L');      //led

it should work?

it should work?

Your the one with the hardware...

i am still having trouble. this is what it looks like now. no leds are changing but something is traveling over usb.

import JMyron.*;

JMyron theMov;
import processing.serial.*;
Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port 

void setup() {
  size(8, 10);

  
  theMov = new JMyron();
  theMov.start(width, height);
  theMov.findGlobs(0);


noStroke();
 //Serial ports for transmission to Arduino 
 String portName = Serial.list()[0];
 myPort = new Serial(this, portName, 115200);
}


void draw() {
  theMov.update();
  int[] currFrame = theMov.image();

  // draw each pixel to the screen
  loadPixels();
  for (int i = 0; i < width*height; i++) {
    float r = red(currFrame[i]);
    float g = green(currFrame[i]);
    float b = blue(currFrame[i]);

    pixels[i] = color(r,g,b);
setRGB(int(i),red(currFrame[i]),blue(currFrame[i]),green(currFrame[i]));
  }
  updatePixels();

}
void setRGB (float i, float r, float g, float b)  {
 
 myPort.write('D');      //board
 myPort.write(int(0));
 myPort.write('L');      //led 
 myPort.write(int(i));
 myPort.write('R');      //red
 myPort.write(int(r));
 myPort.write('G');      //green
 myPort.write(int(g));
 myPort.write('B');      //blue
 myPort.write(int(b));
 
 
 }
public void stop() {
  theMov.stop();
  super.stop();
}
if (Serial.available()>0) { 
  // If data is available to read,
   processing = Serial.read();    // read it and store it in processing variable

    if (processing == 'D') board=Serial.read();
    if (processing == 'L') led=Serial.read();
    if (processing == 'R') red=Serial.read();
    if (processing == 'G') green=Serial.read();
    if (processing == 'B') blue=Serial.read();

If there is at least 1 byte available to read, read 2 bytes. Generally not a good idea. Wait for there to be 2 or more bytes available.

If there is only one byte available, the processing directive, the 2nd Serial.read() will return -1.

In the Processing sketch, how is red() defined? Does it really return a float? What is the range of values returned? 0 to 1? Or 0 to 255?

in processing i printed out each value and all seems correct. i gives me 0-79 r g and b give me 0-255. how should i change my arduino code to read these bytes correctly?

nevermind i changed the serial available to >2 and it works but instead of giving each led a specific pixel to stay at (led 0 only displaying the values for led 0) it is going through each pixel and trying to display rgb values for every single pixel. in other words its scrolling through each led and trying to flash through a ton of random values really quick. this is even more apparent if i just assign one led to turn on. it flashes through tons of colors very quickly.

Since you are sending 10 values, perhaps you need to wait for all 10 values to be received, before calling the matrix function.

The Serial.available() test should involve >= 2, not > 2.

thanks for your help paul.
I wasn't sure of the best way to wait for the values to be received so I made a variable named "counter" that would count each time a pair of data came in and once the counter reached 5 to put my values into the mymatrix function. this seems to work but the displayduino cant really keep up with the constant stream of data. also the display in processing has bad lag too. any ideas on how to fix this?

////arduino code////
#include <MatrixNet.h>
char processing;          // Variable to store data received from serial port via processing
int board;
int led;
int red;
int green;
int blue; // Variables to store 
int counter;

MatrixNet myMatrix;
void setup() 
{  myMatrix.begin();
 Serial.begin(115200); // Start serial communication at 115200 bps
} 

void loop() 
{ 

    
 if (Serial.available()>=2) { 
  // If data is available to read,
   processing = Serial.read();    // read it and store it in processing variable
   counter = 0;
    if (processing == 'D') 
        board=Serial.read();
        counter++;
    if (processing == 'L')
        led=Serial.read();
        counter++;
    if (processing == 'R') 
        red=Serial.read();
        counter++;
    if (processing == 'G') 
        green=Serial.read();
        counter++;
    if (processing == 'B') 
        blue=Serial.read();
        counter++;
    if (counter == 5){
     
    
    myMatrix.changeLED(int(board),int(led),int(red),int(blue),int(green));}
     
 }

}

////processing code////




import JMyron.*;

JMyron theMov;
import processing.serial.*;
Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port 

void setup() {
  size(8, 10);

  
  theMov = new JMyron();
  theMov.start(width, height);
  theMov.findGlobs(0);


noStroke();
 //Serial ports for transmission to Arduino 
 String portName = Serial.list()[0];
 myPort = new Serial(this, portName, 115200);
}


void draw() {
  theMov.update();
  int[] currFrame = theMov.image();

  // draw each pixel to the screen
  loadPixels();
  for (int i = 0; i < width*height; i++) {
    float r = red(currFrame[i]);
    float g = green(currFrame[i]);
    float b = blue(currFrame[i]);

    pixels[i] = color(r,g,b);
setRGB(int(i),red(currFrame[i]),blue(currFrame[i]),green(currFrame[i]));
 
}
  updatePixels();

}
void setRGB (float i, float r, float g, float b)  {
 
 myPort.write('D');      //board
 myPort.write(int(0));
 myPort.write('L');      //led 
 myPort.write(int(i));
 myPort.write('R');      //red
 myPort.write(int(r));
 myPort.write('G');      //green
 myPort.write(int(g));
 myPort.write('B');      //blue
 myPort.write(int(b));
println("LED = " + (i)
  + ", R = " + (r)
  + ", G = " + (g) 
  + ", B = " + (b));
 }
public void stop() {
  theMov.stop();
  super.stop();
}

There are a few things that could be done.

Since you always send 0 for the board, stop sending the command and the value. Have the Arduino assume that the board is 0.

Since you always send 5 commands and 5 values, in the same order, stop sending the commands. Send the values, followed by an end of packet marker. The Arduino then knows what order to use the bytes, and does nothing if the end-of-packet marker arrives prematurely or late.

Doing both would cut the number of bytes sent in half:
"D0LiRrGgBb" ==> "irgb;"
(; is the end-of-packet marker)

If you plan to increase the number of boards, so that you actually have to send a board number, you are still dropping from 10 bytes to 6, for a 40% reduction in traffic.

I reduced the data being sent from processing to just the 5 values i need plus ;
in arduino i am having trouble getting these values read properly. i have the following arduino code for the serial read and it's not working, its getting data but its not being put into the function. let me know if i am horribly messing anything up here.

{ 

    
 if (Serial.available()>=2) { 
  // If data is available to read,
    
     board=Serial.read();
     led=Serial.read();
     red=Serial.read();
     green=Serial.read();
     blue=Serial.read();
   if (Serial.read() == ';'){
  myMatrix.changeLED(int(board),int(led),int(red),int(blue),int(green));}
     
 }

}

nevermind, i took my original command and value list and just added a packet marker to the end of it that would insert the values into the matrix command.
it works just fine, there is not much lag at all in the led matrix.
here is my final arduino code. thank you again paul for your help.

#include <MatrixNet.h>
char processing;
int board;
int led;
int red;
int green;
int blue; // Variables to store 


MatrixNet myMatrix;
void setup() 
{  myMatrix.begin();
 Serial.begin(115200); // Start serial communication at 115200 bps
} 

void loop() 
{ 

    
 if (Serial.available()>=2) { 
  // If data is available to read,
processing = Serial.read();
   if (processing == 'D') 
        board=Serial.read();
        
    if (processing == 'L')
        led=Serial.read();
        
    if (processing == 'R') 
        red=Serial.read();
        
    if (processing == 'G') 
        green=Serial.read();
        
    if (processing == 'B') 
        blue=Serial.read();
        

    if (processing == ';') 
  myMatrix.changeLED(int(board), int(led), int(red), int(green), int(blue));
   
 }

}