V dosedanjih besedilih, ki smo jih namenili programskemu jeziku Python (www.python.org), smo spoznali njegove glavne značilnosti in osnovne gradnike. Spoznali smo, da lahko Python namestimo v različna okolja, s pomočjo preprostih primerov pa smo lahko že z nekaj vrsticami rešili preprostejše probleme. Naučili smo se tudi, kako lahko v primeru zahtevnejših primerov v lastno programsko kodo vključimo že pripravljene module, ki nam razširijo Pythonovo funkcionalnost. Ker v večini primerov uporabljamo programsko opremo tudi za zajem oziroma obdelovanje določenih podatkov, smo spoznali tudi nekatere načine zapisovanja (ter iskanja podatkov) v datoteke oziroma iz njih ter različne podatkovne strukture. Svoje poznavanje Pythona smo počasi nadgrajevali s pomočjo različnih zgledov, na podlagi katerih smo spoznali tudi določene Pythonove zakonitosti. V svojo korist lahko izkoristimo dejstvo, da gre za tolmačen jezik, katerega kodo je s pomočjo pridobljenega znanja (in komentarjev) marsikateri bralec že sposoben uporabiti in ga na podlagi pridobljenega znanja spremeniti v skladu z lastnimi potrebami.

Poceni in zmogljivo razvojno okolje ter ustrezno zmogljiva, zanesljiva in poceni strojna oprema lahko pomenita dobro osnovo za konkurenčen izdelek ali lastno rešitev, ki je lahko tudi zanimiva alternativa komercialnim rešitvam. V našem primeru bomo uporabili eno najcenejših možnosti – »malino« oziroma računalnik Raspberry Pi (http://www.raspberrypi.org/). Ker gre za razmeroma zmogljiv kartični računalnik z majhnimi dimenzijami ter nizko ceno, ga lahko uporabimo za najrazličnejše rešitve in si lahko privoščimo tudi »eksperimentiranje na meji« – ki žal lahko vodi tudi v različne napake in z njimi povezane okvare. Zanemariti ne smemo niti razmeroma majhne porabe energije, kar nam omogoča, da je lahko »malina« vključena tudi v režimu 24 ur/365 dni. No, v tem primeru jo je smiselno nadgraditi s kompletom hladilnih reber, za kar bomo odšteli le nekaj dodatnih evrov.

(VČASIH) PROBLEMATIČNE PODROBNOSTI

Mnenja o računalnikih Raspberry so različna. Nekateri jih preprosto obožujejo in jih »ženejo« do tehnoloških meja, nasprotniki oziroma skeptiki pa so prepričani, da gre le za nadvse uspešen marketinški projekt, ki uspešno prodaja »zastarelo« arhitekturo in ki še zdaleč ni tako odprt (in poceni), kot bi si želeli, zato naj bi bilo »dolgoročno« preživetje projekta negotovo. Kakor koli že, »malina« že s svojo nizko ceno motivira in pomeni dobro osnovo za učenje, saj ni strahu pred velikimi stroški zaradi morebitne okvare, pridobljeno znanje pa lahko brez težav uporabimo tudi v drugih primerih. Ker smo računalniku Raspberry v preteklih številkah že namenili več pozornosti, omenimo le »malenkosti«, ki pa so lahko v našem primeru pomembne.

Raspberry nima priloženega napajalnika, zato vsak kupec oziroma uporabnik problematiko rešuje po svoje. Morda je še največja težava v tem, da je mogoče malčka napajati prek mikro USB-priključka, ki ga za polnjenje uporabljajo tudi določeni mobilni telefoni. Uporaba tovrstnega napajalnika je vabljiva predvsem zaradi cene (še posebno če vam tak napajalnik leži v predalu). Zavedati pa se je treba dejstva, da so tovrstne naprave izdelane z namenom polnjenja baterij mobilnih telefonov, in ne napajanja naprav – kar se posledično kaže v dejstvu, da določeni polnilci ne zagotavljajo zadostne jakosti toka za napajanje »maline«. Priporočena je uporaba napajalnika, ki da na izhodu vsaj 0,7 A (napis – output 5 V 700 mA). A če napis na napajalniku zagotavlja minimalno jakost toka, še ne pomeni, da težav z napajalnikom v nobenem primeru ne bomo imel. Zgodi se lahko, da zaradi neustrezne stabilizacije napetosti in izgub na (nekakovostnem) priključnem kablu oziroma zaradi slabe kakovosti priključnega konektorja napetost na vhodu malčka ne bo v zahtevanih mejah. Težave z napajanjem se lahko kažejo na različne načine: računalnik se ne zažene, po določenem času se ne odziva več ali pa gre v stanje ponovnega zagona … Skratka, kažejo se najrazličnejši znaki nestabilnosti, ki niso povezani z napako na strojni oziroma programski opremi. Da je zgodba, povezana z napajanjem, lahko še bolj zanimiva – »malina« je izdelana v več različicah, ki se po svojih »apetitih« na področju energije razlikujejo. Iz lastnih izkušenj vam lahko povem – v primeru uporabe istega napajalnika je prvi računalnik deloval brez težav, drugi pa je zdržal le 30 sekund, nato pa je šel samodejno v stanje ponovnega zagona – stanje se je ciklično ponavljalo. Zato je dobro v primeru morebitnih težav natančno preveriti, katero različico imamo. Različice se med seboj razlikujejo tako glede na izvedbo kot na proizvajalca in količino delovnega pomnilnika (RAM). Če imamo Linux na »malini« že nameščen, lahko različico ugotovimo s pomočjo ukaznega niza

cat /proc/cpuinfo

, ki nam med drugimi podatki izpiše tudi podatke o različici strojne opreme. V našem primeru je izpisal:

Hardware: BCM2708
Revision: 0002

Oznaka Revision nam sama po sebi ne pove prav veliko, zato si pomagamo z različnimi razpredelnicami (kot recimo na spletni strani http://elinux.org/Rpi_HardwareHistory). Ta nam za naš primer razloži, da imamo model B – različico 1.0.

'0002' => 'Model B Revision 1.0'
'0003' => 'Model B Revision 1.0 + sprememba pri varovalkah odstranitev D14',
'0004' => 'Model B Revision 2.0 256 MB', (Sony)
'0005' => 'Model B Revision 2.0 256 MB', (Qisda)
'0006' => 'Model B Revision 2.0 256 MB', (Egoman)
'0007' => 'Model A Revision 2.0 256 MB', (Egoman)
'0008' => 'Model A Revision 2.0 256 MB', (Sony)
'0009' => 'Model A Revision 2.0 256 MB', (Qisda)
'000d' => 'Model B Revision 2.0 512 MB', (Egoman)
'000e' => 'Model B Revision 2.0 512 MB', (Sony)
'000f' => 'Model B Revision 2.0 512 MB', (Qisda)

Opomba: Model A nima vmesnika ethernet in ima le en vmesnik USB.

Ne glede na različico »maline« pa lahko na težave (povezane z napajanjem) naletimo tudi v primeru priklopa različnih USB-naprav (na primer dodatni vmesnik Wi-Fi), priklopa zaslona prek vmesnika HDMI ali težav z medijem, ki ga uporabljamo (USB-ključek oziroma kartica SD), v večini primerov torej, ko se spremenijo okoliščine oziroma povečajo potrebe po energiji.

ZLATA VREDEN GPIO

Na zgornji strani tiskanega vezja lahko najdemo razširitveni konektor s šestindvajsetimi priključki (2 x 13 priključkov – oznaka P1). Ta vmesnik se imenuje GPIO (General Puropose Input/Output) in je, kot že ime samo pove, namenjen povezavi »maline« z zunanjim svetom – natančneje z drugimi napravami oziroma vezji. Priključne sponke na konektorju GPIO podpirajo različne tipe vmesnikov oziroma komunikacij (serijski vmesnik, I2C, SPI …). Preden nadaljujemo, še opozorilo: priključne sponke nimajo posebne zaščite, zato lahko v primeru nepazljivosti oziroma napake pride do trajne okvare vezja. Vsi signalni nivoji so na nivoju 3,3 V in ne dopuščajo tolerance oziroma napetostnih nivojev 5 V. Zato vse, kar naredite, naredite na lastno odgovornost. Elektronike manj vešči uporabniki zato dodajo ustrezna »razvojna« vezja, ki zmanjšujejo možnost okvare. Opozarjamo še na eno dejstvo. Različica 1.0 in različica 2.0 se po razporeditvi posameznih priključnih sponk razlikujeta, kar je še eden od razlogov, ki govori v prid, da pred »eksperimentiranjem« preverimo, katero različico imamo.

V primeru, ki si ga bomo ogledali, bomo izkoristili možnost, da lahko določene sponke kontroliramo oziroma programiramo prek lastne programske opreme. Praktično vse priključke GPIO (z logičnimi izjemami – priključki za napajanje oziroma skupna točka) je namreč mogoče prekonfigurirati glede na privzete/tovarniške nastavitve. Natančnejši pogled na priključne sponke nam razkrije, da imamo na voljo sedemnajst priključkov, ki jih lahko programiramo po svojih željah oziroma potrebah. Pazljivi moramo biti le, da priključke pravilno »štejemo« ali da jih ne bi po naključju nepravilno povezali (na primer kratek stik). Na tem mestu še eno opozorilo: različica Raspberry 2.0 je glede na različico 1.0 prinesla tudi določene spremembe pri pozicijah oziroma signalih, kar je vidno tudi iz razpredelnice (bolj »plastične« pa so barvne razpredelnice z »razlikami«, ki jih lahko najdemo na različnih spletnih straneh).

P1Oznaka R.1Oznaka R.2P1Oznaka R.1Oznaka R.2
1+3,3 V+3,3 V14GND GND
2+5 V +5 V15GPIO22GPIO22
3GPIO0GPIO216GPIO23GPIO23
4+5 V +5 V17+3,3 V+3,3 V
5GPIO1GPIO318GPIO24GPIO24
6GND GND19GPIO10GPIO10
7GPIO4GPIO420GNDGND
8GPIO14GPIO1421GPIO9GPIO9
9GND GND22GPIO25GPIO25
10GPIO15GPIO1523GPIO11GPIO11
11GPIO17GPIO1724GPIO8GPIO8
12GPIO18GPIO1825GNDGND
13GPIO21GPIO2726GPIO7GPIO7

Načelno pa lahko prepoznamo različico 1.0 tudi po tem, da na tiskanem vezju nima lukenj za montažo.

Ko pojasnjujemo pojme, povezane z vhodno-izhodnimi vmesniki, omenimo še pojem izhoda in vhoda. Na priključni sponki, ki jo konfiguriramo kot izhodno, se »zapisuje« signal, ki ima prirejeno logično vrednost. Podobno lahko na sponki, ki je definirana kot vhodna, »beremo« vrednost sprejetega logičnega signala (vrednost »0« – 0 V, vrednost »1« – 3,3 V).

Vsi, ki poznajo Linux, vedo, da ta dostopa do naprav kot do datotek. To možnost izkoristimo tudi v primeru priključkov GPIO, pogoj pa je, da jih prej primerno pripravimo oziroma »izvozimo«. Če želimo »izvoziti« recimo dva priključka (na primer GPIO8 kot izhodni ter GPIO14 kot vhodni priključek), storimo to kot korenski uporabnik iz ukazne vrstice s pomočjo ukaznih nizov

echo “8″> / sys / class / gpio / export
chmod 777-R / sys/class/gpio/gpio8
echo “out”> / sys/class/gpio/gpio8/direction

ter

echo “14″ > /sys/class/gpio/export
chmod 777-R / sys/class/gpio/gpio14
echo “in”> / sys/class/gpio/gpio14/direction

Če želimo postaviti stanje našega vmesnika GPIO8 na visok nivo, storimo to iz ukazne vrstice s pomočjo ukaza

echo “1″> / sys/class/gpio/gpio8/value

Po pričakovanju pa lahko to vrednost postavimo na nizek nivo s pomočjo niza

echo “0″> / sys/class/gpio/gpio8/value

Podobno lahko preverimo trenutno logično vrednost na vhodu s pomočjo ukaznega niza

more / sys/class/gpio/gpio14/value

Za test obeh funkcionalnosti (vhodnega oziroma izhodnega vmesnika) lahko uporabimo že zelo preprosto vezje. Za test izhodnega vmesnika zadošča že zaporedna vezava svetleče LED-diode (pravilna smer!) ter upora z vrednostjo okrog 1000 omov (1 kΩ). V tem primeru priključna sponka GPIO deluje kot mali napetostni vir, ki ga vključimo s pomočjo programske opreme. Za test funkcionalnosti digitalnega vhoda pa lahko zadošča še preprosto vezje, ki vključuje stikalo oziroma tipko.

Naša tokratna tema je povezana z uporabo Pythona, zato smo s spletne strani
http://pypi.python.org/pypi/RPi.GPIO prenesli knjižnico GPIO za Python, s pomočjo katere lahko krmilimo vmesniške priključke GPIO. Trenutno aktualna različica je Rpi.GPIO-0.5.3a.tar.gz, predlagamo pa vam, da si preberete, v katerih primerih je priporočljiva njena uporaba. Prenos lahko izvedemo na več načinov, zato omenimo le dva. Prva je neposredni prenos s pomočjo ukaza wget, druga pa, da knjižnico prenesemo s pomočjo osebnega računalnika, ki deluje v okenskem okolju, nato pa knjižnico s pomočjo programa WinSPC (http://winscp.net) prekopiramo v želeni imenik.
Knjižnico po prenosu »odpremo« s pomočjo nizov v ukazni vrstici

gunzip Rpi.GPIO-0.5.3a.tar.gz
tar -xvf Rpi.GPIO-0.5.3a.tar

V novo ustvarjeno mapo se prestavimo s pomočjo ukaza cd Rpi.GPIO-0.5.3a. Nato kot korenski uporabnik (root) dodamo knjižnico v Python s pomočjo ukaza python setup.py install. Če želimo recimo pin 24 definirati kot izhodni vmesnik, na katerem bomo imeli stanje logične »1« (3,3 V), napišemo v datoteko test.py naslednje vrstice

import RPi.GPIO as GPIO # uvozimo knjižnico GPIO
GPIO.setmode(GPIO.BOARD) # definira razpored pinov
GPIO.setup(12, GPIO.OUT) # pin 12 definiramo kot izhodni pin
GPIO.output(12, GPIO.HIGH) # visok nivo – 3,3 V napetost – na pinu 12

Drugo vrstico smo uporabili za izbiro, kako bodo oštevilčene priključne sponke. Obstajata namreč dva načina označevanja. Običajno se uporablja tako imenovani BOARD način v skladu z oznakami na P1 priključenem konektorju. Drug način označevanja je BCM, ki je na nižjem nivoju in se nanaša na nivoje kanalov. Natančnejša pojasnila glede pomena in parametrov znotraj posamezne vrstice lahko najdemo na strani http://code.google.com/p/raspberry-gpio-python/wiki/BasicUsage. Našo datoteko poženemo s pomočjo ukaza python test.py.

Ker na vmesniku nimamo priključenega nobenega vezja, je jasno, da ne moremo videti učinka. Zato lahko uporabimo preprosto vezje, ki ga sestavljata upor (približno 1000–2000 omov), ki mu je zaporedno vezana svetleča LED-dioda (v primeru morebitnih težav oziroma nedelovanja poskusite obrniti diodo).

Za različne eksperimente je zanimiva tudi uporaba vezja, ki smo ga našli v drugi številki The MagPi (http://www.themagpi.com/). Gre le za nekoliko kompleksnejše vezje, ki je sestavljeno iz treh uporov, svetleče diode in tipke oziroma stikala. Ker, kot že rečeno, priključki GPIO nimajo ustrezne zaščite, priključimo na priključek GPIO, ki ga želimo uporabljati (na primer GPIO 0), upor z vrednostjo 1000 omov (1 kΩ). Ta upor nam bi v primeru, če bi na priključku napačno definirali vrsto vmesnika (namesto vhodnega bi ga definirali kot izhodnega) in bi pri visokem stanju pritisnili tipko, omejil tok in preprečil nastanek kratkega stika (in uničenje vezja) proti točki O oziroma GND. Tok prek svetleče diode omejuje upor z vrednostjo 470 Ω, ki je na drugi strani povezan z napajalno napetostjo (3,3 V) na sponki ena. Tretji upor z vrednostjo 10 kΩ je uporabljen v vlogi tako imenovane pul-up uporabe, zato z njegovo pomočjo ustrezno fiksiramo logični nivo. V primeru, ko na našem vezju pritisnemo na tipko (sklenemo stikalo), postavimo skupno točko uporov na vrednost 0 V, zato svetleča dioda zasveti. Ustvarimo zdaj novo datoteko tipka.py in vanjo vpišimo

import time #uvoz modula time, ki omogoča funkcijo sleep
import RPi. GPIO as GPIO #uvozimo knjižnico GPIO
GPIO. setmode( GPIO. BOARD) #definiramo označevanje
GPIO. setup( 12, GPIO. IN) # pin 12 definiramo kot vhod

while True: #definiranje logičnega pogoja
tipka = GPIO. input( 12) #na podlagi logične vrednosti priredi vrednost spremenljivki tipka
if tipka == False: #preverjanje stanja priključka 12
print "mojMikro"
time. Sleep( .5 ) #časovni zamik znotraj zanke 0,5 s

Program preverja stanje na sponki 12. Zaradi same strukture vezja je stanje (če stikalo ni sklenjeno) ves čas na visokem nivoju – visok nivo pomeni logično vrednost True. Takoj ko stikalo sklenemo, postavimo napetost na vrednost 0 – nizek logični nivo pa pomeni vrednost False, zato se izpiše sporočilo mojMikro. Program oziroma zanka čaka pol sekunde in ponovno preveri stanje. Zdaj že vemo, kako bi z rahlo modifikacijo naš program spremenili, da bi namesto izpisa sporočil štel število pritiskov. Program stevec.py je videti nekaj podobnega temu:

import time
import RPi. GPIO as GPIO
GPIO. setmode( GPIO. BOARD)
GPIO. setup( 12, GPIO. IN)
stevec = 0 #zacetna vrednost stevca

while True:
tipka = GPIO. input( 12)
if tipka == False:
stevec = stevec+1 #povecanje vrednosti za „1“
print "Stevilo pritiskov tipke je ", stevec #izpis trenutne vrednosti
time. sleep( . 5 )

Podobno bi lahko izvedli tudi utripanje svetleče diode, morebitno »negacijo« pritiska na tipko (da se svetleča LED-dioda ugasne v primeru pritiska na tipko) ali da posamezni pritisk na tipko pomeni vklop oziroma izklop. Večjo uporabno vrednost bi imela poveza z napravo, ki v primeru alarma sproži relejsko vezje (stisne stikalo), s preprostim programom pa bi lahko recimo poslali sporočilo prek elektronske pošte (s pomočjo ustreznega Pythonovega modula). Spretnejši s spajkalnikom in boljšim poznavanjem elektronike lahko kot osnovo za preprosto vezje z več svetlečimi diodami uporabijo shemo na spletni strani http://lwk.mjhosting.co.uk/wp-content/uploads/2012/05/Slice-Schematic-11.... V tem primeru vsako svetlečo diodo krmili ena priključna sponka vmesnika GPIO, zato je treba našo programsko kodo razširiti na večje število vmesnikov. Za večje število diod (na primer 8 x 8 = 64 elementov) pa uporabimo različne »matrične vezave«. Delovanje ene od njih si lahko ogledamo tudi na spletni strani http://www.youtube.com/watch?v=S6P3jcxKh-k.

Uporaba vmesnika GPIO je zanimiva tudi za različne primere avtomatizacije doma. Ena od zanimivejših možnosti je uporaba PiUI, ki pametnemu mobilnemu telefonu z operacijskim sistemom Android oziroma iOS doda možnost povezave z lastnimi projekti na računalniku Raspberry. Več o projektu, namestitvi in uporabi ter možnostih si lahko preberete na spletnih straneh https://github.com/dps/piui in http://blog.davidsingleton.org/introducing-piui/. Rešitve so lahko seveda tudi drugačne. Ena od zanimivejših je uporaba spletne aplikacije WebIOPi, ki omogoča nadzor priključkov GPIO prek spletnega brskalnika. Dobrodošlo je, da WebIOPi namestimo le na Raspberry, za dostop pa lahko uporabimo poljuben spletni brskalnik. Program je uporaben za krmiljenje vmesnikov GPIO, uporabimo pa ga lahko tudi za razhroščevanje. Paket lahko prenesemo s spletne strani http://code.google.com/p/webiopi/ in se po pričakovanju odlično razume s Pythonom (strežnik, razvit v Pythonu, dostopne knjižnice za strežnik in vmesnike). Pred časom smo pisali tudi o daljinskem upravljalniku za konzole Wii (Wii Remote). S pomočjo ustreznega vmesnika Bluetooth in Pythona lahko ta upravljalnik povežemo z Rasbperryjem, ki lahko zaznava pritisk na posamezno tipko. Verjetno je vsaka dodatna beseda na temo uporabe v lastnih projektih odveč. Vsi, ki jih to področje bolj zanima, lahko natančnejše informacije najdejo na spletni strani http://www.brianhensley.net/2012/08/wii-controller-raspberry-pi-python.h....

Za nadzor nad sponkami vmesnika GPIO s pomočjo Pythona lahko uporabimo tudi drugo možnost. Eden od razlogov za takšno odločitev je lahko tudi dejstvo, da skripte ne želimo poganjati kot korenski (root) uporabnik. V tem primeru lahko uporabimo WiringPi-python (https://github.com/WiringPi/WiringPi-Python), ki je različica – port Wiring knjižnice za Raspberry (http://wiringpi.com/extensions/). Uporaba knjižnice je zelo preprosta in je zelo podobna že opisanim primerom. Za primer utripanja svetleče diode na vmesniku GPIO 0 (BCM GPIO 17 oziroma pin 11) bi bil program videti takole:

import wiringpi
from time import sleep
io=wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_SYS) io.pinMode(22,io.OUTPUT)
while True:
io.digitalWrite(22,io.LOW)
sleep(0.5)
io.digitalWrite(22,io.HIGH)
sleep(0.5)

Za pomoč smo uporabili to razpredelnico:

HITREJE, VIŠJE, MOČNEJE…

Naš potep v svet Pythona se bliža koncu. Tako kot običajno pa konec lahko pomeni začetek neke nove zgodbe – morda smo koga navdušili za programiranje v Pythonu. Pythona smo se seveda lahko dotaknili le v »skromnih« osnovah, prepričani pa smo, da smo pokazali, da je lahko programiranje s pravim in zmogljivim »orodjem« dokaj preprosto in včasih celo zabavno (na primer opisani primeri risanja z želvo).

Čeprav je doživel Python v zadnjih letih velik napredek, uporablja veliko uporabnikov še vedno prevzetega tolmača. Morebitne pomisleke glede Pythonove hitrosti lahko odpravi že izbira drugačnega tolmača. S tega stališča je zanimiv PyPy (http://pypy.org/), ki med drugim omogoča hitrejše izvajanje (prevajalnik JIT), optimalnejšo porabo pomnilnika, hkrati pa v visoki meri zagotavlja kompatibilnost s Pythonovo kodo. Po nekaterih informacijah naj bi na x86 platformi lahko tovrsten prehod pomenil bistveno povečanje učinkovitosti (celo desetkrat ali več) pri določenih obremenitvah. Dobrodošlo je tudi dejstvo, da je različica PyPy na voljo tudi za računalnike s procesorji ARM (v6 in v7) – med njimi tudi za Raspberry. Opozoriti pa je treba, da gre v tem primeru za tako imenovano alfa različico, ki ne podpira vseh funkcionalnosti in nima zagotovljene potrebne stabilnosti, zato kot takšna ni primerna za produkcijska okolja. Različica PyPy 2.1 je implementacija različice Pythona 2.7.3 Če vas zadeva zanima, si želeno različico PyPy lahko prenesete s spletne strani http://pypy.org/download.html. Priporočamo vam, da poskusite z zagonom Pythonove kode v standardnem okolju in v PyPy in primerjate rezultate. Razlika bo vidna brez dvoma že pri zagonu (1+), ki je hitrejši. A kot že rečeno, Python ni čarobna paličica za reševanje vseh težav, povezanih s programiranjem, dejstvo pa je, da jih lahko hitro in uspešno reši zelo veliko …

Moj mikro, September Oktober 2013 | Marko Koblar