'Nullpointerexception' error

edited June 2015 in Library Questions

Hi All!

I'm new to Processing so, have mercy... I keep getting a 'nullpointerexception' error but I cant figure out why.

that's my code (I tried to format it as code but, in the preview its still a mess, sorry I'll give it a shot anyway) : I get the 'Nullpointerexception' error on the fill (sensor1Data [k], 0, 0); line in the draw procedure.

import processing.serial.*;

Serial CommPort ;
int [ ] sensor1Data ;
int [ ] sensor2Data ;
int [ ] sensor3Data ;
int [ ] sensor4Data ;
int sensor_cnt = 1 ;
int last_in = 0 ;

void setup() 
  {
  size(800, 800);
  frameRate(30);
  CommPort = new Serial (this, Serial.list( ) [1], 38400);
  CommPort.bufferUntil ('\r');
  println(Serial.list());
  }

void draw()
  {
  background( 100 ) ; 
  if (last_in == 1)
    {
    println( "Update Display" ) ;
    for(int k = 0 ; k < 20 ; k++ )
      {
      fill (sensor1Data [k], 0, 0);
      rect(k*30, 330-k*15, 30, 30) ;
      fill (sensor2Data [k], 0, 0) ;
      rect(k*30, 365-k*5, 30, 30) ;
      fill (sensor3Data [k], 0, 0) ;
      rect(k*30, 400+k*5, 30, 30) ;
      fill (sensor4Data [k], 0, 0) ;
      rect(k*30, 435+k*15, 30, 30) ;
      } 
    last_in = 0 ;
    }
  }

void serialEvent ( Serial CommPort )
{
  println( "Data In!" ) ;
  String usbString = CommPort.readStringUntil ('\r');
  if (usbString != null)
  {
    usbString = trim(usbString);
    switch (sensor_cnt)
    {
    case 1:
      {
        int sensor1Data[ ] = int (split (usbString, ','));
        for (int sensorNum = 0; sensorNum < sensor1Data.length; sensorNum++)
          println( "Sensor1 " + sensorNum + ": " + sensor1Data [sensorNum] );
        sensor_cnt++ ;
      } 
      break ;
    case 2:
      {
        int sensor2Data[ ] = int (split (usbString, ','));
        for (int sensorNum = 0; sensorNum < sensor2Data.length; sensorNum++)
          println( "Sensor2 " + sensorNum + ": " + sensor2Data [sensorNum] );
        sensor_cnt++ ;
      } 
      break ;
    case 3:
      {
        int sensor3Data[ ] = int (split (usbString, ','));
        for (int sensorNum = 0; sensorNum < sensor3Data.length; sensorNum++)
          println( "Sensor3 " + sensorNum + ": " + sensor3Data [sensorNum] );
        sensor_cnt++ ;
      } 
      break ;
    case 4:
      {
        int sensor4Data[ ] = int (split (usbString, ','));
        for (int sensorNum = 0; sensorNum < sensor4Data.length; sensorNum++)
          println( "Sensor4 " + sensorNum + ": " + sensor4Data [sensorNum] );
        sensor_cnt = 1 ;
        last_in = 1 ;
      } 
      break ;
    }
  }
}

Many Thanks

Omer

