Problem with converting variable types & serial communication

Hi everyone,

It’s been a while since I last visited the Arduino Forums, and I slowly got a hang of it how to work with the Arduino. Great fun!
Right now, I am working on a project for which I want my computer to send rgb-values to my arduino, which I ultimately want to cast into integers. I use Processing for communicating over a serial connection with the Arduino.

Setting up the serial connection was not much of a problem, so far so good. As I tried to “make sense” of the output from Processing (I send string like “255,112,145”), I glue the chars that come in together, checking for the “,” as a sort of delimiter.
The first problem I ran into, was that somehow the String that I put everything into (serialBuffer) contains new lines besides the chars that I glue together. This can’t really be casted into integers:

Instead of: 225
It becomes: 2
2
5

So I tried something else. I casted the serialBuffer to int (with the toInt() function). This worked fine for the first two rgb-values, but the third seemed to mess up a little.

Input by Processing: 255,212,111
Output: R:255 G:212 B:-19817

I don’t really get a grip on what is the problem here. Could you guys help me for making sense out of what happens here?

Thanks in advance!
Jeroen


I’ll post both the Processing code and the Arduino code below.
Arduino:

char inChar = '\0';
int inColor[3] = {0,0,0};
String serialBuffer = "";
int currentColor = 0;
void setup(){
  Serial.begin(9600);
}
void loop(){
  while(Serial.available() > 0){
    inChar = Serial.read();
    if(currentColor < 3){
      if(inChar==','){
        inColor[currentColor] = serialBuffer.toInt();
        currentColor++;
        serialBuffer = ""; 
      }
      else {
        //Serial.println(String(inChar).trim());
        serialBuffer += (char)inChar;
        delay(5);
      }
    }
    else {     
      Serial.println("R:"+String(inColor[0])+" G:"+String(inColor[1])+" B:"+String(inColor[2])+" CC:"+currentColor);
      inColor[0] = 0;
      inColor[1] = 0;
      inColor[2] = 0;
      currentColor = 0;
    }
  }
}

Processing:

import processing.serial.*;
Serial port; 
String serial;

void setup() {
  port = new Serial(this, "COM9", 9600);
  port.clear();
  serial = port.readStringUntil(10);
  serial = null;
}

void draw(){
  port.write("255,212,111");
  while (port.available() > 0) { //as long as there is data coming from serial port, read it and store it 
    serial = port.readStringUntil(10);
  }
  if (serial != null) {
    println("incoming:");
    println(serial);
  }
  delay(100);
}

The problem with the third number is that you only store a number when it is followed by a comma:

      if(inChar==','){
        inColor[currentColor] = serialBuffer.toInt();
        currentColor++;
        serialBuffer = ""; 
      }

Ok, thanks! I see what you mean. I will update my code, as soon as I find some time.

Alright, got it working. Many thanks, johnwasser! :slight_smile:

For those who are interested, I am working with the Adafruit Neopixel LED strips. Through Processing, I am generating an image out of RGB-values. I use the Adafruit Neopixel Arduino library for driving the LEDs individually, and loop through the serial output from Processing in order to light all the LEDs. Besides that, I loop through a series of images, so the LED strip animates. It’s pretty awesome!

The updated code (which includes the library from Adafruit: https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library) might still need some extra work and fine-tuning, but it is alive and kicking!
Arduino code:

#include <Adafruit_NeoPixel.h>
#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

uint16_t pixelID = 0;

char inChar = '\0';
int inColor[3] = {0,0,0};
String serialBuffer = "";
int currentColor = 0;
void setup(){
  strip.begin();
  Serial.begin(9600);
  strip.show();
}
void loop(){
  while(Serial.available() > 0){
    inChar = Serial.read();
    if(currentColor < 3){
      if(inChar==','){
        inColor[currentColor] = serialBuffer.toInt();
        currentColor++;
        serialBuffer = ""; 
      }
      else {
        serialBuffer += (char)inChar;
      }
    }
    else {     
      strip.setPixelColor(pixelID,strip.Color(inColor[0],inColor[1],inColor[2]));
      if(pixelID==59){
        strip.show();
        pixelID = 0;
      }
      else {
        pixelID++;
      }
      inColor[0] = 0;
      inColor[1] = 0;
      inColor[2] = 0;
      currentColor = 0;
      
    }
  }
}

