wersja mobilna | kontakt z nami

Android Things oraz Raspberry Pi 3 (3). Obrazy spersonalizowane. Aktualizacja oprogramowania przez Android Things Console

Numer: Styczeń/2018

System Android Things jest dopiero wczesną wersją deweloperską, jednak już w obecnej fazie rozwoju dostarcza wielu funkcjonalności, które mogą pozytywnie wpłynąć na sukces tego projektu. Ciekawym i wartym przybliżenia rozwiązaniem jest platforma Android Things Console, która umożliwia niezwykle łatwe i szybkie budowanie spersonalizowanych obrazów oraz przeprowadzanie zdalnych aktualizacji OTA (Over The Air).

Pobierz PDFMateriały dodatkowe

W tej części cyklu poświęconej systemowi Android Things oraz płytce Raspberry Pi, zbudujemy spersonalizowany obraz systemu – z własnym logo startowym oraz domyślnie zainstalowaną aplikacją użytkownika, której zadaniem będzie obsługa modułu kamery. Następnie – za pomocą narzędzia Android Things Console – przeprowadzona zostanie zdalna aktualizacja aplikacji. Zaczynajmy!

rys1Obsługa modułu kamery Raspberry Pi

Zanim przystąpimy do budowy obrazu systemu z preinstalowaną aplikacją użytkownika, niezbędne jest uprzednie przygotowanie samej aplikacji. Aby nadać temu artykułowi pewien scenariusz oraz większy walor dydaktyczny, załóżmy, że postawionym przed nami zadaniem jest budowa systemu „inteligentnego dzwonka” dla jednego z naszych klientów. W systemie tym – po wciśnięciu przycisku dzwonka – za pomocą dołączonego modułu kamery [1] wykonujemy zdjęcia odwiedzających nas gości. Jednym z wymagań stawianych przez naszego „fikcyjnego klienta” jest to, aby poprzez dołączony do urządzenia wyświetlacz, prezentowana była lista dziesięciu ostatnich zdjęć, wraz z datą i godziną ich wykonania. Po zapełnieniu listy (wykonaniu serii 10 fotografii) lista powinna być czyszczona, a cały proces zostanie powtórzony od początku. Mając tak przedstawiony zarys wymagań, przystąpmy do realizacji zdania.

Proces przygotowania nowej aplikacji rozpoczynamy od podłączenia modułu kamery, wykonania połączeń sprzętowych dla przycisku (rysunek 1) oraz utworzenia nowego projektu, zgodnie z wytycznymi dla systemu Android Things, co opisano w pierwszym artykule opublikowanym w Elektronice Praktycznej 11/2017.

Tworzenie kodu obsługi modułu kamery rozpoczynamy od zdefiniowania uprawnień, wymaganych do uzyskania dostępu do podłączonego sprzętu i sieci Internet. W tym celu w pliku AndroidManifest.xml, definiujemy poniższe uprawnienie:

<uses-permission android:name=”android.permission.CAMERA” />
<uses-permission android:name=”android.permission.INTERNET” />

rys2Uprawnienie dające nam dostęp do zasobów kamery jest zaliczane do kategorii uprawnień „niebezpiecznych”, stąd przy pierwszej instalacji aplikacji niezbędne jest ponowne uruchomienie urządzenia (w odróżnieniu od uprawnień „bezpiecznych”, które są przyznawane aplikacji na etapie jej instalacji).

Operacje związane z dostępem i obsługą urządzeń peryferyjnych są operacjami blokującymi, dlatego też, aby uniknąć problemów z brakiem responsywności interfejsu użytkownika, bardziej złożone i czasochłonne działania „na sprzęcie”, powinny być wykonane w osobnym wątku. W tym celu, w głównej klasie aplikacji (MainActivity.java), utwórzmy nowy wątek tła oraz powiązany z nim Handler [2], jak pokazano na listingu 1.

Ponieważ kod obsługi modułu kamery jest generyczny i może zostać ponownie wykorzystany do budowy innych aplikacji, zostanie on umieszczony w ramach osobnej klasy RPiCamera (plik RPiCamera.java). Do zadań metody initializeCamera() (listing 2), utworzonej w ramach klasy RPiCamera, należeć będzie:

Wykorzystanie serwisu systemowego CameraManager [3] oraz funkcji getCameraIdList() do pobrania listy identyfikatorów wszystkich kamer dostępnych w systemie.

rys3Utworzenie instancji ImageReader’a [4], której zadaniem będzie odczyt danych z modułu kamery oraz przetworzenie ich na obraz w formacie JPEG (o wielkości 640×480 pikseli). Przetwarzanie będzie realizowane w sposób asynchroniczny, a o jego zakończeniu i dostępności gotowego obrazu do dalszego przetwarzania, użytkownik będzie informowany poprzez wskazaną w inicjalizacji funkcję obsługi zdarzenia OnImageAvailableListener [5].

Uzyskanie dostępu do kamery poprzez wywołanie openCamera() z określeniem numeru identyfikacyjnego urządzenia oraz obiektu wywołań zwrotnych związanych ze zmianą stanu pracy urządzenia.

W ramach klasy RPiCamera zdefiniujmy również obiekt wywołań zwrotnych, informujących nas o poprawnym uzyskaniu dostępu do modułu kamery (onOpened), jej odłączeniu (onDisconnected), wystąpieniu błędu (onError) oraz zamknięciu urządzenia (onClosed), co zaprezentowano na listingu 3.

Tym samym przygotowano szkielet klasy RPiCamera, który umożliwia nam poprawną inicjalizację modułu. Do wykorzystania funkcjonalności kamery, zatem brakuje metody umożliwiającej wyzwolenie przechwytywania obrazu z urządzenia. Funkcjonalność ta została zaimplementowana w metodzie takePicture() pokazanej na listingu 4.

Proces przechwytywania obrazu z modułu kamery rozpoczynamy od utworzenia sesji CameraCaptureSession [6], poprzez wywołanie metody createCaptureSession(). W wywołaniu tym określamy powierzchnię (Surface), do której będzie realizowany zapis (w omawianym przypadku jest to powierzchnia uprzednio skonfigurowanego obiektu ImageReader) oraz wskazujemy obiekt wywołań zwrotnych informujący nas o stanie utworzonej sesji. Poprawność utworzenia, aktywność i gotowość sesji do rozpoczęcia procedury przechwytywania obrazu, jest sygnalizowana poprzez wywołanie onConfigured(). Finalna postać funkcji konfigurującej i wyzwalającej przechwytywanie obrazu – triggerImageCapture() – została przedstawiona na listingu 5.

rys4Posiadając kompletny kod klasy RPiCamera, możemy uzupełnić implementację głównej aktywności MainActivity o inicjalizację i realizację przechwytywania obrazu. Inicjalizacja kamery zostanie przeprowadzona w metodzie onCreate(), natomiast wywołanie metody takePicture(), nastąpi po przyciśnięciu dołączonego do wyprowadzenia BCM23 przycisku. Korzystając z informacji przedstawionych w poprzednich częściach artykułu, dodajmy do klasy MainActivity obsługę przycisku i wyzwolenie przechwytywania obrazu, jak na listingu 6.

Wciśnięcie przycisku BCM23 rozpoczyna sesję przechwytywania obrazu, podczas której dane z kamery przesyłane są do ImageReader’a. Zakończenie tego procesu oraz dostępność przechwyconych danych w postaci pliku JPEG jest sygnalizowana poprzez wywołanie metody OnImageAvailableListener. Przechwycony obraz jest przekazywany do funkcji updateGUI(), której zadaniem jest aktualizacja interfejsu użytkownika, według zleconych przez „klienta” założeń (funkcje związane z budową GUI nie będą omawiane w tym artykule – pełny kod źródłowy projektu jest dostępny do pobrania pod linkiem umieszczonym na końcu artykułu). Finalny efektu działania projektu został przedstawiony na filmie dostępnym pod adresem https://goo.gl/6ezmQ1.

Personalizowana animacja startowa

Po wygenerowaniu pliku aplikacji APK, możemy przystąpić do personalizacji obrazu systemu Android Things. Jednym z elementów tej personalizacji, będzie zamiana animacji startowej – wyświetlającej domyślne logo systemu Android Things (rysunek 2), na statyczny obraz z pliku graficznego w formacie PNG.

Format animacji startowej został ściśle zdefiniowany przez dokumentację systemu operacyjnego Android [7]. Plik z animacją w postaci archiwum ZIP (bootanimation.zip), powinien zawierać plik desc.txt (z określonym formatem opisu animacji) oraz katalogi od part0 do partN, zawierające kolejne „klatki” animacji zapisanych w postaci plików PNG.

rys5Pierwsza linia opisu zawarta w pliku desc.txt definiuje następujące parametry animacji:

WIDTH HEIGHT FPS, gdzie:

  • WIDTH – szerokość animacji wyrażona w pikselach, 
  • HEIGHT – wysokość animacji wyrażona w pikselach,
  • FPS – liczba klatek na sekundę z jaką będzie wyświetlana animacja.

Kolejne linie pliku desc.txt definiują poszczególne animacje, jakie będą wyświetlane na ekranie startowym (z uwzględnieniem kolejności zawartej w pliku). Pojedyncza linia opisuje przyjmuje następującą postać

TYPE COUNT PAUSE PATH [#RGBHEX], gdzie:

  • pole TYPE określa sposób wyświetlania danej animacji. Pole to może przyjmować jedną z dwóch wartości literowych:
  • p – wyświetlanie animacji może zostać przerwane w momencie gdy zakończony zostanie proces startu systemu,
  • c – animacja nie zostanie przerwana przez zakończony proces startu systemu,
  • pole COUNT określa ile razy ma zostać odtworzona dana animacja – wartość 0 określa odtwarzanie animacji w pętli,
  • PAUSE – pole określa liczbę klatek pauzy po zakończeniu danej animacji,
  • PATH – pole wskazuje ścieżkę do katalogu zawierającego odpowiednio posortowane pliki PNG z animacją – np. part0, part1, itd.
  • RGBHEX – opcjonalny parametr określający kolor tła (w formacie #RRGGBB).

Poprzez odpowiednią konfigurację pliku desc.txt, użytkownik mam możliwość tworzenia bardziej rozbudowanych, kilku etapowych animacji, złożonych z animacji startowej (wyświetlanej raz) oraz animacji odtwarzanej w pętli, aż do zakończenia procesu uruchamiana systemu. Przykład takiej konfiguracji pliku desc.txt, został przedstawiony poniżej:

800 480 30
p 1 0 part0
p 0 0 part1

rys6(animacja o parametrach 800×480@30 jest dwuetapowa – pierwszy etap, na który składają się pliki PNG z katalogu part0, jest wyświetlany raz, następnie w nieskończonej pętli – aż do momentu zakończenia procesu startu systemu – wyświetlana jest animacja z katalogu part1).

W realizowanym projekcie wykorzystany zostanie statyczny obraz z pliku PNG o rozdzielczości 1200×500 pikseli. Konfiguracja z pliku desc.txt, będzie wówczas prezentowała się następująco:

1200 500 1
p 0 0 part0

Ważnym zagadnieniem przy tworzeniu własnej animizacji startowej jest również sposób utworzenia archiwum bootanimation.zip. Pliki umieszczone w ramach pliku ZIP nie mogę być skompresowane, lecz powinny być umieszczone w archiwum w tzw. trybie „store only”. Utworzenie takiego archiwum z linii poleceń systemu Linux, może zostać zrealizowane następująco (gdzie flaga -0 wymusza tryb „store only”) – zip -0qry -i *.txt *.png *.wav @ ../bootanimation.zip *.txt part*.

Budowa obrazu systemu z Android Things Console

Mając przygotowany plik aplikacji użytkownika APK oraz animację startową w postaci pliku bootanimation.zip, czas przystąpić do budowy obrazu. Do tego celu firma Google przygotowała narzędzie Android Things Console, dostępne pod adresem https://goo.gl/dhvAhG. Narzędzie Android Things Console umożliwia:

budowę personalizowanych obrazów systemu Android Things, zawierających zintegrowaną aplikację użytkownika,

zdalną aktualizację oprogramowania – aplikacji użytkownika i wersji systemu operacyjnego.

Po zalogowaniu się do aplikacji Android Things Console (z wykorzystaniem konta Google) i zaakceptowania warunków świadczenia usługi, użytkownik uzyska możliwość utworzenia nowego produktu, jak przedstawiono to na rysunku 3. W oknie konfiguracji nowego produktu (rysunek 4) użytkownik zostanie poproszony o:

  • określenie nazwy produktu (jest to nazwa wewnętrzna projektu, która nie będzie widoczna dla użytkownika końcowego),
  • wybranie platformy sprzętowej (z listy aktualnie wspieranych zestawów deweloperskich),
  • włączenia/wyłącznie wsparcia dla usług Google Play,
  • określenia wielkości partycji OEM na której będzie instalowana aplikacja użytkownika,
  • opcjonalne podanie opisu nowo utworzonego produktu.

Po wybraniu przycisku CREATE, aplikacja przeniesie nas do zakładki PRODUCT SETTINGS, zawierającej podsumowanie konfiguracji utworzonego produktu.

rys8Zakładka FACTORY IMAGES (rysunek 5) domyślnie podzielona została na dwie części:

  • Bundles – zawierającą informacje o utworzonych pakietach użytkownika, przeznaczonych do personalizacji systemu,
  • Android Things Versions – umożliwiająca użytkownikowi wybranie wersji systemu operacyjnego Android Things.

W domyślnej konfiguracji (bez utworzonego pakietu personalizującego system), po wybraniu przycisku CREATE BUILD CONFIGURATION, użytkownik ma możliwość zbudowania podstawowej wersji obrazu systemu – w postaci, którą można również pobrać pod adresem https://goo.gl/8nQ5gp.

Naszym zadaniem jest przygotowanie wersji systemu, która będzie domyślnie zawierała przygotowaną aplikację użytkownika oraz personalizowaną animację startową. Po wybraniu przycisku UPLOAD w sekcji Bundles, użytkownik zostanie poproszony o wskazanie archiwum ZIP zawierającego dane dla partycji OEM. Archiwum ZIP służące do personalizacji systemu powinno zawierać następujące pliki:

  • bootanimation.zip – [plik nieobowiązkowy] animacja użytkownika przygotowana zgodnie z wytycznymi z podrozdziału „Personalizowana animacja startowa”,
  • <user-space driver.apk> – [plik nieobowiązkowy] sterowniki działające w przestrzeni użytkownika jako serwis systemowy,
  • <main.apk> – [plik obowiązkowy] aplikacja użytkownika definiująca główny punkt wejścia (action=MAIN, category=IOT_LAUNCHER),
  • <sub.apk> – [plik nieobowiązkowy] dowolne inne aplikacje użytkownika, które mogą zostać uruchomione przez aplikację główną.

Utwórzmy zatem nowe archiwum ZIP (tym razem jest to standardowy plik ZIP w odróżnieniu od trybu „store only” dla animacji startowej) zawierające plik APK oraz bootanimation.zip. Po załadowaniu nowego pakietu, sekcja „Bundles” zostanie zaktualizowana, jak przedstawiono to na rysunku 6.

W ostatnim kroku – wybierając z sekcji „Bundles” nasz nowo utworzony pakiet, a następnie z sekcji Android Things Versions ostatnią dostępną wersje systemu – utwórzmy spersonalizowany obraz dla naszego urządzenia. Lista wszystkich zbudowanych obrazów oraz odnośników do ich pobrania, zostanie wyświetlona w sekcji „Build configuration list” – rysunek 7.

Aktualizacje OTA

W naszym hipotetycznie realizowanym scenariuszu, udało nam się dostarczyć 100 urządzeń „inteligentnych dzwonków” dla naszego klienta. Nie trudno wyobrazić sobie jednak sytuację, gdzie przygotowane oprogramowania posiada błąd, który udało się odtworzyć dopiero po kilku miesiącach ciągłego działania urządzenia. W takich przypadkach, bardzo często koszty związane z dostarczeniem urządzeń do producenta
i wgraniem nowego oprogramowania mogą okazać się bardzo wysokie. Z pomocą mogą przyjść aktualizacje OTA (Over The Air), czyli mechanizm aktualizacji zdalnych. Dla obrazów zbudowanych z wykorzystaniem Android Things Console, firma Google udostępnia infrastrukturę umożliwiającą przeprowadzenie zdalnej aktualizacji urządzeń (pakietu użytkownika i wersji systemu Android Things).

Aby przeprowadzić zdalną aktualizację, w systemie Android Things Console, przechodzimy do zakładki OTA UPDATES. Klikając przycisk START A NEW UPDATE, zostaniemy poproszeni o konfigurację nowo przygotowywanej aktualizacji. Panel konfiguracji jest tożsamy z zakładką FACTORY IMAGES. Użytkownik ma możliwość utworzenia nowego pakietu ze zaktualizowaną wersją aplikacji lub wgrania najnowszej wersji systemu Android Things (obie operacje mogą zostać przeprowadzone w ramach jednej aktualizacji). Proces aktualizacji rozpoczyna wybranie przycisku PUSH UPDATE. Od tego momentu, nowa aktualizacja jest dostępna do pobrania dla wszystkich urządzeń końcowych. Serwis update_engine uruchomiony w systemie Android Things sprawdza dostępność zdalnych aktualizacji co 300 minut, tak więc proces aktualizacji nie odbędzie się na wszystkich urządzeniach jednocześnie i może potrwać kilka godzin. Android Things Console udostępnia informacje o aktualnym postępie aktualizacji wszystkich urządzeń, jak pokazano na rysunku 8.

Łukasz Skalski

 

Linki zewnętrzne:

Pozostałe artykuły

NIOS II na maXimatorze, czyli mikroprocesor w układzie FPGA (3). Przerwania, timery i obsługa wyświetlaczy

Numer: Luty/2018

Do tej pory wspólnymi siłami udało nam się wbudować w pełni funkcjonalny system mikroprocesorowy, który odbierał i generował cyfrowe sygnały (powiedzmy dumnie, że przetwarzał sygnały cyfrowe!). Kilkakrotnie wspominałem przy tej okazji, że stosowanie opóźnień jest rozwiązaniem nagannym, jednak dotychczas nie mieliśmy alternatywy - czas ją poznać i wzbogacić system oraz swoją wiedzę o timery i system przerwań.

Systemy dla Internetu Rzeczy (14). Podglądanie ruchu w sieci radiowej z protokołem IEEE 802.15.4

Numer: Luty/2018

Największym problemem podczas pracy z układami komunikacji radiowej jest brak pewności czy nadajnik wysłał to co trzeba i czy odbiornik odbiera poprawnie. Jedynym sposobem pokonania tych kłopotów jest ?podsłuchiwanie? transmisji radiowej. Stosowane są do tego sniffery, zwane też analizatorami sieciowymi lub analizatorami pakietów. Pozwalają śledzić (?wąchać?, ang. sniffing) pakiety przesyłane przez wybrany interfejs sieciowy. Jednym ...

Amazon Alexa (1). Tworzymy umiejętności Skills

Numer: Grudzień/2017

W artykule zaprezentujemy sposób tworzenia ?umiejętności? dla asystentki głosowej Alexa (skills). Wykonamy i opublikujemy umiejętność, dzięki której Alexa będzie symulowała losowanie kostką do gry w grach planszowych.

Systemy dla Internetu Rzeczy (12). Oprogramowanie narzędziowe dla układów CC26xx i CC13xx platformy SimpleLink

Numer: Grudzień/2017

Wielordzeniowe procesory typu SOC (System on Chip) rodziny CC26xx oraz CC13xx firmy Texas Instruments są przeznaczone dla komunikacji bezprzewodowej. Mają one zupełnie nowe możliwości w porównaniu z układami scalonymi modułów radiowych. Od połowy roku 2017 producent zintegrował oferowany sprzęt i oprogramowanie w postaci pojedynczej platformy SimpleLink MCU Platform. Platforma integruje układy scalone, moduły uruchomieniowe, środowisko ...

NIOS II na maXimatorze, czyli mikroprocesor w układzie FPGA (1). Wstęp i pierwszy projekt

Numer: Grudzień/2017

W jednym z poprzednich artykułów na łamach Elektroniki Praktycznej pan Mariusz Księżak wprowadził nas w tematykę implementacji procesora NIOS II na płytce maXimator oraz zaprezentował przykładowy projekt z jego użyciem. Teraz czas, abyśmy wspólnie uporządkowali i pogłębili wiedzę na ten temat.

Mobilna
Elektronika
Praktyczna

Elektronika Praktyczna

Luty 2019

PrenumerataePrenumerataKup w kiosku wysyłkowym

Elektronika Praktyczna Plus

lipiec - grudzień 2012

Kup w kiosku wysyłkowym