Answers

  • GoToLoop Hi!

    That's exactly what I did and that's exactly what I got...

    I just don't know what else to do, I can't even get in the game...

    Thanks

    Omer

  • The error is that sensor1Data [k] (and sensor 2, 3 and 4) is null... most likely serialEvent() did not get called before draw() is executed. You have to somehow make sure sensor1Data [k] is not null before calling it. You could use a boolean to determine if serialEvent() was called yet, or you could simply check if sensor1Data [k] != null before displaying.

    I don't know what your data looks like, but be careful with the for loop at line 26: for(int k = 0 ; k < 20 ; k++ ). Are you sure there are always 20 elements in the array?

  • colouredmirrorball Hi!

    Thanks for your response.

    For your comment, I do check if there was serialEvent() before I read the array, the line: if (last_in == 1) do just that and it works fine, I can see the 'Update Display' comment on the terminal when I should.

    Thanks

    Omer

  • Not entirely, you only check for the fourth sensor...

    Try to add a println(sensor1Data == null) before your for loop in draw(), it should never print true (and if it does, fix your code so it doesn't).

  • colouredmirrorball Hi!

    I added the line you suggested and it does print true but, that is exactly the point.

    How could the sensor1data be null if theserialEvent() just filled it with data?

    I know it does, I print them on the terminal!

    Thanks

    Omer

  • Looks like your assumption is wrong. The simplest solution is probably to be prepared for your arrays to be 0:

    if( sensor1Data == null || sensor2Data == null || sensor3Data == null || sensor4Data == null)
    {
       println("Something was null");
    }
    else
    {
       for(int k = 0; //etc
    
  • colouredmirrorball Hi!

    Thanks for you time and help.

    I think we have a little communication problem, it is clear that the arrays sensorXData are null, the problem is why!

    It's a global variable that was assigned values by another procedure but appear to be null to the draw() procedure.

    Your code additions (that worked very well, thanks again!) only prove that.

    what I can't figure out is why.

    Thanks, Omer

  • I can't tell for sure, maybe the data was not correctly parsed or something. Try a couple println(sensor#Data) and see if they're what you would expect.

  • colouredmirrorball Hi!

    I did that too...

    As you can see in the serialEvent() procedure for every array there is a println() line:

     println( "Sensor1 " + sensorNum + ": " + sensor1Data [sensorNum] );
    

    And it works great, I can see that all my data was received correctly.

    Thanks,

    Omer

  • edited June 2015

    What I can't figure out is why.
    I can't tell for sure, maybe the data was not correctly parsed or something.

    • Callback serialEvent() is run by Serial's Thread.
    • While the rest of the sketch is run by the "Animation" Thread.
    • If draw(), under "Animation" Thread, happens before those int[] arrays are 1st initialized inside serialEvent(), an NPE's gonna be thrown.
    • Easiest fix is delay() the start of draw() until all int[] arrays aren't null at the end of setup().

    while (sensor1Data == null | sensor2Data == null | sensor3Data == null | sensor4Data == null)
      delay(10);
    
  • edited June 2015

    Also, it'd be nicer if you had a 2D int[][] array rather than 4 separate 1D int[] arrays: ;)

    final int[][] sensors = new int[4][];
    
  • GoToLoop Hi!

    The sensor data print in the draw() procedure is conditioned by the last_in flag:

    if (last_in == 1)
        {
        println( "Update Display" ) ;
        for(int k = 0 ; k < 20 ; k++ )
        ...
    

    and this part works fine I can see that on the terminal.

    Thanks,

    Omer

  • edited June 2015
    • You've asked the reason why the NPE happened before. So I've provided an explanation! :-B
    • I see that you rect() only after all of those 4 int[] arrays are "re-filled".
    • So the smartest thing to do is simply issue a noLoop() in setup().
    • Then use redraw() within serialEvent() once you got the last 4th int[] updated.
    • Doing so, the canvas is refreshed exactly when all data is fully updated! :P

    1. https://processing.org/reference/noLoop_.html
    2. https://processing.org/reference/redraw_.html
  • GoToLoop Hi!

    I tried your idea to move the screen update to the serialEvent() procedure but, now I'm getting a different error: Error, disabling serialEvent() for COM8 null

    Now, what is that???

    Thanks,

    Omer

  • Could be serialEvent() relies on draw being called? Maybe post your updated code so we can see if there's something else wrong.

  • edited June 2015

    colouredmirrorball Hi!

    Sorry for the delay...(went to watch 'Entourage', very funny!).

    I attached the new serialEvent() procedure however I don't think the problem is there, I think I'm doing something fundamentally wrong, missing some definition somewhere or some other very basic thing...

    it just doesn't make sense to me that the main function of 'Processing' can not use a global variable!

    I'm just to 'green' with Processing to find it out.

    void serialEvent ( Serial CommPort )
    {
      println( "Data In!" ) ;
      String usbString = CommPort.readStringUntil ('\r');
      if (usbString != null)
      {
        usbString = trim(usbString);
        switch (sensor_cnt)
        {
        case 1:
          {
            int sensor1Data[ ] = int (split (usbString, ','));
            for (int sensorNum = 0; sensorNum < sensor1Data.length; sensorNum++)
              println( "Sensor1 " + sensorNum + ": " + sensor1Data [sensorNum] );
            sensor_cnt++ ;
          } 
          break ;
        case 2:
          {
            int sensor2Data[ ] = int (split (usbString, ','));
            for (int sensorNum = 0; sensorNum < sensor2Data.length; sensorNum++)
              println( "Sensor2 " + sensorNum + ": " + sensor2Data [sensorNum] );
            sensor_cnt++ ;
          } 
          break ;
        case 3:
          {
            int sensor3Data[ ] = int (split (usbString, ','));
            for (int sensorNum = 0; sensorNum < sensor3Data.length; sensorNum++)
              println( "Sensor3 " + sensorNum + ": " + sensor3Data [sensorNum] );
            sensor_cnt++ ;
          } 
          break ;
        case 4:
          {
            int sensor4Data[ ] = int (split (usbString, ','));
            for (int sensorNum = 0; sensorNum < sensor4Data.length; sensorNum++)
              println( "Sensor4 " + sensorNum + ": " + sensor4Data [sensorNum] );
            sensor_cnt = 1 ;
            last_in = 1 ;
              } 
              break ;
          }
        }
      if(last_in==1)
        {
                for (int k=0; k<20; k++ )
              {
              fill (sensor1Data [k], 0, 0);
              rect(k*30, 330-k*15, 30, 30) ;
              fill (sensor2Data [k], 0, 0);
              rect(k*30, 365-k*5, 30, 30) ;
              fill (sensor3Data [k], 0, 0);
              rect(k*30, 400+k*5, 30, 30) ;
              fill (sensor4Data [k], 0, 0);
              rect(k*30, 435+k*15, 30, 30) ;
              } 
              redraw() ;
        last_in = 0 ;        
        }  
    }
    

    Thanks, Omer

  • edited June 2015

    From: http://forum.processing.org/two/discussion/11184/problem-to-change-the-color-according-to-sensor-values

    We should never directly access sketch's canvas outside its "Animation" Thread.
    FYI, serialEvent() is run by Serial's own Thread.

  • GoToLoop Hi!

    I understand what you are saying (although it really hard to accept that such a barrier exist in this kind of software... I thought getting data from the serial port is one of its most basic features).

    So, how do one transfer variables to the draw() procedure from other threads? Since global variables are out, how can it be done?

    Thanks, Omer

  • No, global variables are the way to do it. You store the data in your global variables then display them in draw() instead of in serialEvent(). Why do you think Processing can't handle global variables? It's a bit out of the blue.

    Also, now that I'm "awake", your error

    Error, disabling serialEvent() for COM8 null

    is probably because either the COM port changed or the sensor board got disconnected. Use println(Serial.list()) to detect this.

  • colouredmirrorball Hi!

    I dropped the attempt to update the display in the serialEvent() procedure because well, it didn't work!

    Of course, it still not working in the draw() but at least it make more programming sense...

    The claim that global variable don't work is not 'out of the blue' it comes from a full day of failing to making a very simple chunk of code work!

    Thanks, Omer

  • Posting code might help.

  • colouredmirrorball Hi!

    The code is the same code I started with... see the beginning of this discussion.

    Thanks,

    Omer

  • But didn't you make some changes?

  • colouredmirrorball Hi!

    Yes, and after non of them actually worked I went back to the source.

    Thanks,

    Omer

  • Hi All! I found the problems I had in the code... sadly it was like I said, something very basic.

    The first problem was in the array definition, it should be:

    int [ ] sensor1Data = new int[21] ;

    With the 'new' statement.

    That took care of the 'Nullpointerexception' error.

    The second problem of transferring the data from the serialEvent() to the draw() came from the fact that this line:

    int Sensor1Data[ ] = int (split (usbString, ',')); create a new Local array, with the same name as the global array...

    so, I rename the local array and copy it to the global array :

    case 1: { int TempSensor1Data[ ] = int (split (usbString, ',')); for (int sensorNum = 0; sensorNum < TempSensor1Data.length; sensorNum++) println( "Sensor1 " + sensorNum + ": " + TempSensor1Data [sensorNum] ); arrayCopy(TempSensor1Data, sensor1Data); sensor_cnt++ ; }

    It may not be a prettiest code ever but, it will work for now.

    Anyway, thanks again guys.

    Thanks,

    Omer

Sign In or Register to comment.