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)

A1995c9abe48450ce2f82d93ca0b863f?s=128

Ben Nuttall

January 05, 2016
Tweet

Transcript

  1. GPIO Zero: Developing a friendly Python API for physical computing

    Ben Nuttall Raspberry Pi Foundation UK Charity 1129409
  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
  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)
  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
  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)
  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
  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
  8. Intended audience • Teachers • Children • Beginners • Hobbyists

  9. GitHub

  10. GitHub Issues

  11. Google Doc

  12. GPIO Zero from gpiozero import LED from time import sleep

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

  14. What do you think?

  15. A few minor observations...

  16. Hooked

  17. #4 Name?

  18. #4 Name?

  19. Eben, what do you think?

  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”
  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
  22. CamJam EduKit • £5 starter kit (kit 1) • £7

    sensors kit (kit 2) • £17 robotics kit (kit 3) • Free worksheets • Very reusable
  23. CamJam Kit 1 – starter kit • Components: – LEDs

    – Buzzer – Button • Recipes: – Flash LED – Traffic lights sequence • + Button • + Buzzer – Reaction game – Morse Code
  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
  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
  26. Button polling (pull-up) – RPi.GPIO GPIO.setup(4, GPIO.IN, GPIO.PUD_UP) while True:

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

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

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

    while True: if button.is_pressed: print(“Pressed”)
  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”)
  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”)
  32. Button wait_for_press (pull-up) – GPIO Zero button = Button(4) while

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

    while True: button.wait_for_press() print(“Pressed”)
  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)
  35. Button callback – GPIO Zero button = Button(4) def pressed():

    print(“Pressed”) button.when_pressed = pressed
  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)
  37. Button callback – GPIO Zero button = Button(4) def pressed(button):

    print(“Pin %s pressed” % button.pin) button.when_pressed = pressed
  38. Button + LED from gpiozero import LED, Button led =

    LED(17) button = Button(4) button.when_pressed = led.on button.when_released = led.off
  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
  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)
  41. LED – PWM – GPIO Zero from gpiozero import PWMLED

    led = PWMLED(17) led.on() # on led.off() # off led.value = 0.5 # half brightness
  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)
  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
  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()
  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
  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
  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
  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
  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")
  50. Temperature sensor • w1thermsensor library exists • Yet to be

    implemented in GPIO Zero compatible style
  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
  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)
  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)
  54. Pre-configured robot interfaces robot = RyanteckRobot() robot = CamJamKitRobot()

  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
  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
  57. Analogue - potentiometers from gpiozero import MCP3008 pot = MCP3008()

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

    = PWMLED(2) pot = MCP3008() while True: led.value = pot.value
  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
  60. #76 while True: led.red = pot.value

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

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

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

  64. Dial up the brightness! from gpiozero import PWMLED, MCP3008 led

    = PWMLED(2) pot = MCP3008() led.source = pot.values
  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
  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
  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)
  68. Custom value generators button.when_pressed = led.on button.when_released = led.off led.source

    = button.values
  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
  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
  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)
  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
  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
  74. GPIO Zero • www.pythonhosted.org/gpiozero – Installation instructions – Documentation –

    Examples • GitHub Issues – Suggestions – Feedback • Contact me – ben@raspberrypi.org – @ben_nuttall on Twitter • #gpiozero on Twitter
  75. Zero all the things! • Raspberry Pi Zero • PyGame

    Zero • GPIO Zero
  76. GPIO Zero: Developing a friendly Python API for physical computing

    Ben Nuttall Raspberry Pi Foundation UK Charity 1129409