4 edycja
warsztatów zakończona

Sterowanie Arduino przy pomocy Pythona cz.2

Published: Tue 14 July 2015

Artykuł ten jest drugą i ostatnią częścią minicyklu poświęconego sposobom sterowania platformą Arduino przy pomocy języka Python. W części tej omówione zostaną trochę bardziej zaawanswane przypadki użycia owej platformy.

Obydwie części minicyklu powstały w celu zgromadzenia i przekazania w przystępny sposób najważniejszych zasad działania platformy Arduino wraz z wykorzystaniem języka Python do sterowania nią. Artykuły te skierowane są głównie do osób, które chciałyby rozpocząć zarówno przygodę z platformą Arduino, ale także do osób znających platformę, a myślących o wykorzystaniu w niej języka Python.

W poprzedniej części opisałem podstawowe użycie protokołu Firmata za pomocą Pythonowego odpowiednika pyFirmata, którego będziemy używać także w drugiej części. W części tej skupimy się na odczycie stanów pinów analogowych oraz cyfrowych, a także na połączeniu tych informacji z wiedzą z poprzedniej części w celu zbudowania bardziej interaktywnych układów będących absolutną podstawą do tworzenia dowolnych mechanizmów i urządzeń, włączając w to nawet roboty, drony itp.

Firmata Test Program - niezastąpiony pomocnik

Zanim przejdziemy jednak ponownie do zabawy pinami, chciałbym przedstawić niewielki program, który bardzo ułatwił mi pracę z Arduino, i bez którego prawdopodobnie spędziłbym godziny na zastanawianiu się, czy to ja popełniłem błąd, czy może trafiłem na wadliwy pin.

Firmata Test Program jest oficjalnym, testowym programem protokołu Firmata, który po wgraniu na płytkę Arduino owego protokołu i wskazaniu portu, potrafi przeskanować wszystkie znajdujące się na płytce piny, a następnie udostępnia pełen interfejs, pozwalający na podgląd stanu wszystkich pinów, a także na manipulowanie tymi pinami. W skrócie program ten w znacznym stopniu ułatwia pracę z Arduino i dzięki niemu prosto możemy określić, czy popełniliśmy błąd podczas pisania programu, czy dobrze połączyliśmy dane elementy, a także możemy przetestować zachowania wszystkich pinów we wszelkich dostępnych trybach.

Program jest darmowy i można go ściągnąć w wersji na wszystkie platformy z oficjalnej strony Firmaty oraz GitHuba:
http://firmata.org/wiki/Main_Page
https://github.com/firmata/firmata_test

Wstęp do pinów analogowych

W pierwszej kolejności zajmiemy się odczytem pinów analogowych, jako że to one są chyba najczęściej wykorzystywane do odczytu stanu poszczególnych elementów budowanych urządzeń.

Zależnie od modelu Arduino dostępne jest od 6 do kilkudziesięciu pinów analogowych. Każdy z tych pinów w trybie odczytu dostarcza informacji o aktualnym napięciu skierowanym do danego pinu z zakresu 0 do 5V. Napięcie to jest zamienione za pomocą wbudowanego ADC (Analog Digital Converter) na 10 bitową wartość z zakresu 0-1023. Biblioteka pyFirmata, której używamy, zamienia dane pochodzące z sensora danego pinu na wartość z zakresu od 0 do 1.

Należy tutaj pamiętać, że płytka Arduino jest zbudowana w taki sposób, że piny zasilające POWER 5V i 3.3V są przeznaczone do tworzenia zamkniętego obiegu wraz z uziemieniem oznaczonym jako GND. Oznacza to, że chcąc odczytać stan jakiegoś elementu, musimy wpiąć ten element w obieg tych dwóch pinów, a dodatkowo przekierować z tego obiegu jeszcze jeden przewód, do któregoś z analogowych pinów. Pinami POWER ani GND nie trzeba także tak naprawdę sterować i jeżeli wepniemy np. żarówkę 5V pomiędzy pin 5V a GND, to się ona zaświeci bez naszej ingerencji.

