Urządzenie sterowane gestami

Urządzenie sterowane gestami

Oglądaliście „Raport mniejszości”? W filmie główny bohater obsługuje komputer przy pomocy gestów – fragmenty możecie zobaczyć na tym filmie:

W roku, gdy film ten był prezentowany, taki interface wydawał się futurystyczny i nieosiągalny, a tymczasem już w 2008 powstał prototyp interfejsu sterowanego właśnie w ten sposób:

Oczywiście skonstruowanie go wykracza poza budżet domowego projektu, ale chcę pokazać, jak można wykorzystać trochę elektroniki i komórkę, aby osiągnąć ciekawy efekt urządzenia sterowanego gestami. Być może jest to rozwiązanie mało praktyczne, ale za to będzie trochę fajerwerków :)

Części

Będziemy potrzebować następujących komponentów:

Pierwotnie myślałem też o tym, żeby skorzystać z jakiegoś IMU (akcelerometr + żyro + magnetometr), ale potem doszedłem do wniosku, że będzie to niepotrzebnie komplikować projekt – współcześnie każdy telefon komórkowy wyposażony jest w taki moduł. Dlatego sterowanie odbywać się będzie właśnie z poziomu telefonu komórkowego – napiszemy w tym celu odpowiednią aplikację.

Schemat połączeń

Schemat możemy znaleźć na poniższym obrazku. Należy zwrócić szczególną uwagę, żeby pin VCC Raspberry (+3,3V) podłączyć do pinu VCC na płytce i nie pomylić go z V+, bo ten ostatni połączony jest z linią +5V zasilania serw – można w najgorszym przypadku uszkodzić Raspberry!

Połączenia wyglądają mniej więcej, jak na poniższym zdjęciu.

Programowanie

Część elektroniczna w przypadku tego projektu jest tą łatwiejszą – trochę więcej pracy będziemy musieli włożyć w oprogramowanie Raspbery i komórki.

Sterowanie serwami

Sterowanie serwami z poziomu Raspberry nie jest specjalnie trudnym zagadnieniem, ale można się trochę naciąć. Raspberry potrafi sprzętowo generować sygnał PWM, ale niestety tylko na jednym pinie. Co więcej, standardowa biblioteka RPi.GPIO, przy pomocy której możemy korzystać ze złącz GPIO, potrafi generować PWM tylko programowo – objawi się to zauważalnym „szarpaniem” serwa. Możemy skorzystać z innej biblioteki – wiringpi, która (o ile skrypt uruchomimy z uprawnieniami roota) potrafi już wykorzystać sprzętowe generowanie PWMa, jednak wciąż będziemy ograniczeni do jednego pinu, czyli sterować będziemy tylko jednym serwem, a potrzebujemy dwóch. Dlatego też do zrealizowania tego projektu potrzebujemy płytki sterującej serwami; alternatywnym rozwiązaniem może być wykorzystanie do tego celu Arduino, o ile tylko odpowiednio go oprogramujemy.

Aby skorzystać z układu PCA9685, musimy najpierw doinstalować odpowiednią bibliotekę. W tym celu najpierw instalujemy na Raspberry dwa pakiety:

Drugi z pakietów zawiera narzędzia, które przydają się podczas pracy z urządzeniami podłączonymi poprzez szynę I2C.

Pamiętajmy oczywiście o włączeniu obsługi I2C w konfiguracji Raspberry:

Teraz możemy wywołać polecenie, które pozwoli na sprawdzić, czy moduł jest prawidłowo podłączony do Raspberry:

Powinniśmy otrzymać następujący wynik:

Możemy teraz doinstalować do Pythona bibliotekę obsługi płytki PCA9685. Wpisujemy po kolei:

Alternatywnie możemy ściągnąć źródła z Internetu – nie trzeba wtedy doinstalowywać gita.

Serwer TCP/IP

Najciekawszym, moim zdaniem, sposobem zdalnego sterowania zbudowanym urządzeniem jest protokół TCP/IP – dzięki temu sterowane urządzenie może znajdować się na jednym końcu miasta, a my – na drugim. W ten sposób można skonstruować robota z ramieniem sterowanym gestami lub kamerę monitoringu, która umożliwi podgląd obrazu na ekranie telefonu. Raspberry Pi w wersji 3 ma wbudowany moduł Wifi, co jeszcze bardziej ułatwi komunikację przez Internet. Co więcej, zaprogramowanie serwera TCP w Pythonie jest wyjątkowo łatwe – chyba jak wszystko w tym języku (https://xkcd.com/353/).

Kod źródłowy serwera na Raspberry wygląda następująco:

Najnowszą wersję kodu możecie ściągnąć z repozytorium: https://gitlab.com/spook/looker-raspberry.git

Serwer UDP

Tę samą transmisję możemy przeprowadzić również poprzez protokół UDP. Tym razem serwer będzie nieco krótszy:

Aplikacja na komórkę

Aplikację na komórkę napisałem w Javie – oczywiście jest zbyt długa, by jej kod zamieszczać tu w całości, natomiast można go ściągnąć z repozytorium: https://gitlab.com/spook/looker-android.git . Może on też być dobrą bazą dla innej aplikacji sterującej Raspberry przy pomocy TCP/IP.

Aplikacja prezentuje się następująco:

Jeżeli ktoś nie ma możliwości skompilowania aplikacji samodzielnie, załączam do artykułu plik .apk do zainstalowania na urządzeniu.

Efekt

Efekty możemy podziwiać na poniższych zdjęciach (korzystałem tam ze starszej wersji aplikacji mobilnej).

Wnioski

  • IMU komórki jest wystarczający do opisanego rozwiązania, ale nie jest też zbyt dokładny. Jeżeli zależy nam na dokładności, warto skorzystać z osobnego urządzenia (na przykład Raspberry Pi Zero) i dedykowanego układu IMU
  • Możliwość sterowania gestem (położeniem telefonu) daje mnóstwo frajdy. Zachęcam do spróbowania!

Pliki załączone do artykułu:

Ocena: 4.75/5 (głosów: 8)

Podobne posty

18 komentarzy do “Urządzenie sterowane gestami

  • To nie Python jest wolny, a po prostu tak się serwera nie robi.
    Do sterowania (szczególnie jeśli nie masz informacji zwrotnej) służy protokół UDP a nie TCP.
    Użycie RPi plus jakichś dodatkowych płytek to moim zdaniem przerost formy nad treścią – do tego wystarczy ESP8266 bez żadnych dodatkowych firdymałów – podłączasz pin bezpośrednio do serwa.
    Masz czwórkę przede wszystkim za pomysł.

    Odpowiedz
    • Dzięki za komentarz!

      Napisałem jako alternatywę serwer UDP i rozszerzyłem aplikację androidową – teraz można wybrać, czy dane będą wysyłane przez TCP czy UDP. Jeszcze nie testowałem z podłączonymi serwami, ale po logach wygląda obiecująco – transmisja faktycznie przyspieszyła.

      Natomiast co do użytego kontrolera – to jest kwestia potrzeb. Jeżeli zaprezentowany pan/tilt będzie projektem samym w sobie, to faktycznie można użyć znacznie prostszego rozwiązania. Ale jeżeli chcemy np. zamontować kamerę i przekazywać obraz albo podłączyć taki pan-tilt do większego robota, to moim zdaniem Raspberry będzie jak znalazł.

      Odpowiedz
      • Jeśli miałbym tam montować kamerę, to wolałbym tam wsadzić silniki bezszczotkowe, a nie serwa.
        A tak poza tym, to wolałbym użyć jakiegoś gotowego kontrolera gimbala.
        Mimo wszystko pomysł ciekawy.

        Odpowiedz
  • A nie możesz zastosować binarnej transmisji? Wtedy wystarczą dwa bajty wysyłane przez aplikację na andku, i analizujesz po prostu pojedyncze datagramy?
    Mam jesxcze pytanko: czy ta aplikacja na andka może działać w tle? Bo myślę o zdalnie sterowanej gąsienicówce, VLC wyświetlałby mi obraz z kamery, a taka aplikacja mogłaby sterować pojazdem.

    Odpowiedz
    • Aplikacja na Andka jest przystosowana do transmisji danych binarnych (klasy pchające dane przez sieć mogą wysłać String albo byte[]), natomiast obecnie dane wysyłam tekstowo dla prostoty debuggowania. Myślałem o transmisji binarnej, ale dobrze byłoby ją zabezpieczyć jakimś strażnikiem albo sumą kontrolną, bo jeżeli cokolwiek się rozjedzie podczas transmisji, to zaczną się dziać cuda :)

      Co do drugiego pytania: przesyłanie danych działa na osobnym wątku, więc aplikacja powinna działać w tle tak długo, jak długo system nie ubije jej z powodu braku zasobów (co oczywiście jest mało prawdopodobne, ale możliwe). Natomiast miej na uwadze, że nie pisałem jej z założeniem pracy w tle, więc być może trzeba ją będzie odrobinę do tego przystosować.

      Odpowiedz
      • Hm… czy ta aplikacja na pewno dobrze działa?
        Zainstalowałem apk, wpisałem IP i port… jedynym przejawem życia aplikacji jest “cannot connect” w trybie TCP. Na serwerze nie ma żadnych śladów ruchu (przynajmniej tcpdump nic nie pokazuje, żadnych durnych firewalli nie mam).

        Odpowiedz
        • Cóż mogę powiedzieć – SOA#1, czyli “u mnie działa” :)

          Zmodyfikowałem aplikację w taki sposób, że wyświetla teraz przyczynę problemów z połączeniem – w komunikacie będzie teraz np. “Cannot connect! Error: No route to host”. Ściągnij jeszcze raz, zainstaluj, spróbuj, zobaczymy co dalej.

          W moim przypadku sprawdzam zawsze, czy przyczyna nie leży po stronie sieci – stawiam router Wifi na jednej komórce, a potem łączę się do niej drugą i Raspberry – w ten sposób mam prawie najczystsze możliwe połączenie, bez firewalli i tak dalej.

          Odpowiedz
          • Przed chwilą dla pewności sprawdziłem aplikację w opisanej konfiguracji (telefon robiący za router Wifi) na serwerze TCP – działa bez problemu.

            Odpowiedz
            • No i wszystko jasne – pole gdzie wpisujesz adres IP to tylko dekoracja, mogłeś nas uprzedzić.
              Faktycznie, serwer uruchomiony na 192.168.43.34 działa bardzo ładnie – tyle że ja bym chciał mieć inny adres serwera :(

              Odpowiedz
              • Nie mogłem uprzedzić, bo nie tak to miało działać :) Czeski błąd, zabrakło jednego znaku. Nawiasem, port też był na sztywno. Poprawiłem oba bugi – spróbuj teraz, zamieściłem nową wersję.

                Odpowiedz
  • Przydało by się jeszcze jakieś uśrednianie zrobić, żeby ta głowica tak nie skakała jak czujnik zwróci jakieś nieprawdziwe dane czy złapie zakłócenia.

    Odpowiedz
    • Myślałem o tym, żeby oprócz uśrednienia dorzucić jeszcze medianę. W ten sposób sterowanie minimalnie się wprawdzie opóźni, ale powinien zniknąć problem z błędem pomiaru oraz ewentualnymi skokami (co widać na filmiku). Pobawię się w wolnej chwili.

      Odpowiedz
      • Przy UDP jeśli uda Ci się osiągnąć jakąś sensowną prędkość możesz po prostu odrzucić podejrzaną wartość (zbyt duża różnica) i dopiero jeśli następna wartość będzie podobna uwzględnić ją. Wszelkie próby uśredniania doprowadzą i tak do “myszkowania” głowicy.
        Przy 10 komunikatach na sekundę odrzucenie jednego będzie praktycznie niezauważalne.

        Odpowiedz
        • To nie jest takie proste – a jeżeli po tej “podejrzanej” przyjdzie kolejna “podejrzana” i kolejna i kolejna? Musiałbym zrobić jakiś dodatkowy mechanizm na wypadek, gdyby użytkownik faktycznie zrobił gwałtowny ruch. Wprowadzanie progów (różnica, którą uznaję za “podejrzaną”) zawsze powoduje kłopoty. Mediana ma tę zaletę, że odrzuci “podejrzane” wartości, ale jednocześnie jeżeli użytkownik zrobi gwałtowny ruch, to po krótkim czasie zostanie on zaakceptowany (mediana odrzuci jedną-dwie wartości, a uśrednienie upłynni nieco ruch). Siądę w najbliższym czasie i przetestuję, bo wprowadzenie takiej modyfikacji powinno znacznie upłynnić ruch pan-tilta.

          Odpowiedz

Odpowiedz

anuluj

Masz uwagi?