Why am I getting errors on my server/client data parsing? Why does my data seem to stop sending?

edited November 2017 in Kinect

I am currently trying to setup a LAN between two computers, to send motion tracking data from one location to another. My code appears to work for a random length of time (anything from 2 seconds up to a minute) I either get one of two errors on different lines of code: StringIndexOutofBoundsException: String index out of range: -1 OR ArrayIndexOutofBounds: 1 I have commented in the code which lines I am getting the errors on.

I really have no idea why this is happening - could it be something to do with the rate at which the data is being sent i.e. frameRate? Or am I doing something wrong when parsing the strings into arrays?

There doesn't seem to be any correlation between the data that it crashes on, all I can think of at the moment is that it is something to do with the data not communicating quickly enough? I tried it on a frameRate of 10, and it seemed to work for longer, but I'm not sure if that was just a coincidence. The data continues to be generated and sent from the server but the client stops responding.

Any help would be greatly appreciated.

This is the client code (the one it crashes on that needs work):

import processing.net.*;

Client c;
String input;
String inputB;
String data[];
float xArr[];
float yArr[];

void setup() 
{
  size(displayWidth, displayHeight);
  background(204);
  stroke(0);
  frameRate(10); // Slow it down a little
  // Connect to the server's IP address and port
  c = new Client(this, "192.168.0.2", 61514); // Replace with your server's IP and port
}

void draw() 
{
  // Receive data from server
  if (c.available() > 0) {
    input = c.readString();

    println("Input");
    println(input);

    inputB = input.substring(0, input.indexOf("\n")); // Only up to the newline - this is where the first error happens 
    data = split(inputB, '#'); // Split values into an array

    println("Data");
    printArray(data);

    xArr = float(split(data[0], ":"));
    yArr = float(split(data[1], ":")); //this is where the second error happens (if it gets past the first one)

    for(int i = 0; i < yArr.length ; i++){
    strokeWeight(4);
    point(xArr[i],yArr[i]);
  }
  println("Arrays");
  println(xArr);
  println(yArr);

  }

  //println(input);
  //println(data);



}

This is the server code:

//setting up the server 
import processing.net.*;
Server s;
Client c;
String input;
int data[];

//imports Kinect lib
import SimpleOpenNI.*;

//defines variable for kinect object
SimpleOpenNI kinect;

//declare variables for mapped x y values
float x, y;

//declare variable for number of people 
float peopleNum = 0;

//initialise other variables that we might need
int userId;
float inches;
int count = 0;

//set up arrays for all values - current x/y, previous x/y, depth 
float[] oldXVals;
float[] newXVals;
float[] oldYVals;
float[] newYVals;
float[] storeDepth;

void setup() {

  //set the display size to full screen
  size(displayWidth, displayHeight);

  //declares new kinect object
  kinect = new SimpleOpenNI(this);

  //enable depth image
  kinect.enableDepth();

  //enable user detection
  kinect.enableUser();

  frameRate(10);

  //set background to white 
  background(255);

  //initialise starting array lengths
  oldXVals = new float[20];
  newXVals = new float[20];
  oldYVals = new float[20];
  newYVals = new float[20];
  storeDepth = new float[20];

  //start a simple server on a port
  s = new Server(this, 61514); // Start a simple server on a port

}

void draw() {

  //updates depth image
  kinect.update();

  //draws depth image - if we don't need this comment out 
  //image(kinect.depthImage(),0,0,displayWidth,displayHeight);

  //array to store depth values
  int[] depthValues = kinect.depthMap();

  //access all users currently available to us 
  IntVector userList = new IntVector();
  kinect.getUsers(userList);

  //sets variable peopleNum to the number of people currently detected by the kinect
  peopleNum = userList.size();

  //change the length of the array to the number of people currently present
  newXVals = new float[int (peopleNum)];
  newYVals = new float[int (peopleNum)];
  storeDepth = new float[int (peopleNum)];

  //for every user detected, do this 
  for (int i = 0; i<userList.size (); i++) {

    //get the userId
    userId = userList.get(i);

    //declare PVector position to store x/y position 
    PVector position = new PVector();

    //get the position
    kinect.getCoM(userId, position);
    kinect.convertRealWorldToProjective(position, position);

    //calculate depth
    //find the position of the center of mass *640 to give us a number to find in depth array
    int comPosition = int(position.x) + (int(position.y) * 640);    
    //locate it in the depth array
    int comDepth = depthValues[comPosition];
    //calculate distance in inches
    inches = comDepth / 25.4;

    //map x and y coordinates to full screen
    x = map(position.x, 0, 640, 0, displayWidth);
    y = map(position.y, 0, 480, 0, displayHeight);

    //store current values for each user in arrays
    newXVals[i] = x;
    newYVals[i] = y;

    //store depth values in array for each user (just the current values)
    storeDepth[i] = inches;  

    //DRAW THINGS HERE
    //To draw with only the current values, use newXVals and newYVals
    //i corresponds to position in array

    //setting these parameters means there is no "drop off" at the edges
    if (newXVals[i] >= 50 && newXVals[i] <= width - 50) {
      if (newYVals[i] >= 50 && newYVals[i] <= height - 50)
      //setting this parameter means that if a person is too close (less than 35 inches), they are ignored
        if (storeDepth[i] >= 35) {
          strokeWeight(4);
          point(newXVals[i], newYVals[i]);
        }
    }

    //prints each userId with its corresponding x/y values
    //println("User: " + userId + " xPos: " + x + " yPos: " + y + " depth: " + inches); 
    //prints the number of people present continuously 
    //println("There are " + numPeople + " people present");

  }

 if(newXVals.length >= 1 && newYVals.length >= 1){
 String[] newXValsString = nfc(newXVals, 1);
 //println(newXValsString);  
 String joinedXVals = join(newXValsString, ":");

  String[] newYValsString = nfc(newYVals, 1);
 //println(newYValsString);  
 String joinedYVals = join(newYValsString, ":");

 s.write(joinedXVals + "#" + joinedYVals + "\n");
 println(joinedXVals + "#" + joinedYVals + "\n");


 }

  //copy new value arrays to old value arrays
  arrayCopy(newXVals, oldXVals);
  arrayCopy(newYVals, oldYVals);


}

Answers

  • Answer ✓
    inputB = input.substring(0, input.indexOf("\n")); // Only up to the newline
    // this is where the first error happens 
    

    well, indexOf returns -1 if it doesn't find the character in the string and -1 is an invalid value for substring.

    so, assign the value of the indexOf to a local variable and check it before using it in the substring.

    data = split(inputB, '#');
    ....
    yArr = float(split(data[1], ":")); 
    // this is where the second error happens (if it gets past the first one)
    

    if the inputB doesn't have a # in it then split won't result in two elements in the data array. you can check this before trying to access the second element

    both of these can and should be avoided with better error checking. or, indeed, any error checking. don't just use values without checking they are valid.

    you print the values out, so it should be able to check the above is happening, try and find out when it happens. i would suggest, though, using println("[" + input + "]"); so that you can see the whitespace

  • Seems obvious now, thanks!!

Sign In or Register to comment.