Codebox: Handling exceptions in Processing

Arduino
Codebox: Handling exceptions in Processing
MZ_Codebox.gif

In Codebox: Save sensor data to Google Spreadsheets, reader Stairs observed that the sketch blew up when he didn’t have an Arduino device hooked up. When he dug out the device, plugged it in, and restarted the sketch, it worked fine.

This illustrates a great point about Processing, programming, and life in general: we live in an imperfect world. Nice little sketches get started with no Arduino plugged in, numbers are divided by zero, people run with scissors, and so on and so forth. In Processing, conditions like these are called exceptions, and this post provides a gentle introduction on how to deal with (or, more officially, handle) them. (NB: this post will not prevent running with scissors.)

So, first, how does Processing let you know when something has gone really wrong? In general (unless something has gone hugely wrong!), you’ll start the sketch and then see something like the following figure:

ano_arduino_serial_error_010411.png

Notice all the red error messages in the message area, which is where Processing tells you about what’s gone wrong. In this case, the error is PortInUseException(), which, if you start Googling, you’ll find has something of a checkered reputation in Processing. (More on this later.) The message also tells you on which line the error was thrown. Additionally, the offending line is highlighted in yellow in the text editor. Depending on where the error occurs, the sketch window may or may not appear, and even if it is visible, it almost certainly won’t do what you expect.

To reproduce this error (or one like it — see the caveats section at the bottom of the post!), paste the text for simple_port.pde into Processing. If all goes well, the sketch reads the serial port once a second and displays the elapsed time and the value read from the port.

Of course, we don’t want all to go well (that’s the point of this post), so make sure your Arduino is unplugged when you run the sketch. You should see something resembling the previous figure. Now we’re ready to add code to deal with (or handle, which is the formal term) the disconnected device.

To handle an exception in Processing (and Java, of which Processing is a subset), we place the suspect code inside a “try-catch-finally” block. Processing then “tries” to execute the code, and if any exceptions are thrown, they’re “caught” by other blocks. The syntax looks like this:

try {
   The suspect code you want to try to execute
   ...
} catch (ExceptionType1 e1) {
   // code to execute if ExceptionType1 is thrown in the try block
   println(e1.getMessage());
   ...
} catch (ExceptionType1 e2) {
   // code to execute if ExceptionType2 is thrown in the try block
   println(e2.getMessage());
   ...
} catch (ExceptionType3 e3) {
   // code to execute if ExceptionType3 is thrown in the try block
   println(e3.getMessage());
   ...
} finally {
   // Clean up code here
   ...
}

Since exceptions aren’t covered in Getting Started with Processing, let me answer a few general questions you might have:

  • What do you mean by suspect code? Initially, you might think all code is suspect, but exception handling is mostly used in a few key circumstances, such as reading or writing to a file, pulling data across a network, or communicating with a device (like a serial port). In fact, many libraries require you to enclose certain methods within a try-catch block or the code won’t compile at all. For example, if you removed the try block from the google spreadsheet code, the program wouldn’t even compile. Library designers do this to force programmers into good habits.
  • What are all those catch statements about? Since code can go wrong in all sorts of ways, we need to be able to handle a lot of different possibilities. So, each catch statement is associated with one particular type of error. If that specific type of error occurs, then the corresponding block of code executes. For example, suppose you were trying to read some data from a file. The file simply might not exist, which throws a FileNotFoundException exception. Or, the file might exist, but somehow becomes unavailable while you’re reading it. This throws an EOFException. Or, something just plain weird happens in the IO stream, which throws a hail-mary IOException. You can create a catch block for each of these circumstances. Perhaps the best analogy is the if-then-else block described on page 64 of the Getting Started book.
  • What does the stuff in the parentheses after catch mean? These are like arguments to a function — the first token identifies the type of exception that should cause the block to fire, and the second is a variable that allows you to access the exception’s data and methods. (Exceptions, like everything in Processing, are objects.) For example, if you had a line like this — catch (FileNotFoundException e), that block would execute if the code in the try block couldn’t find a file you were looking for. Inside the block, you would have a variable called e that you could use to find out more about what was going wrong. For example, you could use its getMessage() method to print the details of the error out to the message area
  • Does the order of the catch statements matter? Yes. Processing will fire the first catch block that matches the exception’s class or superclass. Since objects are hierarchical, that means that some exceptions are higher up the food chain than others. Consequently, they match almost everything. (The highest ranking exception class is called Exception, which matches everything.) So, you need to put the most specific types exceptions first and more general exceptions later.
  • What does “finally” mean? The finally block is optional and allows you to add code that will always executes, whether an error occurs or not. This is usually used for cleanup code. For example, if you open a file, you might want to close it in the finally block.
  • What if I don’t have the exact type of error in my catch blocks? The short answer is that your program blows up. This is a situation, called an unhandled exception, is generally what you’re trying to avoid. As a final catch all, you can simply add a catch (Exception e) as the final catch block. This is the most generic type of exception object, so it should catch most errors.

Whew. Enough theory. Let’s return to the original problem of preventing our code from blowing up. (Still, we’ve only scratched the surface. If you want to learn more, check out Lesson: Exceptions, a great tutorial from Oracle.)

Since our code is blowing up on the line port = new Serial(this, arduinoPort, 9600);, this is a pretty obvious place to put a try-catch block. What we want the code to do is test if there are any exceptions at all on this line (we don’t really care what), and if there are, display a “Plug in Arduino” message. As soon as an Arduino is plugged in, we want to start displaying the counter and the current value from the serial port. Here’s a revised version of the code, simple_port2.pde, that does this.

You should see something like the following figure when you run this code.

ano_exception_handling_010411.png

So, what’s happening here? The first thing you’ll notice is that I moved the offending line out of the setup() method and into the draw() method. This makes sure that the sketch will repeatedly test if the Arduino is found; doing the test in setup() would mean that it only happens once, when the sketch starts. Next, I’ve created a flag called ardinoOK — if this flag is false, we want to try to grab the port and display the error message. If the flag it true true, then we want to read the port and display the values. Finally, I’ve embedded the port = new Serial(this, arduinoPort, 9600); line inside a try-catch block. If the command succeeds, then we set arduinoOK to true. If an exception occurs, we catch it with the catch (Exception e) block and set arduinoOK to false. Since this code is inside draw(), it repeats this logic over and over. Voila!

Caveats

As I’ve hinted throughout, exception handling for this project has been a bit difficult to deal with. For example, Stairs (the reader whose comment kicked off this post) reported an ArrayIndexOutOfBoundsExeption. That implied that the code was blowing up at String arduinoPort = Serial.list()[0]:, indicating that there were no devices. “Ha,” I thought, I’ll just test for that exception. However, when I ran it on my Mac, I found several devices already in the list, so it wasn’t blowing up with the same error Stairs was getting. Pluggin in the Arduino merely added two new items to the list, as shown in the following table.

No Arduino Installed Arduino Installed
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
[0] "/dev/tty.Bluetooth-Modem"
[1] "/dev/cu.Bluetooth-Modem"
[2] "/dev/tty.Bluetooth-PDA-Sync"
[3] "/dev/cu.Bluetooth-PDA-Sync"
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
[0] "/dev/tty.usbmodem1d11"
[1] "/dev/cu.usbmodem1d11"
[2] "/dev/tty.Bluetooth-Modem"
[3] "/dev/cu.Bluetooth-Modem"
[4] "/dev/tty.Bluetooth-PDA-Sync"
[5] "/dev/cu.Bluetooth-PDA-Sync"
Experimental:  JNI_OnLoad called.

A bit of Googling indicated that Macs have a couple of processes running by default to pick up new devices, like cameras or bluetooth devices. So, I figured Stairs must be on a PC, which didn’t have these items.

However, my code was still blowing up, but for a different error: gnu.io.PortInUseException. “Ha!,” I though, I can just catch that one. But, this didn’t work, either. Googling around, I discovered that there seems to be a weird bug on OS X that makes catching this exception problematic, and that you have to reinstall or delete various portions of the Serial library to make them work. So, that didn’t work either. Finally, I just settled on catching the most generic Exception to get it to work.

Then, I wanted to do a bit more about how you’d catch errors while the sketch was running. Specifically, I wanted to handle the case where the Arduino is plugged in, the sketch starts running, and the you unplug it mid-stream. However, when I tried this, I got this error message which seemed to come from the operating system:

ano_usb_unplugged_error_010411.png

Since it was handled higher up in the food chain, the error never flowed down into Processing as an exception, so the sketch just hummed along merrily. Hmmm, I thought. So, a bit of Googling revealed that it’s very bad to do what I planned, and that it can lead to all sorts of problems. So, I guess the Mac has safeguards built in to prevent problems downstream. I guess I should be thankful, but it bummed me out for this example.

All this goes to show that it can be really, really difficult to pin down programming errors because there are so many complexities and interdependencies. I think this is probably why so many programmers become Makers. In a profession where 6 months can be an eternity, it’s satisfying to know that the machines you build out of gears and levers would probably be comprehensible to Aristotle. Frankly, it’s incredible that the world runs as smoothly as it does.

Thank you, exception handlers everywhere!

In the Maker Shed:

Makershedsmall

processingCover.jpg

Getting Started with Processing
Learn computer programming the easy way with Processing, a simple language that lets you use code to create drawings, animation, and interactive graphics. Programming courses usually start with theory,but this book lets you jump right into creative and fun projects. It’s ideal for anyone who wants to learn basic programming, and serves as a simple introduction to graphics for people with some programming skills.

What will the next generation of Make: look like? We’re inviting you to shape the future by investing in Make:. By becoming an investor, you help decide what’s next. The future of Make: is in your hands. Learn More.

Tagged
Discuss this article with the rest of the community on our Discord server!

ADVERTISEMENT

Escape to an island of imagination + innovation as Maker Faire Bay Area returns for its 16th iteration!

Prices Increase in....

Days
Hours
Minutes
Seconds
FEEDBACK