Spisu treści:

Wyjście poza standardFirmata – ponownie: 5 kroków
Wyjście poza standardFirmata – ponownie: 5 kroków

Wideo: Wyjście poza standardFirmata – ponownie: 5 kroków

Wideo: Wyjście poza standardFirmata – ponownie: 5 kroków
Wideo: JAK SKONFIGUROWAĆ L4D2 2024, Lipiec
Anonim
Wychodzenie poza standardFirmata – ponownie
Wychodzenie poza standardFirmata – ponownie

Niedawno skontaktował się ze mną dr Martyn Wheeler, użytkownik pymata4, aby uzyskać wskazówki dotyczące dodania obsługi czujnika wilgotności/temperatury DHT22 do biblioteki pymata4. Biblioteka pymata4 w połączeniu z jej odpowiednikiem dla Arduino, FirmataExpress, umożliwia użytkownikom zdalne sterowanie i monitorowanie urządzeń Arduino. W ciągu kilku rund wymiany e-maili dr Wheeler z powodzeniem zmodyfikował zarówno pymata4, jak i FirmataExpress. Dzięki temu obsługa czujników DHT22 i DHT11 jest teraz standardową częścią pymaty4 i FirmataExpress.

W maju 2014 napisałem artykuł o dodaniu wsparcia do Firmata dla dodatkowych urządzeń. Zastanawiając się nad tym artykułem, zdałem sobie sprawę, jak wiele się zmieniło, odkąd wziąłem pióro na papier do tego artykułu. Oprócz tego artykułu dr Wheeler udokumentował swoje wysiłki i możesz również to sprawdzić.

FirmataExpress bazuje na StandardFirmata, a struktura katalogów StandardFirmata ewoluowała. Ponadto API pymata4 jest również nieco inne niż oryginalne API PyMata z 2014 roku. Pomyślałem, że to idealny moment, aby ponownie przejrzeć i zaktualizować ten artykuł. Korzystając z pracy Dr. Wheelera jako podstawy, przyjrzyjmy się, jak rozszerzyć funkcjonalność pymata4/FirmataExpress.

Zanim zaczniemy – kilka podstawowych informacji o Arduino/Firmacie

Czym więc jest Firmata? Cytując ze strony internetowej Firmata, „Firmata to ogólny protokół do komunikacji z mikrokontrolerami z oprogramowania na komputerze-hoście”.

Arduino Firmata wykorzystuje interfejs szeregowy do przesyłania zarówno informacji poleceń, jak i raportów między mikrokontrolerem Arduino a komputerem PC, zwykle przy użyciu łącza szeregowego/USB ustawionego na 57600 bps. Dane przesyłane przez to łącze są binarne, a protokół jest zaimplementowany w modelu klient/serwer.

Strona serwerowa jest wgrywana do mikrokontrolera Arduino w postaci szkicu Arduino. Szkic StandardFirmata, dołączony do Arduino IDE, kontroluje piny Arduino I/O zgodnie z poleceniem klienta. Raportuje również zmiany pinów wejściowych i inne informacje raportu z powrotem do klienta. FirmataExpress to rozszerzona wersja StandardFirmata. Działa z prędkością łącza szeregowego 115200 bps.

Klient Arduino użyty w tym artykule to pymata4. Jest to aplikacja Pythona wykonywana na komputerze PC. Zarówno wysyła polecenia, jak i odbiera raporty z serwera Arduino. Ponieważ pymata4 jest zaimplementowana w Pythonie, działa na komputerach z systemem Windows, Linux (w tym Raspberry Pi) i macOS.

Dlaczego warto korzystać z Firmata?

Mikrokontrolery Arduino to cudowne małe urządzenia, ale zasoby procesora i pamięci są nieco ograniczone. W przypadku aplikacji intensywnie korzystających z procesora lub pamięci często nie ma innego wyboru niż przeniesienie zapotrzebowania na zasoby na komputer, aby aplikacja odniosła sukces.

