$30 off During Our Annual Pro Sale. View Details »

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