Jak działa program odbierający dane z tinyBrd na Raspberry Pi?
W artykule o testowaniu połaczeń z tinyBrd znajdziesz instrukcję jak zainstalować bibliotekę pyNRF od Nettigo oraz przykładowy program testowy.
Jeżeli zajrzysz do wnętrza connectionTester.py
przekonasz się, że odbiór danych z tinyBrd jest bardzo łatwy do oprogramowania. Dzięki naszej bibliotece w Pythonie obsługującej NRF24L01+ na Rasbperry Pi niezbędnę jest tylko kilka czynności. Jeśli chcesz się z nim teraz zpoznać, jest na GitHubie
Pierwszą jest rozpoczęcie nasłuchiwania:
radio = Radio(bytes([0,0,3]),100)
Potrzebne są dwa argumenty, pierwszy to adres pod jakim ma nasłuchiwać Raspberry na pakiety od tinyBrd, a drugi to nr kanału. Oczywiście te dane musza pasować do adresu odbiorcy i kanału jakiego będą używać tinyBrd.
Klasa Radio
jest dostępna po zaimportowniu modułu tinybrd
:
from tinybrd import Radio
Następnie wystarczy sprawdzić czy są dane do odebrania i jeżeli są, to je odczytać.
if radio.available():
data = radio.read()
Nasz biblioteka pyNRF jak i jej odpowiednik dla tinyBrd wspiera domyślnie tzw dynamiczny rozmiar pakietu (dynamic payload). Oznacza to, że klienci mogą wysyłać dowolne struktury (tak długo jak się mieszczą w 32 bajtach).
W naszym testerze sprawdzamy, czy rozmiar odpowiada oczekiwanemu i jeżeli tak, to przekształca go ciąg wartości. Robi to korzystając z funkcji unpack
, która zamienia blok bajtów w tablicę wartości. Jakie to są typy wartości określamy w argumencie przekazywanym do unpack
. Jeżeli masz jeszcze otwarte Arduino IDE sprawdź kod szkicu testowego wgranego na tinyBrd. Definicja struktury, którą wysyłamy do Raspberry wygląda tak:
struct Payload
{
byte id;
unsigned int battery;
unsigned int seq;
byte retry;
unsigned int lost;
} data;
Raspberry odbiera blok bajtów będący tą strukturą, z taką samą kolejnością. Czyli mamy kolejno 1 bajt na identyfikator (data.id
), 2 bajty na napięcie zasilajace (data.battery
), 2 bajty na numer pakietu (data.seq
), 1 bajt na numer kolejnej próby doręczenia pakietu (data.retry
), 2 bajty na łączną liczbę zagubionych pakietów (data.lost
). Łacznie 8 bajtów - dlatego najpierw sprawdzamy czy tyle odebraliśmy. Jeżeli tak, to konwertujemy dane do tablicy wartości.
Tabelka w dokumentacji Pythona będzie pomocna, aby dobrać odpowiedni symbol do typu danych. Dla typu byte
użyjemy B
, dla unsigned int
użyjemy I
.
if radio.available():
data = radio.read()
if (len(data)==8):
value = struct.unpack('=BIIBI', data)
Jeżeli pakiet ma 8 bajtów, zostanie zamieniony na na tablicę, która będzie miała kolejno liczby tak jak podaliśmy w formacie przekazanym do unpack
. Znak =
jest potrzebny, by unpack
nie próbował uzupełniać danych dodatkowymi bajtami.
Jeżeli zmienisz pola w strukturze Payload
to oczywiście zmień format przekazany do unpack
. Na przykład gdy zamiast ostaniej wartości (data.lost
) chciałbyś mieć w tym miejscu np temperaturę, jako liczbę zmiennoprzecinkowa (float) to do rozpakowania paczki danych na Raspberry użyć powinieneś formatu =BIIBf
. Reszta symboli dostepna w tabelce w linku powyżej. Pamiętaj, że często znaczenie ma czy dana wartośc jest ze znakiem czy bez (jest różnica między b
a B
).
Pisząc programy na mikrokontrolery takie jak Arduino, tinyBrd i inne staraj się unikać typów danych zmiennoprzezcinkowych (float, double). Użycie takich zmiennych zwiększy objętość Twojego programu i go spowolni. Operacje na takich liczbach nie są wspomagane sprzętowo. Niektóre większe procesory mają moduł do takich obliczeń. W małych, 8-mio bitowych mikrokontrolerach raczej ich nie spotkasz.
W tym momencie już masz do dyspozycji dane odberane z tinyBrd. Dla ułatwienia warto sobie je przypisać do zmiennych o jednoznacznych nazwach. Jeżeli bedziesz używał dalej w kodzie zapisu typu value[3]
to narażasz się na kilka niedogodności. Pierwsza jest taka, że łatwo się pomylić i użyć złego indeksu. Takie błędy nie zawsze są potem łatwe do namierzenia. Druga jest taka, że jeżeli zmienisz kolejność pól w strukturze, to wszystkie indeksy w kodzie programu musisz ręcznie poprawić. To też prowadzi do błedów w kodzie. Dlatego my w naszym przykładzie zapisujemy wartości w zmiennych o czytelnych nazwach:
sensor_id = value[0]
battery = value[1]
seq_no = value[2]
retry = value[3]
lost_cnt = value[4]
Reszta programu nie jest już związana z odbieraniem danych z tinyBrd, więc nie będziemy go dokładniej omawiać. Wkrótce przygtujemy więcej przykładów jak Raspberry może się komunikować przez NRF24L01 z tinyBrd.