Ale to nie jedyny powód używania StandardFirmata. Podczas opracowywania lżejszych aplikacji Arduino komputer może zapewnić narzędzia i możliwości debugowania niedostępne bezpośrednio w mikrokontrolerze Arduino. Korzystanie z „stałego” klienta i serwera pomaga ograniczyć złożoność aplikacji do komputera, który jest łatwiejszy w zarządzaniu. Gdy aplikacja zostanie dopracowana do perfekcji, można ją przełożyć na niestandardowy, samodzielny szkic Arduino.

Dlaczego warto korzystać z pymaty4?

Będąc jego autorem jestem oczywiście stronniczy. Biorąc to pod uwagę, jest to jedyny klient Firmata oparty na Pythonie, który jest stale utrzymywany przez ostatnie kilka lat. Zapewnia intuicyjny i łatwy w użyciu interfejs API. Oprócz szkiców opartych na StandardFirmata, obsługuje Firmata przez Wi-Fi dla urządzeń takich jak ESP-8266 podczas korzystania ze szkicu StandardFirmataWifI.

Ponadto pymata4 została zaprojektowana tak, aby użytkownik mógł ją łatwo rozbudować o obsługę dodatkowych czujników i elementów wykonawczych, które nie są obecnie obsługiwane przez StandardFirmata.

Krok 1: Zrozumienie protokołu Firmata

Zrozumienie protokołu Firmata
Zrozumienie protokołu Firmata

Protokół komunikacyjny Arduino Firmata wywodzi się z protokołu MIDI, który wykorzystuje jeden lub więcej 7-bitowych bajtów do reprezentacji danych.

Firmata została zaprojektowana tak, aby była rozszerzalna przez użytkownika. Mechanizmem zapewniającym tę rozszerzalność jest protokół przesyłania komunikatów SysEx (System Exclusive).

Format komunikatu SysEx, zdefiniowany przez Protokół Firmata, pokazano na powyższej ilustracji. Zaczyna się od bajtu START_SYSEX o stałej wartości szesnastkowej 0xF0, po której następuje unikalny bajt polecenia SysEx. Wartość bajtu polecenia musi mieścić się w zakresie szesnastkowym 0x00-0x7F. Po bajcie polecenia następuje nieokreślona liczba 7-bitowych bajtów danych. Na koniec komunikat jest zakończony bajtem END_SYSEX o stałej wartości szesnastkowej 0xF7.

Firmata Kodowanie/dekodowanie danych

Ponieważ część wiadomości SysEx zawierająca dane użytkownika składa się z serii 7-bitowych bajtów, możesz się zastanawiać, jak reprezentują one wartość większą niż 128 (0x7f)? Firmata koduje te wartości, rozkładając je na wiele 7-bitowych fragmentów, zanim dane zostaną uporządkowane przez łącze danych. Najmniej znaczący bajt (LSB) elementu danych jest wysyłany jako pierwszy, a następnie, zgodnie z konwencją, coraz bardziej znaczące elementy elementu danych. Najbardziej znaczący bajt (MSB) elementu danych to ostatni wysłany element danych.

Jak to działa?

Załóżmy, że chcemy włączyć wartość 525 do części danych wiadomości SysEx. Ponieważ wartość 525 jest wyraźnie większa niż wartość 128, musimy podzielić ją na 7-bitowe „kawałki”.

Oto jak to się robi.

Wartość 525 w postaci dziesiętnej jest odpowiednikiem wartości szesnastkowej 0x20D, czyli wartości 2-bajtowej. Aby uzyskać LSB, maskujemy wartość, łącząc ją z 0x7F. Poniżej przedstawiono implementacje zarówno w języku C, jak i Python:

// Implementacja "C" do izolowania LSB

int max_distance_LSB = max_distance & 0x7f; // zamaskuj niższy bajt # Implementacja Pythona do odizolowania LSB max_distance_LSB = max_distance & 0x7F # zamaskuj niższy bajt

Po maskowaniu max_distance_LSB będzie zawierać 0x0d. 0x20D i 0x7F = 0x0D.

