Joystick dostarcza na wyjściu dwa sygnały napięciowe, których poziomy są proporcjonalne do wychylenia jego elementu sterującego: czy to drążka czy przesuwnego ślizgacza. Do wytworzenia sygnałów służą zamontowane w joysticku potencjometry. Każdy potencjometr reaguje na ruch elementu sterującego w jednej z dwu osi: X lub Y. W ten sposób sygnały na wyjściu mogą odwzorowywać kierunek ruchu na dwuwymiarowej płaszczyźnie.
Na fotografii 1 zostały pokazane przykładowe miniaturowe joysticki analogowe. Element oznaczony literą A jest sterowany przy pomocy drążka zakończonego nasadką, pozwalającą na wygodną manipulację palcami.
Sygnały joysticka wyprowadzone są na 5-stykowym złączu. Funkcje poszczególnych wyprowadzeń zostały pokazane na rysunku 1. Wyprowadzenie GND łączy się z masą układu a +V z napięciem odniesienia np. 5 V. Sygnały wyjściowe są dostępne na stykach VRx i VRy. Wyjście SW połączone jest z dodatkowym przyciskiem. Przycisk zwiera do masy po przyciśnięciu drążka joysticka i może być użyty jako sygnał zatwierdzenia.
Na fotografii 1B pokazany został typ joysticka, w którym ścieżki potencjometrów zostały napylone bezpośrednio na płytce stanowiącej część obudowy. Elementem sterującym zamiast drążka jest przesuwana palcem płytka, połączona mechanicznie ze ślizgaczami poruszającymi się po ścieżkach potencjometrów.
Na rysunku 2 pokazano widok elementu od dołu wraz z rozmieszczeniem sygnałów na złączu. Do GND i +V doprowadza się napięcie odniesienia, a sygnały wyjściowe są dostępne na stykach VRx i VRy.
Joystick zamiast myszki
Taki analogowy joystick można przystosować do poruszania kursorem po ekranie komputera. Potrzebny jest do tego moduł ESP32 z odpowiednim oprogramowaniem. Tym razem część radiowa modułu nie będzie pracowała w trybie Wi-Fi lecz zostanie użyta jako bezprzewodowy interfejs Bluetooth LE. Litery LE oznaczają, że będzie uruchomiony tryb pracy z niskim poborem mocy (moduł ESP32 może także pracować w trybie „starego” Bluetootha, oba rozwiązania nie są ze sobą kompatybilne).
Sposób połączenia joysticka analogowego z modułem ESP32 został pokazany na rysunku 3. Napięcie odniesienia pobierane jest z wyprowadzenia modułu dostarczającego napięcie 3,3 V. Wybrano tą wartość ponieważ wewnętrzny przetwornik ADC modułu pracuje z takim poziomem, a wyprowadzenia joysticka VRx i VRy podłączone są do wejść tego przetwornika.
Całą pracę przekształcania zmian poziomów napięć odczytywanych z wyjść joysticka na ruch kursora wykonuje oprogramowanie. Jego główną część stanowi biblioteka dla systemu Arduino o nazwie ESP32-BLE-Mouse, można ją pobrać tu [1]. Biblioteka realizuje obsługę typowych zdarzeń związanych z myszą komputerową: reaguje na kliknięcie lewym, środkowym, prawym przyciskiem myszy, a także na naciskanie przycisków wstecz i dalej. Jest obsługiwane kółko przewijania no i oczywiście ruch myszy przekładany na ruch kursora na ekranie. Składnia poleceń biblioteki ESP32-BLE-Mouse jest podobna do składni języka Arduino w bibliotece dla myszy USB, którą opisano tutaj [2].
Przykładowa komenda poruszająca kursorem o żądaną ilość pikseli w stosunku do pozycji bieżącej wygląda tak:
BleMouse bleMouse;
bleMouse.move(xVal, yVal, wheel);
gdzie:
- xVal – wartość przesunięcia wzdłuż osi X, dozwolona jest wartość typu char dodatnia lub ujemna,
- yVal – wartość przesunięcia wzdłuż osi Y, dozwolona jest wartość typu char dodatnia lub ujemna,
- wheel – wartość przesunięcia kółkiem, dozwolona wartość typu char dodatnia lub ujemna.
W ogólnym zarysie program dla joysticka symulującego działanie myszy komputerowej może wyglądać tak jak na listingu 1.
#include <BleConnectionStatus.h>
#include <BleMouse.h>
BleMouse bleMouse;
const int VRxPin = 34;//wejście ADC, wyjscie joysticka VRx
const int VRyPin = 35;//wejście ADC, wyjscie joysticka VRy
int potValueX = 0, potValueY = 0;//wartosci po konwersji ADC
char wektorX=0, wektorY=0;//wartosci przesuniec kursora
int pauza;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
bleMouse.begin();
Serial.println(“Start BLE!”);
delay(500);
}
void loop() {
// put your main code here, to run repeatedly:
potValueX = analogRead(VRxPin);
potValueY = analogRead(VRyPin);
/*
tutaj procedura konwersji poziomow napiec odczytanych
z wyjsc joysticka na przesuniecie kursora
bool stat_poz = KonwersjaADC_przesuwKursora(
&pauza, &wektorX, &wektorY, potValueX, potValueY);
*/
if (bleMouse.isConnected())
{
bleMouse.move(wektorY,wektorX);
}
delay(pauza);
}
W rzeczywistości trzeba go rozbudować o kilka dodatkowych procedur: rozpoznawania bezruchu – gdy joystick pozostaje w pozycji środkowej, detekcji kierunku ruchu kursora oraz szybkości jego przesuwania co zamyka się w głównej procedurze konwersji sygnałów odczytywanych z joysticka na wartości X, Y jego przesunięcia.
/* Program symulujący mysz przy pomocy joystika analogowego
* podłączenie za pośrednictwem ESP32 BlueTooth LE
* v.1-04 */
#include <BleConnectionStatus.h>
#include <BleMouse.h>
BleMouse bleMouse;
const int VRxPin = 34;
const int VRyPin = 35;
int potValueX = 0, potValueY = 0;
int centrum_PortX, centrum_PortY, licznik_usrednienia;
#define ILE_USREDNIEN 50
bool stat_centr;
int pauza;
int wektorX=0, wektorY=0;
static double przesuw_x_ulamek=0, przesuw_y_ulamek=0;
bool WyliczCentrumXY(int ValueX, int ValueY);
bool KonwersjaADC_przesuwKursora(
int *p_pauza, int *p_wektorX, int *p_wektorY, int ValueX, int ValueY);
double ObliczPrzesuw(int przesuw,bool przesuw_plus,double przesuw_ulamek);
//double ObliczPrzesuw1(int przesuw,bool przesuw_plus,double przesuw_ulamek);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Starting BLE work!");
bleMouse.begin();
centrum_PortX = 0;
centrum_PortY = 0;
licznik_usrednienia = 0;
delay(500);
}
void loop() {
// put your main code here, to run repeatedly:
potValueX = analogRead(VRxPin);
potValueY = analogRead(VRyPin);
stat_centr = WyliczCentrumXY(potValueX, potValueY);
if (stat_centr==false) {
pauza =10;
} else {
bool stat_poz = KonwersjaADC_przesuwKursora(
&pauza, &wektorX, &wektorY, potValueX, potValueY);
Serial.println("pauza, x, y, potX, potY");
Serial.print(pauza); Serial.print(" ;");
Serial.print(wektorX); Serial.print(" ;");
Serial.print(wektorY); Serial.print(" ;");
Serial.print(potValueX);Serial.print(" ;");
Serial.println(potValueY);
if (bleMouse.isConnected()) {
bleMouse.move(wektorY,wektorX);
}
delay(pauza);
}
/* wyliczanie centrum X,Y poprzez uśrednione pomiary
we: wartości odczytane z przetwornika dla portów X i Y joystika
wy: true -centra XY wyliczone */
bool WyliczCentrumXY(int ValueX, int ValueY) {
if (licznik_usrednienia >= ILE_USREDNIEN) return true;
centrum_PortX += ValueX;
centrum_PortY += ValueY;
licznik_usrednienia++;
if (licznik_usrednienia >= ILE_USREDNIEN) {
centrum_PortX = centrum_PortX / licznik_usrednienia;
centrum_PortY = centrum_PortY / licznik_usrednienia;
return true;
} else return false;
}
/* konwersja wartości ADC X i Y na przesunięcie kursora
wy: true -ruch kursora */
bool KonwersjaADC_przesuwKursora(int *p_pauza, int *p_wektorX,
int *p_wektorY, int ValueX, int ValueY) {
#define PAUZA_MS_MAX 50
#define PAUZA_MS_MIN 10
#define CENTRUM_ZERO_ADC 300
bool przesuw_plus_x, przesuw_plus_y;
int przesuw_x, przesuw_y;
double wspolcz;
//wyznaczanie kierunku ruchu kursora w osi X i Y
przesuw_x = centrum_PortX - ValueX;
//odwrócenie kierunku przesuwu w osi X
if (przesuw_x < 0) przesuw_plus_x = true;
//dla joystika analogowego typu Thumb Slide Joystick
//- SparkFun COM-09426
else przesuw_plus_x = false;
przesuw_y = centrum_PortY - ValueY;
if (przesuw_y < 0) przesuw_plus_y = false;
else przesuw_plus_y = true;
//określenie czy pozycja absolutna przesunięć obu wektorów
//znajduje się w obszarze centrum
przesuw_x = abs(przesuw_x);
przesuw_y = abs(przesuw_y);
if ((przesuw_x <= CENTRUM_ZERO_ADC) && (przesuw_y <= CENTRUM_ZERO_ADC)) {
//pozycja joystika w strefie zerowego ruchu
*p_pauza = 50;
*p_wektorX = 0;
*p_wektorY = 0;
przesuw_x_ulamek=0;
przesuw_y_ulamek=0;
return false;
} else {
if (przesuw_x>CENTRUM_ZERO_ADC) {
/* to procedura symulacji dla testów
* if (przesuw_plus_x==false) *p_wektorX =-1 *2;
* else *p_wektorX =1 *2;
*/
przesuw_x_ulamek =ObliczPrzesuw(przesuw_x,przesuw_plus_x,przesuw_x_ulamek);
*p_wektorX =przesuw_x_ulamek;
przesuw_x_ulamek-=*p_wektorX;
} else *p_wektorX =0;
if (przesuw_y>CENTRUM_ZERO_ADC) {
/*
* to procedura symulacji dla testów
* if (przesuw_plus_y==false) *p_wektorY =-1 *2;
* else *p_wektorY =1 *2;
*/
przesuw_y_ulamek =ObliczPrzesuw(przesuw_y,przesuw_plus_y,przesuw_y_ulamek);
*p_wektorY =przesuw_y_ulamek;
przesuw_y_ulamek-=*p_wektorY;
}
else *p_wektorY =0;
*p_pauza =1;
return true;
}
}
/* obliczanie przesuwu w funkcji wychylenia joystika */
double ObliczPrzesuw(int przesuw,bool przesuw_plus,double przesuw_ulamek) {
const int delta_stopien_tab[]={CENTRUM_ZERO_ADC+300,CENTRUM_ZERO_ADC+700,
CENTRUM_ZERO_ADC+800,CENTRUM_ZERO_ADC+1000};
const double delta_mnoznik_tab[]={0.33,0.66,1,1.5,2.0};
const char ile_delta=4;
char x;
double ulamek;
for (x=0;x<ile_delta;x++) {
if (przesuw <delta_stopien_tab[x]) break;
}
ulamek =delta_mnoznik_tab[x];
if (przesuw_plus==false) ulamek =0-ulamek;
return przesuw_ulamek+ulamek;
}
Takie kompletne oprogramowanie dla środowiska Arduino zostało pokazane na listingu 2 i jest dostępne do pobrania tu [3].
Ryszard Szymaniak
biuro@ars.info.pl
[1] źródła biblioteki ESP32-BLE-Mouse: https://bit.ly/3spEERC
[2] opis składni poleceń arduinowej biblioteki myszy: https://bit.ly/3GYOkXa
[3] strona internetowa z programem demonstracyjnym: https://bit.ly/32kKxVk