Po co w ogóle rozpoznawać gesty? Tego rodzaju interfejsy mają szereg ciekawych zastosowań. Część z nich jest dosyć niszowa, ale część może niebawem na dobre zagościć w naszym najbliższym otoczeniu. Takie systemy znajdują zastosowanie w interfejsach człowiek-maszyna, gdzie pomagają w wygodnym sterowaniu komputerem. Przykładowe aplikacje to:
- systemy wsparcia dla osób niedosłyszących i niesłyszących,
- interfejsy komputerowe dla małych dzieci,
- systemy kryminalistyczne i policyjne,
- rozpoznawanie języka migowego,
- monitorowanie emocji i stresu pacjentów,
- wykrywacze kłamstw,
- systemy do nawigacji w środowiskach wirtualnych,
- komunikacja i sterowanie systemami do wideokonferencji,
- wsparcie w zdalnej nauce (telenauczaniu),
- monitorowanie czujności/senności kierowców.
W zaprezentowanych projektach, wykrywanie gestów jest stosowane do:
- kontrolowania aplikacji na komputerze (zatrzymywanie i uruchamianie filmów wideo, przełączanie zakładek w przeglądarce itd.),
- sterowanie innymi funkcjonalnościami modułu Arduino,
- sterowanie głośnością,
- wspomagania osób niepełnosprawnych,
- sterowanie zabawką.
Rozpoznawanie gestów
Wszystkie systemy rozpoznawania gestów na podstawowym poziomie działają w ten sam sposób. Pierwszym etapem jest sensor, który zbiera informacje na temat przestrzeni, gdzie pokazywany ma być gest. Dane na temat otoczenia mogą być zbierane sensorami różnego rodzaju, takimi jak kamery wideo czy inne sensory optyczne, kamerami głębi (sensory ToF, mierzące odległość – obraz 3D), sensorami PIR, ultradźwiękowymi itd.
Sensory generują strumień danych (liczb), które opisują obserwowany obszar. Aby możliwe było wychwycenie z nich wartości odpowiadających gestom konieczne jest zastosowanie odpowiednich algorytmów, zwanych klasyfikatorami. Zgodnie z ich nazwą klasyfikują one dane do jakiejś, skończonej liczby klas. W tym przypadku klasy są tożsame z gestami. Klasyfikatory mogą przyjmować różną formę. Od najprostszego algorytmu zapisanego w jawnej formie przez człowieka (np. w postaci jednej lub zestawu funkcji warunkowych), poprzez bardziej złożone algorytmy np. klasyfikacji Bayesowskiej, skończywszy na szerokim spektrum algorytmów kojarzonych ze sztuczną inteligencją – sieci neuronowych itp. Kwestie algorytmiczne wykraczają poza ramy tego artykułu, więc nie będziemy się w nie zagłębiać, tym bardziej, że zaprezentowane poniżej projekty korzystają często z predefiniowanych, gotowych bibliotek do klasyfikacji danych.
Ultradźwiękowe rozpoznawanie gestów
Blok czujników odgrywa kluczową rolę w każdej dziedzinie technologii. Wiele z nich stosowanych jest w interfejsach człowiek-maszyna. Jak napisaliśmy powyżej, tego rodzaju interfejs składa się ze sprzętu i oprogramowania, które pomagają w wymianie danych lub informacji między użytkownikiem (człowiekiem) a maszyną. Urządzenia interfejsu człowiek-maszyna są oparte na rozmaitych czujnikach. W tym przypadku są to ultradźwiękowe sensory odległości, które zastępują klasycznie używane elementy interfejsów, takie jak przełączniki, wskaźniki LED, ekrany dotykowe itp. Autor tej konstrukcji zaimplementował prostą kontrolę gestów rąk z użyciem Arduino i sensorów ultradźwiękowych. Zamiast używać myszki, klawiatury czy joysticka, można dzięki niemu używać gestów dłoni do sterowania niektórymi funkcjami naszych komputerów. Projekt ten używa Pythona do analizy danych. Za jego pomocą można sterować kilkoma funkcjami laptopa lub komputera, takimi jak:
- odtwarzanie i wstrzymywanie wideo,
- przełączanie między kartami przeglądarki,
- zwiększanie i zmniejszanie głośności dźwięku w systemie,
- wyciszanie dźwięku w wideo.
Zasada działania tego systemu jest prosta. Zawiera on dwa czujniki ultradźwiękowe, które, gdy machamy lub przesuwamy ręce przed czujnikami, obliczają odległość między dłonią a czujnikiem (fotografia 1). Obliczona w ten sposób odległość jest analizowana przez Arduino, a jej wyniki są przesyłane do komputera PC, gdzie mogą być wykorzystane przez program napisany w Pythonie. Oprogramowanie to, za pomocą specjalnej biblioteki o nazwie PyAutoGui konwertuje otrzymane komendy na akcje kliknięcia klawiatury itp. Korzystając z tych informacji, komputer wykonuje odpowiednie zadania.
Na rysunku 1 został pokazany schemat układu. Oprócz wejść zasilania, każdy sensor ultradźwiękowy, ma dwa piny – trigger (wyzwalanie) oraz echo (sygnał odebrany). Zliczając czas pomiędzy wyzwoleniem impulsu, a echem otrzymujemy podwojoną odległość pomiędzy sensorem a dłonią. W oprogramowaniu na Arduino odpowiedzialnie działania realizuje funkcja find_distance(), która uzyskuje gotowe odległości i zapisuje je do zmiennych globalnych distance1 oraz distance2.
void loop() {
find_distance();
if (distance2 <= 35 && distance2 >= 15) {
temp = millis();
while (millis() <= (temp + 300))
find_distance();
if (distance2 <= 35 && distance2 >= 15) {
temp = distance2;
while (distance2 <= 50 || distance2 == 0) {
find_distance();
if ((temp + 6) < distance2) {
Serial.println("Vup");
}
else if ((temp - 6) > distance2) {
Serial.println("Mute"); # komenda Mute do komputera
break;
}
}
}
else {
Serial.println("VDown");
}
}
else if (distance1 <= 35 && distance1 >= 15) {
temp = millis();
while (millis() <= (temp + 300)) {
find_distance();
if (distance2 <= 35 && distance2 >= 15) {
Serial.println("change");
l = 1;
break;
}
}
if (l == 0) {
Serial.println("Play/Pause"); # komenda Play/Pause
while (distance1 <= 35 && distance1 >= 15)
find_distance();
}
l = 0;
}
}
Część decyzyjna systemu jest bardzo prosta. Fragment skryptu rozpoznający predefiniowane gesty zaprezentowano na listingu 1.
Po stronie komputera skrypt napisany w Pythonie, korzystając z biblioteki PySerial, odbiera komunikaty przesyłane przez Arduino. Następnie, korzystając z biblioteki PyAutoGui, są one konwertowane do komunikatów z emulowanej klawiatury. Pozwala to na sterowanie dowolnym oprogramowaniem na komputerze PC bez potrzeby komunikowania się z jego API czy wykonywania innych operacji – skrypt po prostu udaje klawiaturę.
Przewodzące pola w rękawiczce do rozpoznawania gestów
Kolejny projekt zawiera rękawiczkę z przewodzącymi polami, która została użyta do rozpoznawania prostych, predefiniowanych gestów, polegających na stykaniu ze sobą poszczególnych palców. Rękawiczka wyposażona jest w styki na każdym z palców, a moduł Arduino próbkuje poszczególne kombinacje i rozpoznaje, które dwa palce zostały ze sobą zetknięte. Na fotografii 2 pokazano rękawiczkę, będącą przedmiotem tego projektu.
Po wykryciu jednego z ustalonych gestów, moduł Arduino wysyła do odbiornika komunikat poprzez interfejs podczerwony. Dzięki temu odbiornik, sterujący przekaźnikiem, do którego podłączona jest żarówka, może ją zapalać w pełni w oparciu o wykonywane dłonią gesty. Algorytm rozpoznawania gestów jest w tym wypadku również bardzo prosty i oparty na instrukcjach warunkowych. Nie zmienia to faktu, że pozwala na zbudowanie bardzo funkcjonalnego systemu i (z odrobiną zdolności programistycznych) rozpoznawanie szerokiej palety gestów.
Sensory PIR do rozpoznawania gestów
Pasywny czujnik podczerwieni (czujnik PIR) to czujnik elektroniczny, który mierzy światło podczerwone (IR) promieniujące z obiektów znajdujących się w jego polu widzenia. Najczęściej stosowane są w czujkach ruchu. Wszystkie obiekty o temperaturze powyżej zera bezwzględnego emitują energię cieplną w postaci promieniowania. Zazwyczaj promieniowanie to nie jest widoczne dla ludzkiego oka, ponieważ dla temperatur, jakie nas na ogół otaczają, przypada w zakresie fal podczerwonych, ale może ono być wykryte przez urządzenia elektroniczne zaprojektowane specjalnie do tego celu. Termin pasywny w tym przypadku odnosi się do faktu, że urządzenia PIR nie generują promieniowania do celów wykrywania ruchu. Działają całkowicie poprzez wykrywanie promieniowania podczerwonego emitowanego przez lub odbitego od poruszających się obiektów. Nie wykrywają ani nie mierzą też ciepła.
Sensor TPA81 to macierz termoelektryczna wykrywająca podczerwień w zakresie spektralnym od 2 µm do 22 µm. Jest to długość fali promieniowania cieplnego. Czujniki piroelektryczne, które są powszechnie używane w alarmach przeciwwłamaniowych i do włączania światła zewnętrznego, wykrywają podczerwień w tym samym paśmie. Czujniki te mogą jednak wykryć tylko zmiany poziomu ciepła – dlatego są one jedynie czujnikami ruchu. Chociaż są przydatne w robotyce, ich zastosowania są ograniczone, ponieważ nie są w stanie wykryć i zmierzyć temperatury statycznego źródła ciepła. Innym rodzajem czujnika jest tzw. macierz termoelektryczna. Są one stosowane w bezdotykowych termometrach na podczerwień. Mają bardzo szeroki kąt widzenia (FOV) równy około 100° i wymagają osłony lub soczewki (zazwyczaj tego i tego ), aby uzyskać bardziej użyteczny FOV na poziomie 12°, co pozwala dosyć dobrze ukierunkować sensor. Co więcej niektóre mają nawet wbudowany obiektyw.
Niedawno pojawiły się czujniki z szeregiem termostosów, wbudowaną elektroniką i soczewką krzemową. Przykładem takiego elementu jest właśnie wspominany sensor TPA81. Ma on macierz ośmiu termostosów ułożonych w rzędzie. TPA81 może jednocześnie mierzyć temperaturę 8 sąsiednich punktów. Może również sterować serwomechanizmem do obracania modułu i tworzenia obrazu termicznego. Sensor TPA81 może wykryć płomień świecy, znajdującej się w zasięgu do 2 metrów i nie ma na niego wpływu światło otoczenia. Na fotografii 3 pokazano układ, jaki zbudowano do rozpoznawania gestów z zastosowaniem sensora na podczerwień.
Czujniki PIR są podobne do kamer termowizyjnych. W dużym uproszczeniu mówiąc, TPA81 to kamera termowizyjna o rozdzielczości 8 pikseli. Ciało ludzkie zawsze emituje ciepło, które widoczne jest dla tej kamery. Jeśli czujnik PIR jest dołączony do mikrokontrolera, może on umożliwić obserwację otoczenia w podczerwieni, a co za tym idzie na wykrywanie gestów. W tym projekcie utworzono system do wykrywania gestów z zastosowaniem matrycowego sensora PIR i modułu Arduino.
Autor konstrukcji użył wspomniany sensor TPA81, ale jeśli układ ten jest dla Was zbyt drogi nic nie stoi na przeszkodzie, aby zamiast niego zamontować osiem dyskretnych sensorów PIR. Na rysunku 2 pokazano schematy budowy obu układów.
Układ TPA81 komunikuje się poprzez interfejs I2C i jest kompatybilny z Arduino Nano. Opisany projekt pozwala poznać podstawy przetwarzania obrazu i wykrywania gestów z użyciem tej prostej platformy. W pierwszej kolejności należy zainstalować bibliotekę do komunikacji z TPA81. Pozwala ona odczytywać dane z sensora za pomocą modułu Arduino poprzez obiekt nazwany w listingu 2 tpa. Metoda tpa.getPoint(i) pozwala na odczytanie i-tego punktu. Dalsza część algorytmu widoczna jest na listingu. Utworzony algorytm jest już bardziej złożony, niż opisywane wcześniej podejścia. Mimo wszystko zawiera relatywnie prostą analizę numeryczną, do uzyskania klasyfikacji gestów. Po wykryciu konkretnego gestu, system wysyła komunikat do dalszych systemów, którymi ma sterować – w tym przypadku o konieczności zwiększenia bądź zmniejszenia głośności.
Serial.println("start gesture");
gcount = 0;
while (sum < 8) {
sum = 0;
for (int i = 0; i <= 7; i++) {
if (tpa.getPoint(i) > 29) {
Serial.print("# ");
gesture[i][gcount] = 1;
}
else {
Serial.print(". ");
gesture[i][gcount] = 0;
}
}
for (int y = 0; y <= 7; y++) {
sum += gesture[y][gcount]; // suma 8 pikseli
delay(5);
}
Serial.println(" ");
delay(50); // prędkość odczytu
gcount++; // długość gestu
}
Serial.print("suma : ");
Serial.println(sum);
Serial.print("długość gestu : ");
Serial.println(gcount);
delay(5);
for (int c = 0; c <= 7; c++) {
for (int z = 0; z <= gcount; z++) {
tgesture[c] += gesture[c][z];
delay(5);
}
Serial.println("processing");
}
tgesture[0] += tgesture[1];
tgesture[2] += tgesture[3];
tgesture[4] += tgesture[5];
tgesture[6] += tgesture[7];
tgesture[0] += tgesture[2];
tgesture[4] += tgesture[6];
if (tgesture[0] < tgesture[4]) {
vol += (gcount / 2);
Serial.print("volume up");
}
if (tgesture[4] < tgesture[0]) {
vol -= (gcount / 2);
Serial.print("volume down");
}
sflag = 0;
Rękawiczka z elastycznymi sensorami
Rękawiczka HANDTALK została zaprojektowana dla osób potrzebujących, chorych i starszych, jako metoda prostej komunikacji awaryjnej. W zależności od ruchów dłoni, urządzenie to zamienia gesty na sygnał dźwiękowy oraz na tekst, które transmitowane są przez GSM np. do opiekuna, personelu szpitalnego itp. HANDTALK wyczuwa ruchy za pomocą czujników zgięcia, które wykrywają różne wzorce ruchu dłoni. Urządzenie to potrafi dokładnie wyczuć każdy ruch ręką. Obecnie w systemie prototypowym zamontowano jedynie kilka sensorów, więc liczba stopni swobody i rozpoznawanych gestów jest ograniczona. W przyszłości, jak zapowiada autor, liczba sensorów może zostać rozszerzona. Prototyp konstrukcji pokazano na fotografii 4.
Schemat blokowy całego systemu został pokazany na rysunku 3. Analogowe czujniki Flex podłączone są do wejść A0...A3 modułu Arduino, jak pokazano na rysunku 4. Do Arduino podłączono także moduł GSM do komunikacji, ekran LCD, buzzer itp. Wszystkie gesty wykonywane w rękawiczce są konwertowane na różne komunikaty i komendy do obsługi urządzeń. Przykładowo, jeśli chcemy uruchomić wentylator to komenda jest wysyłana do odbiornika przez mikrokontroler z pomoc modułu radiowego. W przypadku, gdy użytkownik potrzebuję wody (lub wózka inwalidzkiego lub czegokolwiek innego), wystarczy, że wykona odpowiedni gest, a zostanie on zamieniony na np. SMS i przesłany drugiej osobie przez moduł GSM.
Rękawiczka, jako dodatkowa funkcja, mierzy także tętno, aby monitorować stan osoby i móc zawiadomić opiekuna w razie problemów.
System wykrywa obecnie siedem gestów. Jako klasyfikator zastosowano prosty Bayesowski klasyfikator pracujący na czterowymiarowym wektorze, złożonym z wartości analogowych, zmierzonych na wejściach analogowych. Nic jednak nie stoi na przeszkodzie, aby zastosować bardziej złożone rozwiązania programistyczne w celu wykrywania większej liczby gestów.
Scalony sensor gestów
Najpraktyczniejszym, chociaż niekoniecznie najciekawszym rozwiązaniem, jest wykorzystanie scalonego sensora gestów. Przykładem takiego elementu jest układ PAJ7620U2, dostępny na wielu modułach dla hobbystów, takich jak pokazany na fotografii 5 moduł Grove. Układ scalony PAJ7620U2 integruje w sobie sensor optyczny, układ rozpoznawania gestów, czujnik zbliżeniowy (aby wiedzieć, kiedy zbliżyliśmy dłoń do sensora). Wyposażony jest w interfejs cyfrowy I2C, co pozwala podłączyć go w prosty sposób np. do mikrokontrolera.
Korzystając z scalonego sensora rozpoznawać można nawet do 15 gestów. Na listingu 3 pokazano przykładowy szkic Arduino, który rozpoznaje 15 gestów użytkownika. Składają się one z dziewięciu podstawowych gestów, rozpoznawanych przez układ:
- przesunięcie ręki w górę,
- przesunięcie ręki w dół,
- przesunięcie ręki w lewo,
- przesunięcie ręki w prawo,
- przybliżenie dłoni,
- oddalenie dłoni,
- obrót zgodnie z kierunkiem ruchu wskazówek zegara,
- obrót przeciwnie do kierunku ruchu wskazówek zegara,
- falowanie dłonią.
void setup() {
Serial.begin(9600); // Inicjalizacja portu szeregowego
paj7620Init(); // Inicjalizacja układy PAJ7620
}
void loop() {
uint8_t data = 0, data1 = 0, error;
error = paj7620ReadReg(0x43, 1, &data); // Odczyt danych gestu
if (!error) {
switch (data) { // Analiza danych
case GES_RIGHT_FLAG:
delay(GES_REACTION_TIME); // Odczyt drugiego gestu
paj7620ReadReg(0x43, 1, &data);
if (data == GES_LEFT_FLAG) {
Serial.println("Right-Left");
} else if (data == GES_FORWARD_FLAG) {
Serial.println("Forward");
delay(GES_QUIT_TIME);
} else if (data == GES_BACKWARD_FLAG) {
Serial.println("Backward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Right");
}
break;
case GES_LEFT_FLAG:
delay(GES_REACTION_TIME);
paj7620ReadReg(0x43, 1, &data);
if (data == GES_RIGHT_FLAG) {
Serial.println("Left-Right");
} else if (data == GES_FORWARD_FLAG) {
Serial.println("Forward");
delay(GES_QUIT_TIME);
} else if (data == GES_BACKWARD_FLAG) {
Serial.println("Backward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Left");
}
break;
break;
case GES_UP_FLAG:
delay(GES_REACTION_TIME);
paj7620ReadReg(0x43, 1, &data);
if (data == GES_DOWN_FLAG) {
Serial.println("Up-Down");
} else if (data == GES_FORWARD_FLAG) {
Serial.println("Forward");
delay(GES_QUIT_TIME);
} else if (data == GES_BACKWARD_FLAG) {
Serial.println("Backward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Up");
}
break;
case GES_DOWN_FLAG:
delay(GES_REACTION_TIME);
paj7620ReadReg(0x43, 1, &data);
if (data == GES_UP_FLAG) {
Serial.println("Down-Up");
} else if (data == GES_FORWARD_FLAG) {
Serial.println("Forward");
delay(GES_QUIT_TIME);
} else if (data == GES_BACKWARD_FLAG) {
Serial.println("Backward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Down");
}
break;
case GES_FORWARD_FLAG:
delay(GES_REACTION_TIME);
paj7620ReadReg(0x43, 1, &data);
if (data == GES_BACKWARD_FLAG) {
Serial.println("Forward-Backward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Forward");
delay(GES_QUIT_TIME);
}
break;
case GES_BACKWARD_FLAG:
delay(GES_REACTION_TIME);
paj7620ReadReg(0x43, 1, &data);
if (data == GES_FORWARD_FLAG) {
Serial.println("Backward-Forward");
delay(GES_QUIT_TIME);
} else {
Serial.println("Backward");
delay(GES_QUIT_TIME);
}
break;
case GES_CLOCKWISE_FLAG:
Serial.println("Clockwise");
break;
case GES_COUNT_CLOCKWISE_FLAG:
Serial.println("anti-clockwise");
break;
default:
paj7620ReadReg(0x44, 1, &data1);
if (data1 == GES_WAVE_FLAG) {
Serial.println("wave");
}
break;
}
}
delay(100);
}
Dodatkowe sześć gestów, to złożenia w/w gestów, wykonywanych jeden po drugim. Szkic jest bardzo prosty. W pierwszej kolejności układ jest inicjalizowany funkcją paj7620Init() a następnie w pętli układ zbiera dane odczytując rejestr 0x43 –paj7620ReadReg(0x43, 1 &data), do zmiennej data. Dalsza część skryptu to analiza – po wykryciu pierwszego gestu układ odczekuje krótki czas, aby ponownie odczytać gest, co pozwala na wykrywanie bardziej złożonych ruchów, np. poruszenia dłoni w lewo i z powrotem w prawo, czyli machanie nią na boki. Po wykryciu konkretnego gestu, Arduino przesyła informację przez interfejs szeregowy.
Podsumowanie
Powyższe projekty pokazują jak różnorodny jest świat rozpoznawania gestów. Jest to idealny interfejs człowiek maszyna, który pozwala na kontrolowanie w naturalny sposób urządzeń elektronicznych. Istnieje wiele różnorodnych podejść, sensorów i algorytmów, jakie można zastosować, aby skonstruować interfejs oparty na rozpoznawaniu gestów.
Dzięki temu, że interfejsy rozpoznawania gestów są tak różnorodne, można implementować je w szerokim spektrum urządzeń – od niewielkich, mobilnych systemów opartych na 8-bitowych mikrokontrolerach, po duże urządzenia z procesorami aplikacyjnymi itp. Do każdego z nich znajdzie się odpowiednie rozwiązanie do wykrywania gestów, dzięki czemu można istotnie usprawnić interfejs użytkownika ciekawym rozwiązaniem. W zasadzie każdy z powyższych systemów, nadaje się do prostej aplikacji we własnym projekcie.
Nikodem Czechowski, EP
Bibliografia:
- https://bit.ly/3jwUJ3i/
- https://bit.ly/3qDqgSC
- https://bit.ly/2Uk7Dr6
- https://bit.ly/2SFIxlZ
- https://bit.ly/3qFyB8I
- S. Mitra, T. Acharya, „Gesture Recognition: A Survey”, IEEE Transactions on Systems, Man And Cybernetics 37 (2007).
- https://bit.ly/360XOkm