Następnie musimy wyizolować MSB dla tej 2-bajtowej wartości. W tym celu przesuniemy wartość 0x20D w prawo o 7 miejsc.

// Implementacja "C" w celu wyizolowania MSB o wartości 2 bajtów

int max_distance_MSB = max_distance >> 7; // przesuń bajt wyższego rzędu # Implementacja Pythona, aby wyizolować MSB o wartości 2 bajtów max_distance_MSB = max_distance >> 7 # przesunięcie, aby uzyskać wyższy bajt Po przesunięciu max_distance_MSB będzie zawierać wartość 0x04.

Po odebraniu „zgrupowanych” danych uporządkowanych należy je ponownie złożyć w jedną wartość. Oto jak dane są ponownie składane zarówno w „C”, jak i w Pythonie

// Implementacja "C" do ponownego złożenia 2 bajtów, // 7 wartości bitowych w jedną wartość int max_distance = argv[0] + (argv[1] << 7); # Implementacja Pythona do ponownego złożenia 2-bajtowych, # 7-bitowych wartości w jedną wartość max_distance = data[0] + (data[1] << 7)

Po ponownym złożeniu wartość jest ponownie równa 525 dziesiętnie lub 0x20D szesnastkowo.

Ten proces demontażu/ponownego składania może być wykonywany przez klienta lub serwer.

Krok 2: Zacznijmy

Obsługa nowego urządzenia wymaga zmian zarówno w serwerze rezydentnym Arduino, jak i w kliencie Python rezydującym na komputerze PC. Praca dr Wheelera zostanie wykorzystana do zilustrowania niezbędnych modyfikacji.

Być może najważniejszym krokiem jest podjęcie decyzji, czy chcesz zintegrować istniejącą bibliotekę urządzeń pomocniczych ze stroną Arduino równania, czy napisać własną. Zaleca się, aby jeśli możesz znaleźć istniejącą bibliotekę, znacznie łatwiej jest z niej korzystać niż pisać własną od zera.

W celu obsługi urządzeń DHT dr Wheeler oparł swój kod rozszerzenia na bibliotece DHTNew. Dr Wheeler bardzo sprytnie podzielił funkcjonalność biblioteki DHTNew na strony równania Arduino i pymata4, aby zapewnić minimalne blokowanie po stronie Arduino.

Jeśli spojrzymy na DHTNew, wykonuje wszystkie następujące czynności:

  • Ustawia wybrany pinowy tryb wyjścia cyfrowego.
  • Odlicza zakodowany sygnał, aby pobrać najnowsze wartości wilgotności i temperatury.
  • Sprawdza i zgłasza wszelkie błędy.
  • Oblicza czytelne dla człowieka wartości temperatury i wilgotności na podstawie pobranych surowych danych.

Aby zachować jak największą wydajność po stronie FirmataExpress, dr Wheeler przeniósł procedury konwersji danych z Arduino do pymata4.

Krok 3: Modyfikacja FirmataExpress do obsługi DHT

Drzewo katalogów FirmataExpress

Poniżej znajdują się wszystkie pliki składające się na repozytorium FirmataExpress. To drzewo jest identyczne z drzewem StandardFiramata, tylko niektóre nazwy plików odzwierciedlają nazwę repozytorium.

Pliki, które wymagają modyfikacji, to te, które mają obok siebie gwiazdkę (*).

FirmataExpress

├── * Tablice.h

├── przykłady

FirmataExpress

│ ├── tablicax

* FirmataExpress.ino

LICENCJA.txt

│ └── Makefile

├── * FirmataConstants.h

├── * FirmataDefines.h

├── FirmataExpress.cpp

├── FirmataExpress.h

├── FirmataMarshaller.cpp

├── FirmataMarshaller.h

FirmataParser.cpp

└── FirmataParser.h

Przyjrzyjmy się każdemu z plików i dokonanym zmianom.

Tablice.h

Ten plik zawiera definicje makr typu pin dla każdego z obsługiwanych typów płyt. Definiuje maksymalną liczbę obsługiwanych urządzeń, gdy więcej niż jedno urządzenie musi być obsługiwane.

