Variables, Strings, and Array

I am working on an art project for school. I have processing capturing video and converting it into an 8 x 8 matrix. As the video changes, the the color in each cell changes and sends the hex equivalent of the color to the Arduino board. The Arduino is connected to an led matrix from Sparkfun. I have never written a code this in depth and having some issues. Here’s a quick run down of what the code should do… It receives a code like this (no spaces): 0M1N FF4 73B 493P. Where the 0 is the column (M), 1 is the row (N), and FF4 73B 493 is the color in terms of red, blue, and green. It then fills the buffer. When it finds “M” in the buffer, it looks at the byte before. This is the column number. It does the same for the row. When it gets to “P” (aka, color code), it fills the color array with 8 bytes (Yes, I have to drop the LSB of the green). Finally when the main loop starts again, it sets the pixel using the RGBMatrix library.

First, I am not sure if the code will even work. The led matrix should arrive tomorrow. Second, I am getting this error. “call of overloaded ‘String(String [9], int)’ is ambiguous”. I have no clue what I’m doing. But I have a feeling, I have all sorts of problems. Thanks in advance for the help.

#include <RGB.h>
#include <RGBMatrix.h>

//Board Constants
int NUM_BOARDS = 1;

//Format of incoming data is # M # N ###### P
int b_size = 13; //Byte size of 1 cell location + color

//Set initially to zero
int row = 0;
int col = 0;
int color_temp;
String color[9] = “00000000”; //LED Color Array

char buffer[17] = “0000000000000000”; //Buffer Array

void setup()
{
RGBMatrix.begin(NUM_BOARDS); //Start the communication with the LED matrices.
Serial.begin(11500);
}

void loop()
{
//Write some values
color_temp = String(color, HEX);
RGBMatrix.fillPixel(0, row, col, color_temp);
RGBMatrix.display();

//Start reading incoming serial values to set values
while (Serial.available() > 0) {
for (int i=0; i < b_size; i++) {
buffer* = buffer[i+1];*

  • }*
    buffer[b_size] = Serial.read();
  • if (buffer[b_size] == ‘M’) {*
  • col = int(buffer[(b_size - 1)]);*
  • }*
  • if (buffer[b_size] == ‘N’) {*
  • row = int(buffer[(b_size - 1)]);*
  • }*
  • if (buffer[b_size] == ‘P’) {*
  • for (int j = 0; j < 9; j++){ //Read only 8 of the 9 hex color value*
  • color[j] = j;*
  • } *
  • }*
  • }*
    }
    [/quote]

I'm not familiar with the RGBMatrix library, so I have no idea if your code is doing what it should be doing. But I think the cause of your compilation error is this line:

 color_temp = String(color, HEX);

There is no implementation of the String constructor that uses a specified base (HEX) with a string argument(color). Just for integers and long integers: http://arduino.cc/en/Reference/StringConstructor

Thanks for the quick reply. Let me see if I understand. So I need to convert the color code into a decimal number before using the HEX option? Also, I can not use a string variable inside String. In other words… x = String(random_variable, HEX) is not legal? I guess I should be asking, what is the proper way to read from an array and make a variable from what it reads from the array? And this variable must be in a decimal from, so I can convert it into a hexadecimal number?

String color[9] = "00000000"; //LED Color Array

This is declaring an array of String objects, referred to as color. Only the first of 9 values is explicitly initialized.

      for (int j = 0; j < 9; j++){ //Read only 8 of the 9 hex color value

The variable j will take on values of 0, 1, 2, 3, 4, 5, 6, 7, and 8 as the loop is executed. Even without taking my shoes off, I can count 9 values there.

I’d recommend that you get rid of the String objects altogether. You want to be using an array of characters, not an array of string objects.

If the 9 characters before P represent a color, what does a red value of FF4 mean? The range of color values is 0 to 255 decimal or 0 to 0xFF. FF4 is NOT in that range. 73B and 493 are not, either.

Thanks Paul. I have changed that 9 to an 8. I have also gotten rid of the String array and replaced it with a char array. At some point, do I still need to convert a char array to a variable? On line of code "RGBMatrix.fillPixel(0, row, col, color_temp);" color_temp must be in a variable form, not array. I haven't found a way to do this using char array.

I was also wrong about those HEX values. You're absolutely correct, they are way to high. Sigh. I will work on getting the correct RGB values.

Once you get the correct value in the char array, portions of the char array will need to be copied and converted to integers (color_temp), if you are sending the data as characters.

It is possible to have Processing send the data as a mix of binary and character data. Send a binary value, the letter M, a binary value, the letter N, three binary values, and the letter P.

I'd suggest, though, that MxNyPrrrgggbbb would make more sense than xMyNrrrgggbbbP.

By mixing binary and character data, 8 bytes need to be sent ('M', a byte, 'N', a byte, 'P', and 3 bytes) instead of 14 bytes as all character data. That will cut nearly in half the time it takes to transmit the data. Factoring in not having to convert from numeric to string representation, and back, and your throughput can double.

Hey Paul,

I have re-wrote the code last night. It was having too many issues. The new incoming data is: C#D#R###.0G###.0B###.0 where ### is a number from 0 - 255. Much easier to work with. The new code creates an int from each of the ###. But I am still having trouble doing some simple math. For example, the code says multiply the value by 10. I send it R4.0, it prints 400. Last I checked, 4*10 = 40.

int red_val;

    if(SerIn == 'R'){
      SerIn = Serial.read();
      int i = 0;
      while(SerIn != '.'){
        red_array[i] = SerIn;
        SerIn = Serial.read();
        i = i++;
      }

      //Convert Red Array to variable
      char red_char[red_array.length() + 1]; //determind size of new array
      red_array.toCharArray(red_char, sizeof(red_array)); //put red_array to array
      red_val = atoi(red_char); //convert to variable

      red_val = red_val * 10;

Also, when I send C1 for column 1, it returns 49. I can use print(col, BYTE); and it prints 1. But what is the Arduino seeing as the col variable? I need it to see 1 and not 49.

The ASCII code for '1' is 49. The ASCII code for '0' is 48.

So, '1' - '0' = 1.

For one digit numbers, this is how to convert the character to an integer.

The new incoming data is: C#D#R###.0G###.0B###.0 where ### is a number from 0 - 255.

What is the purpose of the .0 for the red, green, and blue values?

        i = i++;

The statement

i++;

is equivalent to

i = i + 1;

So, your statement is equivalent to

i = i = i + 1;

Perhaps you should consider removing the redundancy here.

If your application sends 40.0 for a color, your Arduino code is storing the '4', the '0', and the '0' in the String object. If it sends 4.0 for the color, your Arduino code is storing the '4' and the '0' in the String object.

The need to multiply by 10 escapes me, as does the .0 on the end of the integer value. If you can explain why you send the .0, and why you need to multiply by 10, we can help you determine what to do. At first glance, obviously, you should break out of the loop that is reading the R, G, or B value when the '.' is encountered, rather than continue reading.

Thanks, that solved the row and column problem. And I changed the redundancy to simply i++;.

By default processing sends the value in a number from 0-255.0 for each color. It's not nice enough to send 025 or 001, it just sends 25.0 or 1.0. So I left the decimal in there so I could use the decimal as a stopping point when running the while loop. But, the while loop should not be saving the zero after the decimal. Once it reads the decimal, it should exit the loop and ignore anything after the decimal point. It's not. Here's what I've noticed...

if I just say print(var_red); and send R4. it prints 4 ->Good if I just say print(var_red); and send R4.0 it prints 4 ->Good

if I say var_red = var_red + 1; print(var_red); and send it R4. it prints out 6 ->No good if I say var_red = var_red + 1; print(var_red); and send it R4.0 it prints out 7 ->No good

if I say var_red = var_red + 1; print(var_red); and send it R40. it prints out 42 ->No good if I say var_red = var_red + 1; print(var_red); and send it R40.0 it prints out 43 ->No good

The pattern I see (only looking at the R40.0 since I know it will always have .0) is it adds 2 to the appropriate answer. So subtract 2. It prints 17. :(

The reason I need to do math is because of the rgbmatrix library. They explain it here http://www.sparkfun.com/tutorials/201 . Look under colors about 1/4 down the page. So I figure if I divide each number for each given color by 64. Then multiply the green value by 10 and the red value by 100. Finally add those numbers together and convert it into a hex as the library requires. I know it loses all sorts of resolution, but it gets me in the ballpark.

Thanks for the help. I can post the code if it helps. I've starring at this for hours and can't figure out what I am doing wrong. :0

By default processing sends the value in a number from 0-255.0 for each color.

Not if the variable in Processing is an int, or is cast to an int.

But, the while loop should not be saving the zero after the decimal. Once it reads the decimal, it should exit the loop and ignore anything after the decimal point. It's not.

You haven't told it to break out of the loop.

if I just say print(var_red); and send R4. it prints 4 ->Good

There are a number of problems with this statement. First, I'm not sure what hardware you have connected to Processing, or what libraries you have linked, that supports voice activation at run time. I'm pretty sure you can say to a Processing application "print(var_red)" and expect anything to happen.

Second, if Processing is printing the value in var_red, where does the "send R4" come into play?

Finally, "it" is a pronoun with no referent. I have no idea what "it" is that prints 4.

I understand your frustration with getting two different applications developed that communicate properly with each other. It would be helpful if you posted your Processing code, too.

The var_red variable in Processing should be an int. Then, "?.print("R");?.print(var_red);", when var_red contains the value 4, will result in R4 being sent to the serial port, not R4.0.

Of course, that will make receiving the value on the Arduino easier.

Even easier, of course, would be to do the math with the color numbers in Processing, and send just a color value, as an int, to the Arduino.

But, the Arduino is capable of doing integer math properly, if coded properly, so we need to see the Arduino code, too.

Sorry, for the confusion Paul. Let me try explaining it again. The project is to have a webcam pixelate video into an 8 x 8 matrix. The color of each cell in the matrix is passed to the Arduino that is connected to an 8 x 8 rgb led matrix. As the video changes, the color of each RGB led in the matrix will mimic the color in the cell in processing. The format in which the colors are passed looks like this. C#D#R###.0G###.0B###.0. C is the column and D is the row. R,G,B are a number from 0.0-255.0. Not all numbers Processing sends are 3 digits. It will send 25.0 or 1.0, therefore I have purposely left the .0 in the output from processing. I use the decimal as a stopping point when Arduino is reading the incoming bytes and converting them into an array. This is where you are saying my array is not stopping at the decimal.

Here is my processing code. It needs a webcam for it to work. Also, you’ll need to change the port the Arduino connects to.

import processing.video.*;
import processing.serial.*;


// Size of each cell in the grid
int cellSize = 100;
// Number of columns and rows in our system
int cols, rows;
// Variable for capture device
Capture video;
Serial myPort;


void setup() {
  size(800, 800, P2D);
  //set up columns and rows
  cols = width / cellSize;
  rows = height / cellSize;
  colorMode(RGB, 255, 255, 255, 100);
  rectMode(CENTER);

  // Uses the default video input, see the reference if this causes an error
  video = new Capture(this, width, height, 15);

  background(0);

  println(Serial.list());
  myPort = new Serial(this, Serial.list()[0], 115200); //PORT!
}

void draw() {



  if (video.available()) {
    video.read();
    video.loadPixels();

    background(0, 0, 0);

    // Begin loop for columns
    for (int i = 0; i < cols;i++) {

      // Begin loop for rows
      for (int j = 0; j < rows;j++) {

        // Where are we, pixel-wise?
        int x = i * cellSize;
        int y = j * cellSize;
        int loc = (video.width - x - 1) + y*video.width; // Reversing x to mirror the image

        // Each rect is colored white with a size determined by brightness
        color c = video.pixels[loc];
        float sz = (brightness(c)) * cellSize/20;
        sz = int(sz);
        c = int(c);
        fill(c);
        noStroke();
        rect(x + cellSize/2, y + cellSize/2, 100, 100);

        //Send matrix value - D stands for row
        //print(i + "C" + j + "D" + int(red(c)) + int(green(c)) + int(blue(c)) );
        //myPort.write(i + "C" + j + "D" + int(red(c)) + int(green(c)) + int(blue(c)) );
        print("C" + i + "D" + j + "R" + red(c) + "G" + green(c) + "B" + blue(c));
        myPort.write("C" + i + "D" + j + "R" + red(c) + "G" + green(c) + "B" + blue(c));
        //delay(10);
      }
    }
    //delay(100);
  }
}

And here is a sample output:

C0D0R31.0G19.0B11.0C0D1R22.0G15.0B15.0C0D2R29.0G20.0B22.0C0D3R38.0G24.0B18.0C0D4R42.0G28.0B26.0C0D5R37.0G23.0B17.0C0D6R34.0G20.0B17.0C0D7R0.0G0.0B0.0C1D0R30.0G17.0B17.0C1D1R32.0G19.0B21.0C1D2R38.0G25.0B19.0C1D3R46.0G33.0B28.0C1D4R64.0G49.0B38.0C1D5R57.0G41.0B27.0C1D6R39.0G27.0B15.0

On the Ardunio side, I have it connected to an led matrix. I am only using one command from the library, which is to address a pixel. This is from the library webpage:

RGBMatrix.fillPixel(1,5,7,RED); //Set the pixel on screen 1, row 5, column 7 to red.

And There are 8 colors made available by the library: BLACK, RED, GREEN, BLUE, ORANGE, MAGENTA, TEAL and WHITE. You can use these variable names (case sensitive) in your sketch to send the corresponding colors to the matrix. You can also create your own colors. A color is a single character. The RGB Values are split within the character byte. The most significant 3 bits of the character define the brightness of the Red component; the second 3 bits define the Green brightness, and the last 2 bits define the Blue brightness.

For example, if I wanted to make the color red at full brightness I would use the character 0xE0 (in binary, this is 11100000). Play around with different values to see how the colors on the matrix change.

I have developed a scheme to divide the R, G, and B numbers by 64. Then multiplying the red value by 100 and the green value by 10. Add the new R,G,B values up and convert to Hex like the library requires. I am not worried too much about the math right now. I can mess with this to get it to work right. If we can get the Arduino to do the math properly.

The Ardunio Code. I have commented out half the math stuff and writing to the matrix for troubleshooting purposes. You can also send a code via the Serial Monitor. It can either be just 1 variable, such as C3 (column 3). Or multi-variables, such C3D2R255.0 which is column 3, row 2, r_val 255 . On the line that reads “red_val = red_val + 1;”, if you take out the +1, the code prints red_val just fine. But when I add the +1, or -2, or any other math function, it prints some other random number.

#include <RGB.h>
#include <RGBMatrix.h>

//Incoming Data has this form: C#D#R###.0G###.0B###.0
//We know the number that comes after R, G, and B will be less than 3 digits

int SerIn = 0;

int col = 0;
int row = 0;
float final_val = 0;

String red_array = "000";
String green_array = "000";
String blue_array = "000";

char red_char;
char green_char;
char blue_char;

int red_val;
int green_val;
int blue_val;

void setup() {
  Serial.begin(115200);
  RGBMatrix.begin(1);
}

void loop() {

  //Reset Arrays
  for(int j = 0; j < 3; j++){
    red_array[j] = 0;
    green_array[j] = 0;
    blue_array[j] = 0;
  }

  while(Serial.available() > 0){
    SerIn = Serial.read();

    //Read Column Number
    if(SerIn == 'C'){
      col = Serial.read();
      col = col - '1' + 1;
    }

    //Read Row Number
    if(SerIn == 'D'){ //Row is taken. Use D for Row
      row = Serial.read();
      row = row - '1' + 1;
    }

    if(SerIn == 'R'){
      SerIn = Serial.read();
      int i = 0;
      while(SerIn != '.'){
        red_array[i] = SerIn;
        SerIn = Serial.read();
        i++;
      }
      //Convert Red Array to variable
      char red_char[red_array.length() + 1]; //determind size of new array
      red_array.toCharArray(red_char, sizeof(red_array)); //put red_array to array
      red_val = atoi(red_char); //convert to variable
    }

    if(SerIn == 'G'){
      SerIn = Serial.read();
      int i = 0;
      while(SerIn != '.'){
        green_array[i] = SerIn;
        SerIn = Serial.read();
        i++;
      }
      //Convert Green Array to variable
      char green_char[green_array.length() + 1]; //determind size of new array
      green_array.toCharArray(green_char, sizeof(green_array)); //put red_array to array
      green_val = atoi(green_char); //convert to variable
    }

    if(SerIn == 'B'){
      SerIn = Serial.read();
      int i = 0;
      while(SerIn != '.'){
        blue_array[i] = SerIn;
        SerIn = Serial.read();
        i++;
      }
      //Convert Green Array to variable
      char blue_char[blue_array.length() + 1]; //determind size of new array
      blue_array.toCharArray(blue_char, sizeof(blue_array)); //put red_array to array
      blue_val = atoi(blue_char); //convert to variable
    }


    //Convert to 4 digit binary equivlent. Yes, you lose all significance. Lame.
    //red_val = red_val / 64;
    //green_val = green_val /64;
    //blue_val = blue_val /64;

    //Last conversion for final value of led
    //green_val = green_val * 10;
    //red_val = red_val * 100;
    red_val = red_val + 1; //Here is where things get screwy.
    final_val = blue_val + green_val + red_val;
    //final_val = (final_val, HEX);

    //Write to the LED Matrix
    //RGBMatrix.fillPixel(0, row, col, (final_val, HEX));
    //RGBMatrix.display();

  }
  delay(2000); //Only for troubleshooting
  Serial.print("Column: ");
  Serial.println(col);
  Serial.print("Row (D): ");
  Serial.println(row);
  Serial.print("Int Red: ");
  Serial.println(red_val);
  Serial.print("Int Green: ");
  Serial.println(green_val);
  Serial.print("Int Blue: ");
  Serial.println(blue_val);  
  Serial.print("Final Value: ");
  Serial.println(final_val);
}

I hope this helps. Thanks again.

      col = col - '1' + 1;

should be:

col -= '0';

On the line that reads "red_val = red_val + 1;", if you take out the +1, the code prints red_val just fine. But when I add the +1, or -2, or any other math function, it prints some other random number.

Print out red_array, red_char, and red_val at the time red_val is valued. Then, increment red_val, and print it again. Show the results.

One issue is that you are reading from the serial port when you haven't established that anything is there.

    if(SerIn == 'R'){
      SerIn = Serial.read();
      int i = 0;
      while(SerIn != '.'){
        red_array[i] = SerIn;
        SerIn = Serial.read();
        i++;
      }

Although your high baud rate may be masking the problem, the Serial.read in your while loop may be returning -1. If so, you'll eventually be writing on memory past the end of your array. That could certainly account for some funky results.

I don't understand this bit (frankly I'm surprised it compiles)

      char red_char[red_array.length() + 1]; //determind size of new array
      red_array.toCharArray(red_char, sizeof(red_array)); //put red_array to array
      red_val = atoi(red_char); //convert to variable

I think you're trying to declare a dynamic char array each time to collect your numbers in to run atoi on. Easier and safer to declare a small global char array and share it between the three colours - you don't need it long anyway.

But clear up the serial piece - if it isn't causing you trouble now, it will eventually

Paul you are genius. Here are the results and below is what I did to fix it. I added code to print “Start” at the beginning of the code and “Adding One” when it adds one. The test number I used is 5.

Start
red_val before +1: 5
red_char before +1: