Sterowanie aparatem fotograficznym po BLE – uzupełnienie charakterystyk

W poprzednim tekście o sterowaniu aparatem fotograficznym przedstawiłem, jak taki wyzwalacz można zbudować w oparciu o micro:bit z użyciem komunikacji po BLE. Powstał ciekawy gadżecik, który można umieścić na stopce lampy.

Pierwsze testy były na tyle zachęcające, że postanowiłem rozszerzyć funkcjonalność i trochę doszlifować kod.

Więcej zdjęć, dłuższy czas naświetlania

Problem: Kod używał 8-bitowych liczb do konfiguracji ilości zdjęć, szybkości migawki i czasu między zdjęciami. Maksymalne wartości były w ten sposób ograniczone do 256.

Rozwiązanie: Charakterystyki przekazują tablicę wartości 16-bitowych, zamiast pojedynczej wartości 32-bitowej.

Kod opierał się na jednej charakterystyce konfiguracyjnej (shooterConfigCharacteristic), do której klient zapisywał jednocześnie ilość zdjęć do wykonania (shots), czas naświetlania (speed) i czas między zdjęciami (elapse). Charakterystyka ta przyjmowała jedną liczbę całkowitą (unsigned int, 4 bajty), gdzie każda z 3 wartości miała dla siebie 8 bitów (ostatni bajt nie był używany). W związku z tym maksymalnie mogłem zaprogramować 256 zdjęć i 256 sekund naświetlania. O ile pierwsza wartość była w zupełności wystarczająca – czas naświetlania wcale nie. Szybko zrozumiałem, że zamiast 1 integera (32 bity, bez znaku) – trzeba przekazać tablicę 3 wartości np. 16-bitowych (unsigned short). Problem polegał na tym, że takiego typu charakterystyki nie ma w bilbiotece BLEPeripheral.

Na szczęście dodanie jej nie było skomplikowane. Oparłem się tu na kodzie znalezionym w https://github.com/melvyniandrag/arduino-BLEPeripheral/blob/master/src/BLECharArrayCharacteristic.cpp. Na jego podstawie stworzyłem charakterystykę BLEUnsignedShortArrayCharacteristic. W tym samym katalogu, co projekt eosShutterBLEino, dodałem dwa pliki: nagłówkowy h i implementację cpp:

BLEUnsignedShortArrayCharacteristic.h:

BLEUnsignedShortArrayCharacteristic.cpp:

Konieczne było też zmodyfikowanie definicji charakterystyk – typu i rozszerzenie konstruktora o ilosć wartości w tablicy zwracanych wartości:

Teraz wartości do poszczególnych paramaterów konfiguracji odczytuje się wywołując metodę BLEUnsignedShortArrayCharacteristic::getUShortValues():

Modyfikacjom musiała również ulec charakterystyka shooterProgressCharacteristic (raportująca postęp w robieniu zdjęć) – bo jej jeden bajt  na numer  wykonanego zdjęcia po prostu by nie wystarczył:

Android

Oczywiście odpowiednie modyfikacje wykonałem też po stronie aplikacji androidowej.

Tutaj wystąpił problem z elementami listy, które zawartość pól tekstowych potraktowały jak łańcuchy znaków. W rezultacie wystąpił problem niezgodności typów przy wysłaniu po BLE. Niestety App Inventor nie ma funkcji do konwersji łańcuch-liczba (wszystko ma się dziać automatycznie:)). Użyłem więc bloczka z kategorii „Math” – dodając „0” do wartości pola tekstowego. Paskudny trick, ale teraz w liście miałem już tylko liczby.

Inne

Pozostałe zmiany w kodzie, wykonane w tzw. międzyczasie:

  • Migotanie diodką zajmowało aż 200 ms (1/5 sekundy) – kod zmieniony, nie wykonuje się w ogóle, gdy zostało mniej czasu niż 100ms,
  • Usunięty elapse po zakończonej serii zdjęć,
  • Klawisz B na micro:bit przerywa serię (kod błędu zwraca STATUS_ABORTED),
  • Podczas oczekiwania między zdjęciami wysyłany jest status STATUS_ELAPSE
  • Jeżeli do shooterConfigCharacteristic dla czasu otwarcia migawki (short na pozycji [1], licząc od 0) na najstarszym bicie podacie „1” – oznacza to, że w pozostałej wartości znajdują się części sekundy, np. 20 interpretowane będzie jako 1/20 sekundy (czyli 50ms) – chociaż tutaj właśnie 1/20 wydaję się na moich 450d wartością graniczną – poniżej 1/20 aparat nie robi zdjęcia,

Wszystkie opisane zmiany znajdziecie na github: https://github.com/arekmerta/dobsonMotorizedBase/experimental/microbit

Dodatek: złożenie zdjęć w filmik

Możecie użyć ffmpeg do złożenia zdjęć w filmik:

Kilka uwag:

  • Nazwy plików muszą być numerowane, np. zawierać w nazwie 51, 52, 53, czy 100, 101, 102 – i to numerowanie musi być ciągiem (np. 222,223, 225 – ostatnie ramka nie będzie brana pod uwagę),
  • Domyślna fps to 25.

Użyte opcje:

  • „-r”: ilość ramek w sekundzie (fps), tutaj: 10,  ale „-framerate 1/5” – 1 ramka co 5 sekund,
  • „-i”: schemat nazywania plików; tutaj: wszystkie nazwywają się np. IMG_6861.JPG (pierwsza ramka); dzieki temu ffmpeg wie, które ramki należy dodać do wideo, „%02d” to inaczej dwie liczby dziesiątkow,
  • „-start_number”: pierwsza ramka w serii, zauważcie zgodność z parametrem „-i”, ffmpeg zakłada, że sekwencja zacznie się od „000” – jeżeli jest inaczej, musicie dodać „-start_number”,
  • „-vframes” – ilość ramek w wideo,
  • „-s”: rozdzielczość, np:
  • „-vcodec libx264 „: kodek, h264,
  • „-crf”: jakość (ale i rozmiar pliku wynikowego) 15..25 jest ok,
  • „-pix_fmt yuv420p” format pixeli,

Źródła

  • https://github.com/melvyniandrag/arduino-BLEPeripheral/blob/master/src/BLECharArrayCharacteristic.cpp
  • https://hamelot.io/visualization/using-ffmpeg-to-convert-a-set-of-images-into-a-video/
  • https://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/image_sequence