Error with streaming from Arduino

edited July 2017 in Arduino

Hey everyone! I'm using this code that I saw from another post somewhere in this forum and adapted it to generate a heat map using data from an arduino. However, for some reason whenever I try streaming data in order to create the heat map, I always get back an error of some kind because of the data streaming. I'm specifically asking about lines 25 and 26 which is where the error happens. I think it might be because of some index out of bounds exception but I do not understand the library enough.

import cc.arduino.*;
import org.firmata.*;
import apsync.*;
import processing.serial.*;

float[][] interp_array;
Serial myPort;  // Create object from Serial class
String val;     // Data received from the serial port
int lf = 10;

void setup() {
  //String portName = Serial.list()[2]; 
  myPort = new Serial(this, "COM3", 9600);
  size(400, 400);
  interp_array = new float[400][400];
  makeArray();
  applyColor();
}

// Fill array with Perlin noise (smooth random) values
void makeArray() {
  for (int r = 0; r < height; r++) {
    for (int c = 0; c < width; c++) {
      if ((r == 50 || r == 150 || r == 250 || r == 350) && (c == 50 || c == 150 || c == 250 || c == 350)) {
        String data = myPort.readStringUntil(lf);
        interp_array[c][r] = Float.parseFloat(data);
      } 
      //else {
      //// Range is 24.8 - 30.8
      //interp_array[c][r] = 24.8 + 6.0 * noise(r * 0.02, c * 0.02);
      //}
    }
  }
  for (int r = 0; r < height; r++) {
    for (int c = 0; c < width; c++) {
      int[] closest_r_array = {abs(50 - r), abs(150 - r), abs(250 - r), abs(350 - r)};
      int[] closest_c_array = {abs(50 - c), abs(150 - c), abs(250 - c), abs(350 - c)};
      int closest_r = min(closest_r_array);
      int closest_c = min(closest_c_array);
      if (!(r == 50 || r == 150 || r == 250 || r == 350) && !(c == 50 || c == 150 || c == 250 || c == 350)) {
        interp_array[c][r] = lerp(closest_r, closest_c, 0.5);
      }
    }
  }
}

void applyColor() {  // Generate the heat map
  pushStyle(); // Save current drawing style
  // Set drawing mode to HSB instead of RGB
  colorMode(HSB, 1, 1, 1);
  loadPixels();
  int p = 0;
  for (int r = 0; r < height; r++) {
    for (int c = 0; c < width; c++) {
      // Get the heat map value 
      float value = interp_array[c][r];
      // Constrain value to acceptable range.
      value = constrain(value, 25, 30);
      // Map the value to the hue
      // 0.2 blue
      // 1.0 red
      value = map(value, 25, 30, 0.2, 1.0);
      pixels[p++] = color(value, 0.9, 1);
    }
  }
  updatePixels();
  popStyle(); // Restore original drawing style
}
Tagged:

Answers

  • Answer ✓

    Check the following link:

    https://forum.processing.org/two/search?Page=p2&Search=arduino

    For example:

    https://forum.processing.org/two/discussion/comment/101680/#Comment_101680

    In your case, line 25 should be handle in serialEvent() function. You also need to make sure that the value returned by this function is not null. You can check previous examples where this is demonstrated.

    Kf

  • If the code in line 25 is taken out of the for loop, how will I be able to stream continuous data from the arduino?

  • Answer ✓

    Setup is not a good place to do this operations as this function runs only once.

    The serialEvent() is a callBack function that gets executed every time data arrives via serial. It is there where you handle the data. However, it is advised not to work in your sketch in that function. Any draw operation needs to be done in the drawing thread which you own and you can access via draw(): https://processing.org/reference/draw_.html

    Here is my attempt on your code. Since I don't have an arduino, I have disabled about 5 lines in your code. For your code to work with your arduino, you need to adjust the min/max range to 25/30 and enable those 5 lines related to arduino and serial event. Or you can run the code as it is. I use key events to simulate your arduino's input data. For the code to work, you need to set your min/max to 0/9 and type 16 times to fill the array. as soon as the array is full, it populates the second and bigger table array using a modify version of your makeArray. I believe there is some work still to be done in your heat map code. You might need to create a separate post to address this issue.

    Kf

    //import cc.arduino.*;     // ##  ENABLE/DISABLE for serial operation  ON/OFF
    //import org.firmata.*;    // ##  ENABLE/DISABLE for serial operation  ON/OFF
    //import apsync.*;         // ##  ENABLE/DISABLE for serial operation  ON/OFF
    import processing.serial.*;
    
    final int N=16;
    final int MINVAL=0; //25; 
    final int MAXVAL=9; //30;
    
    int ctr=0;
    boolean full=false;
    float[] data = new float[N];
    
    
    
    float[][] interp_array;
    Serial myPort;  // Create object from Serial class
    String val;     // Data received from the serial port
    int lf = 10;
    
    void setup() {
      size(400, 400);
      // Set drawing mode to HSB instead of RGB
      colorMode(HSB, 1, 1, 1);
    
    
      //String portName = Serial.list()[2]; 
      // myPort = new Serial(this, "COM3", 9600);  // ##  ENABLE/DISABLE for serial operation  ON/OFF
      interp_array = new float[400][400];
    }
    
    void draw() {
    
      if (full) {
        background(0);
        makeArray();
        applyColor();
    
        println("Execution completed!");
        full=false;
      }
    }
    
    void keyReleased() {
    
      if (key>='0' && key<='9') {
        storeData((float)(key-'0'));
      }
    }
    
    void serialEvent(Serial port) {
    
      String dataStr = "";
      // dataStr=myPort.readStringUntil(lf);   // ##  ENABLE/DISABLE for serial operation  ON/OFF
      if (data!=null) {    
        storeData(Float.parseFloat(dataStr));
      }
    }
    
    
    void storeData(float val) {
      data[ctr++]=val;
    
      print(ctr + " ");
    
      if (ctr==N) {
        full=true;
        ctr=0;
        printMyData();
        println("\nTrigger heat map execution... Please wait.");
      }
    }
    
    void printMyData() {
      println();
      println();
      for (int i=0; i<N; i++) {
        print(data[i]+"\t");
        if ( (i+1)%4==0)
          println();
      }
    }
    
    boolean isSpecialCell(int c){
      return (c == 50 || c == 150 || c == 250 || c == 350);
    
    }
    
    // Fill array with Perlin noise (smooth random) values
    void makeArray() {
      int index=0;
      for (int r = 0; r < height; r++) {
        for (int c = 0; c < width; c++) {
          if (isSpecialCell(r) && isSpecialCell(c)) {
            interp_array[c][r]=data[index++];
          } 
          //else {
          //// Range is 24.8 - 30.8
          //interp_array[c][r] = 24.8 + 6.0 * noise(r * 0.02, c * 0.02);
          //}
        }
      }
      for (int r = 0; r < height; r++) {
        for (int c = 0; c < width; c++) {
          int[] closest_r_array = {abs(50 - r), abs(150 - r), abs(250 - r), abs(350 - r)};
          int[] closest_c_array = {abs(50 - c), abs(150 - c), abs(250 - c), abs(350 - c)};
          int closest_r = min(closest_r_array);
          int closest_c = min(closest_c_array);
          if (!isSpecialCell(r) && !isSpecialCell(c)) {
            interp_array[c][r] = lerp(closest_r, closest_c, 0.5);
          }
        }
      }
    }
    
    void applyColor() {  // Generate the heat map
      pushStyle(); // Save current drawing style
    
      loadPixels();
      int p = 0;
      for (int r = 0; r < height; r++) {
        for (int c = 0; c < width; c++) {
          // Get the heat map value 
          float value = interp_array[c][r];
          // Constrain value to acceptable range.
          value = constrain(value, MINVAL, MAXVAL);
          // Map the value to the hue
          // 0.2 blue
          // 1.0 red
          value = map(value, MINVAL, MAXVAL, 0.2, 1.0);
          pixels[p++] = color(value, 0.9, 1);
        }
      }
      updatePixels();
      popStyle(); // Restore original drawing style
    }
    
Sign In or Register to comment.