2025 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2025-01-13 06:58
Wstęp
Magiczna ręka pozwala osobom niepełnosprawnym i upośledzonym ruchowo cieszyć się kreatywnością rysowania i pisania w symulowanym środowisku. Magiczna Dłoń to rękawica do noszenia, która wyczuwa ruch palca wskazującego i przekłada to na rysowanie linii na ekranie komputera.
Potrzebne materiały
LSM9DOF Breakout Board --- 24,95 USD ---
Piórko Adafruit z Wi-Fi --- 18,95 USD ---
Przewody żeńskie/żeńskie --- 1,95 USD ---
Taśmy / paski na rzep --- 3 USD
Dwa magnesy o równej sile --- Ceny różnią się
Jak to działa
Za pomocą akcelerometru możemy zebrać dane dotyczące przyspieszenia osi y, które pomogą nam określić, kiedy palec użytkownika porusza się w górę iw dół. Ze względu na to, że nasz akcelerometr mierzy przyspieszenie względem środka Ziemi, nie możemy określić przyspieszenia osi x (lewej lub prawej). Na szczęście tabliczka zaciskowa LSM9DOF zawiera również magnetometr, który pozwala nam zbierać dane o polach magnetycznych. Umieszczamy dwa magnesy w odległości 30 cm i między nimi mamy rękawicę. Jeśli dane magnetyczne są dodatnie, wiemy, że rękawica porusza się w prawo i odwrotnie. Po zebraniu wszystkich danych w akcelerometrze/magnetometrze, przesyła on dane przewodem do pióra, które jest podłączone do komputera Wi-Fi, a następnie przesyła dane do komputera, który możemy następnie wykorzystać w naszym kodzie.
Krok 1: Fizyczny prototyp 1
Ten prototyp ma być zszytymi luźno rękawiczkami na dłoni, aby mógł nasunąć się na urządzenia elektroniczne. Urządzenie elektroniczne zostanie następnie przymocowane rzepem do podstawy rękawa pod zbroją w połączeniu z podstawową rękawicą na dłoni. Wtedy zielona rękawiczka ześlizgnie się na podstawę i urządzenia elektroniczne….
Etapy wykonania prototypu rękawicy:
- Zdobądź dwa kawałki materiału wystarczająco duże, aby prześledzić rękę
- Narysuj dłoń na obu kawałkach materiału i wytnij je
- Połącz dwa wycięcia na dłonie, aby były idealnie dopasowane
- Następnie, aby przygotować maszynę do szycia, przeciągnij nić przez wskazane miejsca na maszynie
- Po ustawieniu maszyny do szycia podnieś igłę i umieść dwa połączone kawałki materiału pod igłą
- Upewnij się, że igła jest wyrównana na samym brzegu materiału, uruchom maszynę i zszyj wzdłuż brzegów materiału, pozostawiając dwie części nie zszyte na nadgarstku, aby ręka mogła się zmieścić.
Krok 2: Fizyczny prototyp 2
Nasz ostateczny prototyp to zwykła rękawica połączona z paskiem na rzep, który można dopasować do każdego nadgarstka. Rękawica i pasek są zszyte, a urządzenia elektroniczne przymocowane do rękawicy za pomocą rzepa.
Etapy wykonania drugiego prototypu rękawicy:
- Kup rękawicę, materiał rękawicy nie ma znaczenia.
- Kup pasek na nadgarstek z rzepem
- Kup przenośną baterię
- Kup Sticky Velcro
- Za pomocą igły do szycia przymocuj pasek na nadgarstek z rzepem do podstawy rękawicy
- Pasek na nadgarstek powinien być w stanie dopasować się do różnych rozmiarów nadgarstka.
- Przymocuj taśmę klejącą do podstawy akcelerometru i przymocuj ją do palca wskazującego rękawicy
- Przyklej taśmę klejącą do pióra i przymocuj ją do górnej części rękawicy.
- Za pomocą przewodów połącz pin 3V3 w piórku z pinem VIN w akcelerometrze
- Za pomocą przewodów połącz pin GND w piórku z pinem GND akcelerometru.
- Za pomocą przewodów połącz pin SCL w piórku z pinem SCL akcelerometru.
- Za pomocą przewodów połącz pin SDA w piórze z pinem SDA akcelerometru.
- Podłącz co najmniej 5-woltową baterię przez USB do pióra, aby zapewnić zasilanie.
Krok 3: Magnesy
Krok 1: Umieść dwa magnesy o jednakowej sile naprzeciwko siebie.
Krok 2: Odmierz 30 cm odstępu między dwoma magnesami
Krok 3: umieść magnetometr dokładnie pośrodku dwóch magnesów. Powinieneś otrzymać dane około 0, gdy jest w środku. Jeśli otrzymasz odczyt równy zero, przejdź do kroku 5.
Krok 4: Jeśli odczyt nie jest zerowy lub bliski zera, musisz dostosować odległość magnesów. Jeśli odczyt jest ujemny, przesuń lewy magnes o cm lub 2 w lewo lub aż odczyt wyniesie zero. Jeśli jest pozytywny, zrób to samo, z wyjątkiem właściwego magnesu.
Krok 5: Napisz kod, który akceptuje dane z magnetometru i odczytuje, czy jest dodatni, czy ujemny. Jeśli kod jest dodatni, narysuj linię w prawo, a jeśli ujemny, narysuj linię w lewo.
Krok 4: Kod
github.iu.edu/ise-e101-F17/MuscleMemory-Sw…
Wstęp:
Aby przetworzyć dane z akcelerometru, należy ustanowić relację klient/serwer pomiędzy piórkiem Adafruit a serwerem przetwarzającym dane (działającym na laptopie/komputerze). Trzeba będzie stworzyć dwa pliki kodu: jeden dla klienta (piórko Adafruit), a drugi dla serwera (w tym przypadku laptopa Jaroda). Klient jest napisany w C++, a serwer w Pythonie. Język używany dla klienta ma znaczenie, ponieważ Arduino to głównie język C++, a zmiana go na inny język jest trudna. Serwer może być napisany w dowolnym języku, o ile posiada funkcje sieciowe.
Konfiguracja Klienta:
Najpierw skonfigurujemy kod klienta. Większość kodu połączenia Wi-Fi jest łatwo dostępna za pośrednictwem bibliotek Adafruit. Zaczynamy od włączenia odpowiednich klas.
#include #include #include #include #include
Ustaw kilka zmiennych, które będą używane w całym kodzie.
// Połącz się z siecią const char* ssid = "MMServer"; const char* hasło = "MMServer-Password"; // IP i port serwera, który otrzyma dane const char* host = "149.160.251.3"; const int port = 12347; bool podłączony = fałsz;
// Zainicjuj detektor ruchu
Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(1000);
Klient WiFiClient;
Utwórz funkcję setup(), która zostanie uruchomiona, gdy tylko zacznie się wtapianie.
// Skonfiguruj połączenie WiFi i połącz się z serwerem. setup() { Serial.begin(9600); opóźnienie (100);
Serial.println();
Serial.println(); Serial.print("Łączenie z"); Serial.println(ssid); // Uruchom WiFi WiFi.begin(ssid, hasło); // Łączenie… while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Pomyślnie połączono z WiFi Serial.println(""); Serial.println("Połączenie WiFi"); Serial.println("adres IP: "); Serial.println(WiFi.localIP());
#ifndef ESP8266
while(!Serial); #endif Serial.begin(9600); Serial.println("Test czujnika");
// Zainicjuj czujnik
if(!lsm.begin()) { // Wystąpił problem z wykryciem LSM9DS0 Serial.print(F("Ups, nie wykryto LSM9DS0… Sprawdź okablowanie lub I2C ADDR!")); natomiast(1); } Serial.println(F("Znaleziono LSM9DS0 9DOF")); // Rozpocznij połączenie z serwerem Serial.print("Łączenie z "); Serial.println(host);
// Sprawdź pomyślne połączenie. Jeśli się nie powiedzie, przerwij
if (!client.connect(host, port)) { Serial.println("połączenie nie powiodło się"); połączony = fałsz; powrót; } else { połączony = prawda; }
//Ustaw wzmocnienie czujnika i czas integracji
configureSensor(); }
Następnie potrzebujemy funkcji pętli, która będzie wielokrotnie zapętlać. W tym przypadku służy do wielokrotnego przesyłania danych z akcelerometru na serwer w postaci „[z_accel]:[y_mag]:[z_mag]”. Klient.print(liczby); funkcja jest tym, co wysyła dane do serwera.
void loop() { opóźnienie(250); if(connected){ // Spowoduje to wysłanie danych do serwera sensor_event_t accel, mag, gyro, temp; lsm.getEvent(&akceleracja, &mag, &żyroskop, &temp); Numery ciągów; liczby += akceleracja.przyspieszenie.z; liczby += ":"; liczby += mag.magnetyczny.y; liczby += ":"; liczby += mag.magnetyczny.z; Serial.print(liczby); klient.print(liczby); Serial.println(); } else { ustanawianiePołączenia(); } }
W przypadku niektórych funkcji narzędziowych potrzebujemy go do ustanowienia połączenia między piórem a serwerem.
void EstablishConnection(){ if (!client.connect(host, port)) { Serial.println("połączenie nie powiodło się"); połączony = fałsz; powrót; } else { połączony = prawda; } }
Musimy również skonfigurować czujnik i podać mu zakres wartości, które będzie odczytywał. Na przykład przyspieszenie ma 5 opcji dla zakresu: 2g, 4g, 6g, 8g i 16g.
void configureSensor(void){ // Ustaw zakres akcelerometru //lsm.setupAccel(lsm. LSM9DS0_ACCELRANGE_2G); lsm.setupAccel(lsm. LSM9DS0_ACCELRANGE_4G); //lsm.setupAccel(lsm. LSM9DS0_ACCELRANGE_6G); //lsm.setupAccel(lsm. LSM9DS0_ACCELRANGE_8G); //lsm.setupAccel(lsm. LSM9DS0_ACCELRANGE_16G); // Ustaw czułość magnetometru //lsm.setupMag(lsm. LSM9DS0_MAGGAIN_2GAUSS); //lsm.setupMag(lsm. LSM9DS0_MAGGAIN_4GAUSS); //lsm.setupMag(lsm. LSM9DS0_MAGGAIN_8GAUSS); lsm.setupMag(lsm. LSM9DS0_MAGGAIN_12GAUSS);
// Skonfiguruj żyroskop
lsm.setupGyro(lsm. LSM9DS0_GYROSCALE_245DPS); //lsm.setupGyro(lsm. LSM9DS0_GYROSCALE_500DPS); //lsm.setupGyro(lsm. LSM9DS0_GYROSCALE_2000DPS); }
Konfiguracja serwera:
Serwer będzie plikiem Pythona, który będzie działał w wierszu poleceń komputera. Aby rozpocząć, zaimportuj wymagane klasy.
import socketimport ponownie import pyautogui
gniazdo jest używane do pracy w sieci. re jest używany do manipulacji wyrażeniami regularnymi lub łańcuchami. pyautogui to biblioteka Pythona, która pozwoli na rysowanie (omówione później).
Następnie powinniśmy zdefiniować kilka zmiennych. Będą to zmienne globalne, więc będą dostępne w wielu funkcjach. Zostaną użyte w dalszej części kodu.
i = 0n = 0 linia = 1
lista_danych =
mag_dane =
mag_calib_y = 0 mag_offset_y = 0
z_kalib = 0
z_przesunięcie = 0 z_przesunięcie_ruchu = 0 z_różnica = 0 z_rzeczywista = 0 z_velo = 0 z_poz = 0
zachowaj_przesunięcie = Fałsz
pierwsze_dane = Prawda
Potrzebujemy teraz funkcji do tworzenia serwera i otwierania go dla połączeń przychodzących.
def startServer(): globalne i globalne pierwsze_dane # zainicjuj gniazdo serwera serverocket = socket.socket(socket. AF_INET, socket. SOCK_STREAM) serverocket.setsockopt(socket. SOL_SOCKET, socket. SO_REUSEADDR, 1) # Adres IP serwera i host portu = " 149.160.251.3" port = 12347 adres_serwera = (host, port) # Otwórz serwer i nasłuchuj połączeń przychodzących print ('Uruchamianie serwera na porcie %s %s' % adres_serwera) serverocket.bind(adres_serwera) serverocket.listen(5) # Czekaj na połączenia… while True: print ('Oczekiwanie na połączenie…') # Zaakceptuj połączenie przychodzące (clientsocket, adres) = serverocket.accept() # Spróbuj przeanalizować otrzymane dane try: print ('Połączenie ustanowione z ', adres) while True: # Odbierz dane i wyślij je do przetwarzania dane = customersocket.recv(25) accel_data = re.split('[:]', str(data)) accel_data[0] = accel_data[0][2:] accel_data[1] = accel_data[1] accel_data[2] = accel_data[2][1:-1] print(accel_data) i+=1 if(i < 51): calibData(accel_data) else: moveAcce l(accel_data[0]) processData(accel_data) first_data = False w końcu: # Zamknij gniazdo, aby zapobiec niepotrzebnemu wyciekowi danych customersocket.close()
Teraz potrzebujemy funkcji, które będą przetwarzać wszystkie dane. Pierwszym krokiem, który należy wykonać i pierwszą wywołaną funkcją, jest kalibracja czujnika do celów obliczeniowych.
def calibData(list): global z_calib global z_offset global mag_data global mag_calib_y global mag_offset_y z_calib += float(list[0]) mag_calib_y += float(list[1]) if(i==50): z_offset = z_calib / 50 mag_offset_y = mag_calib_y / 50 z_calib = 0 mag_calib_y = 0 mag_data.append(mag_offset_y)
Następnie tworzymy przesunięcie przyspieszenia ruchu. Dzięki temu program rozpoznaje, kiedy ktoś przestaje poruszać palcem, ponieważ wszystkie wartości przyspieszenia wysyłane do serwera powinny być w tym czasie takie same.
def movingAccel(num): global z_calib global z_diff global z_moving_offset global z_offset global data_list global n global keep_offset if(n 0.2 lub z_diff < -0.2): # ruch wykryty w danych, uruchom ponownie keep_offset = True n = 0 z_calib = 0 z_moving_offset = 0 z_diff = 0 data_list = przerwa, jeśli nie zachowaj_przesunięcie: # nieruchome w danych, ustaw nowe z_offset z_offset = z_moving_offset print("Nowe z_offset: ") print(z_offset) n = 0 z_calib = 0 z_moving_offset = 0 z_diff = 0 data_list = keep_offset = False keep_offset = False
Następnie robimy główny ciężar matematyki. Wiąże się to z przetłumaczeniem danych przyspieszenia na dane pozycji, które pozwolą nam określić kierunek, w którym użytkownik porusza palcem.
def processData(list): #[accel.z, mag.y] global z_offset global z_real global z_velo global z_pos global first_data global mag_data
z_real = float(list[0]) - z_offset
mag_y = lista[1] mag_z = lista[2] left = False right = False # Nie przetwarzaj przyspieszenia, dopóki nie jest absolutnie pewien, że przyspieszyło # Zapobiega wpływowi hałasu mechanicznego na pozycję if(z_real -0.20): z_real = 0 #Begin integracje do znalezienia pozycji if(first_data): mag_data.append(mag_y) z_pos = (0.5 * z_real * 0.25 * 0.25) + (z_velo * 0.25) + z_pos z_velo = z_real * 0.25 pyautogui.moveTo(1500, 1000) else: z_pos = (0.5 * z_real * 0.25 * 0.25) + (z_velo * 0.25) + z_pos z_velo = (z_real * 0.25) + z_velo del mag_data[0] mag_data.append(mag_y) if(float(mag_data[1]) - float(mag_data[0]) > 0.03): right = True elif(float(mag_data[1]) - float(mag_data[0]) < -0.03): left = True if(right): movement(50, int(z_pos* 1000)) elif(po lewej): ruch(-50, int(z_pos*1000)) z_velo = 0 z_pos = 0
Teraz wreszcie przesuwamy kursor! Aby to zrobić, otworzyliśmy okno farby i ustawiliśmy je na pełnym ekranie. Biblioteka pyautogui zawiera funkcję o nazwie pyautogui.dragRel(x, y); którego używamy do przeciągania kursora myszy z jednego punktu do następnego. Wykorzystuje dane pozycji względnej, więc ruch jest względny do ostatniej pozycji kursora.
def ruch(x, y): print("przejście do", x, -y) pyautogui.dragRel(x, -y)
Na koniec musimy wywołać funkcję main, aby nawet umożliwić uruchomienie całego tego kodu.
# Wywołuje funkcję, aby rozpocząć serverstartServer()