Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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)

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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)

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Intended audience ● Teachers ● Children ● Beginners ● Hobbyists

Slide 9

Slide 9 text

GitHub

Slide 10

Slide 10 text

GitHub Issues

Slide 11

Slide 11 text

Google Doc

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

What do you think?

Slide 15

Slide 15 text

A few minor observations...

Slide 16

Slide 16 text

Hooked

Slide 17

Slide 17 text

#4 Name?

Slide 18

Slide 18 text

#4 Name?

Slide 19

Slide 19 text

Eben, what do you think?

Slide 20

Slide 20 text

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”

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

CamJam EduKit ● £5 starter kit (kit 1) ● £7 sensors kit (kit 2) ● £17 robotics kit (kit 3) ● Free worksheets ● Very reusable

Slide 23

Slide 23 text

CamJam Kit 1 – starter kit ● Components: – LEDs – Buzzer – Button ● Recipes: – Flash LED – Traffic lights sequence ● + Button ● + Buzzer – Reaction game – Morse Code

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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)

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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)

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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)

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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)

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Temperature sensor ● w1thermsensor library exists ● Yet to be implemented in GPIO Zero compatible style

Slide 51

Slide 51 text

CamJam Kit 3 - robot ● Components: – Motor Controller Board – Motors – Ultrasonic Sensor – Line Sensor ● Recipes: – Driving and turning – Line follower – Obstacle avoidance – Add a camera

Slide 52

Slide 52 text

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)

Slide 53

Slide 53 text

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)

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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)

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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)

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

Zero all the things! ● Raspberry Pi Zero ● PyGame Zero ● GPIO Zero

Slide 76

Slide 76 text

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