Programujeme Raspberry Pi Pico v jazyku MicroPython
základy práce s doskami RPi Pico v jazyku MicroPython
Videá pre cvičenie
Upozornenie
Pred príchodom na cvičenie si doma nainštalujte editor Thonny a na cvičenie si prineste vlastné Raspberry Pi Pico 2 WH minimálne so senzorom DHT11, tlačítkom a NeoPixel (alebo RGB LED diódu)! Pokiaľ máte dosku Cytron Robo Pico alebo Cytron Maker Pi Pico Base, potrebujete len senzor DHT11.
V prípade, že nemáte k dispozícii fyzické komponenty, môžete na účely cvičenia využiť online simulátor Wokwi, kde si už doma pripravte zapojenie so senzorom DHT11 a tlačítkom v jazyku MicroPython.
Jednotlivé elektronické prvky pripojte nasledovne:
- senzor DHT11 - pin
27
- tlačidlo - pin
20
- NeoPixel - pin
18
Motivácia
Našim cieľom na nasledujúcich cvičeniach bude vytvoriť chytrý senzor pre meranie teploty a vlhkosti. Čo je podstatné - pri návrhu a implementácii sa budeme snažiť o to, aby sa nejednalo o prvoplánové riešenie, ale budeme sa snažiť o bezpečnú a funkčnú implementáciu s ohľadom na koncového zákazníka.
Ciele
naučiť sa základy programovania v jazyku MicroPython na doske Raspberry Pi Pico
zoznámiť sa s editorom Thonny a jeho možnosťami programovania mikrokontrolérov v jazyku MicroPython
naučiť sa pracovať s LED diódou ako spätnou väzbou pre používateľa
naučiť sa pracovať s objektom typu
Pin
Postup
Predtým, ako naozaj začneme
Ešte predtým, ako začneme, si nainštalujte editor Thonny a na dosku Raspberry Pi Pico 2 nahrajte firmvér s jazykom MicroPython. Podrobnejšie pokyny nájdete na tejto stránke.
Niekoľko tipov pre prácu:
Pico na doske neobsahuje tlačidlo
RESET
. Najjednoduchšie ho môžete reštartovať odpojením a opätovným pripojením USB kábla. Nikdy ho však neodpájajte ani nepripájajte na strane dosky mikrokontroléra! Vyhnete sa tak možnosti odtrhnutia konektora na doske a tým pádom aj jej celkovému poškodeniu. Miesto toho odpájajte USB kábel vždy na strane počítača!V prípade, že chcete mikrokontrolér reštartovať softvérovo, môžete tak urobiť príkazom:
from machine import reset; reset()
Tzv. mäkký reset (z angl soft reset) zariadenia sa dá vykonať dokonca ešte jednoduchšie - stlačením klávesovej skratky
CTRL+D
v prostredíREPL
(terminál, resp. v paneli Shell) vývojového prostredia Thonny.
Funkčné minimum
V prvom kroku vytvoríme veľmi jednoduchú a prvoplánovú implementáciu (budúceho) chytrého senzora. Vytvoríme teda jednoduchý kód, pomocou ktorého odmeriame aktuálne hodnoty zo senzora a vypíšeme ich do terminálu.