W przypadku urządzenia DHT można jednocześnie podłączyć do 6 urządzeń, a wartość ta jest zdefiniowana jako:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Ponadto dla nowego urządzenia można opcjonalnie zdefiniować makra typu pin, dla wszystkich typów płytek lub tylko dla tych, które Cię interesują. Te makra są używane głównie do celów raportowania i nie służą do sterowania urządzeniami. Te makra definiują oba piny obsługujące urządzenie:

#define IS_PIN_DHT(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_DHTS)

Jak również makro do zdefiniowania konwersji numeru PIN.

#define PIN_TO_DHT(p) PIN_TO_DIGITAL(p)

FirmataConstants.h

Ten plik zawiera numer wersji oprogramowania układowego, który możesz zmodyfikować, aby śledzić wersję załadowaną do Arduino. Zawiera również wartości komunikatów Firmata, w tym komunikaty Firmata SysEx.

W tym pliku musisz przypisać nową wiadomość lub zestaw wiadomości dla swojego urządzenia. W przypadku DHT dodano dwie wiadomości. Jeden konfiguruje pin jako pin „DHT”, a drugi jako wiadomość reportera podczas wysyłania najnowszych danych DHT z powrotem do klienta.

statyczna statyczna int DHT_CONFIG = 0x64;

statyczna statyczna int DHT_DATA = 0x65;

Tryby pinów są również określone w tym pliku. Dla DHT stworzono nowy tryb pinów:

stała statyczna int PIN_MODE_DHT = 0x0F; // pin skonfigurowany dla DHT

Podczas dodawania nowego trybu przypinania należy dostosować TOTAL_PIN_MODES:

statyczna statyczna int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Ten plik musi zostać zaktualizowany, aby odzwierciedlić nowe wiadomości dodane do FirmataConstants.h:

#1::PIN_MODE_DHT

FirmataExpress.ino

W tej dyskusji omówimy „największe punkty” zmian wprowadzonych w tym szkicu Arduino.

Aby FirmataExpress mogła obsługiwać do sześciu urządzeń DHT jednocześnie, utworzono 3 macierze do śledzenia każdego z skojarzonych numerów pinów urządzenia, jego wartości WakeUpDelay oraz typu urządzenia, czyli DHT22 lub DHT11:

// czujniki DHT

int numActiveDHTs = 0; // liczba dołączonych DHT uint8_t DHT_PinNumbers[MAX_DHTS]; uint8_t DHT_WakeUpDelay[MAX_DHTS]; uint8_t DHT_TYPE[MAX_DHTS];

Ponieważ oba typy urządzeń wymagają około 2 sekund między odczytami, musimy upewnić się, że odczytujemy każdy DHT tylko raz w ciągu 2 sekund. Niektóre urządzenia, takie jak urządzenia DHT i czujniki odległości HC-SR04, są dostępne tylko okresowo. Daje im to czas na interakcję z otoczeniem.

uint8_t nextDHT = 0; // indeks do dht dla następnego urządzenia do odczytania

uint8_t bieżącyDHT = 0; // Śledzi, który czujnik jest aktywny. int dhtNumLoops = 0; // Docelowa liczba prób uzyskania przez pętlę b4 dostępu do DHT int dhtLoopCounter = 0; // Licznik pętli

Konfigurowanie i odczytywanie urządzenia DHT

Gdy FirmataExpress odbiera polecenie SysEx, aby skonfigurować pin do działania DHT, sprawdza, czy nie została przekroczona maksymalna liczba urządzeń DHT. Jeśli nowy DHT może być obsługiwany, macierze DHT są aktualizowane. Jeśli typ DHT jest nieznany, tworzony jest komunikat tekstowy SysEx i przesyłany z powrotem do pymata4

