Je eerste elektronica project: Grove Base Kit voor Raspberry Pi
- December 4, 2020
- 0
Heb je altijd al willen experimenteren met elektronica op de Raspberry Pi, maar weet je niet hoe te beginnen? In deze workshop gaan we aan de slag met de Grove Base Kit. We maken een eenvoudig alarmsysteem om de werking van verschillende componenten te illustreren.
Filip Vervloesem
Ook al heb je geen ervaring met het aansturen van elektronica, toch heb je enige voorkennis nodig om deze workshop te volgen:
– je bent al vertrouwd met de Raspberry Pi en de commandline
– je hebt een basiskennis programmeren in Python
Verder heb je natuurlijk een Raspberry Pi nodig en de eerder vermelde Grove Base Kit. Die kit kost ongeveer €50 en bevat een tiental elektronicacomponenten, zoals:
– een knop
– een zoemer
– een klein lcd-scherm (enkel voor tekstweergave)
– verschillende sensoren: beweging, licht, temperatuur, enzovoorts
Meer informatie vind je op deze site. Je kunt de kit kopen bij verschillende gespecialiseerde Raspberry Pi webshops in Nederlands.
Eenvoudig starten
Je hoeft niet te solderen om componenten van de Grove Base Kit aan te sluiten op de Raspberry Pi. De kit is dus ideaal als eerste kennismaking met elektronica. Als voorbeeld gaan we aan de slag met drie componenten: een lichtsensor, een lcd-scherm en een knop met ingebouwd led-lampje. Ter illustratie programmeren we een eenvoudig alarm in Python. Uiteraard mag je dat project letterlijk nabouwen, maar aarzel vooral niet om af te wijken van ons voorbeeld! De kans is groot dat jij andere eisen stelt aan jouw project. Het leuke aan het programmeren van elektronica is net dat je alles helemaal naar jouw wens kan afstellen. Misschien wil je de lichtsensor wel vervangen door een bewegingssensor of het lcd-scherm door een zoemer? Of wat dacht je van waarschuwingen via e-mail? Alles is mogelijk! Je hoeft enkel de documentatie van de gebruikte componenten te raadplegen en te experimenteren met je Python-code.
De Grove Base Kit is erg eenvoudig te gebruiken. Schakel je Raspberry Pi uit en open de behuizing. Plug de Grove Base Hat (het printplaatje met 15 witte aansluitingen) in de 40-pins connector van de Raspberry Pi. De Base Hat ligt dus bovenop het moederbord van de Pi. Start de Pi opnieuw en open raspi-config:
$ sudo raspi-config
Ga naar “5 Interfacing Options” > “5 I2C” om de I2C interface in te schakelen. Installeer vervolgens de grove Python-modules (we installeren hier zowel de Python 2- als de Python 3-versie van pip, zodat het installatiescript voor beide versies uitgevoerd wordt):
$ mkdir grove $ cd grove $ sudo apt install python-pip python3-pip $ curl -sL https://github.com/Seeed-Studio/grove.py/raw/master/install.sh | sudo bash -s -
Verschillende interfaces
Ook al zijn alle connectoren op de Base Hat identiek, je kunt niet zomaar elke module eender waar inpluggen. Als je goed kijkt, zie je dat elke connector een label heeft. Er zijn namelijk vijf verschillende interfaces:
– D: 6 digitale connectoren
– A: 4 analoge connectoren
– I2C: 3 connectoren
– PWM: 1 connector
– UART: 1 connector
Je hoeft niet de specifieke details van elk type connector te kennen. Onthoud gewoon dat elke Grove module gemaakt is voor een bepaald type connector (soms zijn er ook meerdere mogelijkheden). De minuscule handleiding bij elke module geeft dat aan, al is die informatie niet altijd even duidelijk. Zo stond in de beschrijving van de Temp&Humi Sensor dat het een digitale sensor is, terwijl je die op een analoge connector zou moeten aansluiten! Voor deze workshop gebruiken we drie verschillende interfaces: digitaal, analoog en I2C.
Lichtsensor
In onze test stellen we het alarm op in een ruimte zonder daglicht. De lichtsensor is bijgevolg een logische keuze om het alarm af te laten gaan. Sluit de Grove Light Sensor aan op een analoge connector naar keuze en gebruik het bijhorende poortnummer in volgend script (wij gebruikten poort 0):
from grove.adc import ADC from time import sleep poort = 0 class GroveLightSensor: def __init__(self, channel): self.channel = channel self.adc = ADC() @property def light(self): return self.adc.read(self.channel) lichtsensor = GroveLightSensor(poort) while True: print('Lichtsterkte: {}'.format(lichtsensor.light)) sleep(1)
Start het script en bestudeer de sensorwaardes terwijl je de lichtsterkte in de ruimte laat variëren, bijvoorbeeld door een deur te openen of een licht in te schakelen. Dat zou je een goed idee moeten geven van een drempelwaarde waarboven het alarm moet afgaan.
Lcd-scherm
Het kleine lcd-schermpje toont twee regels tekst van maximaal 16 karakters. Zo kan de Pi feedback tonen over bepaalde acties. Sluit om te beginnen het schermpje aan op één van de I2C-connectoren. Je stuurt het scherm aan via een object van het type JHD1802:
from grove.display.jhd1802 import JHD1802 lcd = JHD1802()
Dat object bevat volgende methodes:
clear(): om het scherm volledig te wissen home(): om de cursor linksboven te plaatsen setCursor(x, y): om de cursor op rij x en kolom y te positioneren (beginnend bij 0) write(): om tekst te tonen vanaf de huidige cursorpositie
Let op: de functie lcd.write() overschrijft de bestaande tekst op het scherm, zonder die te verwijderen. Stond er bijvoorbeeld eerst een tekst van 16 karakters en schrijf je slechts 10 nieuwe karakters, dan zie je de 6 laatste karakters van de oude tekst nog. Vergeet dus niet om eerst de clear()-methode te gebruiken in zulke gevallen.
In het voorbeeld uit de vorige paragraaf kunnen we de print-functie in het while-blok eenvoudig vervangen door een opdracht om de sensorgegevens op het lcd-scherm te tonen:
lcd.setCursor(0, 0) lcd.write('Lichtsterkte {}'.format(lichtsensor.light))
Led-knop
De Red LED Button is een combinatie van een drukknop en een led-lampje. Verbind de knop met een digitale connector naar keuze en definieer een GroveLedButton-object (in dit voorbeeld met digitale connector nummer 5):
from grove.button import Button from grove.grove_ryb_led_button import GroveLedButton knop = GroveLedButton(5)
Vervolgens kun je het lampje in- of uitschakelen:
knop.led.light(True) knop.led.light(False)
Of je laat het knipperen:
knop.led.blink(True)
Gebruik volgende code om te controleren of de knop is ingedrukt:
from time import sleep def on_event(index, event, tm): if event & Button.EV_SINGLE_CLICK: print('Knop kort ingedrukt') elif event & Button.EV_LONG_PRESS: print('Knop lang ingedrukt') while True: knop.on_event = on_event sleep(1)
Workflow
Intussen heb je alle benodigde componenten aangesloten en getest via korte stukjes Python-code. De volgende stap is om goed na te denken hoe je die verschillende componenten aan elkaar wilt koppelen. Zeker voor grote projecten helpt het soms om de workflow even op voorhand uit te schrijven. Zodra je alles op een rijtje hebt, begin je die workflow dan te programmeren in Python. Voor ons voorbeeld ziet die er als volgt uit:
– Elke 15 seconden controleren we de sensorwaarde.
– Is die waarde hoger dan de drempelwaarde, dan heb je 10 seconden de tijd om het alarm uit te schakelen door kort op de knop te drukken.
– Gedurende die 10 seconden knippert het led-lampje en telt het lcd-scherm af.
– Heb je het alarm uitgeschakeld, dan krijg je een minuut de tijd vooraleer het alarm weer kan afgaan.
– Heb je het alarm niet uitgeschakeld, dan licht het lampje rood op en toont het lcd-scherm de datum en uur waarop het alarm is afgegaan.
– Om het alarm te resetten, druk je lang op de rode knop. Je krijgt dan 5 minuten tijd vooraleer het weer kan afgaan.
Het script
from datetime import datetime from grove.adc import ADC from grove.button import Button from grove.display.jhd1802 import JHD1802 from grove.grove_ryb_led_button import GroveLedButton from math import ceil from time import sleep, time sensor_poort = 0 drempelwaarde = 500 interval = 15 uitschakeltijd = 10 wachttijd = 60 class GroveLightSensor: def __init__(self, channel): self.channel = channel self.adc = ADC() @property def light(self): return self.adc.read(self.channel) def on_event(index, event, tm): global knop_kort global knop_lang if event & Button.EV_SINGLE_CLICK: knop_kort = True elif event & Button.EV_LONG_PRESS: knop_lang = True def wis_scherm(tekst): lcd.clear() lcd.setCursor(0, 0) lcd.write(tekst) # maak objecten aan voor elke component lichtsensor = GroveLightSensor(sensor_poort) lcd = JHD1802() knop = GroveLedButton(5) knop.on_event = on_event # controleer elke 15 seconden de sensorwaarde while True: # maak het scherm leeg en schakel het lampje uit knop.led.light(False) wis_scherm('Alarm aan') # sensorwaarde te hoog, start alarmprocedure if lichtsensor.light > drempelwaarde: knop.led.blink(True) knop_kort = False eindtijd = time() + uitschakeltijd wis_scherm('Alarm gaat af in:') while time() < eindtijd: timer = str((ceil(eindtijd - time()))) lcd.setCursor(1, 0) lcd.write('{} seconden '.format(timer)) # annuleer alarm indien knop kort ingedrukt wordt if knop_kort: knop.led.light(False) wis_scherm('Alarm {}s uit'.format(wachttijd)) sleep(wachttijd) wis_scherm('Alarm aan') break else: sleep(1) # knop niet ingedrukt, alarm gaat af else: knop.led.light(True) tijdstip = datetime.today() wis_scherm(tijdstip.strftime("%d/%m/%Y")) lcd.setCursor(1, 0) lcd.write(tijdstip.strftime("%H:%M:%S")) knop_lang = False while True: # reset alarm indien knop lang ingedrukt wordt if knop_lang: knop.led.light(False) wis_scherm('Alarm {}s uit'.format(wachttijd * 5)) sleep(wachttijd * 5) wis_scherm('Alarm aan') break else: sleep(1) # sensorwaarde ok, wacht op de volgende controle sleep(interval)
Je herkent allicht de verschillende codeblokken om de componenten aan te sturen. We hebben ook nog een korte functie wis_scherm geschreven om het lcd-scherm volledig te wissen en meteen één regel tekst te tonen. Dat bespaart ons een tiental regels code. In de on_event-functie passen we de globale variabelen knop_kort en knop_lang aan om elders in het script te detecteren of de knop al dan niet ingedrukt wordt. De gehele workflow bestaat uit drie while-loops. De buitenste loop leest de sensor om de 15 seconden uit. Is die waarde te hoog, dan start er een nieuwe loop van 10 seconden om het alarm te annuleren. Druk je binnen die tijd kort op de knop, dan wordt de rest van de code (het else-blok van die while-loop) niet uitgevoerd. Druk je niet op de knop, dan gaat het alarm af en kom je in een loop van onbepaalde duur terecht. Die controleert of je de knop lang ingedrukt houdt en reset het alarm in dat geval. Aan het einde van beide loops beland je hoe dan ook weer in de buitenste loop en wordt de sensor opnieuw uitgelezen.