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
  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. GPIO Zero from gpiozero import LED from time import sleep

    led = LED(17) while True: led.on() sleep(1) led.off() sleep(1)
  9. 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”
  10. 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
  11. CamJam EduKit • £5 starter kit (kit 1) • £7

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

    – Buzzer – Button • Recipes: – Flash LED – Traffic lights sequence • + Button • + Buzzer – Reaction game – Morse Code
  13. 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
  14. 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
  15. Button polling (pull-up) – GPIO Zero button = Button(4) while

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

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

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

    while True: button.wait_for_press() print(“Pressed”)
  19. Button callback – GPIO Zero button = Button(4) def pressed():

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

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

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

    led = PWMLED(17) led.on() # on led.off() # off led.value = 0.5 # half brightness
  26. 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)
  27. 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
  28. 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()
  29. 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
  30. 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
  31. Motion sensor from gpiozero import LED, MotionSensor led = LED(2)

    sensor = MotionSensor(3) sensor.when_motion = led.on sensor.when_no_motion = led.off
  32. 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")
  33. Temperature sensor • w1thermsensor library exists • Yet to be

    implemented in GPIO Zero compatible style
  34. CamJam Kit 3 - robot • Components: – Motor Controller

    Board – Motors – Ultrasonic Sensor – Line Sensor • Recipes: – Driving and turning – Line follower – Obstacle avoidance – Add a camera
  35. 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)
  36. 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)
  37. 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
  38. 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
  39. Dial up the brightness! from gpiozero import PWMLED, MCP3008 led

    = PWMLED(2) pot = MCP3008() while True: led.value = pot.value
  40. 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
  41. Dial up the brightness! from gpiozero import PWMLED, MCP3008 led

    = PWMLED(2) pot = MCP3008() led.source = pot.values
  42. 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
  43. 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
  44. 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)
  45. 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
  46. 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
  47. 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)
  48. 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
  49. 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
  50. 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
  51. GPIO Zero: Developing a friendly Python API for physical computing

    Ben Nuttall Raspberry Pi Foundation UK Charity 1129409