Chcąc otrzymać faktyczne napięcie na danym pinie, musimy otrzymaną wartość pomnożyć przez 5 (zależnie od użytego pinu zasilającego POWER) w przypadku użycia pyFirmata.

Kolejną ważną rzeczą, która może wprawić w zakłopotanie przy używaniu pinów analogowych, a którą należy wyróżnić, jest losowość wartości na pinach analogowych, którą możemy zobaczyć np. uruchamiając Firmata Test Program. Jest to zwyczajnie szum mogący pochodzić z portu serial, do którego wpięliśmy Arduino i jeżeli dany pin analogowy nie jest do niczego podłączony, wtedy będzie na nim widoczna losowa wartość wahająca się w jakimś przedziale zależnym od różnych czynników, takich jak np. czy jakieś elementy są wpięte w pozostałe piny analogowe. Nie należy się tym przejmować, ale należy mieć to na uwadze przy monitorowaniu wartości wszystkich pinów.

Odczyt pinów analogowych

Chyba najprostrzym przykładem pozwalającym na przećwiczenie odczytu z pinów analogowych jest stworzenie prostego układu z potencjometrem, który będzie zwracał różne wartości zależnie od ustawienia potencjometra.

Aby to zrobić, użyłem znajdującego się w chyba każdym zestawie startowym Arduino i pochodnych potencjometru 10K, który można także za grosze dostać w każdym sklepie elektronicznym.

Układ powinien wyglądać następująco:

podlączenie potecjonometru Rys.1. Schemat podłączenia potencjometru

Należy zwrócić uwagę w tym miejscu na typ posiadanej płytki i na wersję Firmaty, jaką wgraliśmy. Ja posiadam kopię Arduino Mega z układem ATmega2560 i po wgraniu standardowej wersji Firmaty nie mogłem uzyskać dostępu do pinu 0. Po uruchomieniu Firmata Test Program okazało się, że standardowa wersja Firmaty odczytuje u mnie jedynie piny analogowe 2, 5, 8, 11, 14 i 15 . Użyłem zatem pinu nr. 2.

Przejdźmy teraz do kodu Pythonowego obsługującego powyższy układ. W przypadku odczytu pinów analogowych zaleca się użycie iteratora, który utworzy nam osobny wątek, dzięki czemu zapobiegniemy zalaniu danymi z płytki Arduino. Robimy to za pomocą:

from pyfirmata import Arduino, util

iterator = util.Iterator(board)
iterator.start()

Gdzie board jest zmienną trzymającą referencję do płytki podłączonej pod dany serial port. Następnie przypiszemy sobie pin, którym jesteśmy zainteresowani, do zmiennej, a także włączymy na danym pinie raportowanie:

analog_0 = board.get_pin('a:0:i')
analog_0.enable_reporting()

Teraz możemy dowolnie odczytywać stan danego pinu za pomocą metody read(). Całość działającego kodu obsługującego przedstawiony wcześniej układ może wyglądać następująco:

from pyfirmata import Arduino, util
from time import sleep

board = Arduino('\.\COM3')
iterator = util.Iterator(board)
iterator.start()

analog_0 = board.get_pin('a:2:i')
analog_0.enable_reporting()

while True:
    analog_0_value = analog_0.read()
    if analog_0_value:
        print 5 * analog_0_value
    sleep(0.1)

Powyższy kod odczytuje stan pinu analogowego nr. 0 i zwraca faktyczne napięcie zależnie od ustawienia potencjometru, a jeżeli napięcie wynosi 0 wtedy nie zwraca niczego i układ uznawany jest za wyłączony. Wartość Arduino('.\COM3') zamieniamy oczywiście na właściwy dla nas adres serial portu, pod który podłączona została płytka Arduino.

Dodajmy trochę fantazji