przypadek DHT_CONFIG: int DHT_Pin = argv[0]; int typ_DHT = argv[1]; if (numActiveDHTs < MAX_DHTS) { if (DHT_type == 22) { DHT_WakeUpDelay[numActiveDHTs] = 1; } else if (DHT_type == 11) { DHT_WakeUpDelay[numActiveDHTs] = 18; } else { Firmata.sendString("BŁĄD: NIEZNANY TYP CZUJNIKA, WAŻNE CZUJNIKI TO 11, 22"); przerwa; } // test czujnika DHT_PinNumbers[numActiveDHTs] = DHT_Pin; DHT_TYPE[liczbaActiveDHTs] = typ_DHT; setPinModeCallback(DHT_Pin, PIN_MODE_DHT);

FirmataExpress następnie próbuje skomunikować się z urządzeniem DHT. Jeśli są jakieś błędy, tworzy wiadomość SysEx z danymi błędu i wysyła wiadomość SysEx z powrotem do pymat4. Zmienna _bits przechowuje dane zwrócone przez urządzenie DHT do dodatkowego przetwarzania przez pymata4 w razie potrzeby.

Firmata.write(START_SYSEX);

Firmata.zapis(DHT_DANE); Firmata.write(DHT_Pin); Firmata.write(typ_DHT); dla (uint8_t i = 0; i > 7 & 0x7f); } Firmata.write(abs(rv)); Firmata.zapis(1); Firmata.write(END_SYSEX);

Jeśli zwrócone zostaną prawidłowe dane, zwiększa się liczba aktywnych DHT. Zmienna, która śledzi, ile iteracji pętli należy wykonać przed sprawdzeniem następnego DHT pod kątem danych, jest również dostosowywana. Ta zmienna zapewnia, że bez względu na to, ile DHT zostanie dodanych do systemu, wszystkie zostaną odczytane w ciągu 2 sekund.

int rv = readDhtSensor(liczbaAktywnychDHT);