Task
V súbore main.py
vytvorte kód, pomocou ktorého prečítate
aktuálne hodnoty zo senzora a vypíšete ich do terminálu.
Súbor main.py
má dôležité postavenie, pretože sa spustí
po zapnutí mikrokontroléra.
Do tohto súboru vložte nasledujúci kód:
# main.py
from dht import DHT11 as DHT
from machine import Pin
= Pin(27, Pin.IN)
pin = DHT(pin)
sensor
sensor.measure()= sensor.temperature()
temp = sensor.humidity()
hum
print(temp, hum)
Poznámka
Ak miesto senzora DHT11 používate senzor DHT22,
stačí v programe prepísať prvý import
nasledovne:
from dht import DHT22 as DHT
Task
Spustite vytvorený program a overte jeho správnosť.
Spustiť program je možné viacerými spôsobmi:
V editore Thonny môžete spustiť aktuálne otvorený skript kliknutím na tlačidlo
Spustiť aktuálny skript
alebo stlačiť klávesF5
.Odpojením a pripojením dosky.
Stlačením klávesovej skratky
CTRL+D
, čím dôjde k mäkkému resetu zariadenia.
Poznámka
Po skončení programu sa v paneli Shell zobrazí prompt REPL jazyka Python. V jeho kontexte však zostali všetky vytvorené premenné (objekty). To je možné využiť pre ďalšie experimentovanie alebo ladenie. Vyskúšať si to môžete jednoducho - do panelu Shell napíšte napr. nasledovné volanie, čím vypíšete obsah nameranej teploty:
>>> print(temp)
Konfigurácia chytrého senzora
Niektoré vlastnosti chytrého zariadenie bude môcť meniť používateľ za behu, ako napr. údaje pre pripojenie do WiFi siete alebo interval snímania. Niektoré naopak bude definovať výrobca a nebude ich možné nijako zmeniť, ako napr. pracovná frekvencia mikrokontroléra alebo čísla GPIO pinov, ku ktorým budú pripojené jednotlivé elektronické prvky. Nami vytváraný chytrý senzor pripravíme na obe možnosti konfigurácie.
Nemennú, resp. statickú konfiguráciu vyriešime v podobe
samostatného modulu jazyka Python, v ktorom jednotlivé
vlastnosti zadefinujeme v podobe premenných s príslušnými hodnotami.
Tento modul sa bude volať constants.py
.
Konfiguráciu, ktorú bude možné meniť, budeme volať používateľské
nastavenia. To bude možné napr. pomocou webového rozhrania senzora,
pomocou mobilnej aplikácie alebo vzdialene pomocou vhodného
komunikačného protokolu. Samotné vlastnosti budeme ukladať na zariadení
do súboru typu JSON, pretože manipulácia s týmto typom súborov
je v jazyku Python veľmi jednoduchá. Súbor, v ktorom budú
používateľské nastavenia uložené, sa bude volať
settings.json
.
V tomto kroku vytvoríme statickú konfiguráciu zariadenia.
Task
Vytvorte modul constants.py
a v ňom vytvorte premenné
označujúce GPIO piny, ku ktorým sú pripojené jednotlivé elektronické
komponenty.
V našom prípade to budú premenné:
DHT_PIN
- pin, ku ktorému je pripojený senzor DHT11BTN_PIN
- pin, ku ktorému je pripojené tlačidloNP_PIN
- pin, ku ktorému je pripojený NeoPixel
Výsledný modul môže vyzerať takto:
# constants.py
= 27
DHT_PIN = 20
BTN_PIN = 18 NP_PIN
Poznámka
Tým, že sa jedná o modul jazyka Python je možné využívať všetky vlastnosti jazyka pri jeho písaní. Napríklad je možné s výhodou využívať komentáre na opísanie významu jednotlivých premenných.
Task
Upravte vašu implementáciu v module main.py
tak, aby
použila vytvorený modul so statickou konfiguráciou
constants.py
.
Task
Otestujte aktualizovaný kód.
Ak ste postupovali správne, funkcionalita kódu sa nezmení.
Používateľské nastavenia
Pre prácu s používateľskými nastaveniami (a nie len s nimi) budeme používať tzv. dátové triedy. Je to špeciálny typ triedy, ktorý slúži predovšetkým na ukladanie dát a uľahčuje prácu s objektmi, ktoré majú prevažne iba atribúty (premenné) a nepotrebujú veľa špeciálnej logiky.
Jazyk MicroPython však neobsahuje priamu podporu pre dátové triedy a ako jazyk má značné obmedzenia vo vlastnostiach, ktoré sa pre prácu s nimi používajú (hlavne tzv. typehinting). Pre naše potreby použijeme jednoduchú implementáciu, ktorá sa podobá na populárnu knižnicu pydantic.
Naša konfigurácia bude aktuálne obsahovať len jednu vlastnosť a tou bude jednotka teploty, v ktorej budeme vracať nameranú hodnotu. Senzor predvolene meria teplotu v stupňoch Celzia. Okrem toho bude náš chytrý senzor možné nastaviť, aby vedel vrátiť hodnotu v stupňoch Fahrenhaita alebo v Kelvinoch.
Vlastnosť v konfiguračnom súbore sa bude volať units
a
jej možné hodnoty sú:
metric
- stupne Celziaimperial
- stupne Fahrenhaitastandard
- Kelvin, predvolená hodnota
Task
V module constants.py
vytvorte samostatnú triedu
TempUnit
, ktorá bude obsahovať konštanty pre reprezentáciu
jednotlivých merných jednotiek teploty.
Trieda TempUnit
bude fungovať podobne ako enumeračný typ
- bude obsahovať iba potrebné konštanty. Jej implementácia môže vyzerať
napr. takto:
class TempUnit:
str = 'imperial'
IMPERIAL: str = 'standard'
STANDARD: str = 'metric' METRIC:
Task
V koreňovom priečinku zariadenia vytvorte balík models
a
stiahnite do neho modul udataclasses.py
.
V tomto balíku sa budú nachádzať všetky naše modely, ktoré vytvoríme pre chytré zariadenie.
Upozornenie
Nezabudnite, že priečinok je balíkom až vtedy, keď obsahuje súbor
__init__.py
. Balík models
bude teda spolu s
modulom udataclasses.py
v súborovom systéme vyzerať
takto:
models/
├── __init__.py
└── udataclasses.py
Task
Pridajte nový model Settings
, ktorý bude potomkom triedy
Dataclass
a bude obsahovať jednu premennú s názvom
units
s predvolenou hodnotou
TempUnit.STANDARD
.
from udataclasses import Dataclass
from constants import TempUnit
class Settings(Dataclass):
str = TempUnit.STANDARD units:
Task
V triede Settings
vytvorte funkciu
check_units()
, ktorá bude reprezentovať validátor na
overenie, či hodnota priradená do členskej premennej units
obsahuje správnu hodnotu.
@validator('units')
def check_units(self, value):
if value not in (TempUnit.METRIC, TempUnit.STANDARD, TempUnit.IMPERIAL):
raise ValueError(f'Unit "{value}" is invalid.')
Task
Otestujte vytvorenú implementáciu.
Vašu vytvorenú triedu môžete otestovať priamo z REPL režímu napr. takto:
>>> from models.settings import Settings
>>> s = Settings()
>>> s
='standard')
Settings(units>>> s.units = 'kosicka standarda'
Traceback (most recent call last):"<stdin>", line 1, in <module>
File "models/udataclasses.py", line 76, in __setattr__
File "models/udataclasses.py", line 17, in __call__
File "models/settings.py", line 25, in check_units
File ValueError: Unit "kosicka standarda" is invalid.
Načítanie používateľských nastavení zo súboru
Používateľské nastavenia sa na zariadení budú nachádzať v súbore
settings.json
. V tomto kroku vytvoríme funkciu
get_settings()
, pomocou ktorej ich načítame.
Task
Do modulu constants.py
vložte premennú
SETTINGS_FILE
, ktorá bude obsahovať cestu k súboru s
nastaveniami používateľa.
Hodnota premennej bude obsahovať absolútnu cestu k súboru s
nastaveniami a teda /settings.json
.
Task
Vytvorte súbor s používateľskými nastaveniami a do kľúču
units
uložte hodnotu metric
.
Súbor settings.json
bude vyzerať takto:
{
"units": "metric"
}
Task
V module helpers.py
vytvorte funkciu
get_settings()
, ktorá načíta konfiguračný súbor zo
súborového systému mikrokontroléra a vráti ho ako objekt typu
Settings
.
Jednoduchá implementácia funkcie môže vyzerať napríklad takto:
# helpers.py
import json
from constants import SETTINGS_FILE
from models.settings import Settings
def get_settings() -> Settings:
with open(SETTINGS_FILE, 'r') as file:
= json.load(file)
settings return Settings(**settings)
Task
Overte správnosť svojej implementácie.
Nezabudnite, že funkciu viete otestovať aj priamo z REPL (v paneli Shell) napríklad takto:
>>> from helpers import get_settings
>>> s = get_settings()
>>> s
='metric') Settings(units
Meriame teplotu v správnych jednotkách
Zo senzora teploty získame teplotu ako celé číslo v stupňoch
Celzia. V tomto kroku vytvoríte funkciu
convert_temp()
, ktorá premení a vráti hodnotu teploty v
jednotkách podľa nastavení používateľa. Funkciu vytvoríte v module
helpers.py
.
Task
Vytvorte funkciu convert_temp()
, ktorá prevedie hodnotu
teploty do správnych jednotiek.
Funkcia bude mať tieto parametre:
value
- nameraná hodnota v stupňoch Celzia, ktorá bude typu intunits
- reťazec, ktorého hodnota môže byť jedna z hodnôtstandard | metric | imperial
Funkcia vráti hodnotu typu float
, ktorá bude
reprezentovať hodnotu teploty v jednotkách zadaných v parametri
units
. V prípade, že hodnota parametra units
nebude správna, vyvolajte výnimku ValueError
.
from constants import TempUnit
def convert_temp(value: float, units: str) -> float:
if units == TempUnit.METRIC:
return value
if units == TempUnit.IMPERIAL:
return value * 9/5 + 32
if units == TempUnit.STANDARD:
return value + 273.15
raise ValueError(f'Unit "{units}" is invalid.')
Task
Overte vytvorenú implementáciu.
Ak ste postupovali správne, zmenou hodnoty kľúča v konfiguračnom súbore dostanete nameranú hodnotu teploty v rozdielnych jednotkách.
Signalizácia LED diódou
Chytrý senzor je vybavený viacfarebnou LED diódou, ktorej hlavnou funkciou je pomocou rozličných farieb poskytovať spätnú väzbu pre používateľa ohľadom stavu senzora. V tomto kroku túto LED diódu oživíme.
Najprv v module constants.py
vytvoríme triedu
Color
, ktorá bude obsahovať definície RGB trojíc
predstavujúcich farby používané senzorom. Následne na začiatku merania
rozsvietime LED diódu na zeleno a po jeho ukončení ju zhasneme.
Task
V module constants.py
vytvorte triedu
Color
, ktorá bude obsahovať definície RGB trojíc
predstavujúcich farby používané senzorom.
Definícia triedy Color
môže vyzerať napr. takto:
class Color:
tuple = (255, 0, 0)
RED: tuple = (0, 255, 0)
GREEN: tuple = (0, 0, 255)
BLUE: tuple = (255, 255, 0)
YELLOW: tuple = (0, 255, 255)
CYAN: tuple = (255, 0, 255)
MAGENTA: tuple = (255, 165, 0)
ORANGE: tuple = (0, 0, 0) OFF:
Task
Zabezpečte, aby sa dióda po zapnutí senzora rozsvietila na zeleno.
Implementácia závisí od použitej diódy. V prípade, že používate adresovateľné RGB LED diódy NeoPixel, tak rozsvietenie na zelenú farbu bude vyzerať takto:
from neopixel import NeoPixel
from constants import NP_PIN, Color
= NeoPixel(Pin(NP_PIN, Pin.OUT), 1)
led 0] = Color.GREEN
led[ led.write()
Task
Rovnako zabezpečte, aby dióda po ukončení merania zhasla.
Podobne, ako sme diódu rozsvietili, tak ju aj zhasneme. Za
predpokladu, že je objekt led
stále inicializovaný, LED
diódu zhasneme nasledovne:
0] = Color.OFF
led[ led.write()
Task
Overte vytvorenú implementáciu.
Ak ste postupovali správne, tak sa LED dióda pri spustení mikrokontroléra rozsvieti na zeleno a po ukončení merania zhasne. Nakoľko celý proces prebehne veľmi rýchlo, bude sa jednať o krátke bliknutie.
Pred odchodom z cvičenia…
Upozornenie
Ak máte dosku Raspberry Pi Pico 2 WH od cvičiaceho požičanú, tak pred odchodom z cvičenia prosím:
- uložte si vytvorený kód, ktorý ste na cvičení urobili
- zmažte obsah Flash pamäte mikrokontroléra nahratím fimrvéru flash_nuke.uf2
- nahrajte na mikrokontrolér najnovší firmvér
Ďalšie úlohy
Súbor s konfiguráciou nemusí byť valídny. V prípade, že sa tak stane, dôjde pri jeho načítaní k výnimke. Aktualizujte preto funkciu
read_settings()
tak, aby v prípade pokusu o načítanie nevalídneho konfiguračného súboru tento súbor prepísala predvolenou konfiguráciou.Jazyk MicroPython nemá k dispozícii modul na logovanie. Preto vytvorte samostatný modul
log.py
, ktorý chýbajúcu funkcionalitu poskytne. V tomto module vytvorte (minimálne) tieto funkcie:debug()
- Funkcia na vypísanie logovacích správ úrovneDEBUG
.info()
- Funkcia na vypísanie logovacích správ úrovneINFO
.warning()
- Funkcia na vypísanie logovacích správ úrovneWARNING
.error()
- Funkcia na vypísanie logovacích správ úrovneERROR
.critical()
- Funkcia na vypísanie logovacích správ úrovneCRITICAL
.
Pre potreby logovania vytvorte globálnu premennú
LOG_LEVEL
, pomocou ktorej bude možné nastaviť úroveň logovania globálne pre celé zariadenie. To znamená, že ak bude nastavená vyššia úroveň logovania (napr. úroveňERROR
), nebudú sa zobrazovať logovacie správy nižších úrovní (napr. v prípade úrovne logovaniaERROR
sa nebudú zobrazovať správy úrovníDEBUG
,INFO
aWARNING
).
Ďalšie zdroje
Getting started with Raspberry Pi Pico - Návod ako začať s RPi Pico pre každého
Getting started with your Raspberry Pi Pico W - Návod, ako začať s RPi Pico W
Introduction to Raspberry Pi Pico: LEDs, buzzers, switches, and dials - sada návodov na prácu s RPi Pico
Quick reference for the RP2 - (krátka) dokumentácia jazyka MicroPython pre dosku Raspberry Pi Pico
MicroPython Chapters: Súborový systém
MicroPython Chapters: Dátové triedy
MicroPython: Controlling NeoPixels
MicroPython: Quick reference for the RP2: NeoPixel and APA106 driver
Random Nerd Tutorials: MicroPython: WS2812B Addressable RGB LEDs with ESP32 and ESP8266 - This tutorial shows how to control WS2812B addressable RGB LEDs (neopixels) with the ESP32 and ESP8266 using MicroPython.
Last Minute Engineers: Interfacing DHT11 and DHT22 Sensors with Arduino
Last Minute Engineers: Controlling WS2812B Addressable LEDs with Arduino