A teraz bez wprowadzania większych zmian możemy zastosować mały zabieg, aby uzyskać bardzo ciekawy efekt. Kod programu zostawiamy taki sam, a jedyne co robimy, to zamieniamy potencjometr na fotorezystor dodawany do każdego zestawu startowego Arduino, łatwy do nabycia również w każdym elektronicznym sklepie. Dodatkowo dodajemy przed fotorezystorem zwykły rezystor, np. 10K ohm, czyli taki sam, jaki w pierwszej części dodawaliśmy przed diodami LED. Jakby ktoś miał problemy z określeniem jak wygląda fotorezystor, to jest to coś przypominającego płaską diodę z wyraźnie widoczną, zawiłą ścieżką. Wszystko jest ładnie widoczne na poniższym schemacie prezentującym jak powinien wyglądać taki układ:

Podłączenie Fotorezystatora Rys.2. Schemat podłączenia fotorezystora

Co w ten sposób osiągnęliśmy? Fotorezystor jest niczym innym jak prostym czujnikiem światła, czyli właśnie zbudowaliśmy sobie bardzo prosty czujnik podobny do tych montowanych obecnie w większości urządzeń takich jak laptopy, tablety czy smartfony. Możemy teraz rozwinąć nasz kod i ingerując w funkcje systemowe możemy automatycznie dostosowywać jasność naszego ekranu w zależności od natężenia światła w pomieszczeniu. Możemy także zautomatyzować sobie w ten sposób mieszkanie.

Odczyt z pinów cyfrowych

Przejdziemy teraz do obsługi pinów cyfrowych, które są prostsze w obsłudze, ale też posiadają parę haczyków, o których należy pamiętać.

Tak jak w przypadku pinów analogowych, cyfrowe także potrafią się dziwnie zachowywać kiedy nie są do niczego podłączone i zauważalne wtedy też są losowe wahania wartości. W przypadku pinów cyfrowych jednak wartości te są zaokrąglane do 5 lub 0V czyli w efekcie dostajemy drgania pomiędzy stanem HIGH i LOW. Oznacza to, że normalnie nie jesteśmy w stanie miarodajnie nasłuchiwać na dany pin i np. gdy podłączymy do niego zwykły przycisk, to nie jesteśmy w stanie z pewnością stwierdzić, czy został on wciśnięty, czy może to tylko drania wartości zostały zaokrąglone “do góry” i zinterpretowane jako stan HIGH.

Oczywiście jest na to rozwiązanie, a mianowicie wystarczy wpiąć przycisk do obiegu tak aby zawsze był połączony z rezystorem np. 10K ohm. W ten sposób wartość drgania zawsze będzie odpowiednio zaniżona i traktowana zawsze jako stan LOW. Po wciśnięciu przycisku zostanie wygenerowane napięcie także pomniejszone przez wpięty w układ rezystor, ale i tak na tyle duże, że zawsze zinterpretowane jako HIGH, więc zawsze będziemy w ten sposób w stanie stwierdzić czy przycisk jest faktycznie wciśnięty.

Przykład takiego rozwiązania został przedstawiony na poniższym układzie:

dzialanie przycisku Rys.3. Schemat poprawnego działania przycisku

Poniższy kod stanowi poprawną obsługę przedstawionego układu. Użyta została także wbudowana w płytkę Arduino dioda pod pinem nr. 13, która zapala się po naciśnięciu przycisku. Przy montowaniu przycisku należy zwrócić uwagę na jego nóżki ponieważ są one połączone ze sobą parami i ważne jest, żeby ustawić przycisk tak, aby pin 2 był zawsze w zamkniętym układzie z rezystorem i GND.

from pyfirmata import Arduino, util
from time import sleep

board = Arduino('\.\COM3')
iterator = util.Iterator(board)
iterator.start()

digital_13 = board.get_pin('d:13:o')

digital_2 = board.get_pin('d:2:i')
digital_2.enable_reporting()

while True:
    print digital_2.read()
    if digital_2.read():
        digital_13.write(1)
    else:
        digital_13.write(0)
    sleep(0.1)

Pełen kod programu

Zapis do pinów analogowych i PWM

