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 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 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 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 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 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 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 Slide

  8. Intended audience

    Teachers

    Children

    Beginners

    Hobbyists

    View Slide

  9. GitHub

    View Slide

  10. GitHub Issues

    View Slide

  11. Google Doc

    View Slide

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

    View Slide

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

    View Slide

  14. What do you think?

    View Slide

  15. A few minor observations...

    View Slide

  16. Hooked

    View Slide

  17. #4 Name?

    View Slide

  18. #4 Name?

    View Slide

  19. Eben, what do you think?

    View Slide

  20. 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 Slide

  21. 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 Slide

  22. CamJam EduKit

    £5 starter kit (kit 1)

    £7 sensors kit (kit 2)

    £17 robotics kit (kit 3)

    Free worksheets

    Very reusable

    View Slide

  23. CamJam Kit 1 – starter kit

    Components:
    – LEDs
    – Buzzer
    – Button

    Recipes:
    – Flash LED
    – Traffic lights sequence

    + Button

    + Buzzer
    – Reaction game
    – Morse Code

    View Slide

  24. 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 Slide

  25. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  30. 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 Slide

  31. 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 Slide

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

    View Slide

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

    View Slide

  34. 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 Slide

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

    View Slide

  36. 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 Slide

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

    View Slide

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

    View Slide

  39. 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 Slide

  40. 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 Slide

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

    View Slide

  42. 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 Slide

  43. 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 Slide

  44. 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 Slide

  45. 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 Slide

  46. 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 Slide

  47. 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 Slide

  48. 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 Slide

  49. 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 Slide

  50. Temperature sensor

    w1thermsensor library exists

    Yet to be implemented in GPIO Zero compatible style

    View Slide

  51. 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 Slide

  52. 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 Slide

  53. 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 Slide

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

    View Slide

  55. 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 Slide

  56. 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 Slide

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

    View Slide

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

    View Slide

  59. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. 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 Slide

  66. 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 Slide

  67. 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 Slide

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

    View Slide

  69. 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 Slide

  70. 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 Slide

  71. 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 Slide

  72. 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 Slide

  73. 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 Slide

  74. 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 Slide

  75. Zero all the things!

    Raspberry Pi Zero

    PyGame Zero

    GPIO Zero

    View Slide

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

    View Slide