My sketch reads one pixel from arduino, then gives me an ArrayIndexOutOfBoundsException

edited December 2015 in Questions about Code

Dear Forum,

I'm building a drawbot that draws bitmaps. I'm almost there -thanks to the good people here-, but I can't get my head around this issue here.

I have a Processing sketch that can parse coordinates from a string from my arduino, display the corresponding pixel on screen and send the brightness of that pixel back to the arduino. Then I have an arduino code that can move to the next pixel and send its location coordinates as a string.

This seems to work, but only for one pixel. Then processing sends me and ArrayIndexOutOfBoundsException. I guess I need to flush a string somewhere. But I don't know which one. The debuggerer somehow gets stuck on my sketch too. So some advice would be really helpful.

Here's the Processing sketch:

    import processing.serial.*; //import the Serial library

    Serial myPort;  //the Serial port object
    String strIn = "";  //Declare a string with name strIn, this will store the coordinates received from the arduino
    String strOut = "";  //Declare a string with name strOut, this will store the coordinates and corrseponding geryvalue of a pixel in the bitmap.
    String portName = "";  //apparently this is necessary
    String coordinates;
    int locX= 0;
    int locY= 0;

    PImage img;

    void setup()
    {

      size(182, 262);  //This is the size of the canvas and the range of the printer //<>//
      // Make a new instance of a PImage by loading an image file
      img = loadImage("parel.bmp");
      tint(255, 100);
      image (img, 0, 0);
      String portName = Serial.list()[0];
      myPort = new Serial(this, portName, 9600);
    }


    void draw()
    { 
      if (myPort.available() > 0)                     // If data is available,
      {
        strIn = myPort.readStringUntil('\n');         // read it and store it in a string called strIn
        String[] coordinates = split(strIn, ",");    
        //Cut the strIn string at the comma into two strings called coordinates. 
        //We expect a message coming in something like "XXX,YYY"
        int locX = int(trim(coordinates[0]));        //This says that the first string is an integer called LocX
        int locY = int(trim(coordinates[1]));       //This says that the next string is an integer called LocX
        color pix = img.get(locX, locY);             //look up the colour of the requested pixel
        stroke(pix);                                 //show the pixel on the canvas on screen
        point(locX, locY);
        int Bright = round(brightness(pix));        //sending pix will send a large negative string, so we will just send the brightness
        strOut = locX + "," + locY + "," + Bright + "L" + "\n";  //put all the needed values into a string called strOut
        myPort.write(strOut);                                    //send it over serial port to the arduino to parse
        }
    }

And here's the arduino sketch:

// Jerry Wirerammer lives!

unsigned int xPos ;           //this integer sets the X position of the robot
unsigned int yPos   ;         //this integer sets the Y position of the robot
unsigned int xGoal  ;        //this integer sets the X location of the pixel where the mothership thinks the robot is. If the Robot is in position, it can put a dot.
unsigned int yGoal   ;       //this integer sets the X location of the pixel where the mothership thinks the robot is. If the Robot is in position, it can put a dot.
unsigned int GreyValue ;
char val;
int CanvasWidth = 182;
int CanvasHeight = 263;
String received ;

void setup() {

  Serial.begin(9600);                             //Serial communication, we are using it


  goHome();        //move to the 0,0 position.
}



void loop() {


  Serial.print(xPos);
  Serial.print(",");
  Serial.println(yPos);


  if ( Serial.available() ) // if data is available to read
  {
    val = Serial.read();    // read it and store it in 'val'
    if ( val != 'L' ) {     // if not an 'L'
      received += val;          // add it to the received string
    }

    else {
      // if 'L' was received (our designated termination char)
      //Look for the location of the first comma
      int commaIndex = received.indexOf(',');
      //  Search for the next comma just after the first
      int secondCommaIndex = received.indexOf(',', commaIndex + 1);

      String firstValue = received.substring(0, commaIndex);  //the first series of characters before the first comma
      String secondValue = received.substring(commaIndex + 1, secondCommaIndex); //the next series of characters between the first and second comma
      String thirdValue = received.substring(secondCommaIndex); //the final series of characters before the L that we didn't add to the "received" string

      xGoal = firstValue.toInt();
      yGoal = secondValue.toInt();
      GreyValue = thirdValue.toInt();

/*    debugging purposes only:
      Serial.print("received:");
      Serial.println(received);
      Serial.print("xGoal =");
      Serial.println(xGoal);
      Serial.print("yGoal =");
      Serial.println(yGoal);
      Serial.print("xPos =");
      Serial.println(xPos);
      Serial.print("yPos =");
      Serial.println(yPos);
*/

      received = "";                // Flush the string so we can receive new data
    }
  }
  else {
    delay (1000); // wait a bit and try again
  }


  if (xGoal == xPos) {
    if (yGoal == yPos) {
      MoveOn();
    }
  }
}