W pierwszej części artykułu wspomniałem o tym, że na płytkach Arduino z reguły są 3 rodzaje pinów: analogowe, cyfrowe i z grupy POWER, ale dodałem tam także, że niektóre rodzaje płytek, te większe, mają jeszcze dodatkowe piny do specjalnych zastosowań. Takie piny ma np. Arduino Mega i są one oznaczone jako PWM. Są to piny cyfrowe, ale specjalnie dostosowane tak, aby można na nich użyć coś co się nazywa Pulse Width Modulation.

PWM to nic innego jak technologia pozwalająca używać pinów cyfrowych w trybie OUTPUT w taki sam sposób, jak pinów analogowych, czyli z możliwością nadania napięcia także pomiędzy 0 a 5V. Aby to zrobić, trzeba zainicjować dany pin w specjalnym trybie.W pyFirmacie robi się to za pomocą komendy:

digital_15_pwn = board.get_pin('d:15:p')
digital_15_pwn.write(0.5)

Powyższe polecenie informuje płytkę Arduino poprzez protokół firmata, aby otworzyć cyfrowy pin 15 w specjalnym trybie PWM , a następnie nadaje mu napięcie 2.5V. Jest to możliwe dzięki temu, że pin w trybie PWM dostaje wtedy na przemian napięcia 0 i 5V z odpowiednią częstotliwością tak, że dostajemy na wyjściu oczekiwaną wartość napięcia z tego przedziału. Jak się dobrze przyjrzeć np. sterowanej w ten sposób diodzie, to można także zauważyć jej subtelne pulsowanie, co jest skutkiem właśnie zmienianych szybko skrajnych napięć.

Dokładnie w ten sam sposób używa się pinów analogowych w trybie OUTPUT, z tym że inicjalizuje je się już normalnie jako analogowe:

analog_0 = board.get_pin('a:0:o')
analog_0.write(0.5)

Ot cała filozofia. Zarówno tryb PWM , jak i zwykły zapis analogowy można prosto przetestować za pomocą Firmata Test Program, lub po prostu wykorzystać dotychczasową wiedzę do stworzenia np. układu z diodą sterowaną w trybie PWM na podstawie analogowych danych z potencjometru.

Dodatkowo jest jeszcze tryb SERVO, ale bazuje on na trybie PWM i wykorzystuje się go w ten sam sposób, tyle że służy do sterowania specjalnymi silnikami krokowymi, które się wykorzystuje m.in. do budowy robotów.

Podsumowanie

Wiedza przedstawiona w obydwóch artykułach powinna stanowić solidne podstawy do tworzenia nawet bardziej zaawansowanych urządzeń. Jest parę rzeczy, o których nie wspomniałem i pewnie jeszcze więcej aspektów, o których nie mam pojęcia, ale tak jak napisałem na wstępie pierwszej części, ten artykuł jest po prostu zbiorem doświadczeń początkującego użytkownika Arduino, który chciałby zaoszczędzić innym początkującym szukania wiedzy rozproszonej w internecie. Nie ma sensu także na początku zagłębiać się w tematy, które tylko mogłyby niepotrzebnie skomplikować naukę platformy.

Mam nadzieję, że artykułami tymi chociaż trochę obniżyłem próg wejścia w zabawę Arduino i że okażą się pomocne. W razie pytań zawsze chętnie pomogę, więc można śmiało się ze mną kontaktować mailowo.

Powodzenia w konstruowaniu swojego osobistego imperium robotów i mam nadzieję do zobaczenia w kolejnych artykułach, już pewnie o innej tematyce!

PS. Jakby ktoś się zastanawiał skąd się wzięły wizualizacje płytek ARduino i bradboarda w ninejszym artykule, to do ich generowania służy darmowy program Fritzing.

Michał Janiszewski Michał Janiszewski

Jestem JavaScript oraz Python Developerem tworzącym złożone aplikacje webowe wraz z zespołem świetnych ludzi w poznańskim STX Next. Z zamiłowania jestem także UI Designerem, po godzinach lubię czasem pogrzebać przy grach HTML5, a w przeszłości także pyGame. Czasem można mnie posłuchać na mniejszych i większych eventach, takich jak meet.js

comments powered by Disqus
Współpraca: programista