-40% na bestsellery wydawnictwa HELION, min.: Java, C++, TensorFlow, PHP, MySQL. Sprawdź listę tytułów »

Tworzenie aplikacji Android – #4 – Sterowanie robotem

Tworzenie aplikacji Android – #4 – Sterowanie robotem

Tym razem zagłębimy się dokładniej w możliwości naszego środowiska. Konkretnie, zajmiemy się bardziej algorytmicznymi aspektami programów.

W przykładach wykorzystamy zmienne, warunki oraz pętle. Następnie dane z akcelerometru wyślemy przez Bluetooth do telefonu.

« Poprzedni artykuł z serii

Użyjemy też organizerów do zarządzania naszymi elementami na ekranie, a podczas całego odcinka pokażę również kilka ciekawostek ułatwiających pracę.

Po co nam aktualny odczyt z akcelerometru telefonu w budowanym układzie? Szczerze mówiąc poza robotem nie mam racjonalnego oraz praktycznego pomysłu. Niemniej kurs zakładał tworzenie aplikacji z myślą o sterowaniu robotem i tak zrobimy. Nawet jeśli nie jesteście fanami tego typu rozrywki, zapewne widzieliście gry wyścigowe gdzie sterowanie odbywało się poprzez pochylanie telefonu. Może warto tę wyścigówkę przełożyć do materialnego świata?

Zapewne cześć osób już widziała trailer tej części kursu, jeśli nie, to warto nadrobić zaległość teraz:

Przy okazji, podziękowania dla młodszego brata, który w ostatniej scenie pokazał, że obsługa aplikacji jest dziecinnie łatwa.

Aby jednak zrobić podobną aplikację będziemy potrzebowali kilku, nieomawianych wcześniej elementów, które są podstawą konwencjonalnego programowania. Na końcu zajmiemy się przygotowaniem do instalacji na telefonie naszej aplikacji „na stałe”.

Zmiana nazwy i przygotowanie elementów

Otwórzmy naszego App Inventora oraz edytor blokowy. Utwórzmy nowy projekt i podłączamy telefon w trybie debugowania, tak jak było to opisywane wcześniej. Na ekran dodajemy przycisk „Button” oraz „TextBox” oba z kategorii „basic”. W edytorze blokowym w sekcji „My blocks” możemy zidentyfikować nasze elementy bez problemu. To dlatego, że mamy jeden „Button” i jeden „TextBox”. A co powiecie na coś takiego?

Zdecydowania dłuższa lista elementów.

Zdecydowania dłuższa lista elementów.

Przyznacie chyba, że nie jest to zbyt logiczne, a może być jeszcze gorzej. W drugiej części wspomniałem, że lista użytych komponentów na danym ekranie widoczna jest w części „Components” możemy je tam usuwać, zmieniać ich nazwy.

Tak, to jest to! Możemy ustalić nazwę każdego elementu na własną, dowolną frazę. Tak więc już teraz z racji na późniejszą większą ilość komponentów zachęcam do nazywania każdego elementu najlepiej, tak aby nazwa opisywała ich funkcję.

Spójrzmy więc na edytor ekranów, zaznaczmy element i przeciekiem Rename z sekcji Components zmieńmy nazwy. Tu muszę zaznaczyć, że zmieniając nazwy lepiej zostawić początek wskazujący na konkretny typ elementu, co posegreguje nam elementy typem oraz ułatwi szybką interpretację w edytorze blokowym.

Tak więc polecam zmienić nazwy na kolejno „Button_dodaj1” i „TextBox_wynik”. Jak już się pewnie domyślacie, przycisk ten będzie nam coś dodawał, tak wiec w jego parametrach ustalmy „text” jako „Dodaj 1” – Ta nazwa powinna być wyświetlana na ekranie.

Zmiana nazwy komponentu w App Inventor.

Zmiana nazwy komponentu w App Inventor.

Aby zmienić nazwę wyświetlaną na górze aplikacji „Tytuł” należy zmienić parametr „Title” ekranu - domyślnie „Screen1”. Po tych zabiegach ekran telefonu powinien wyglądać mniej więcej tak:

Ekrany telefonu.

Ekrany telefonu.

Zmienne oraz operacje matematyczne

Przejdźmy teraz to edytora blokowego. Będziemy potrzebowali zmiennej, podobnie jak podczas zwykłego programowania musimy ją zdefiniować. Wybieramy Build-In -> Definition -> i trzecią pozycję od góry (variable). W celu nadania nazwy naszej zmiennej klikamy w miejscu napisu „variable” i wpisujemy nazwę np. „wynik”.

Uwaga na wykrzyknik!

Uwaga na wykrzyknik!

Jest to spowodowane tym, ze App Inventor wymaga zainicjowania każdej zmiennej wartością początkową, nawet jeśli jest ona nieistotna lub równa 0. Tak więc przy „as” dodajemy stałą (Built-In -> Math -> numer (pierwsza pozycja)). Ma ona domyślnie wartość 123, po kliknięciu w tę liczbę możemy ją zmienić i wpisać dowolną wartość. Dla naszych potrzeb 0 (zero) będzie idealne.

Przypisanie wartości do zmiennej.

Przypisanie wartości do zmiennej.

Aby oczytać lub nadać wartość zmiennej musimy użyć bloczków z My Blocks -> My Definitions:

Odczytywanie i nadawanie wartości zmiennym.

Odczytywanie i nadawanie wartości zmiennym.

Pierwszy bloczek (czerwona strzałka) przekazuje wartość zmiennej jako parametr. Drugi bloczek (zielona strzałka) przyjmuje wartość i wpisuje ją do zmiennej. Oczywiście musi być to wykonywane w jakimś zdarzeniu. Teraz zróbmy, aby po naciśnięciu przycisku zmienna zwiększała się o 1.

Tak więc dodajemy zdarzenie My blocks -> Button_dodaj1 -> Button_dodaj1.click. W nim musimy dodać 1 do wartości zmiennej wynik. Wybieramy bloczek odpowiedzialny za przypisywanie nowej wartości zmiennej (zielona strzałka - na obrazku powyżej) i wstawiamy go w zdarzenie kliknięcia przycisku. Jeśli już programowałeś zapewne wiesz jak to teraz rozwiązać.

Musimy przypisać tej zmiennej wartość zmienna + 1. Dodajemy więc bloczek sumowania, z Built In -> Math -> +. Ma on dwa miejsca na wejścia dla wartości oraz jedno wyjście, które przekazuje sumę wartości liczbowych bloczków umieszczonych wewnątrz.

W bloczek sumowanie wkładamy wartość zmiennej (czerwona strzałka – na obrazku wyżej) oraz stałą o wartości 1 (dodajemy ją tak samo, jak wcześniej deklarując wartość początkową zmiennej „wynik”). Powinno to wyglądać tak:

AK_7

Inkrementacja zmiennej.

Jedyne czego nam teraz brakuje to umieszczenie wyniku w polu „EditBox” za wyświetlanie wartości odpowiada bloczek TextBox_wynik.Text jako źródło wartości dajemy bloczek przekazujący wartość zmiennej. Całość powinna wyglądać następująco:

Gotowy program w App Inventor.

Gotowy program w App Inventor.

Dodajmy teraz jeszcze jeden przycisk do odejmowania. Nazywamy go "Odejmij 1". Oraz oprogramujmy analogicznie do dodawania, z wyjątkiem bloku dodawania, który teraz zastąpiliśmy bloczkiem odejmowania. Oczywiście nic nie stoi na przeszkodzie, aby dodawać (-1) jednak z powodu przejrzystości radzę zastosować dedykowany bloczek.

App Inventor gotowy program z odejmowaniem.

App Inventor gotowy program z odejmowaniem.

Pozostałe operacje matematyczne działają w analogiczny sposób, możemy oczywiście jako parametry podać dowolne zmienne i/lub stałe. W tej części kursu użyjemy jeszcze na pewno mnożenia oraz zaokrąglania liczb. Na tym etapie moglibyśmy zrobić prosty kalkulator, jednak myślę, że nie jest to zbyt interesujące. Lepiej czas spędzony nad App Inventorem przeznaczyć na coś bardziej konstruktywnego.

Zarządzanie elementami na ekranie

Teraz zastanówmy się jak rozwiązać problem ułożenia przycisków. Jak ułożyć je obok siebie? Z pomocą przyjdą nam organizery - „Screen Arrangement”:

App Inventor - organizery.

App Inventor - organizery.

Pierwszy z nich umożliwi nam położenie dowolnej ilości elementów poziomo, ostatnio pionowo, a środkowy tworzy tabelę – siatkę o z góry ustalonej ilości rzędów i kolumn, przy czym do jednej komórki może należeć tylko jeden element.

Chcemy, aby przyciski dodaj/odejmij były obok siebie więc wybieramy „HorizontalArrangement” Wstawiamy go na samej górze i przenosimy przyciski do jego wnętrza.

Ustawienie elementów na ekranie.

Ustawienie elementów na ekranie.

Jak możemy zauważyć w części „Components”, nasze przyciski są przynależne do elementu grupującego. Natomiast na telefonie przyciski powinny już pokazywać się obok siebie.

Podgląd programu na telefonie.

Podgląd programu na telefonie.

Ułatwianie pracy, poszukiwanie błędów

Do it. Watch. Deactivate. Kliknijmy teraz prawym przyciskiem myszy na jeden z bloczków akcji (ciemnoniebieski), np. od przypisywania wartości zmiennej podczas dodawania, ostatnią pozycją na liście jest „Do it”.

Podgląd opcji Do it.

Podgląd opcji Do it.

Dzięki niej możemy z poziomu naszego komputera wywoływać poszczególne akcje, nawet jeśli zdarzenie nie zostało wykonane. Tak więc kliknijmy „Do it” na bloczku przypisania wartości o 1 większej od aktualnej (inkrementacja) następnie zróbmy to samo na bloczku wyświetlającym zawartość zmiennej „wynik” w TextBox’ie. Nasza zmienna została powiększona o 1, a jej wartość wyświetlona na ekranie telefonu.

Co prawda w przypadku przycisku nie jest to nadzwyczaj przydatna funkcja, jednak, gdy użyjemy zdarzeń, które nie będą wykonywane przez użytkownika okaże się bardzo przydatna.

Do testowania również przydatną funkcją jest „watch”, która pozwoli nam śledzić aktualnie wykonywane operacje, lub obserwować aktualne wartości zmiennych. Kliknijmy prawym przyciskiem myszy na deklaracji naszej zmiennej i zaznaczmy „watch”.

AK_14

Obserwowanie zmiennej.

Od tego momentu w dymku mamy wyświetlaną aktualną wartość zmiennej. Ostatnią funkcją tego typu jest „Deactivate”, która działa również na bloczkach zdarzeń. Polecenie to, po prostu, dezaktywuje część programu.

Gospodarowanie przestrzenią, komentarze

Przestrzeń na nasz algorytm jest dynamiczna. Innymi słowy mówiąc, w razie potrzeb, rozszerza w dół i w prawo. Jednak wielki algorytm, niczym program napisany w jednej funkcji nie jest "atrakcyjny" wizualnie. Dlatego każde zdarzenie możemy sobie „zwinąć” Aby już nie zaśmiecało nam przestrzeni roboczej.

Zwijać możemy je za pomocą małego czarnego trójkącika w lewym górnym rogu każdego ze zdarzeń, lub grupowo używając poleceń „Oranize/Collapse all blocks” klikając odpowiednie pozycję z menu kontekstowego spod prawego przycisku myszki.

Zwijanie części programu.

Zwijanie części programu.

Komentarze, to nieodzowny element każdego języka programowania. Dodany zostały również do App Inventora, według mnie lekko na siłę, przez co są średnio użyteczne. Komentarze możemy dodawać do każdego bloczku.

Opcja „Add comment” jest dostępna z menu pod prawym przyciskiem myszki. Bloczki z dodanymi komentarzami posiadają symbol znaku zapytania, po najechaniu na niego ujrzymy naszą krótka notatkę.

Przykładowy komentarz.

Przykładowy komentarz.

Akcelerometr – aplikacja do zdalnego sterowania

Myślę, że teoretycznych rozważań nad samym środowiskiem w tej części wystarczy. Przejdźmy do praktycznego celu tej części kursu, czyli sterowania naszego robota za pomocą telefonu.

Utwórzmy więc nowy projekt i edytor blokowy, dodajmy wszystko co jest potrzebne, aby połączyć się poprzez bluetooth oraz dodatkowo z zakładki „Sensors” obiekt „AccelerometerSensor” możemy oczywiście nadać stosowne nazwy elementom. Jednak będą występowały one pojedynczo, więc nie jest to konieczne. Ustawmy orientację ekranu „ScreenOrientation” na „Landscape”, pozostałe parametry mogą pozostać niezmienione, lub ustalone według gustu.

Całość powinna wyglądać tak:

Wygląd aplikacji.

Wygląd aplikacji.

Najpierw musimy zająć się samym akcelerometrem. Nie zamierzam opisywać jego budowy. Wystarczy zaznaczyć, ze jest to element mierzący przyspieszenie liniowe. Wychylenie względem pozycji jest wyliczane na podstawie naturalnego przyspieszenia ziemskiego wynoszącego w przybliżeniu 9.81m/s2.

Dla jeszcze większego uproszczenia przyjmijmy, że maksymalną wartością jaką możemy osiągnąć jest 10m/s2. Musimy sobie jednak zdawać sprawę z tego, że ziemia nie jest jedynym źródłem przyspieszenia liniowego, każdy ruch może spowodować zmianę wartości większą niż nasza planeta. My jednak chcemy badać tylko aktualne położenie, więc zakres +/-10 będzie idealny.

W przybliżeniu wygląda to tak:

AK_18_telefon

Oczywiście pomijam już ułożenie fizyczne samego czujnika w obudowie. Dla naszych zastosowań niema to większego znaczenia. Wygodniej jest trzymać telefon jako poziomą kierownicę.

Rozpatrzmy jak to będzie wyglądało:

AK_19_telefon

Możemy zauważyć, że do wykrywania skrętu wystarczy nam oś Y i tak też będzie. Na podstawie jednego odczytu zyskujemy wychylenie telefonu względem pozycji 0. Jakie jednak będziemy mieli teoretycznie odczyty?

AK_20_telefon

Należy jednak zaznaczyć, że wartość otrzymana z akcelerometru nie zmienia się liniowo wraz ze zmianą kąta. Możemy to oczywiście przeliczyć z wektorów.

W uproszczeniu aktualne przyspieszenie wynosi sinus kąta między wektorem Fg, a osią OY akcelerometru razy przyspieszanie, które przyjęliśmy 10m/s2. Dlatego dla kąta 45º otrzymamy nie 5 jakby to wynikało z proporcji, a ~7, bo:

sin(45)= sqrt(2)/2 => sqrt(2)/2=0.7 => 0.7 *10m/s2 = 7m/s2 (w przybliżeniu)

Aby dokonać przemiany odwrotnej (z przyspieszenia na aktualny uchyb względem poziomu podawany w stopniach) musimy wyliczyć odwrotność sinusa, czyli sin-1(aktualne przyspieszenie/10)=kąt w stopniach.

Przekształcenie takie powinno działać tak, jak przykład z Excela [=STOPNIE(ASIN(A2/10))]:

Obliczenia w Excelu.

Obliczenia w Excelu.

My jednak nie będziemy się zajmować taką korekcją, gdyż bez niej również otrzymamy nie wiele gorszy rezultat. Dla chcących podałem wzór, więc bez problemów działając analogicznie do innych działań matematycznych, powinno się udać wykonać taką korekcję.

Przekształcanie wartości przyspieszenia

Zastanówmy się jednak jak przesłać liczbę, która nie dość, że nie jest naturalna, to nie jest nawet całkowita. Przykładowej liczby -2.14587 nie prześlemy tak prosto. Oczywiście możemy ją pomnożyć przez 105, aby otrzymać liczbę całkowitą -214587 jeśli teraz wyślemy ją jako bezwzględną (bez znaku -) możemy to zrobić za pomocą 3 bajtów (choć z powodu wynikającego z ograniczeń inventora - 4 bajtów).

Nie jest to dobre rozwiązanie. Jak widzisz, nie dość, że nasz mikrokontroler będzie musiał się męczyć z dużymi liczbami, to algorytm będzie bardziej skomplikowany, a ilość wysyłanych ramek z odczytem na sekundę drastycznie spadnie. A co jeśli można by wysłać ten odczyt za pomocą 1 bajta? Jest to jak najbardziej wykonalne, musimy tylko nasz odczyt poddać kilku operacjom matematycznym.

Jak już wcześniej mówiłem za pomocą jednego bajta możemy przesłać liczbę z zakresu 0 do 255 więc zarezerwujmy liczby 0-200 (aby mieć ładny okrągły zakres) dla odczytów, pozostałe liczby (od 201 do 255) posłużą nam do wysyłanie poleceń sterujących.

Jak może to wyglądać?

Mając bezpośredni odczyt (-10 do 10), przy czym do przedziału należą wszystkie liczby wymierne, pomnóżmy go przez 10. Nasz zakres powiększy się i jednocześnie zyskamy większą dokładność.

Tak więc następnie zaokrąglamy odczyt do liczb całkowitych. Otrzymujemy wynik z przedziału (-100 do 100) przy czym mamy tylko i wyłącznie liczby całkowite. Ostatnie co nam pozostało to dopasować zakres do możliwości oferowanych przez uart. Jeśli do otrzymanej liczby dodamy 100 przesuniemy zakres, co da w rezultacie liczbę z zakresu od 0 do 200, gdzie 0 to położenie telefonu skrajnie obróconego w lewo (do góry nogami), 200 odwrotnie. Natomiast dla pozycji neutralnej (poziom) odczyt powinien wynosić 100.

Aktualne przyspieszenie przechowywane jest w zmiennej „AkcelelometrSensor1.Yaccel” należącej do grupy elementów obiektu akcelerometru. Implementacja algorytmu w App Inventorze powinna wyglądać tak:

Fragment programu z AppInventor.

Fragment programu z AppInventor.

Myślę, że nie jest konieczne jego dokładne omawianie, wszystkie klocki są dostępne w „math”. Nowy bloczek - „round” służy do zaokrąglania liczb. Jako, że będziemy przedstawionego wyrażenia używali wielokrotnie, najlepiej zadeklarować zmienną, która będzie przechowywała wartość tego wyrażenia. Nazwijmy ją „axy” możemy ją zainicjować dowolną wartością.

Dodatkowa zmienna.

Dodatkowa zmienna.

Kolejną ważną kwestią jest to, że przypisywanie (i wysyłanie, które ma przebiegać automatycznie) nie będzie się wykonywać „luzem” musi być w jakimś zdarzeniu. Zdarzeniem, które cyklicznie wykonuje operacje, jest przerwanie od zegara. Przejdźmy do edytora ekranów i dodajmy element „clock” z zakładki „Basic” Element ten posiada bardzo istotny dla nas parametr.

Ustawienie sygnału zegarowego.

Ustawienie sygnału zegarowego.

Jest to interwał czasowy, który określa czas (w ms = 1/1000s), co ile ma zostać wykonane przerwanie. Dla pierwszych testów proponuję określić tę wartość na 250. Da to w rezultacie przerwanie do 1/4 sekundy (4 razy na sekundę). pozwoli to na dość płynne obserwowanie tego „co się dzieje” i nie spowoduje opóźnień i innych problemów w przypadku błędu w algorytmie.

Chyba, że ktoś doda, tu np. zamykanie aplikacji lub jakąś czasochłonną akcję. Myślę jednak, że takie ewentualności możemy pominąć. Przejdźmy teraz do edytora blokowego i dodajmy przerwanie zegara:

Dodawanie sygnału zegarowego w App Inventor.

Dodawanie sygnału zegarowego w App Inventor.

Do niego wstawimy przypisywanie zmiennej wartość uzyskaną z operacji opisanych wcześniej. Cały algorytm w tym momencie powinien wyglądać tak:

Przygotowany program.

Przygotowany program.

Ograniczenie zakresu

Jeśli mamy już odczyt i przerwanie zegara musimy zauważyć, że nasz akcelerometr nie ma ograniczonego zakresu pomiarowego do wartości jaką założyliśmy wcześniej. Może przybrać odczyt np.: -15m/s2 co dla ciągu naszych działań dałoby w rezultacie -50. Takiej liczby nie wyślemy w jednym bajcie po uarcie.

Dlatego konieczne jest ograniczenie zakresu. Czyli dla liczby <=0 algorytm musi zwracać 0, dla liczby >=200 zwracać 200, a dla liczb z zakresu (0 do 200) liczbę z odczytu. Możemy to zrobić za pomocą kilku wyrażeń warunkowych, które również dodamy w przerwaniu zegara. W App Inventorze mamy dwa podstawowe wyrażenia warunkowe if oraz ifelse.

Tworzenie warunków w App Inventorze.

Tworzenie warunków w App Inventorze.

Pierwszy wykonuje operacje zamieszczone w „then-do” jeśli warunek „test” jest spełniony. Drugi posiada dodatkowo „else-do”, w którym operacje będą wykonywane jeśli warunek nie zostanie spełniony.

Po sprawdzeniu warunków wartość będziemy od razu wysyłali za pomocą bluetooth jako liczbę w 1 bajcie „BluetoothClient1.Send1ByteNumber”. Czyli tak jak liczby w start/stop dla LineFollowera w poprzedniej części kursu.

Finalnie, ograniczenie zakresów i wysyłanie odpowiedniej wartości powinno wyglądać tak:

Wykorzystanie warunków w praktyce.

Wykorzystanie warunków w praktyce.

Bloczki porównania „<=” i „>=” są dostępne w sekcji „math”. Powyższy fragment może wyglądać nieco skomplikowanie, jednak zapewniam, że tak nie jest. Na początku sprawdzamy, czy nasza zmienna „axy” jest większa lub równa 0.

Jeśli warunek jest spełniony sprawdzamy, czy „axy” jest też mniejsze, lub równe 200. Jeśli tak jest wysyłamy niezmienioną wartość zmiennej „axy” po bluetooth. Jeśli natomiast zmienna jest większa, lub równa 0 i nie spełnia drugiego warunku („axy” <= 200), to po bluetooth zostaje wysyłana liczba 200. Jeśli natomiast „axy” nie jest większa lub równa 0 (czyli jest mniejsza od 0) wysyłamy 0.

Warunek połączenia

Nasz algorytm ma poważną wadę. Nie sprawdza czy jesteśmy podłączeni i wysyła dane nawet, gdy nie zostaliśmy podłączeni z modułem bluetooth. Wydaje się, że w niczym to nie przeszkadza (ew. jest tylko nieeleganckie) jest toi jednak poważnym problemem. Przy próbie wysłania, będąc niepodłączonym, pojawi się komunikat:

App Inventor i brak połączenia Bluetooth.

App Inventor i brak połączenia Bluetooth.

Komunikat nie dość, że zasłana część ekranu to się kolejkuje, w związku z czym nawet po podłączeniu lub nawet po zamknięciu naszej aplikacji komunikat nie zniknie tak szybko. Należy się więc zabezpieczyć przed takim przypadkiem. Możemy to zrobić na co najmniej dwa sposoby.

  1. Warunek sprawdzający czy jesteśmy podłączeni, wykonujący operacje wysyłania tylko jeśli warunek jest spełniony.
  2. Taki sam warunek, jednak w zależności od tego czy jesteśmy podłączeń, czy też nie, aktywujący, lub dezaktywujący wszystkie elementy które mogą powodować wysyłanie danych po bluetooth.

Jako, że pierwsze rozwiązanie jest bardziej uniwersalne i sprawdzi się w każdym przypadku. Rozpatrzymy tylko ten sposób. Utwórzmy więc warunek „if”, w którym operacje będą się wykonywały tylko wtedy, gdy będziemy podłączeni. Na szczęście w obiekcie Bluetooth’a znajdziemy stosowny element zwracający „true” jeśli jesteśmy podłączeni.

Gotowy warunek powinien wyglądać tak:

Warunek związany z Bluetoothem.

Warunek związany z Bluetoothem.

Należy oczywiście pamiętać, że podobny warunek musimy dodać przy KAŻDEJ operacji wysyłania jakichkolwiek danych. Tak więc dodajmy ten warunek na całą część ograniczającą wartość liczb.

Poprawiona wersja oprogramowania bluetooth.

Poprawiona wersja oprogramowania bluetooth.

Od tego momentu, nie mamy problemu z uciążliwym komunikatem, a sam algorytm stał się bardziej „elegancki” i nie będzie próbował wysyłać danych, jeśli nie będziemy podłączeni.

Przycisk kluczujący i regulacja prędkości

Do oprogramowania zostały nam dwa elementy aplikacji. Wielki przycisk (który właściwie nie jest przyciskiem) oraz buttony do ustalania prędkości. Zacznijmy od tego pierwszego. Jest to dość prosty element „Canvas” (basis w edytorze ekranów). Ustalmy jego szerokość (width) na „fit to screen”, a wysokość dopasujmy do naszego ekranu. U mnie jest to ok 200 pikseli, ustalmy jeszcze jego kolor tła na czerwony.

Komponent Canvas w AppInventorze.

Komponent Canvas w AppInventorze.

Zapewne zastanawiacie się, dlaczego używamy jakiegoś dziwnego elementu, który przystosowany jest ponadto do przekazywania pozycji dotknięcia palca, rysowania itp.? Otóż należy zwrócić uwagę na działanie standardowego buttona. Mamy przerwanie od jego kliknięcia, jednak kliknięciem nazywana jest operacja puszczenia przycisku po jego wcześniejszym dotknięciu. Ponadto nie ma możliwości sprawdzenia, w którym momencie dotknęliśmy button.

W naszym rozwiązaniu mamy do dyspozycji dwa interesujące nas zdarzenia „TouchDown” i „TouchUp”. Odpowiadają kolejno za moment dotknięcia oraz puszczanie pola. Dla lepszego efektu wizualnego proponuję dodać efekt zmiany koloru. Czerwony w memencie nie dotykania (stoi), zielony podczas dotykania (robot jedzie). Zmiana kolorów w naszych zdarzeniach od „canvas” powinna wyglądać mniej więcej tak:

Wykorzystanie Canvas w praktyce.

Wykorzystanie Canvas w praktyce.

Wszystko poza kolorami jest dostępne w bloczkach elementu „Canvas”. Kolory możemy znaleźć w „Colors” w „Built-In”. Działanie jest dość proste. Po naciśnięciu pola kolor tła jest ustawiany na zielony, po puszczeniu na czerwony. Zauważmy, że nasze zdarzenia posiadają wbudowane zmienne „x” , „y”, „x1: itd. są to zmienne przechowujące pozycję dotknięcia i puszczenia palca. My nie będziemy z nich teraz korzystać.

Teraz dodajmy wysyłanie poleceń start i stop. Jako, że wysyłane liczby z zakresu od 0 do 200 są już zajęte, użyjmy kolejno 201 do startu i 202 do zatrzymania robota. Tak jak wczesnej wysyłaliśmy przetworzony odczyt z akcelerometru (za pomocą jednego bajta).

Pamiętamy oczywiście o warunkach, które uniemożliwią nam wysyłanie poleceń, gdy nie jesteśmy podłączeni. Możemy ten warunek założyć na całą zawartość zdarzenia, dzięki czumu również kolory nie będą się zmieniały, co będzie obrazowało faktyczny stan robota (gdy nie jesteśmy podłączeni to stoi nieruchomo). Warunek połączenia się po bluetooth możemy skopiować skrótami klawiszowym Ctrl+c i Ctrl+v tak, jak przy normalnej pracy w innych programach systemie. Zapewne skopiuje nam się również zawartość warunku. Musimy ją po prostu usunąć.

Dalsza część programu.

Dalsza część programu.

Ostatnim elementem naszego programu jest zmiana prędkości. Możemy ją zrobić na kilka sposobów. Dla uproszczenia użyjemy przycisku, z którego korzystaliśmy wielokrotnie.

Oczywiście ich ilość może być dowolna, jednak trzy z pewnością wystarczą. Tak więc dodajemy przyciski. Dla ładniejszego wyglądu umieśćmy je w poziomym rzędzie. Korzystamy więc z wcześniej opisywanego „HorizontalArrangement” i wkładamy do niego trzy przyciski.

W robocie będziemy ustawiali prędkość za pomocą ośmiobitowego PWM (0 do 255) ustalmy możliwe prędkości na 25, 50 i 100. Dlatego tam podpisujemy nasze przyciski i nazywamy je B_25, B_50 i B_100 dla łatwiejszej lokalizacji w następnym etapie. Proponuję też ustawić stałą szerokość na np. 100px. Jeśli w ustawieniach „HorizontalArrangement” zaznaczymy szerokość na „fit to parent” oraz ustalimy wyrównanie na „Center” to nasze przyciski zostaną wyśrodkowane.

Tak to wygląda w Inventorze i na ekranie naszego telefonu:

Teraz pora oprogramować przyciski. Poza wysyłaniem informacji o wyborze prędkości proponuję dezaktywować ten przycisk, który przed chwilą wybraliśmy, pozwoli to na identyfikację aktualnej prędkości. Dodajmy zdarzenie kliknięcia dla każdego z trzech przycisków w edytorze blokowym.

Przyjmijmy liczby 203 dla 25 PWM, 204 dla 50 PWM, oraz 205 dla 100 PWM.

Regulacja prędkości robota.

Regulacja prędkości robota.

Proponuję, aby po połączeniu się była automatycznie wybierana prędkość 50. Dlatego w „ListPicker1.AfterPicking” należy dodać wysyłanie 204 oraz wygaszenie przycisku od ustalenia prędkości 50 PWM. Jednocześnie konieczne jest aktywowanie pozostałych.

Aktywacja przycisków w App Inventorze.

Aktywacja przycisków w App Inventorze.

Proponuję też dodać wygaszanie również przy dotykaniu klawiszy wyboru prędkości. Należy pamiętać, że pozostałe musimy aktywować.

Aktywowanie i dezaktywowanie pozostałych przycisków.

Aktywowanie i dezaktywowanie pozostałych przycisków.

Mam teraz dobrą wiadomość. Nasza aplikacja została ukończona! Całość powinna wyglądać tak:

Gotowa aplikacja w App Inventor wykorzystująca Bluetooth.

Gotowa aplikacja w App Inventor wykorzystująca Bluetooth.

Testowanie w terminalu

Chciałem zwrócić jeszcze tylko uwagę na jedną kwestię. Wyliczania konkretnych wartości pwm dla silników. Tu musimy obarczyć nasz procesor dodatkowym zadaniem - dostosowaniem mnożnika dla wartości przechylenia do aktualnej prędkości (jeśli chcemy, aby kierowanie było komfortowe). Możemy to oczywiście robić w samym telefonie, jednak doszedłem do wniosku, że oba sposoby są w praktyce identyczne, więc nie widzę konieczności, aby wszystko wyliczał telefon.

Algorytm w robocie. Jeśli zdecydujesz się skorzystać z mojego niezmienionego algorytmu, krótko opiszę jak powinien wyglądać algorytm w samym robocie. Potrzebujemy dwóch zmiennych:

  • Vd – prędkość domyślna
  • K – dzielnik
  • Zmiana – zmiana prędkości względem Vd

W pętli głównej odczytujemy ostatnią odebraną wartość po UART. Jeśli jest to:

  • 201 – ustawiamy porty od mostka Ain1, Ain2, Bin1, Bin2 Tak aby robot zaczął jechać
  • 202 - ustawiamy porty od mostka Ain1, Ain2, Bin1, Bin2 Tak aby robot się zatrzymał
  • 203 – ustawiamy Vd na 25 i K na 4
  • 204 - ustawiamy Vd na 50 i K na 2
  • 205 - ustawiamy Vd na 100 i K na 1

Kody od 0 do 200:

  • Od wartości odejmujemy 100 i dzielimy przez K i przypisujemy wartość do zmiany
  • Ustawiamy wartości PWM silnika lewego na Vd=Vd+zmiana
  • Ustawiamy wartości PWM silnika prawego na Vd=Vd-zmiana

Oto cały algorytm. Należy go przetłumaczyć na wybrany język dla mikrokontrolera. Nie powinno być to wielkim problemem, mamy tu kilka zmiennych i wyrażeń warunkowych, PWM i UART.

Jeśli wszystko działa jak należy proponuję zmienić jeszcze tylko interwał czasowy przerwania zegara. 250ms to bardzo dużo czasu i reakcja na nasze wychylanie jest powolna.

Na koniec krótka prezentacja:

Instalowanie aplikacji

Ostatnim zagadnieniem w tej części kursu jest instalowanie „na stałe” naszej aplikacji w smartfonie. Wspominałem już o tym w 2 części, jednak myślę, że należy o tym jeszcze powiedzieć kilka słów.

Przechodzimy do edytora ekranów i wybieramy „Package for Phone”:

Wybór odpowiedniej opcji w App Inventor.

Wybór odpowiedniej opcji w App Inventor.

Mamy tu kilka możliwości. Możemy wyświetlić qr-code, który przekierowuje do strony download z naszą aplikacją. Możemy pobrać aplikację w formie pliku instalacyjnego .apk oraz zainstalować bezpośrednio w telefonie. Jeżeli aktualnie debugujemy naszą aplikację w telefonie najwygodniej będzie nam zainstalować ją bezpośrednio.

Wybieramy więc trzecią opcję. Pojawi się pasek postępu i po chwili komunikat „Application successfully downloaded to phone.”. Jeśli byliśmy podłączeni przewodem, możemy cieszyć się bo nasza aplikacja została zainstalowana już na telefonie. Jeśli korzystamy z debugowania po wi-fi pojawi się nam taki komunikat:

Instalowanie aplikacji na telefonie.

Instalowanie aplikacji na telefonie.

Wszystko byłoby pięknie, gdyby nie problem przy instalowaniu kilka razy tej samej aplikacji (po aktualizacjach) nie wiem z jakiego powodu pakiet instalacyjny, który jest kopiowany na kartę pamięci nie uaktualnia się, zmuszeni jesteśmy do każdorazowego jego usuwania lub instalacji z ręcznie wgranego pliku, wcześniej pobranego na komputer.

Oczywiście polecam przed operacją zainstalowania aplikacji zmienić choćby ikonę, (parametr „Icon” ekranu głównego „Screen1”). Najlepiej w formie pliku png o proporcjach 1:1 i rozsądnej rozdzielczości. Przeźroczystości są dopuszczalne.

Podsumowanie kursu Androida i App Inventor

Mam nadzieję, że artykuł się podobał, zachęcam do komentowania, oceniania i konstruktywnej krytyki. Dziękuję też za wyrozumiałość, jednak opóźnienia tej części spowodowane były brakiem czasu, ale chyba przyznacie, że część ta wyszła dość obszerna.

« Poprzedni artykuł z serii

 Artykuł był już wcześniej publikowany na forum.

akcelerometr, anndroid, bluetooth, komunikacja, kurs, kursAndroid

Trwa ładowanie komentarzy...