[SOLVED] ArrayIndexOutOfBoundsException: 1

Using an arduino Mega to collect temperature and humidity data then using Processing to display data on meters. Everything works fine for a few seconds then I receive this error: ArrayIndexOutOfBoundsException: 1. Not sure why?

Arduino Code:

#include <Wire.h>
#include "Wire.h"
#include "Adafruit_HTU21DF.h"
#include <SPI.h>
#include <SoftwareSerial.h>
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);

uint8_t type;
#define TCAADDR 0x70 // mux 1 #define TCAADDR 0x70 // mux 1 
#define TCAADDR2 0x71 // mux 2 #define TCAADDR 0x71 // mux 2 
#define TCAADDR3 0x72 // mux 3 #define TCAADDR 0x72 // mux 3
#define TCAADDR4 0x73 // mux 4 #define TCAADDR 0x73 // mux 4

Adafruit_HTU21DF htu = Adafruit_HTU21DF();
// array of temperature designated by [ ] when calling call from 0-9 for an array of size 10
float temperature[3]= {-1, -1, -1};
float humidity[3]= {-1, -1, -1};
float humiditymax[10]={60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0};
float humiditymin[10]={24.0, 24.0, 24.0, 24.0, 24.0, 24.0, 24.0,  24.0, 24.0, 24.0};
//temperature max is 100F and min is 60F
float temperaturemax[10]={37.8, 37.8, 37.8, 37.8, 37.8, 37.8, 37.8, 37.8, 37.8, 37.8};
float temperaturemin[10]={15.55, 15.55, 15.55, 15.55, 15.55, 15.55, 15.55, 15.55, 15.55, 15.55};
//temp below  60 above 100


void setup() {

  // put your setup code here, to run once:
            Wire.begin(); // Initiate the Wire library
            Serial.begin(9600);
            tcaselect(7);
            htu.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  

//Serial.println("in loop");

            ///////////////send data from sensors to the lath house , main room, green house 1 and 2 ////////////
            // Ex. tcaselect(1) is option 1 temperature/humidity reading, tcaselect(2) is option 2  temperature/humidity reading..etc
            //total 10 options/readings, mux1 reads from sensors 0-3, mux2 reads from sensors 4-7, mux3 reads from sensors 8 & 9
            //mux1
            tcaselect(1);
            temperature[0] = htu.readTemperature();
            humidity[0] = htu.readHumidity();
            
            tcaselect(2);
            temperature[1] = htu.readTemperature();
            humidity[1] = htu.readHumidity();
            
            tcaselect(6);
            temperature[2] = htu.readTemperature();
            humidity[2] = htu.readHumidity();

    Serial.print((int)temperature[0]);
    Serial.print(",");
  Serial.println((int)temperature[1]);

  
  delay(2500);
            
}

void tcaselect(uint8_t i) {   
      // set the mux we want to the correct loacation// reading from mux1, disable other muxes
      if (i > 7) return;
          Wire.beginTransmission(TCAADDR);
          Wire.write(1 << i);
          Wire.endTransmission(); 
             //disable all other muxes
             Wire.beginTransmission(TCAADDR2);
             Wire.write(0); // no channel selected
             Wire.endTransmission();
             Wire.beginTransmission(TCAADDR3);
             Wire.write(0); // no channel selected
             Wire.endTransmission();
             Wire.beginTransmission(TCAADDR4);
             Wire.write(0); // no channel selected
             Wire.endTransmission();
}

Processing Code:

/***********************************
 First upload the Arduino code to the Arduino and then run this code.
 Make sure that the Port number and baudrate are the same.
***********************************/
import meter.*;
import processing.serial.*;

Serial port;
String[] list;

Meter m, m2;

void setup() {
  size(950, 400);
  background(0);
  
  port = new Serial(this, "/dev/ttyACM0", 9600);
 

  fill(120, 50, 0);
  m = new Meter(this, 25, 100);
  // Adjust font color of meter value  
  m.setTitleFontSize(20);
  m.setTitleFontName("Arial bold");
  m.setTitle("Temperature (C)");
  m.setDisplayDigitalMeterValue(true);
  
  // Meter Scale
  String[] scaleLabelsT = {"0", "10", "20", "30", "40", "50", "60", "70", "80"};
  m.setScaleLabels(scaleLabelsT);
  m.setScaleFontSize(18);
  m.setScaleFontName("Times New Roman bold");
  m.setScaleFontColor(color(200, 30, 70));
  
  m.setArcColor(color(141, 113, 178));
  m.setArcThickness(10);
  m.setMaxScaleValue(80);
  
  m.setNeedleThickness(3);
  
  m.setMinInputSignal(0);
  m.setMaxInputSignal(80);

  // A second meter for reference
  int mx = m.getMeterX();
  int my = m.getMeterY();
  int mw = m.getMeterWidth();
  
  m2 = new Meter(this, mx + mw + 20, my);
  m2.setTitleFontSize(20);
  m2.setTitleFontName("Arial bold");
  m2.setTitle("Humidity (%)");
  m2.setDisplayDigitalMeterValue(true);
  
  String[] scaleLabelsH = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m2.setScaleLabels(scaleLabelsH);
  m2.setScaleFontSize(18);
  m2.setScaleFontName("Times New Roman bold");
  m2.setScaleFontColor(color(200, 30, 70));
  
  m2.setArcColor(color(141, 113, 178));
  m2.setArcThickness(10);
  m2.setMaxScaleValue(100);
  
  m2.setNeedleThickness(3);
  
  m2.setMinInputSignal(0);
  m2.setMaxInputSignal(100);
  
}

public void draw() {
  
  textSize(30);
  fill(0, 255, 0);
  text("Temperature and Humidity", 270, 50);
  
  if (port.available() > 0) {
    String val = port.readString();
    list = split(val, ',');
    float temp = float(list[0]);
    float hum = float(list[1]);
    
    println("Temperature: " + temp + " C  " + "Humidity: " + hum + " %");
    
    m.updateMeter(int(temp));
    m2.updateMeter(int(hum));
  delay(2500);
  }
}


1 Like

What confuses me is that, from what you’ve showed us, it splits “Val” fine, until suddenly it doesn’t.

I’m not too familiar with Arduino stuff -

How do you know this line will, for certain, spit out two floats every draw() cycle?

You could put some debug code in the loop:

if( list.length < 2)
     println(val);

Or if the length is less than 2, reread the port.

1 Like

This is code from a tutorial on youtube https://www.youtube.com/watch?v=YgjsWvFRpSE&feature=youtu.be that I’m using and in the tutorial it works fine. I think it should spit out two values because of the line: list = split(val, ‘,’); it should split the data according to the comma it reads.

My theory is that the serial monitor isn’t printing out values consistently. For example it should be:

29, 29
29, 29
30, 29

BUT maybe its printing out like:

29,29
29,
30, 29

which it might crash/freeze? I’m not sure honestly

This sounds the most likely. As @shawnlau suggests, I would test if length > 1before reading from the list.

2 Likes

I suggest you check previous code related to Arduino. For instance: https://forum.processing.org/two/discussion/16618/processing-with-arduino-void-serialevent#Item_5

Notice your data stream ends with a new character so you could use:

port.bufferUntil('\n');

After that you need to:

  1. Check the data you got is not null
  2. Proceed to splitting (you are doing that above)
  3. Before you access your data, you need to make sure you have an array of size 2. Doing this type of check it is to ensure you dont run into null point exceptions (NPEs) or similar situations
  4. Apply trim(), just in case, to ensure you remove unwanted characters
  5. Extract values
if (port.available() > 0) {
    String val = port.readStringUntil(`\n`);
    if(val!=null){
       list = split(val, ',');
       if(list.length==2){
           float temp = float(trim(list[0]));
         float hum = float(trim(list[1]));
        }
    }
}

Kf

For multiple data transmission, I recommend you to read this post below: :electric_plug:

  1. As you can see, on the Arduino side, separate the data w/ \t using print() + write().
  2. And then send the last data w/ println().
  3. On the Processing side, inside serialEvent(), use Serial::readString() + PApplet.splitTokens() in order to get all the data as a String[] array.
  4. Of course, you’re still gonna need to convert each data in that received array to their corresponding datatype if that data isn’t a String.
  5. And don’t forget to use bufferUntil(ENTER) after instantiating the class Serial. :warning:

i would enclose this part:

if (port.available() > 0) {
    String val = port.readString();
    list = split(val, ',');
    float temp = float(list[0]);
    float hum = float(list[1]);
    
    println("Temperature: " + temp + " C  " + "Humidity: " + hum + " %");
    
    m.updateMeter(int(temp));
    m2.updateMeter(int(hum));
  delay(2500);
  }

in a try function, probably your sensor fails to recover tmperatura or humidity and don’t send anithing, another thing to do is to verify (in the arduino code) the integrity of the data before sending it.

@erwrow I wouldn’t recommend using the delay within the Processing code. The serial event is a call back function. It will return as soon as some data is present in its buffer. Checking for data integrity could be done in the arduino or in Processing. I recommend to do it in the Processing side as it is easier to debug. I see the arduino more of a hub between the sensors and the user: it relays the data without many modifications. This is my prefered concept but it is up to the designer of the code to do what he thinks is most convenient for his project.

Kf

i agreed, i don’t use delays either, i just copyed that part of the code. About data integrity i was refering to “see” if the sensor returns NaN or a correct value, but yes, you’re right!.

this seems to have solved the issue and it was a simple fix. Thanks!

Thank you for your suggestion. Debugging helped!

1 Like