Jump to content
 

DavidB-AU

Members
  • Posts

    3,096
  • Joined

  • Last visited

Blog Entries posted by DavidB-AU

  1. DavidB-AU
    This is the first of hopefully a series of tutorials on using a Raspberry Pi to do what modellers often do with more mundane devices such as switches. These are aimed at the modeller rather than the serious hardcore programmer or electronics hobbyist, but does assume a basic knowledge of electronics and assumes you have already set up your RPi and installed the RPi.GPIO package. I won't go into that here - if you have any trouble see the Raspberry Pi or Adafruit forums.
     
    Note that my RPi is running Raspbian (Debian Linux). This is not the only operating system available but I haven't looked at the others.
     
    I have also attached the Adafruit GPIO breakout kit and breadboard sitting on a Pi Dish.
     
    I connected one positive rail to 3.3V (pin 1), the other positive rail to 5V (pin 2) and the negative rails to 0V/GND (pin 6). This is not the only way to do things but I found it convenient.
     

     

  2. DavidB-AU
    In the previous tutorial we saw two different ways to control an LED and how the same state can have the opposite effect depending on how the circuit is designed. We can use this to our advantage by driving both LEDs from the same GPIO pin. This requires a little more electronics.

     
    This does two things.
    - When pin 18 is HIGH (True), it triggers the NPN transistor to power the red LED but prevents powering the green LED because the anode and cathode are both at 3.3V.
    - When pin 18 is LOW (False), the transistor is turned off, hence the red LED is turned off, and the green LED is powered because the anode is at 3.3V and cathode is at 0V.
     
    Any general purpose NPN transistor should work. I used a BC548 because I had one handy. Here's how it looks on the board.

     
    The code to run this is very simple.
    import RPi.GPIO as GPIOimport time# Set up header pin 18 (GPIO24) as outputGPIO.setup(18, GPIO.OUT)state = Truewhile 1: GPIO.output(18, state) time.sleep(1) state = not state
    Run this as root and the LEDs will alternate, driven from the same pin.
     
    Now let's adapt the previous signal control program. Create a program called signal2.py and enter the following:
    import os, sys, termiosimport RPi.GPIO as GPIOGPIO.setup(18, GPIO.OUT) # Set up pin 18 (GPIO24) as outputGPIO.output(18, True) # Set the signal to red# Set up detection of keypressdef getKey(): fd = sys.stdin.fileno() old = termios.tcgetattr(fd) new = termios.tcgetattr(fd) new[3] = new[3] & ~termios.ICANON & ~termios.ECHO new[6][termios.VMIN] = 1 new[6][termios.VTIME] = 0 termios.tcsetattr(fd, termios.TCSANOW, new) key = None try: key = os.read(fd, 3) finally: termios.tcsetattr(fd, termios.TCSAFLUSH, old) return keystate = True # The initial state for the signal is redwhile 1: x = str(getKey()) if x == "r": # If keypress is r state = True # ... set the state that turns the signal red if x == "g": # If keypress is g state = False # ... set the state that turns the signal green if x == "q": # If keypress is q GPIO.output(18, True) # ... set the state that turns the signal red break # ... and quit else: # In all other cases pass # ... do nothing GPIO.output(18, state) # Set the state of the signal
    Run as root and the signal control will work as in tutorial 4, but driven from only one GPIO pin.
     

  3. DavidB-AU
    Now let's set up a simple circuit with a resistor and a red LED. The resistor is between the 3.3V rail and the anode (long leg) of the LED. The cathode of the LED is connected to GPIO24 (pin 18).

     
    The value of the resistor isn't critical but should be in the range of 300R-1K. I used 470R because I had plenty to hand. This is what it looks like on the breadboard.

     
    Now to control the LED from the RPi. GPIO must be run as root so after the prompt (pi@raspberrypi ~$) type sudo python.
    pi@raspberrypi ~$ sudo python
     
    python will start and display something like this. The >>> is the prompt.
    Python 2.7.3 (default, Jan 26 2013, 11:20:46)[GCC 4.6.3] on linux2Type "help", "copyright", "credits" or "license" for more information.>>>
    First import the GPIO package.
    >>> import RPi.GPIO as GPIO
    Then set up pin 18 (GPIO24) as output.
    >>> GPIO.setup(18, GPIO.OUT)
    By default the GPIO pins are HIGH (3.3V). Bu setting them LOW, it drops to 0V and allows power to flow. To do this, set the pin to "False". (This is not the only way to do this. More on this later.)
    >>> GPIO.output(18, False)
    This will turn the LED on. To it off, set the pin as HIGH by making the setting "True".
    >>> GPIO.output(18, True)
    You can repeat these GPIO.output settings until you get bored.
     
    Exit the python shell by hitting CTRL-D.
     
    Controlling the LEDs by typing python commands every time will get tedious, so instead we'll write a little program to automate it. Open a new file called ledtest1.py with your favourite text editor. I use nano (long time users of Linux may recognise this as a cut down version of pico) so the command is:

    pi@raspberrypi ~$ nano ledtest1.py
     
    Add the following. The items after the hash (#) are comments which are not processed and can be left out if desired. However it is good programming practice to ad comments so you remember what each command or block of commands is intended to do.

    import RPi.GPIO as GPIO # Imports the GPIO packageimport time # Imports a timer packageGPIO.setup(18, GPIO.OUT) # Set up header pin 18 (GPIO24) as outputwhile 1: # Starts a loop GPIO.output(18, False) # Turns the LED on time.sleep(1) # Waits for 1 second GPIO.output(18, True) # Turns the LED off time.sleep(1) # Waits for 1 second
     
    Save the file and close the editor.
     
    Again, GPIO must be run as root so from the Linux command line type:
    pi@raspberrypi ~$ sudo python ledtest1.py
    The LED should now flash on and off, changing about every 1 second. It may not be exactly 1 second as the RPi is doing other things in the background which may affect the timer.
     
    Quit the program by hitting CTRL-C.
     

  4. DavidB-AU
    Now let's add a green LED adjacent to the red one and connect it to GPIO25 (pin 22).

     
    Now create a new file called ledtest2.py and enter the following:
    import RPi.GPIO as GPIOimport time# Set up GPIO25 (pin 22) as outputGPIO.setup(22, GPIO.OUT)while 1: # Turn green LED on GPIO.output(22, False) time.sleep(1) # Turn green LED off GPIO.output(22, True) time.sleep(1)
     
    Run the program as root.
    pi@raspberrypi ~$ sudo python ledtest2.py
     
    If all goes well, the green LED will flash on and off. Quit the program by hitting CTRL-C.
     
    Now let's get a little more complicated. Create a new file called ledtest3.py and enter the following:
    import RPi.GPIO as GPIOimport time# Set up pins 18 (GPIO24) and 22 (GPIO25) as outputGPIO.setup(18, GPIO.OUT)GPIO.setup(22, GPIO.OUT)while 1: GPIO.output(18, False) # Turn red LED on GPIO.output(22, True) # Turn green LED off time.sleep(1) GPIO.output(18, True) # Turn red LED off GPIO.output(22, False) # Turn green LED on time.sleep(1)
     
    Run the program.
    pi@raspberrypi ~$ sudo python ledtest3.py
     
    The LEDs should now flash between red and green.
     

  5. DavidB-AU
    We use the same electronic set up as the previous tutorial, but now pretend it is a simple 2-aspect colour light signal. Instead of LEDs on the breadboard, there could be leads out to a real signal on the layout.

     
    We want to be able to control this "signal" remotely by pressing the appropriate keys on the keyboard. Unfortunately this requires importing some more packages and adding more code to detect when a key is pressed. (You don't necessarily need to understand how this bit works.)
     
    Create a new file called signal.py with the following:
    import os, sys, termios # This imports packages needed to detect key pressesimport RPi.GPIO as GPIO # This imports the GPIO package# Set up pins 18 (GPIO24) and 22 (GPIO25) as outputGPIO.setup(18, GPIO.OUT)GPIO.setup(22, GPIO.OUT)# This sets the default state with the "signal" set to RED.GPIO.output(18, False) # Turns red LED onGPIO.output(22, True) # Turns green LED off# Set up detection of keypress.def getKey(): fd = sys.stdin.fileno() old = termios.tcgetattr(fd) new = termios.tcgetattr(fd) new[3] = new[3] & ~termios.ICANON & ~termios.ECHO new[6][termios.VMIN] = 1 new[6][termios.VTIME] = 0 termios.tcsetattr(fd, termios.TCSANOW, new) key = None try: key = os.read(fd, 3) finally: termios.tcsetattr(fd, termios.TCSAFLUSH, old) return key while 1: x = str(getKey()) # This detects a key being pressed and saves the value into a variable called x if x == "r": # If key pressed is equal to r... GPIO.output(18, False) # ...turn the red LED on GPIO.output(22, True) # ...and turn the green LED off if x == "g": # If key pressed is equal to g... GPIO.output(18, True) # ...turn the red LED of GPIO.output(22, False) # ...and turn the green LED on if x == "q": # If keypress is equal to q... GPIO.output(18, False) # ...turn the red LED on (safety first on our railway!) GPIO.output(22, True) # ...and turn the green LED off break # ...then quit the program else: # In all other cases... pass # ...do nothing
     
    Now run the program as root.
    pi@raspberrypi ~$ sudo python signal.py
     
    Note that the program is set up to detect lower case letters to make sure Caps Lock is off. When you press keys on the keyboard things will start to happen to the "signal".
     
    If you press g, the signal turns green.
    If you press r, the signal turns red.
    If you press q, the signal returns to red (safety first!) and the program quits.
    If you press other keys, the program ignores them.
     

     
    This is a very basic demonstration of how to control a "signal". In this case the signal is controlled by pressing keys on the keyboard, but it's not the only way. The signal could be triggered by other events such as a train passing (and resetting the signal to danger) or by detecting some other event or trigger. We'll come to inputs next.
     

  6. DavidB-AU
    An earlier tutorial showed one way of driving an LED, connecting the anode side to the 3.3V rail and the cathode side to GPIO. As mentioned, the default state of the GPIO output is HIGH (3.3V) to setting it LOW (0V) allows power to flow through the circuit. Alternatively, the anode of the LED can be connected to GPIO and the cathode to GND. This changes the way to drive it, HIGH (True) to turn on, LOW (False) to turn off.

    GPIO.output(x, False) to turn on, GPIO.output(x, True) to turn off.
     

    GPIO.output(x, True) to turn on, GPIO.output(x, False) to turn off.
     
    Both options can be useful depending on the application. Here's how the second one looks on the board.

     
    Crate a new program called ledtest4.py and add the following:
    import RPi.GPIO as GPIOimport timeGPIO.setup(18, GPIO.OUT)while 1: # Turn LED on GPIO.output(18, True) time.sleep(1) # Turn LED off GPIO.output(18, False) time.sleep(1)
     
    Run as root and the LED will flash on and off until you hit CTRL-C to stop the program.
    pi@raspberrypi ~$ sudo python ledtest4.py
    Now let's see both in action. Here is the set up with the red LED powered from GPIO24 (pin 18) and the cathode connected to GND, and the green LED powered from 3.3V and the cathode connected to GPIO25 (pin 22).

     
    This means that setting True on both pins will turn the red LED on and the green LED off, and setting False on both pins will turn the red LED off and the green LED on. By saving the state in a variable you can output the same variable to both pins. After waiting for a second, you can change the state and run the loop again. The not command will change the state from whatever it is to whatever it is not, i.e. if the state is True it will change to False and vice versa. Because there is no separate 'on' and 'off' sequence, the program gets a bit simpler. Create a new program called ledtest5.py with the following:
    import RPi.GPIO as GPIOimport timeGPIO.setup(18, GPIO.OUT)GPIO.setup(22, GPIO.OUT)# Set up the initial statestate = Truewhile 1: GPIO.output(18, state) GPIO.output(22, state) time.sleep(1) state = not state # Change the state
     
    Run as root.
    pi@raspberrypi ~$ sudo python ledtest5.py
    The two LEDs should now flash alternately with with somewhat simpler code.
     

  7. DavidB-AU
    So far we have looked at outputs to control LEDs. Now let's look at inputs. There are two ways to detect an input.
     

     
    In Method 1:
    GPIO is HIGH when button is down.
    GPIO is LOW when button is up.
    In Method 2:
    GPIO is LOW when button is down.
    GPIO is HIGH when button is up.
    Either method can be used depending on the application.
     
    Here's how it looks on the breadboard. Method 1 is on the left, attached to GPIO24 (pin18). Method 2 is on the right, attached to GPIO25 (pin 22).

     
    I have shown pushbuttons here but it can be any sort of on/off tigger. Other ways to trigger an input could include:
    magnet passing over a reed switch
    a photodiode detecting a UV light (or detecting when the light is blocked)
    a relay triggered by a higher voltage application
    a DCC inductive current
    Now to control it. This time I am using a different Python extension module called curses which is a library of commands for character printing and keyboard handling on text-based terminals. This is particularly useful if you are using a small LCD screen (one of the RPi accessories) instead of full monitor. I won't go into describing how curses works. Full documentation is available here and a "how to" here. There is also a useful tutorial here (PDF).
     
    Here's the code for a program called buttontest1.py.
    import cursesimport RPi.GPIO as GPIO# Set up header pins 18 (GPIO24) and 22 (GPIO25) as inputGPIO.setup(18, GPIO.IN)GPIO.setup(22, GPIO.IN)stdscr=curses.initscr() # Initialise the screenstdscr.nodelay(1) # Act on key presses immediatelycurses.noecho() # Don't echo a key press on the screenwhile 1: stdscr.addstr(0, 0, "Button 1 is") # Writes text at position y = 0, x = 0 stdscr.addstr(0, 20, "Button 2 is") # Writes text at position y = 0, x = 20 if GPIO.input(18): # Tests if button 1 on GPIO pin 18 is True (HIGH) stdscr.addstr(0, 12, "DOWN") # If True, that means the button is down. Print it on the screen in the right position. else: stdscr.addstr(0, 12, "UP ") # If False, that means the button is up. Print it on the screen in the right position. if GPIO.input(22): # Tests if button 2 on GPIO pin 22 is True (HIGH) stdscr.addstr(0, 32, "UP ") # If True, that means the button is up. Print it on the screen in the right position. else: stdscr.addstr(0, 32, "DOWN") # If False, that means the button is down. Print it on the screen in the right position. stdscr.addstr(1, 0, "") # Moves the cursor to the next line out of the way stdscr.refresh() # Refresh the screen if stdscr.getch() == ord('q'): # Checks if the 'q' key is pressed break # If so, quit Run the program as root.
    pi@raspberrypi ~$ sudo python buttontest1.py When you push down either or both of the buttons, this will be shown to you on the screen.
     
    This is just a very simple demonstration of inputs. The input triggers could be anything and when you detect an input you can do anything. For example you could have a basic representation of a layout drawn using curses and use multiple inputs to display which tracks are occupied. Or you can use the inputs to trigger an output on another GPIO pin, but more on that later!
     

×
×
  • Create New...