Null Pointer Exceptions problem

hello hi, sorry am trying to get data from arduino through serial port to processing ide but a getting an error that say Null Pointer Exceptions. below is my full processing code.

// Import Meter library
import meter.*;

// Import serial library
import processing.serial.*;

Serial serial_port = null;        // the serial port

// serial port buttons
Button btn_serial_up;              // move up through the serial port list
Button btn_serial_dn;              // move down through the serial port list
Button btn_serial_connect;         // connect to the selected serial port
Button btn_serial_disconnect;      // disconnect from the serial port
Button btn_serial_list_refresh;    // refresh the serial port list
String serial_list;                // list of serial ports
int serial_list_index = 0;         // currently selected serial port 
int num_serial_ports = 0;          // number of serial ports in the list

PImage img;

Meter m, m2, m3, m4, m5, m6, m7, m8;

void setup(){
  // First we need to create a empty window
  size(1860, 800); // Size of the window (width, height)
  background(10, 10, 82); // Background color of window (R,G,B)
  
 // create the buttons
  btn_serial_up = new Button("^", 140, 730, 40, 20);
  btn_serial_dn = new Button("v", 140, 690, 40, 20);
  btn_serial_connect = new Button("Connect", 190, 670, 100, 25);
  btn_serial_disconnect = new Button("Disconnect", 190, 710, 100, 25);
  btn_serial_list_refresh = new Button("Refresh", 190, 750, 100, 25);
  
  // get the list of serial ports on the computer
  serial_list = Serial.list()[serial_list_index];
  
  //println(Serial.list());
  //println(Serial.list().length);
  
  // get the number of serial ports in the list
  num_serial_ports = Serial.list().length;
  
 
  // TANK 1
  
  m = new Meter(this, 10, 51);  // here 25, 10 are x and y coordinates of meter's upper left corner
  
  m.setTitleFontSize(20);
  m.setTitleFontName("Arial bold");
  m.setTitle("TANK 1 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m.setScaleLabels(scaleLabels);
  m.setScaleFontSize(18);
  m.setScaleFontName("Times new roman bold");
  m.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m.setArcColor(color(141, 113, 178));
  m.setArcThickness(15);
  
  m.setMaxScaleValue(100);
  
  m.setMinInputSignal(0);
  m.setMaxInputSignal(100);
  
  m.setNeedleThickness(3);
  
  // TANK 2
  // lets take some refference from first meter
  int mx = m.getMeterX(); // x coordinate of m
  int my = m.getMeterY(); // y coordinate of m
  int mw = m.getMeterWidth();
  
  m2 = new Meter(this, mx + mw + 20, my);
  
  m2.setTitleFontSize(20);
  m2.setTitleFontName("Arial bold");
  m2.setTitle("TANK 2 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels2 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m2.setScaleLabels(scaleLabels2);
  m2.setScaleFontSize(18);
  m2.setScaleFontName("Times new roman bold");
  m2.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m2.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m2.setArcColor(color(141, 113, 178));
  m2.setArcThickness(15);
  
  m2.setMaxScaleValue(100);
  
  m2.setMinInputSignal(0);
  m2.setMaxInputSignal(100);
  
  m2.setNeedleThickness(3);
  
  ////WATER TANK 3

  // lets take some refference from first meter
  int mx1 = m.getMeterX(); // x coordinate of m
  int my1 = m.getMeterY(); // y coordinate of m
  int mw1 = m.getMeterWidth();
  
  //m3 = new Meter(this, 250, 400);
   m3 = new Meter(this, mx + mw + 490, my);
  
  m3.setTitleFontSize(20);
  m3.setTitleFontName("Arial bold");
  m3.setTitle("TANK 3 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels3 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m3.setScaleLabels(scaleLabels3);
  m3.setScaleFontSize(18);
  m3.setScaleFontName("Times new roman bold");
  m3.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m3.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m3.setArcColor(color(141, 113, 178));
  m3.setArcThickness(15);
  
  m3.setMaxScaleValue(100);
  
  m3.setMinInputSignal(0);
  m3.setMaxInputSignal(100);
  
  m3.setNeedleThickness(3);
  
  
   ////WATER TANK 4

  // lets take some refference from first meter
  int mx2 = m.getMeterX(); // x coordinate of m
  int my2 = m.getMeterY(); // y coordinate of m
  int mw2 = m.getMeterWidth();
  
  //m3 = new Meter(this, 250, 400);
   m4 = new Meter(this, mx + mw + 950, my);
  
  m4.setTitleFontSize(20);
  m4.setTitleFontName("Arial bold");
  m4.setTitle("TANK 4 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels4 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m4.setScaleLabels(scaleLabels4);
  m4.setScaleFontSize(18);
  m4.setScaleFontName("Times new roman bold");
  m4.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m4.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m4.setArcColor(color(141, 113, 178));
  m4.setArcThickness(15);
  
  m4.setMaxScaleValue(100);
  
  m4.setMinInputSignal(0);
  m4.setMaxInputSignal(100);
  
  m4.setNeedleThickness(3);
  
  
  
  // TANK 5
  
  m5 = new Meter(this, 10, 380);  // here 25, 10 are x and y coordinates of meter's upper left corner
  
  m5.setTitleFontSize(20);
  m5.setTitleFontName("Arial bold");
  m5.setTitle("TANK 5 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels5 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m5.setScaleLabels(scaleLabels5);
  m5.setScaleFontSize(18);
  m5.setScaleFontName("Times new roman bold");
  m5.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m5.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m5.setArcColor(color(141, 113, 178));
  m5.setArcThickness(15);
  
  m5.setMaxScaleValue(100);
  
  m5.setMinInputSignal(0);
  m5.setMaxInputSignal(100);
  
  m5.setNeedleThickness(3);
  
  
   // TANK 6
  // lets take some refference from first meter
  int mx3 = m.getMeterX(); // x coordinate of m
  int my3 = m.getMeterY(); // y coordinate of m
  int mw3 = m.getMeterWidth();
  
   m6 = new Meter(this, 470, 380);  // here 25, 10 are x and y coordinates of meter's upper left corner
  
  m6.setTitleFontSize(20);
  m6.setTitleFontName("Arial bold");
  m6.setTitle("TANK 6 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels6 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m6.setScaleLabels(scaleLabels6);
  m6.setScaleFontSize(18);
  m6.setScaleFontName("Times new roman bold");
  m6.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m6.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m6.setArcColor(color(141, 113, 178));
  m6.setArcThickness(15);
  
  m6.setMaxScaleValue(100);
  
  m6.setMinInputSignal(0);
  m6.setMaxInputSignal(100);
  
  m6.setNeedleThickness(3);
  
  
  
  // TANK 7
  // lets take some refference from first meter
  int mx4 = m.getMeterX(); // x coordinate of m
  int my4 = m.getMeterY(); // y coordinate of m
  int mw4 = m.getMeterWidth();
  
   m7 = new Meter(this, 941, 380);  // here 25, 10 are x and y coordinates of meter's upper left corner
  
  m7.setTitleFontSize(20);
  m7.setTitleFontName("Arial bold");
  m7.setTitle("TANK 7 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels7 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m7.setScaleLabels(scaleLabels7);
  m7.setScaleFontSize(18);
  m7.setScaleFontName("Times new roman bold");
  m7.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m7.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m7.setArcColor(color(141, 113, 178));
  m7.setArcThickness(15);
  
  m7.setMaxScaleValue(100);
  
  m7.setMinInputSignal(0);
  m7.setMaxInputSignal(100);
  
  m7.setNeedleThickness(3);
  
  
  
  // TANK 8
  // lets take some refference from first meter
  int mx5 = m.getMeterX(); // x coordinate of m
  int my5 = m.getMeterY(); // y coordinate of m
  int mw5 = m.getMeterWidth();
  
   m8 = new Meter(this, 1400, 380);  // here 25, 10 are x and y coordinates of meter's upper left corner
  
  m8.setTitleFontSize(20);
  m8.setTitleFontName("Arial bold");
  m8.setTitle("TANK 8 WATER LEVEL(%)");
  
  // Change meter scale values
  String[] scaleLabels8 = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
  m8.setScaleLabels(scaleLabels8);
  m8.setScaleFontSize(18);
  m8.setScaleFontName("Times new roman bold");
  m8.setScaleFontColor(color(200, 30, 70));
  
  // We can also display the value of meter
  m8.setDisplayDigitalMeterValue(true);
  
  // Lets do some more modifications so our meter looks nice
  m8.setArcColor(color(141, 113, 178));
  m8.setArcThickness(15);
  
  m8.setMaxScaleValue(100);
  
  m8.setMinInputSignal(0);
  m8.setMaxInputSignal(100);
  
  m8.setNeedleThickness(3);
  
}


void mousePressed() {
  // up button clicked
  if (btn_serial_up.MouseIsOver()) {
    if (serial_list_index > 0) {
      // move one position up in the list of serial ports
      serial_list_index--;
      serial_list = Serial.list()[serial_list_index];
    }
  }
  // down button clicked
  if (btn_serial_dn.MouseIsOver()) {
    if (serial_list_index < (num_serial_ports - 1)) {
      // move one position down in the list of serial ports
      serial_list_index++;
      serial_list = Serial.list()[serial_list_index];
    }
  }
  // Connect button clicked
  if (btn_serial_connect.MouseIsOver()) {
    if (serial_port == null) {
      // connect to the selected serial port
      serial_port = new Serial(this, Serial.list()[serial_list_index], 9600);
    }
  }
  // Disconnect button clicked
  if (btn_serial_disconnect.MouseIsOver()) {
    if (serial_port != null) {
      // disconnect from the serial port
      serial_port.stop();
      serial_port = null;
    }
  }
  // Refresh button clicked
  if (btn_serial_list_refresh.MouseIsOver()) {
    // get the serial port list and length of the list
    serial_list = Serial.list()[serial_list_index];
    num_serial_ports = Serial.list().length;
  }
}

void draw(){
  
  
   if (serial_port.available()> 0){
    String val = serial_port.readString(); // read incoming string on serial port
    // First we need to separate  values
    String[] list = split(val, ','); // splits value separated by ','
    int tank_1 = int(list[0]); // Tank1
    int tank_2 = int(list[1]);  // Tank2
    int tank_3 = int(list[2]);  //  Tank3
    int tank_4 = int(list[3]);  // Tank4
    int tank_5 = int(list[4]);  // Tank5
    int tank_6 = int(list[5]);  // Tank6
    int tank_7 = int(list[6]);  // Tank7
    int tank_8 = int(list[7]);  // Tank8
    m.updateMeter(int(tank_1)); // int is used due to updateMeter accepts only int values
    m2.updateMeter(int(tank_2));
    m3.updateMeter(int(tank_3));
    m4.updateMeter(int(tank_4));
    m5.updateMeter(int(tank_5));
    m6.updateMeter(int(tank_6));
    m7.updateMeter(int(tank_7));
    m8.updateMeter(int(tank_8));
    println("Water Tank 1 Level: " + tank_1 + " %  " + "Water Tank 2 Level: " + tank_2+ "%"+"Water Tank 3 Level: "+tank_3+ "%"+"Water Tank 4 Level: "+tank_4+ "%"+"Water Tank 5 Level: "+tank_5+ "%" +"Water Tank 6 Level: "+tank_6+ "%"+"Water Tank 7 Level: "+tank_7+ "%"+"Water Tank 8 Level: "+tank_8+ "%");
  }
  
   // draw the buttons in the application window
  btn_serial_up.Draw();
  btn_serial_dn.Draw();
  btn_serial_connect.Draw();
  btn_serial_disconnect.Draw();
  btn_serial_list_refresh.Draw();
  // draw the text box containing the selected serial port
  DrawTextBox("Select Port", serial_list, 10, 690, 120, 60);
}

// function for drawing a text box with title and contents
void DrawTextBox(String title, String str, int x, int y, int w, int h)
{
  fill(255);
  rect(x, y, w, h);
  fill(0);
  textAlign(LEFT);
  textSize(14);
  text(title, x + 10, y + 10, w - 20, 20);
  textSize(12);  
  text(str, x + 10, y + 40, w - 20, h - 10);
}

// button class used for all buttons
class Button {
  String label;
  float x;    // top left corner x position
  float y;    // top left corner y position
  float w;    // width of button
  float h;    // height of button
  
  // constructor
  Button(String labelB, float xpos, float ypos, float widthB, float heightB) {
    label = labelB;
    x = xpos;
    y = ypos;
    w = widthB;
    h = heightB;
  }
  
  // draw the button in the window
  void Draw() {
    fill(218);
    stroke(141);
    rect(x, y, w, h, 10);
    textAlign(CENTER, CENTER);
    fill(0);
    text(label, x + (w / 2), y + (h / 2));
  }
  
  // returns true if the mouse cursor is over the button
  boolean MouseIsOver() {
    if (mouseX > x && mouseX < (x + w) && mouseY > y && mouseY < (y + h)) {
      return true;
    }
    return false;
  }
}

The errors that I got are all related to trying to use fonts that are not available on my system. You can use printArray(PFont.list()); to find the font list for your system. Then you will have to find/replace all the unavailable fonts in your source code to use fonts which are available on your system. There is an Examples/meter/Change_Fonts demo which might be helpful; it runs on my Mac without changing any of the fonts in the meter library, so in theory all you have to do is change the fonts in your source code. However, this alone wonā€™t make the error message go away. You also forgot to set the serial_port; need to use something like this:

serial_port = new Serial(this, Serial.list()[2], 9600);

Then your demo should run.
fonts

Hello @Emmanuel,

These should help with the ā€œNull Pointer Exceptionā€:

:)

@Emmanuel Hi, There are several challenges hereā€¦

Fault finding technique: To find where the problem is I put
print("Setup A ");
at the start of setup, and similar with ā€˜Zā€™ at the end. Then similar with various letters in draw to find the problem.

As @svan says you havenā€™t initialised the port. I put

  serial_port = new Serial(this, "COM9", 9600);

as the last line of setup and it went past that problem. Change it for your correct port name. (Iā€™ve never liked the example given with serial_list[index], it causes too much confusion.)

The sketch has buttons and functions to disconnect and change to another port once running. The challenge is that itā€™s trying to use the serial before itā€™s displayed those buttons and the user has made the selection. If you want to make all that work, you need to use logic to stop the serial action until that selection has been made and is successful.

Next issue was indexing beyond an array. I tried adding ā€˜delay(500)ā€™ after the ā€˜new Serialā€™ to give the Ard a moment to start. Didnā€™t fix it by itself. I donā€™t have your Ard code, so I made mine send a long string ā€œ1,2,3,4,5ā€¦ā€ etc. Still not fixed.

This code is unreliable

   if (serial_port.available()> 0){
    String val = serial_port.readString(); // read incoming string on serial port
    // First we need to separate  values
    String[] list = split(val, ','); // splits value separated by ','
    int tank_1 = int(list[0]);  // Tank1
    int tank_2 = int(list[1]);  // Tank2
    ...

because you are taking action as soon as there are any chars available, but the code needs the whole string to have arrived. Just to make it work, but this is not correct I put
if (serial_port.available()> 20){
That let the whole program run, and look alright sort-of, but the values are wrong.

You need a method of not reading the data until itā€™s all arrived, and staying in-sync with the sets of values. A common method is to put a linefeed character ā€˜\nā€™ on the end of what is sent, and use readStringUntil(ā€˜\nā€™). This has been mentioned in lots of topics e.g. here. In my example I put A and Z on either end of the string to check that it was complete.

Some of us donā€™t use Windows.

1 Like

@svan, aah yes, well done. On Pi use ā€˜ls /devā€™ to see what you have. For me, one Ard is showing as ttyUSB0, another as ttyACM0. So e.g.

  serial_port = new Serial(this, "/dev/ttyUSB0", 9600);

I think Mac will be the same.

On Mac Iā€™ve got /dev/cu.Something and /dev/tty.Something for each port.