Jul 132013
 
RasPiTV-RPi.GPIO-EXIT

You might think I’m going about this series in a funny way. You’d be right! I am. That’s because I’m trying to highlight the bits that people don’t read about in other tutorials/documentation/manuals/books. These bits are useful, important and often overlooked.

If I covered inputs and outputs first, you might not get to the rest because you’d already “know all I need”. That’s only partially true though. Although you can get away with not knowing or using this stuff, it’s much better and safer if you know it and use it.

So today we’re focussing on how to exit cleanly from a program that uses RPi.GPIO
I know – I’m bonkers! I haven’t even told you how to use RPi.GPIO yet and I’m already showing you how to exit cleanly. Bear with me! It makes sense. You need to know this stuff.

Correct use of GPIO.cleanup()

RPi.GPIO provides a built-in function GPIO.cleanup() to clean up all the ports you’ve used. But be very clear what this does. It only affects any ports you have set in the current program. It resets any ports you have used in this program back to input mode. This prevents damage from, say, a situation where you have a port set HIGH as an output and you accidentally connect it to GND (LOW), which would short-circuit the port and possibly fry it. Inputs can handle either 0V (LOW) or 3.3V (HIGH), so it’s safer to leave ports as inputs.

Here’s a simple example of how to use GPIO.cleanup()

import RPi.GPIO as GPIO

# the rest of your code would go here

# when your code ends, the last line before the program exits would be...
GPIO.cleanup()

# remember, a program doesn't necessarily exit at the last line!

If you use this, and the program exits normally, all the ports you’ve used will be cleaned up and ready for use straight away. But life’s not often as simple as that is it? More on that in a minute. First I want to show you…

Incorrect use of GPIO.cleanup()

I have seen people using GPIO.cleanup() wrongly at the start of a program, thinking it will clean up all the ports on the Pi. It does no such thing.1 If you put it at the top of your script, it’s just a wasted line of code. It does nothing until you’ve set up some ports for input or output (which we’re covering soon).

Use GPIO.cleanup() on exit, as I’ve shown above, and in slightly more complex situations, as I will show below…

Reasons for a program exit

There are at least three reasons, that I can think of, for exiting a program…

  1. Natural, controlled end – the program finished doing what it was written to do. Hurrah! It worked :)
  2. Error – something went wrong and the program “throws a wobbly” and “errors out”. Either a process failed in an unforeseen way, or there was a coding error in the program.
  3. Keyboard Interrupt – you pressed CTRL+C to stop the program. This is called a Keyboard Interrupt.

Both 2 & 3 are types of “exceptions”.

So what?

The problem is that, unless you code for these situations, any ports which are in use at the time of an error or Keyboard Interrupt will stay set exactly as they were, even after the program exits.

That’s an out of control situation – unacceptable, when you’re trying to take over the world with GPIO programming! Everything has to be under control.

If you then try to run the program again, when you try to set up the ports that are “still set” you’ll get warnings that the ports are “already in use”.

Switch off the warnings?

You can switch off the warnings, but that’s the “chicken’s way out”. It hides the problem, but doesn’t solve it. Still, you may choose to do it, so here’s how you do. Just place…

GPIO.setwarnings(False)

…near the top of your script, before you start setting up any ports.

Let’s try: a better way

My preferred method to catch errors and Keyboard Interrupts uses a try: except: block.
If you put your main piece of code in a try: block, it won’t “bomb straight out” of the program if an exception occurs (something doesn’t go according to plan).

You can specify different types of exceptions, including KeyboardInterrupt, and/or have a general one to catch every exception. There’s a list of Python Exceptions here. I’ve only ever used a couple of them.

Have a look at the code below to see how the exceptions are coded…

import RPi.GPIO as GPIO

# here you would put all your code for setting up GPIO,
# we'll cover that tomorrow
# initial values of variables etc...
counter = 0

try:
    # here you put your main loop or block of code
    while counter < 9000000:
        # count up to 9000000 - takes ~20s
        counter += 1
    print "Target reached: %d" % counter

except KeyboardInterrupt:
    # here you put any code you want to run before the program 
    # exits when you press CTRL+C
    print "\n", counter # print value of counter

except:
    # this catches ALL other exceptions including errors.
    # You won't get any error messages for debugging
    # so only use it once your code is working
    print "Other error or exception occurred!"

finally:
    GPIO.cleanup() # this ensures a clean exit

If you let the program run for ~22 seconds, it will count up to 9 million, tell you it reached its target, clean up any GPIO ports you've used and exit normally. This is the code within the try: block (lines 8-13).

The code in the except KeyboardInterrupt: block (lines 15-18) covers the CTRL+C situation. So when you press CTRL+C, it prints the current value of counter, cleans up any GPIO ports you've used, and exits.

The code in the except: block (lines 20-24) covers all other exceptions - including program errors. So if another exeption occurs, it warns you, cleans up any GPIO ports you've used, and exits.

This program will run until it finishes, or a keyboard interrupt or other exception occurs. Whichever of these occurs, the finally: block (lines 26-27) will run, cleaning up the GPIO ports on exit.

Also note, that we haven't actually used any GPIO ports here, so the cleanup isn't really doing anything yet, but this is a template you can use when we do start using ports.

If you want to try it out, it's a bit long for a live Python session, so you could retype it, or cut and paste it into a program as we did in the first post in this series...

Now you know how to exit an RPi.GPIO program cleanly, without leaving a trail of uncontrolled ports behind you.

That's about it for the preliminaries

So now we've covered...

  1. How to check what RPi.GPIO version you have
  2. How to check what Pi board Revision you have
  3. How to Exit GPIO programs cleanly, avoid warnings and protect your Pi

What next?

Tomorrow, we're actually going to set up the GPIO, talk about different pin/port numbering schemes and take a look at reading inputs.


 
_____________________________
1 If it did clean up all the ports, this would mean you could have major conflicts between different programs, which might not even be trying to use the same ports. Clearly, not a desirable situation!

  12 Responses to “RPi.GPIO basics 3 – How to Exit GPIO programs cleanly, avoid warnings and protect your Pi”

  1. Instead of duplicating the cleanup() call in 3 places why not just put it in a finally block?

    • Good question. And the answer is…

      because I didn’t know how to use it. I do now though ;) I’ve just read up on “finally”, although I’d heard of it before, I wasn’t quite sure of the usage.

      Thanks for the tip – I’ve updated the script and the blog post to incorporate it.

  2. Hallo Alex,

    following all your excellent lessons
    i encounter in Basics3 an
    AtttributeError: ‘ module’ object has no attribute ‘cleanup’

    Is this correct?

    Regards
    Olaf

    • What version of RPi.GPIO are you running? See RPi.GPIO basics part 1 to find out.

      • find /usr | grep -i gpio says RPi.GPIO-0.5.3a but when i check

        >>>PYTHON.VERSION

        get allways above error message.

        This python Installation obviously is faulty, even after update and upgrade the latest Raspbian.
        Now used another os-installation without too much application installed and all is OK.

        • Apparently, if you installed RPi.GPIO using a .deb at some point in the past, it needs to be manually removed or it can cause conflicts. I’m not entirely sure how to do that.

  3. According to comments on http://code.google.com/p/raspberry-gpio-python/issues/detail?id=4 you can get the same error if you install RPi.GPIO via pip as well as apt-get (the latest versions of Raspbian include RPi.GPIO pre-installed via apt-get).
    AIUI pip and apt-get are independent install/packaging systems, and neither is aware of the other, so if you’ve installed RPi.GPIO both via pip *and* via apt-get then you might get into confusing situations…

    • Hi AndrewS,
      I’m shure i have done this in the past without thinking about a conflict. In general python is working
      properly in this Installation. I’am only confused about the above error message.

      Alex and AndrewS thank you for the answers
      Olaf

      • Hurra,

        sudo pip install RPi.GPIO –upgrade

        …also repaired my python RPi.GPIO.
        A Version 0.4.0 is now replaced by 0.5.3a
        thanks for the link.
        Olaf

  4. [...] Part 3: “how to Exit GPIO programs cleanly, avoid warnings and protect your Pi”: [...]

  5. Thanks for posting this – it’s saved me from keep blowing my transistors whenever I exit my glockenspiel control program. I’ve linked it into my blog too.