3D Spherical Mouse sketch è la parte che, forse, da qualche settimana stavi aspettando.
Hai letto prima le parti maker del progetto, quelle relative all’idea, alla progettazione ed alla realizzazione 3D con la stampante FDM.
Se le altre componenti ti sono piaciute vedrai che in questa fase apprenderai alcune nozioni su arduino e sull’interfaccia HID molto interessanti.
Premessa 3D Spherical Mouse sketch
Il 3D Spherical Mouse sketch ha come premessa l’utilizzo di un Arduino Micro che, come hai letto nei precedenti articoli, si basa sull’Atmega32u4:
che ha tra le sue caratteristiche principali quella di non necessitare di un convertitore USB-Seriale, come sei abituato con l’Arduino Uno.
Della famiglia Arduino la prima board che ha beneficiato di questa particolarità è stata la Leonardo che utilizza il medesimo integrato core.
Insieme all’arduino Leonardo sono state rilasciate due librerie che per la prima volta si interfacciavano come Mouse o tastiera al computer, le due librerie sono:
- Mouse.h
- Keyboard.h
che trovi descritte sul sito arduino.cc nella sezione reference delle librerie:
e che puoi utilizzare anche con altre schede della famiglia Arduino tra cui la Micro, che puoi usare per questo progetto.
Grazie alla libreria Mouse.h la realizzazione è davvero semplice.
3D Spherical Mouse sketch
Passiamo al 3D Spherical Mouse sketch vero e proprio con il codice che segue:
#include "Mouse.h" #include <Adafruit_NeoPixel.h> #ifdef __AVR__ #include <avr/power.h> #endif const byte pinThumb = 5; const byte pinIndex = 6; const byte pinMiddle = 7; const byte pinRing = 3; const byte pinLittle = 5; const byte pinJoySw = 4; const byte pinJoyX = A1; const byte pinJoyY = A0; const byte pinThumbX = A3; const byte pinThumbY = A2; const boolean invertX = false; const boolean invertY = true; #define PIN 8 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, PIN, NEO_GRB + NEO_KHZ800); // parameters for reading the joystick: int range = 24; // output range of X or Y movement int responseDelay = 5; // response delay of the mouse, in ms int threshold = range / 12; // resting threshold int center = range / 2; // resting position value int wRange = 2; // output range of X or Y movement int wInterval = 10; // response delay of the wheel int wLoopCount= 0; int wThreshold = wRange / 2; // resting threshold int wCenter = wRange / 2; // resting position value boolean mouseIsActive = true; // whether or not to control the mouse byte defaultColor[3] = { 22,93,160 }; void setup() { Serial.begin( 115200 ); //while ( !Serial ) { ; } Serial.println( "Serial Start" ); pinMode(pinThumb,INPUT); pinMode(pinIndex,INPUT); pinMode(pinMiddle,INPUT); pinMode(pinRing,INPUT); pinMode(pinLittle,INPUT); pinMode(pinJoySw,INPUT); pinMode(pinJoyX,INPUT); pinMode(pinJoyY,INPUT); pinMode(pinThumbX,INPUT); pinMode(pinThumbY,INPUT); Serial.println( "Sketch Start" ); // take control of the mouse: Mouse.begin(); #if defined (__AVR_ATtiny85__) if (F_CPU == 16000000) clock_prescale_set(clock_div_1); #endif pixels.begin(); // This initializes the NeoPixel library. pixels.setPixelColor(0, pixels.Color(defaultColor[0],defaultColor[1],defaultColor[2])); // blue pixels.show(); } void loop() { int xReading = readAxis(pinJoyX); int yReading = readAxis(pinJoyY); int wReading = 0; if ( wLoopCount > wInterval ) { wReading = readWheel(pinThumbY); wLoopCount=0; } if (mouseIsActive) { Mouse.move(xReading, yReading, wReading); } buttonControl( pinIndex, 1 ); buttonControl( pinMiddle, 4 ); buttonControl( pinRing, 2 ); /************************* SET COLOR ****************************/ pixels.setPixelColor(0, pixels.Color((analogRead(pinJoyY)/4),(analogRead(pinJoyX)/4),(analogRead(pinThumbY)/4))); // red pixels.show(); /************************* SERIAL *******************************/ Serial.print("X: ");Serial.print( analogRead(pinJoyX) ); Serial.print(" "); Serial.print("Y:");Serial.print( analogRead(pinJoyY) ); Serial.print(" "); Serial.print("W:");Serial.print( analogRead(pinThumbY) ); Serial.print(" "); Serial.print("mX: ");Serial.print( xReading ); Serial.print(" "); Serial.print("mY:");Serial.print( yReading ); Serial.print(" "); Serial.print("mW:");Serial.print( wReading ); Serial.print("\n"); /****************************************************************/ wLoopCount++; delay(responseDelay); } void buttonControl( byte button, byte type ) { if (digitalRead(button) == HIGH) { if (!Mouse.isPressed(type)) { Mouse.press(type); } } else { // if the mouse is pressed, release it: if (Mouse.isPressed(type)) { Mouse.release(type); } } } int readAxis(int thisAxis) { // read the analog input: int reading = analogRead(thisAxis); if ( thisAxis == pinJoyX && invertX ) { reading = (1023-reading); } if ( thisAxis == pinJoyY && invertY ) { reading = (1023-reading); } // map the reading from the analog input range to the output range: reading = map(reading, 0, 1023, 0, range); // if the output reading is outside from the rest position threshold, use it: int distance = reading - center; if (abs(distance) < threshold) { distance = 0;} // return the distance for this axis: return distance; } int readWheel(int thisAxis) { int distance = (map(analogRead(thisAxis), 0, 1023, 0, wRange) - wCenter); if (abs(distance) < wThreshold) { distance = 0;} // return the distance for this axis: return distance; }
la prima linea include propio la liberia Mouse.h;
le linee 002-005: includono la libraria Adafruit Neopixel ed il controllo dell’architettura __AVR_ che imposta l’inclusione della avr/power.h
linee 007-018: definisci tutte le costanti di tipo byte a cui assegni i pin relativi ai 5 bottoni e switch di base a cui aggiungi i pin relativi gli assi X ed Y dei due Joystick;
linee 020-021: definisci due costanti di tipo boolean a ciascuna delle quali imposti se invertire o meno la direzione del corrispondente asse del joystick alla base, questa scelta ti consentirà di semplificare la configurazione del mouse una volta montato;
linea 023: definisci il PIN a cui è connesso il led NeoPixel;
linea 024: inizializza la libreria NeoPixel passandole in ordine: il numero di led ( 1 ), il pin a cui è connesso ( 8 ), la costante NEO_GRB + NEO_KHZ800 definita nella libreria stessa;
linee 028-037: imposta alcuni parametri di soglia e tempo di risposta per rendere il mouse più semplice da utilizzare e migliorare l’epserienza utente, analizzerai nel corso dello sketch l’uso di queste impostazioni;
linea 039: imposta la possibilità o meno di controllare il mouse mediante un tipo di variabile di tipo boolean;
linea 040: imposta il colore di default del led, quello utilizzato di base per il led ( 22,93,160 );
Le linee 043-047 del 3D Spherical Mouse sketch imposta il monitor Seriale;
linee 049-058: definisci le modalità di utilizzo dei pin, sono tutti impostati a INPUT in quanto acquisisci i segnali provenienti da ciascun sensore;
linea 062: inizializza l’istanza Mouse;
linee 064-066: impostano un diverso prescaled per i processori di tipo Attiny85;
linee 068-070: inizializza la comunicazione verso il led neopixel ws2812b, imposta il colore di default per tale led e visualizza il colore sul led;
linea 073: definisci la funzione di loop();
linee 074-075: leggi i valori relativi agli assi X ed Y usando la funzione readAxis a cui passi prima il pin relativo all’asse X del joystick e poi il pin relativo al all’asse Y;
linea 076: imposta, ad ogni ciclo di loop() il valore di una nuova variabile wReading;
linee 077-080: se il valore di wLoopCount supera il tempo impostato alla linea 34 ( wInterval ) il reimposta il valore di wReading leggendo il valore dell’asse Y del Joystick posto sotto il pollice e reimposta a 0 il valore di wCount;
Questo tipo di controllo serve a ridurre il valore di letture eseguite sul joystick presente sul 3D Spherical Mouse sketch in prossimità del pollice rispetto al numero di letture eseguite per lo spostamento degli assi X ed Y sullo schermo.
La linea 082: se il valore di mouseIsActive è true invia i valori di posizione rilavati dal mouse di base e dal mouse della sfera al computer mediante il metodo move() della classe Mouse.h;
linee 083-085: richiami 3 volte la funzione buttonControl passandole il pin di cui vuoi il valore ed il corrispondente da passare alla libreria Mouse.h;
linee 088-089: imposta il colore del led ws2812b in funzione dei valori letti sui tre assi del joystick ( 2 per il joystick in basso ed uno per il joystick in alto );
linea 100: incrementa ad ogni loop il valore di wLoopCount;
linea 101: imposta il delay, la pause di ciascun ciclo di loop, come definito alla linea 029;
Le funzioni del 3D Spherical Mouse sketch
il 3D Spherical Mouse sketch si avvale di alcune funzioni che semplificano la funzione di loop():
- buttonControl()
- readAxis()
- readWheel()
Leggi a cosa servono e come funzionano:
Funzione buttonControl
è la funzione che si occupa di trasferire il controllo dei bottoni installati sulla superficie del mouse al computer.
I parametri passati alla funzione sono:
- il pin relativo al pulsante da leggere;
- il valore da passare alla classe Mouse per impostare la pressione del corrispettivo pulsante;
La linea 107: legge il valore relativo al pin passato come primo valore e lo confronta con il valore HIGH per verificare se è stato premuto;
linea 108: verifica se il valore da passare alla libreria Mouse corrisponda o meno ad un pulsante già premuto ed in caso contrario simula la pressione di tale tasto usando il metodo press();
linea 109: in caso di mancata pressione del bottone esegue la successiva linea.
linea 111: esegue nuovamente la verifica di pressione del rispettivo bottone e nel caso lo fosse usa il metodo relese() per rilasciare il corrispondente bottone del mouse.
Semplicemente quindi la funzione verifica se sia già stato premuto un pulsante, inteso come simulazione di pressione del corrispondente bottone del mouse, e agisce in funzione del comando che riceve dalla tua pressione di uno dei bottoni.
Funzione readAxis
E’ la funzione più importante del 3D Spherical Mouse sketch in quanto legge il valore dell’asse corrispondente al pin passato come unico parametro della funzione e restituisce un valore di tipo intero dopo aver opportunamente valutato tale valore;
linea 117: leggi il valore analogico dell’asse relativo al pin passato come parametro;
linee 119-120: valuta il tipo di asse in modo da agire solo per il joystick alla base del mouse e lo confronta con la variabile boolean che definisce se invertire o meno il valore dell’asse corrispondente. Se il valore deve essere invertito tale valore viene sottratto dal valore massimo che puoi leggere su tale asse 1023;
linea 123: fai uso della funzione map per rimappare il valore letto nell’output da 0 a range ( definito alla linea 028) ;
linea 126: sottrae al valore ottenuto quello di centro definito alla linea 031;
linea 128: esegue la funzione abs() che calcola il valore assoluto di distanza e lo confronta con il valore di soglia ( threshold ) sotto la quale il valore di distanza è considerato nullo ed impostato a 0;
linea 131: restituisce il valore di distanza calcolato e termina la funzione.
Funzione readWheel
L’ultima funzione del 3D Spherical Mouse sketch è quella che legge i valori dell’asse Y del joystick presente sulla sfera.
La linea 136: esegui in una sola linea quello che nella funzione precedente eseguiva nelle linee 117,123,126;
linea 137: esegui la medesima operazione della linea 128;
linea 140: restituisce il valore di distanza calcolato.
Conclusione
Grazie alla libreria Mouse.h, come hai letto, lo sketch è davvero semplice e non devi preoccuparti di tutta la parte di interfaccia con il computer per far riconoscere il mouse 3d al computer.