ESP32 – czytanie charakterystyk z Thingy:52 (Mark II)

Kontroler sterujący podstawą teleskopu musi mieć możliwość łączności po Wifi, BLE, kilka GPIO – w tym analogowe, i2c do wyświetlacza, serial do Arduino. Zastanawiałem się, co by tu spełniało moje wymagania… Raspberry – zawsze, ale trochę to przyciężkawe. micro:bit zapowiadał się obiecująco – ale nie ma trybu central – nie mógłbym na niego ściągnąć charakterystyk z thingy.  esp8266po prostu nie ma BLE. I tu wpadłem na pomysł esp32. Jeszcze z nim nie pracowałem, ale wydaje się mieć wszystko co potrzebuję.

Tutaj znajdziecie indeks tekstów na temat budowy podstawy teleskopu

Co na pokładzie?

ESP32 to „starszy” brat ESP8266 – mocniejszy, z większą ilością pamięci i przede wszystkim z BT 4.2 z BLE na pokładzie.

esp8266 ESP32
RAM 160KB 520KB
FLASH 4MB 4MB
ROM brak 448kB (boot/core)
Taktowanie 80 MHz 160MHz
WiFi HT20 HT40
Bluetooth Nie 4.2+BLE
CAN Nie Tak
Ethernet MAC Nie Tak
Czujnik dotyku Nie Tak
Czujnik temperatury Nie Tak
Czujnik Halla Nie Tak
GPIO 17 36

Opis GPIO (link zewnętrzny do github):

Uwagi:

  • Piny SD0, SD1, SD2, SD3, CMD and CLK używane są do komunikacji z pamięcią SPI; nie używajcie ich,
  • GPIO16 and GPIO17 mogą być używane przez niektóre płytki (ESP32-WROVER), lepiej ich unikać,
  • Na płytce znajdziecie też przyciski EN i BOOT. EN to reset a BOOT umożliwia pobranie nowego firmware (wciśnięcie EN przy przytrzymany BOOT),
  • Jeżeli kod się nie ładuje, wciśnijcie EN gdy w okienku komend pojawi się „Connecting…….._____….._____”.

Instalacja – Arduino IDE

Podobnie jak np. micro:bit, esp32 można programować za pomocą Arduino IDE. Specjalny core esp32 możecie pobrać z githuba: https://github.com/espressif/arduino-esp32. Do ściągnięcia jest kilkaset megabajtów, więc zarezerwujcie sobie na to odpowiednio dużo czas. Pod Linux MINT (u mnie Arduino IDE zainstalowane jest w katalogu ~/dev/arduino-1.8.12):

W tools/Board ustawiłem ESP32 Dev Module. Podłączyłem ESP do portu USB i załadowałem pusty przykład. Nie powiem, kompilacja bibliotek trwała trochę… Teraz otworzyłem przykład: File->Examples->Esp32->ChipID->GetChipId. I uzyskałem wyjście:

Przykład skanera BLE możecie znaleźć w examples/esp 32 ble arduino/BLE_Scan. Tutaj też się udało bez problemów – już po chwili miałem kompletną listę urządzeń BLE w domu.

Uwaga: czasami załadowanie kodu wymaga kilku prób:)

Charakterystyki do odczytu

Więcej o czytaniu charakterystyk znajdziecie:

Będę łączył się do urządzenia o MAC: E3:F2:CA:0B:88:1E. Charakterystyki, które chcę odczytać:

Co Wartość Typ Wyjście Uwagi
UUID usługa ruchu (motion) EF680400-9B35-4933-9B10-52FFA9740042 Usługa
Kierunek (heading) EF680409-9B35-4933-9B10-52FFA9740042 Notyfikacja
  • int32
W stopniach, format 16q16 (16 bitów znaczących i 16 dziesiętnych)
Kąty Eulera EF680407-9B35-4933-9B10-52FFA9740042 Notyfikacja
  • int32_t – roll
  • int32_t – pitch
  • int32_t – yaw
W stopniach, format 16q16

Kod klienta

Pełny kod klienta znajdziecie na github: https://github.com/arekmerta/dobsonMotorizedBase

Kod klienta – na podstawie przykładu BLE_client:

  • Domyślnie funkcja BLEClient::connect używa adresu publicznego (BLE_ADDR_TYPE_PUBLIC), trzeba to zmienić:
  • Odczytuje wartości dwóch charakterystyk – dla kierunku (charUUIDHeading) i kątów eulera (charUUIDEuler),
  • W „loop” dodałem procedury na ponowne podłączenie – w przypadku jego utraty, wykorzystuje „MyClientCallback”,
  • ’notifyCallback' odbiera powiadomienia z charakterystyk
  • Zmienna connected może być modyfikowana w przerwaniu i kodzie głównym – warto zaznaczyć ją jako volatile,
  • Zamiast serial.print i serial.println używam makr log_v i log_vln (verbose) i log_i i log_iln (info) – w zależności czy zdefiniowane jest LOG_LEVEL_INFO_VERBOSE lub LOG_LEVEL_INFO; możliwość wyłączania danych wysyłanych przez serial będzie mi potrzebna później,
  • deg_to_dms, bin2float – więcej o nich Dekodowanie wartości zwracanych przez charakterystyki,

Problem z notyfikacjami

Problem polega na tym, że powyższy kod… nie działa poprawnie z Thingy. Zresztą, nie jestem pewien, czy to kwestia tylko thingy – ale w tej wersji do klienta nie dochodzą żadne notyfikacje, tzn. 'notifyCallback' nie jest wywoływany. Wydaje mi się jednak, że problem nie leży w samym kodzie – ale w bibliotece.

Na rozwiązanie naprowadził mnie jeden z defektów w forku – dokładniej #391.

Ten kod 'ręcznie' dodaje notyfikacje – wyręczając funkcję BLERemoteCharacteristic::registerForNotify. Zapisuje wartość 1 do identyfikatora CCID usługi (0x2902). Teraz, spójrzcie do pliku BLERemoteCharacteristic.cpp właśnie do metody BLERemoteCharacteristic::registerForNotify, linia od 467:

Poprawka to dodanie „true” w ostatniej linijce, tak:

Teraz notyfikacje już się wywoływały.

Za mało pamięci

Co ciekawe, po skompilowaniu i załadowaniu kodu, środowisko pokazało:

73% procent… biorąc pod uwagę ile funkcji muszę tu jeszcze dodać… robi się ciasno. Cóż, niestety stos BLE jest bardzo pamięcio-żerny. Na szczęscie można to poprawić. Ustawienie Tools/Partition Scheme można przestawić, żeby zwiększając ilość miejsca na aplikację z domyślnych 1.2MB na „Huge APP (3MB No OTA/ 1MB SPIFFS)”. Oczywiście – są tego konsekwencje:

  • OTA: możliwość ładowania kodu przez WiFi – właczając opcje 'hudge' kod można ładować tylko przez USB,
  • SPIFFS – tylko 1MB – SPIFFS to system plików w pamięci NOR

Ten sam kod zajmuje teraz tylko 30% pamięci:

Podsumowanie

W całym tym eksperymencie podłączenie do thingy uzyskałem dosłownie w kilkanaście minut. Moduł ESP32 wystartował od pierwszego strzału – żadnych problemów. Później sprawy trochę się skomplikowały w związku problemem niewywoływanej notyfikacji. W rezultacie wszysko poszło dobrze, platforma działa stabilnie.

Źródła

  • https://github.com/espressif/arduino-esp32/issues/1685