void MoveOn() //this subroutine tells the robot how to move to the next position.
{
  if (xPos != CanvasWidth) {   //if we are not at the end of the x axis
    xPos = xPos + 1;          //and adjust x position by increasing by one
  }
  else if (yPos != CanvasHeight) { //if we are not at the end of the y axis
    xPos = 0;           //and adjust x position to its starting value
    yPos = yPos + 1;                  //and adjust y position by increasing by one
  }
  else {
    delay(1);                       //Do nothing. This will make the robot print the last pixel over and over again.
  }
}




void goHome() //this subroutine tells the robot how to move to position 0,0
{
  while (xPos != 0) {         //if we are not x position 0
    xPos = xPos - 1;          //and adjust x position by increasing by one
    //this will repeat until we are at position x=0
  }

  while (yPos != 0) {         //if we are not x position 0
    yPos = yPos - 1;          //and adjust x position by increasing by one
  }
}

Answers

  • edited December 2015

    Which code line does the ArrayIndexOutOfBoundsException happen?
    Your code would be easier to manage if you relied on readBufferUntil(), serialEvent() & readString():

    1. https://Processing.org/reference/libraries/serial/Serial_bufferUntil_.html
    2. https://processing.org/reference/libraries/serial/serialEvent_.html
    3. https://processing.org/reference/libraries/serial/Serial_readString_.html
  • It happens on line 35.

    Your code would be easier to manage if you relied on readBufferUntil(), serialEvent() & readString():

    Do you have an example of such a code?

  • I tweaked the sketch a bit by flushing all strings at the end of each reading. The AIOOBE error is gone and I can run the debugger now. Don't really understand why.

    Now Arduino is no longer responding after two or three pixels.

    New code:

        import processing.serial.*; //import the Serial library 
    
        Serial myPort;  //the Serial port object
        String strIn = "";  //Declare a string with name strIn, this will store the coordinates received from the arduino
        String strOut = "";  //Declare a string with name strOut, this will store the coordinates and corrseponding geryvalue of a pixel in the bitmap.
        String portName = "";  //apparently this is necessary
        String coordinates;
        int locX= 0;
        int locY= 0;
    
        PImage img;
    
        void setup()
        {
    
          size(182, 262);  //This is the size of the canvas and the range of the printer 
          // Make a new instance of a PImage by loading an image file
          img = loadImage("parel.bmp");
          tint(255, 100);
          image (img, 0, 0);
          String portName = Serial.list()[0];
          myPort = new Serial(this, portName, 9600);
          myPort.clear();
        }
    
    
        void draw()
        { 
           if (myPort.available() > 0)                     // If data is available,
          {
            strIn = myPort.readStringUntil('\n');         // read it and store it in a string called strIn
            String[] coordinates = split(strIn, ",");    
            //Cut the strIn string at the comma into two strings called coordinates. 
            //We expect a message coming in something like "XXX,YYY"
            int locX = int(trim(coordinates[0]));        //This says that the first string is an integer called LocX
            int locY = int(trim(coordinates[1]));       //This says that the next string is an integer called LocX
            color pix = img.get(locX, locY);             //look up the colour of the requested pixel
            stroke(pix);                                 //show the pixel on the canvas on screen
            point(locX, locY);
            int Bright = round(brightness(pix));        //sending pix will send a large negative string, so we will just send the brightness
            strOut = locX + "," + locY + "," + Bright + "L" + "\n";  //put all the needed values into a string called strOut
            delay(10);                                   //wait a bit
            myPort.write(strOut);                                    //send it over serial port to the arduino to parse
            coordinates = null;                          //flush all strings
            strOut= null;
            strIn=null;
          }
        }
    
Sign In or Register to comment.