if (rv == DHTLIB_OK) { numActiveDHTs++; dhtNumLoops = dhtNumLoops / liczbaAktywnychDHTs; // wszystko w porządku }

Jeśli jedno lub więcej urządzeń DHT zostało skonfigurowanych w funkcji pętli szkicu, odczytywane jest następne urządzenie DHT. Prawidłowe dane lub ich status błędu są zwracane do pymata4 w postaci komunikatu SysEx:

if (dhtLoopCounter++ > dhtNumLoops) { if (numActiveDHTs) { int rv = readDhtSensor(nextDHT); uint8_t aktualny_pin = DHT_PinNumbers[następnyDHT]; uint8_t bieżący_typ = DHT_TYPE[następnyDHT]; dhtLoopCounter = 0; obecnyDHT = następnyDHT; if (nextDHT++ >= numActiveDHTs - 1) { nextDHT = 0; } if (rv == DHTLIB_OK) { // SUMA KONTROLNA TESTU uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3]; if (_bity[4] != suma) { rv = -1; } } // odeślij wiadomość ze statusem błędu Firmata.write(START_SYSEX); Firmata.zapis(DHT_DANE); Firmata.write(bieżący_pin); Firmata.write(bieżący_typ); for (uint8_t i = 0; i < sizeof(_bitów) - 1; ++i) { Firmata.write(_bits); // Firmata.write(_bits; } Firmata.write(abs(rv)); Firmata.write(0); Firmata.write(END_SYSEX); } }

Kod używany do komunikacji z urządzeniem DHT pochodzi bezpośrednio z biblioteki DHTNew:

int readDhtSensor(indeks int){

// INIT BUFFERVAR W CELU ODBIERANIA DANYCH uint8_t mask = 128; uint8_t idx = 0; // PUSTY BUFOR // memset(_bits, 0, sizeof(_bits)); for (uint8_t i = 0; i 5 BYTES for (uint8_t i = 40; i != 0; i--) { loopCnt = DHTLIB_TIMEOUT; while (digitalRead(pin) == LOW) { if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; } uint32_t t = micros(); loopCnt = DHTLIB_TIMEOUT; while (digitalRead(pin) == HIGH) { if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; } if ((micros() - t) > 40) { _bits[idx] |= maska; } maska >>= 1; if (maska == 0) // następny bajt? { maska = 128; idx++; } } return DHTLIB_OK; }

Krok 4: Modyfikowanie Pymata4 do obsługi DHT

private_constants.h

Aby obsługiwać DHT, musimy dodać do tego pliku zarówno nowe komunikaty typu pin, jak i SysEx:

# tryb pinów WEJŚCIE = 0x00 # pin ustawiony jako wejście WYJŚCIE = 0x01 # pin ustawiony jako wyjście ANALOG = 0x02 # pin analogowy w trybie wejścia analogowego PWM = 0x03 # pin cyfrowy w trybie wyjścia PWM SERVO = 0x04 # pin cyfrowy w trybie wyjścia Servo I2C = 0x06 # pin zawarty w konfiguracji I2C KROKOWY = 0x08 # dowolny pin w trybie krokowym SERIAL = 0x0a PULLUP = 0x0b # Dowolny pin w trybie podciągania SONAR = 0x0c # Dowolny pin w trybie SONAR TONE = 0x0d # Dowolny pin w trybie tonowym PIXY = 0x0e # zarezerwowane dla trybu kamery pixy DHT = 0x0f # Czujnik DHT IGNORE = 0x7f # Komunikaty poleceń DHT SysEx DHT_CONFIG = 0x64 # polecenie konfiguracji dht DHT_DATA = 0x65 # odpowiedź czujnika dht

Dodany typ pinu i polecenia SysEx muszą być zgodne z wartościami w FirmataConstants.h dodanym do FirmataExpress.

pymata4.py

Pymata4 używa słownika Pythona do szybkiego powiązania przychodzącej wiadomości Firmata z obsługą wiadomości. Nazwa tego słownika to report_dispatch.

Format wpisu słownikowego to:

{MessageID: [message_handler, liczba bajtów danych do przetworzenia]}

Do słownika dodano wpis do obsługi przychodzących wiadomości DHT:

{PrywatneStałe. DHT_DATA: [self._dht_read_response, 7]}

7 bajtów danych w wiadomości to cyfrowy pin Arduino, typ urządzenia DHT (22 lub 11) oraz 5 bajtów surowych danych.

Metoda _dht_read_response sprawdza wszelkie zgłoszone błędy. W przypadku braku zgłoszonych błędów wilgotność i temperatura są obliczane przy użyciu algorytmu przeniesionego z biblioteki Arduino DHTNew.

Obliczone wartości są zgłaszane za pośrednictwem dostarczonej przez użytkownika metody wywołania zwrotnego. Są one również przechowywane w wewnętrznej strukturze danych pin_data. Ostatnia zgłoszona wartość może zostać przywołana przez odpytywanie danych pin_data przy użyciu metody dht_read.

Konfiguracja nowego urządzenia DHT

Podczas dodawania nowego urządzenia DHT wywoływana jest metoda set_pin_mode_dht. Ta metoda aktualizuje pin_data dla pinów cyfrowych. Tworzy również i wysyła komunikat DHT_CONFIG SysEx do FirmataExpress.

Krok 5: Podsumowanie

Jak widzieliśmy, dodanie obsługi Firmata dla nowego urządzenia wymaga modyfikacji kodu serwera Arduino FirmataExpress oraz kodu klienta pymata4 opartego na Pythonie. Kod FirmataExpress może być trudny do debugowania. Metoda o nazwie printData została dodana do FirmataExpress, aby pomóc w debugowaniu. Ta metoda pozwala na przesłanie wartości danych z FirmataExpress i wydrukowanie ich na konsoli pymata4.

Ta funkcja wymaga zarówno wskaźnika do ciągu znaków, jak i wartości, którą chcesz wyświetlić. Jeśli wartość danych jest zawarta w zmiennej o nazwie argc, możesz wywołać printData z następującymi parametrami.

printData((char*)"argc= ", argc);

Jeśli masz jakieś pytania, zostaw komentarz, a chętnie odpowiem.

Udanego kodowania!

Zalecana: