Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GPIO Zero: Developing a friendly Python API for physical computing - campug

GPIO Zero: Developing a friendly Python API for physical computing - campug

Talk on developing GPIO Zero at campug (Cambridge Python User Group)

Ben Nuttall

January 05, 2016
Tweet

More Decks by Ben Nuttall

Other Decks in Programming

Transcript

  1. GPIO Zero:
    Developing a friendly Python API
    for physical computing
    Ben Nuttall
    Raspberry Pi Foundation
    UK Charity 1129409

    View full-size slide

  2. Ben Nuttall

    Education Developer Advocate at the
    Raspberry Pi Foundation
    – Runs www.raspberrypi.org
    – Software & project development
    – Learning resources & teacher
    training
    – Outreach

    Hobbyist turned employee

    @ben_nuttall on Twitter

    View full-size slide

  3. RPi.GPIO
    import RPi.GPIO as GPIO
    from time import sleep
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(17, GPIO.OUT)
    while True:
    GPIO.output(17, True)
    sleep(1)
    GPIO.output(17, False)
    sleep(1)

    View full-size slide

  4. Current state of affairs with RPi.GPIO

    Broad use of RPi.GPIO
    – Used in Raspberry Pi learning resources
    – 132k code search results on github.com

    Lots of typing required for basic examples

    Lots of copy/paste code when using more complicated devices
    like sensors

    Requires fundamental understanding of electronics

    Lots of use of polling

    Implementation in C – exposes a non-Pythonic API

    View full-size slide

  5. sudo

    In Raspbian Wheezy, root access was needed to access the
    GPIO pins

    This meant running Python files with sudo

    This also meant opening IDLE from the menu did not allow
    GPIO access, must be opened with sudo idle &

    The pi user was given access to GPIO pins in Raspbian Jessie
    (released during development of GPIO Zero)

    View full-size slide

  6. Motivation

    CamJam talk 12/9/15 - How to build Python APIs for
    Raspberry Pi Hardware

    Teachers saying it's too hard to use Python

    Too much code to write to flash an LED (what is this, Java?)

    Too much boilerplate code needed to get started

    Too many electronics concepts required to understand (or
    ignore) e.g. pull-up vs. pull-down, and falling/rising edge

    Lots of bad code out there – all being copied

    View full-size slide

  7. Inspiration

    Python libraries for Pimoroni add-on boards

    Community users like Martin O'Hanlon commonly using LED
    class, etc.

    Picamera Python library

    Flotilla

    PyGame Zero – zero boilerplate wrapper for Pygame

    View full-size slide

  8. Intended audience

    Teachers

    Children

    Beginners

    Hobbyists

    View full-size slide

  9. GitHub Issues

    View full-size slide

  10. GPIO Zero
    from gpiozero import LED
    from time import sleep
    led = LED(17)
    while True:
    led.on()
    sleep(1)
    led.off()
    sleep(1)

    View full-size slide

  11. GPIO Zero
    from gpiozero import LED
    led = LED(17)
    led.blink()

    View full-size slide

  12. What do you think?

    View full-size slide

  13. A few minor observations...

    View full-size slide

  14. Eben, what do you think?

    View full-size slide

  15. Some initial comments

    “You're making it too easy”

    “Part of the fun is learning how it works”

    “It shouldn't be this easy to blink an LED”

    “You're dumbing down the flexibility of RPi.GPIO”

    “It's nice but I'll still use RPi.GPIO for the complex stuff”

    View full-size slide

  16. More initial comments

    “I'll have one of those. Can you get it ready for the next
    Raspbian release?” - Eben Upton

    “It's great! I never meant for RPi.GPIO to be an end-user library
    anyway!” - Ben Croston

    View full-size slide

  17. CamJam EduKit

    £5 starter kit (kit 1)

    £7 sensors kit (kit 2)

    £17 robotics kit (kit 3)

    Free worksheets

    Very reusable

    View full-size slide

  18. CamJam Kit 1 – starter kit

    Components:
    – LEDs
    – Buzzer
    – Button

    Recipes:
    – Flash LED
    – Traffic lights sequence

    + Button

    + Buzzer
    – Reaction game
    – Morse Code

    View full-size slide

  19. LED
    from gpiozero import LED
    from time import sleep
    led = LED(17)
    led.on() # on
    led.off() # off
    led.toggle() # on­>off or off­>on
    led.blink() # flash on/off continuously

    View full-size slide

  20. Buzzer
    from gpiozero import Buzzer
    from time import sleep
    buzzer = Buzzer(18)
    buzzer.on() # on
    buzzer.off() # off
    buzzer.toggle() # on­>off or off­>on
    buzzer.beep() # beep on/off continuously

    View full-size slide

  21. Button polling (pull-up) – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)
    while True:
    if not GPIO.input(4):
    print(“Pressed”)

    View full-size slide

  22. Button polling (pull-down) – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_DOWN)
    while True:
    if GPIO.input(4):
    print(“Pressed”)

    View full-size slide

  23. Button polling (pull-up) – GPIO Zero
    button = Button(4)
    while True:
    if button.is_pressed:
    print(“Pressed”)

    View full-size slide

  24. Button polling (pull-down) – GPIO Zero
    button = Button(4, pull_up=False)
    while True:
    if button.is_pressed:
    print(“Pressed”)

    View full-size slide

  25. Button wait_for_edge (pull-up) – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)
    while True:
    GPIO.wait_for_edge(4, GPIO.FALLING)
    print(“Pressed”)

    View full-size slide

  26. Button wait_for_edge (pull-down) – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_DOWN)
    while True:
    GPIO.wait_for_edge(4, GPIO.RISING)
    print(“Pressed”)

    View full-size slide

  27. Button wait_for_press (pull-up) – GPIO Zero
    button = Button(4)
    while True:
    button.wait_for_press()
    print(“Pressed”)

    View full-size slide

  28. Button wait_for_press (pull-down) – GPIO Zero
    button = Button(4, pull_up=False)
    while True:
    button.wait_for_press()
    print(“Pressed”)

    View full-size slide

  29. Button callback – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)
    def pressed(pin):
    print(“Pressed”)
    GPIO.add_event_detect(4, GPIO.FALLING, pressed)

    View full-size slide

  30. Button callback – GPIO Zero
    button = Button(4)
    def pressed():
    print(“Pressed”)
    button.when_pressed = pressed

    View full-size slide

  31. Button callback – RPi.GPIO
    GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)
    def pressed(pin):
    print(“Pin %s Pressed” % pin)
    GPIO.add_event_detect(4, GPIO.FALLING, pressed)

    View full-size slide

  32. Button callback – GPIO Zero
    button = Button(4)
    def pressed(button):
    print(“Pin %s pressed” % button.pin)
    button.when_pressed = pressed

    View full-size slide

  33. Button + LED
    from gpiozero import LED, Button
    led = LED(17)
    button = Button(4)
    button.when_pressed = led.on
    button.when_released = led.off

    View full-size slide

  34. GPIO Music Box
    from gpiozero import Button
    import pygame.mixer
    from pygame.mixer import Sound
    pygame.mixer.init()
    sound_pins = {
    2: Sound("samples/drum_tom_mid_hard.wav"),
    3: Sound("samples/drum_cymbal_open.wav"),
    }
    buttons = [Button(pin) for pin in sound_pins]
    for button in buttons:
    sound = sound_pins[button.pin]
    button.when_pressed = sound.play

    View full-size slide

  35. LED – PWM – RPi.GPIO
    GPIO.setup(17, GPIO.OUT) # pin 17
    p = GPIO.PWM(17, 100) # pin 17, frequency 100Hz
    p.start(0) # initial duty cycle
    for i in range(101):
    p.ChangeDutyCycle(i)
    sleep(0.01)

    View full-size slide

  36. LED – PWM – GPIO Zero
    from gpiozero import PWMLED
    led = PWMLED(17)
    led.on() # on
    led.off() # off
    led.value = 0.5 # half brightness

    View full-size slide

  37. Full colour LED
    from gpiozero import RGBLED
    led = RGBLED(red=2, green=3, blue=4)
    led.red.on() # full red
    led.color = (1, 0, 1) # purple
    led.blue = 0.3 # dim the blue value to 0.3
    # now (1, 0, 0.3)

    View full-size slide

  38. Traffic Lights
    from gpiozero import TrafficLights
    lights = TrafficLights(9, 10, 11)
    lights.on() # all on
    lights.off() # all off
    lights.red.on() # red on
    lights.toggle() # swap state of all lights

    View full-size slide

  39. Traffic Lights sequence
    lights.green.on()
    lights.amber.off()
    lights.red.off()
    while True:
    sleep(10)
    lights.green.off()
    lights.amber.on()
    sleep(1)
    lights.amber.off()
    lights.red.on()
    sleep(10)
    lights.amber.on()
    sleep(1)
    lights.green.on()
    lights.amber.off()
    lights.red.off()

    View full-size slide

  40. TrafficHat
    from gpiozero import TrafficHat
    th = TrafficHat()
    th.lights.red.on()
    th.lights.amber.on()
    th.button.when_pressed = th.on
    th.button.when_released = th.off

    View full-size slide

  41. TrafficHat - PWM
    from gpiozero import TrafficHat
    th = TrafficHat(pwm=True)
    th.lights.red.value = 0.2
    th.lights.amber.value = 0.4
    th.lights.green.value = 0.8

    View full-size slide

  42. CamJam Kit 2 - sensors

    Components:
    – LEDs
    – Buzzer
    – Motion Sensor
    – Light Sensor
    – Temperature Sensor

    Recipes:
    – High/low temperature
    triggers LEDs
    – Light/dark triggers LEDs
    – Alarm – motion triggers
    buzzer

    View full-size slide

  43. Motion sensor
    from gpiozero import LED, MotionSensor
    led = LED(2)
    sensor = MotionSensor(3)
    sensor.when_motion = led.on
    sensor.when_no_motion = led.off

    View full-size slide

  44. Light sensor
    from gpiozero import LED, LightSensor
    led = LED(2)
    sensor = LightSensor(3)
    while True:
    sensor.wait_for_light()
    print("It's light!")
    sensor.wait_for_dark()
    print("It's dark")

    View full-size slide

  45. Temperature sensor

    w1thermsensor library exists

    Yet to be implemented in GPIO Zero compatible style

    View full-size slide

  46. CamJam Kit 3 - robot

    Components:
    – Motor Controller Board
    – Motors
    – Ultrasonic Sensor
    – Line Sensor

    Recipes:
    – Driving and turning
    – Line follower
    – Obstacle avoidance
    – Add a camera

    View full-size slide

  47. Motor
    from gpiozero import Motor
    from time import sleep
    motor = Motor(forward=17, backward=18)
    while True:
    motor.forward()
    sleep(5)
    motor.backward()
    sleep(5)

    View full-size slide

  48. Robot
    from gpiozero import Robot
    from time import sleep
    robot = Robot(left=(17, 18), right=(22, 23))
    while True:
    robot.forward()
    sleep(10)
    robot.left()
    sleep(1)

    View full-size slide

  49. Pre-configured robot interfaces
    robot = RyanteckRobot()
    robot = CamJamKitRobot()

    View full-size slide

  50. Button controlled Robot
    from gpiozero import RyanteckRobot, Button
    robot = RyanteckRobot()
    left = Button(26)
    right = Button(16)
    fw = Button(21)
    bw = Button(20)
    fw.when_pressed = robot.forward
    fw.when_released = robot.stop
    left.when_pressed = robot.left
    left.when_released = robot.stop
    right.when_pressed = robot.right
    right.when_released = robot.stop
    bw.when_pressed = robot.backward
    bw.when_released = robot.stop

    View full-size slide

  51. Push button stop motion
    from gpiozero import Button
    from picamera import PiCamera
    button = Button(4)
    with PiCamera() as camera:
    camera.start_preview()
    frame = 1
    while True:
    button.wait_for_press()
    camera.capture('/home/pi/frame%03d.jpg' % frame)
    frame += 1

    View full-size slide

  52. Analogue - potentiometers
    from gpiozero import MCP3008
    pot = MCP3008()
    while True:
    print(pot.value)

    View full-size slide

  53. Dial up the brightness!
    from gpiozero import PWMLED, MCP3008
    led = PWMLED(2)
    pot = MCP3008()
    while True:
    led.value = pot.value

    View full-size slide

  54. Analogue - potentiometers
    from gpiozero import RGBLED, MCP3008
    led = RGBLED(red=2, green=3, blue=4)
    red_pot = MCP3008(channel=0)
    green_pot = MCP3008(channel=1)
    blue_pot = MCP3008(channel=2)
    while True:
    led.red = red_pot.value
    led.green = green_pot.value
    led.blue = blue_pot.value

    View full-size slide

  55. #76 while True: led.red = pot.value

    View full-size slide

  56. #76 while True: led.red = pot.value

    View full-size slide

  57. #76 while True: led.red = pot.value

    View full-size slide

  58. #76 while True: led.red = pot.value

    View full-size slide

  59. Dial up the brightness!
    from gpiozero import PWMLED, MCP3008
    led = PWMLED(2)
    pot = MCP3008()
    led.source = pot.values

    View full-size slide

  60. Analogue - potentiometers
    from gpiozero import RGBLED, MCP3008
    led = RGBLED(red=2, green=3, blue=4)
    red_pot = MCP3008(channel=0)
    green_pot = MCP3008(channel=1)
    blue_pot = MCP3008(channel=2)
    led.red.source = red_pot.values
    led.green.source = green_pot.values
    led.blue.source = blue_pot.values

    View full-size slide

  61. Custom value generators
    blue = PWMLED(16)
    blue.source = [i / 10000.0 for i in range(10000)]
    red = PWMLED(12)
    red.source = blue.values
    blue.source = [i / 10000.0 for i in range(10000)]
    sensor = LightSensor(18)
    blue.source = sensor.values

    View full-size slide

  62. Custom value generators
    def read_slowly(iterable):
    for i in iterable:
    yield i
    sleep(0.1)
    red.source = read_slowly(blue.values)
    blue.source = read_slowly(sensor.values)

    View full-size slide

  63. Custom value generators
    button.when_pressed = led.on
    button.when_released = led.off
    led.source = button.values

    View full-size slide

  64. GPIO Zero Timeline

    12 Sept – CamJam talk sparked idea

    14 Sept – Initial commit on GitHub

    15 Sept – Named GPIO Zero, first PR, first alpha released on PyPi

    23 Sept – Mentioned in talk at PyConUK

    28 Sept – v0.6 public beta 1

    09 Oct – v0.7 public beta 2

    16 Oct – v0.8 public beta 3

    25 Oct – v0.9 public beta 4

    29 Oct – Featured in The MagPi

    16 Nov – v1.0 released

    21 Nov – Released in Raspbian Jessie

    View full-size slide

  65. v1.0

    ~200 commits

    2 contributors (+4 minor contributions)

    103 GitHub issues (53 issues, 50 PRs)

    4 alpha releases

    4 beta releases

    68 days between initial commit and major release

    View full-size slide

  66. Future development

    Add more components

    Integrate more add-ons

    Add test suite

    Replace RPi.GPIO dependency

    Promote use of “gpiozero standard” to allow other modules to
    provide objects which plug-in to gpiozero objects easily (e.g.
    source/values)

    View full-size slide

  67. What have I learned?

    Issue-driven development works really well

    Dave Jones is awesome (ok I already knew that)

    User-focused API design is important

    Getting feedback from teachers is hard

    Getting code contributions is hard

    Getting documentation contributions is easier

    View full-size slide

  68. Install GPIO Zero

    Pre-installed in Raspbian Jessie since November

    Update with:
    sudo apt­get update

    Install with:
    sudo apt­get install python3­gpiozero
    or:
    sudo apt­get install python­gpiozero

    View full-size slide

  69. GPIO Zero

    www.pythonhosted.org/gpiozero
    – Installation instructions
    – Documentation
    – Examples

    GitHub Issues
    – Suggestions
    – Feedback

    Contact me
    [email protected]
    – @ben_nuttall on Twitter

    #gpiozero on Twitter

    View full-size slide

  70. Zero all the things!

    Raspberry Pi Zero

    PyGame Zero

    GPIO Zero

    View full-size slide

  71. GPIO Zero:
    Developing a friendly Python API
    for physical computing
    Ben Nuttall
    Raspberry Pi Foundation
    UK Charity 1129409

    View full-size slide