Processing code (might still need some optimalization, work in progress):

import processing.serial.*;
Serial port; 
String serial;
PImage[] images = new PImage[8];
String serialPrint = "";
String[] val = new String[8];
String intBetween = "";
int id = 0;

void setup() {
  size(10,6);
  port = new Serial(this, "COM9", 9600);
  port.clear();
  serial = port.readStringUntil(10);
  serial = null;
  for ( int i = 0; i< images.length; i++ )
  {
    images[i] = loadImage("gentle/1-gentle" + i + ".jpg" );
    images[i].loadPixels();
    val[i] = ""; // reset val[i]: remove null value
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        int loc = x + y * width;
        val[i] += makeInt(red(images[i].pixels[loc]))+",";
        val[i] += makeInt(green(images[i].pixels[loc]))+",";
        val[i] += makeInt(blue(images[i].pixels[loc]))+",";   
      }
    }
  }
}

void draw(){
  port.write(val[id]);
  id = (id==7) ? 0 : id + 1;
}
int makeInt(Float c){
  intBetween = c.toString();
  int iL = intBetween.length();
  return int(intBetween.substring(0,(iL-2)));
}

Okay, for further reference: I updated my code, as there seemed to be some hiccups in it. :roll_eyes: But now it works pretty well! With this code, I can import a series of images (6x9 24-bit BMP, the least compression and errors in the pixels) with Processing, and project them onto the LED strip with Arduino (I cut the strip into a flexible matrix).

  • First of all, the communication between Processing and Arduino was not going smoothly. There is no control over when the communication should begin.
  • Second of all, I wanted to send rgb-values of the pixels from an 9x6 image (+ 6 extra pixels). The problem here is the amount of values (both min and max). Minimally, there would be 360 bytes (“x,x,x,” * 60 = 360 bytes), and maximally 720 bytes (“xxx,xxx,xxx” * 60 = 720 bytes). Quite a variety! I’d better send it differently!
  • Consequently, this floods the Arduino in data. As the serial buffer can only contain 128 bytes, the data should be divided into chunks, in order to control the input and make it consistent.

This resulted into a couple of additions/changes.

  • First of all, I integrated a function called establishContact(). With this function, I let Processing “initiate” the communication (Arduino responds, after which they both have isSerialStarted=true, so they both “know” the data that comes now is relevant).

  • Second of all, I used a different method for sending the pixel-values: through hexadecimal values. Always the same byte-length, namely 420 bytes (“xxxxxx,” * 60 = 420). This required some encoding and decoding for both Processing and Arduino, but it works.

  • Thirdly, I chopped the data into chunks, by checking its length() in Processing. This means that, only when the length is smaller than 121 (128 minus the data to be added), it is safe to add another hex-value. Otherwise, start “filling up” the next chunk.

  • To let the Arduino make sense of the data, the entire hex-value data heap should have an SOP and EOP (e.g. start with “<” and end with “>”). This way, the Arduino knows when to update the entire LED strip, based on the collected data.

  • After having it up and running, the animation of images on the strip was not that fast (maybe 2 FPS, but heck, what is realistic?). I tried to turn up the speed, and it worked by increasing the baud-rate of the communication (115200 instead of 9600). The Arduino is able to handle all the code that I use, but it needs a moment to breathe in between. So after sending a chunk of data in Processing, I set a delay of 10ms to let the Arduino read out the serial buffer. It worked! I doubled the speed. :slight_smile:

So there you have it. A LED matrix that displays a sequence of 9x6 images, controlled by Arduino through Processing. I had to remove the comments from the code, otherwise I exceed a message length limit on this forum… :stuck_out_tongue:

Arduino code:

#include <Adafruit_NeoPixel.h>
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
uint16_t pixelID = 0;
char inChar = '\0';
char serialBuffer[6];
int sI = 0;
boolean isSerialOpen = false;
boolean isSerialStarted = false;
boolean isResponse = false;

void setup(){
  strip.begin();
  Serial.begin(115200);
  strip.show();
}
void loop(){
  while(Serial.available() > 0){
    inChar = (char)Serial.read(); 
    isResponse = true;
    if(isSerialStarted==true){
      if(inChar=='<'){
        isSerialOpen = true;
      }
      else{
        if((inChar==',')||(inChar=='>')){          
          long int r = strtol(String(serialBuffer).substring(0,2).c_str(),0,16);
          long int g = strtol(String(serialBuffer).substring(2,4).c_str(),0,16);
          long int b = strtol(String(serialBuffer).substring(4,6).c_str(),0,16);
          strip.setPixelColor(pixelID,strip.Color(r,g,b));
          pixelID++;
          sI = 0;
          serialBuffer[sI] = '\0'; 
          if(inChar=='>'){
            isSerialOpen = false;
            strip.show();
            pixelID = 0;
          }
        }
        else {
          if(isSerialOpen==true){
            serialBuffer[sI] = inChar;
            sI++;
            serialBuffer[sI] = '\0';
          }
        } 
      }
    }
    else {
      if(inChar=='A'){
        Serial.println("B");
        isSerialStarted=true;
      }
    }
  }
  if(Serial.available() == 0) {
    if((isSerialStarted==true)&&(isSerialOpen == true)&&(isResponse==true)){
      Serial.println("A");
      isResponse = false;
    }
  }
}

Processing code:

import processing.serial.*;
Serial port; 
byte[] serVal = new byte[2];
String[][] val = new String[7][4];
PImage[] images = new PImage[7];
int id = 0;
int bufID;
boolean justSend = true;
boolean isSerialStarted = false;

void setup(){
  size(9,6);
  colorMode(RGB,255);
  port = new Serial(this, "COM9", 115200);
  port.clear();
  serVal = null;
  for ( int i = 0; i< images.length; i++ )
  {
    images[i] = loadImage("imgs/g" + i + ".bmp" );
    bufID = 0;
    image(images[i], 0, 0);
    loadPixels();
    val[i][0] = "<"; 
    val[i][1] = "";
    val[i][2] = "";
    val[i][3] = "";
    for (int y = 0; y < 6; y++) {
      for (int x = 0; x < 9; x++) {
        if(val[i][bufID].length() > 121){ 
          bufID++;
        }
        if((y < 3)&&(x==0)){
          val[i][bufID] += (y==0) ? "c85000," : "c8c8c8,";
        }
        String pixelColor = hex(get(x,y),6); 
        if(val[i][bufID].length() > 121){ 
          bufID++;
        } 
        val[i][bufID] += pixelColor+","; 
        if(val[i][bufID].length() > 121){ 
          bufID++;
        }
        if((y < 3)&&(x==8)){
          val[i][bufID] += (y==0) ? "c85000," : "c8c8c8,";
        }
        if((y*x) == 40){
          val[i][bufID] = val[i][bufID].substring(0,(val[i][bufID].length()-1));
          val[i][bufID] += ">";
        } 
      }
    }
    println("val["+i+"]:");
    println(val[i]);
    bufID = 0;
  }
}
void draw(){
  if(isSerialStarted == false){
    establishContact(port);
  }
  else {
   if(justSend==true){
      delay(10);
      port.write(val[id][bufID]);
       if(bufID==3){
         bufID = 0;
         id = (id==6) ? 0 : id + 1;
       }
       else {
         bufID++;
       }
       justSend = false;
    }
  }
}

void serialEvent(Serial port){
   serVal = port.readBytes();
   port.readBytes(serVal);
   byte serialVal = serVal[0];
   switch(serialVal){
     case 65: 
       justSend = true; 
       break;
     case 66: 
       isSerialStarted = true; 
       justSend = true; 
       break;
   }
}
void establishContact(Serial port){
  if(port.available() <= 0) {
    port.write("A");   
    delay(300); 
  }
}