🧪 Stanno arrivando nuovi tutorial — dal braccio robotico al sensore
Vai al contenuto
Acquista questo prodottoNegozio ufficialeSito ufficiale

Applicazione desktop SCS0009 (GUI e CLI) ​

Questa pagina è il tutorial del controllo desktop per la versione bus seriale SCS0009. Per il controllo web vedi Controllo web SCS0009, per il cablaggio hardware vedi Cablaggio SCS0009.

Avvio rapido ​

  1. Installa Python 3.10+ e le dipendenze: Installazione.
  2. Collega la scheda driver bus e verifica la porta seriale: Requisiti dell'ambiente.
  3. Avvia la GUI: amazing-hand-gui oppure python amazing_hand_gui.py.
  4. Segui Calibrazione per verificare mani, angoli e posizione centrale.
  5. Usa gli slider dito per dito, le pose predefinite e le sequenze per eseguire i movimenti.

Strumento di controllo Python AmazingHand (valido per mano sinistra e destra) ​

Strumento GUI e da riga di comando scritto in Python che controlla 8 servo Feetech SCS0009 tramite la scheda driver bus seriale, azionando la mano robotica AmazingHand di Pollen Robotics.

Sono supportate entrambe le mani. All'avvio scegli la mano destra (ID servo 1-8) o la mano sinistra (ID servo 11-18); --hand permette di saltare la domanda. La libreria di pose è condivisa tra le due mani; ogni mano mantiene in data/config.yaml la propria mappatura dei servo, l'offset di montaggio e i target dei valori raw. Per i dettagli vedi la selezione della mano.

Interfaccia principale dello strumento di controllo AmazingHand


Struttura del progetto ​

text
amazing_hand_gui.py   – Programma principale della GUI
amazing_hand_cmd.py   – Strumento da riga di comando
hand_logic.py         – Logica di business condivisa (indipendente dalla UI)
pyproject.toml        – Metadati del pacchetto, dipendenze, configurazione pytest
data/
  config.yaml         – Impostazioni dell'applicazione (seriale, limiti, target raw)
  hand_config.yaml    – Gesti e sequenze salvati
docs/
  REQUIREMENTS.md       – Requisiti e criteri di accettazione
  CONFIG_FORMAT.md      – Descrizione del formato del file di configurazione
  scs_servo_protocol.md – Riferimento ai registri SCS0009
  CHANGES.md            – Modifiche rispetto alla versione originale e relative motivazioni
  user_manual.md        – Pagina di reindirizzamento migrata al tutorial centrale
tests/
  test_hand_logic.py      – Test unitari di hand_logic (155 voci)
  test_gui_utils.py       – Test unitari delle funzioni di utilità della GUI (51 voci)
  test_cmd.py             – Test unitari della CLI (42 voci)
  test_integration.py     – Test di integrazione (14 voci)
  test_system.py          – Test di sistema su sottoprocesso (22 voci)
  test_system_hardware.py – Test hardware (33 voci, richiede --hardware)
  test_cmd_hardware.py    – Test hardware della CLI (21 voci, richiede --hardware)

Requisiti dell'ambiente ​

  • Python 3.10 o versione successiva (la GUI richiede Tkinter)
  • Alimentazione esterna 5V separata per gli 8 servo
  • Adattatore USB-seriale bus con driver installato

Installazione ​

Si consiglia l'installazione con pip (legge pyproject.toml):

bash
pip install -e .

Oppure installa direttamente le dipendenze:

bash
pip install -r requirements.txt

Ambiente di sviluppo e test:

bash
pip install -r requirements-dev.txt

Calibrazione ​

Il sistema di angoli dei servo, le pose predefinite e la posizione centrale dipendono dal singolo assemblaggio meccanico della mano. Questi parametri sono tutti concentrati in data/config.yaml.

Selezione della mano ​

Le due mani usano servo e strutture meccaniche diverse, quindi la scelta avviene prima che compaia l'interfaccia:

text
  AmazingHand — which hand?
    1 = right hand  (servo IDs 1-8)
    2 = left hand   (servo IDs 11-18)
  Enter 1 or 2 [1]:
  LEFT hand — servo IDs 11-18
    Ring (11, 12)  Middle (13, 14)  Pointer (15, 16)  Thumb (17, 18)
    middle position raw: [571, 451, 571, 451, 571, 451, 571, 451]

Per saltare la domanda:

bash
python amazing_hand_gui.py --hand left
python amazing_hand_cmd.py --pose victory --hand left

Senza --hand viene usato il valore hand: di data/config.yaml.

Perché una mano non è solo un cambio di gruppo di ID. Oltre alla numerazione dei servo (destra 1-8, sinistra 11-18, e la numerazione delle dita della mano sinistra è speculare — prima l'anulare), la mano sinistra ha due differenze meccaniche, gestite automaticamente dal programma:

Mano destraMano sinistra
ID servo1-811-18
Dito → IDindice 1,2 / medio 3,4 / anulare 5,6 / pollice 7,8anulare 11,12 / medio 13,14 / indice 15,16 / pollice 17,18
MiddlePos del produttore[451, 571, …][571, 451, …]
Offset di montaggio0°−35.16° (hands.left.angle_offset)
Doppio servo dello stesso dito(a, b)(b, a) (hands.left.mirror_pose)

Se manca una delle ultime due voci, ogni gesto si deforma: l'offset di montaggio fa deviare ogni dito di 35°, senza lo scambio tra i servo dello stesso dito la direzione di apertura si inverte completamente (le due dita del gesto a V si avvicinano, mentre le tre dita che dovrebbero stare unite si divaricano).

data/hand_config.yaml è condiviso da entrambe le mani e memorizza sempre l'ordine della mano destra; la mano sinistra converte in lettura e riconverte al salvataggio.

Calibrare una nuova mano. Prendi come modello i valori in hands.left, poi verifica in questo ordine:

  1. Premi Middle position e controlla se la riga Current (0-1023) legge il valore raw atteso
  2. Premi Open All / Close All — la corsa dovrebbe arrivare al finecorsa meccanico senza bloccarsi
  3. Prova un gesto di apertura (victory che forma una V, greeting con tre dita unite)

Se una voce non va bene, quale parametro regolare:

SintomoCosa modificare
Lettura di Middle position erratahands.<nome>.raw_positions.middle
Direzione di apertura invertitahands.<nome>.mirror_pose
Corsa insufficiente o eccessivahands.<nome>.raw_positions.open / close

Sistema di angoli ​

GUI e CLI usano entrambe valori angolari, che il driver rustypot converte nei valori raw interni del servo:

text
raw = 1024 × angle / 300° + 511        (0.29297°/step, intervallo raw 0–1023)
AngoloSignificato
−35°Completamente aperto (disteso)
0°Posizione centrale, dita naturalmente leggermente flesse
+75°Completamente chiuso (pugno)

I due servo di ogni dito sono affiancati con assi collineari: la rotazione nello stesso verso produce la divaricazione, quella in versi opposti produce la flessione. I servo con ID pari sono negati rispetto a quelli dispari, quindi uno stesso valore di apertura/chiusura fa muovere i due servo in direzioni opposte; il programma lo gestisce automaticamente, non serve convertire a mano.

Limiti ​

text
limits:
  servo_min: -75      # limite inferiore/superiore assoluto di corsa per qualsiasi comando ai servo
  servo_max: 75
  base_min: -75       # intervallo dello slider apertura/chiusura
  base_max: 75
  side_min: -35       # intervallo dello slider laterale
  side_max: 35

side_min/side_max controllano l'apertura laterale. Poiché il programma normalizza (u = |side_offset| / |side_min|), modificare solo questo intervallo non cambia l'ampiezza effettiva della divaricazione, ma comprime soltanto la scala dello slider. Per cambiare davvero l'angolo di divaricazione delle dita bisogna modificare anche auto_extremes.

Target dei valori raw ​

I tre pulsanti di posizione globale portano i servo a valori raw precisi, senza passare dal modello degli angoli:

text
raw_positions:              # indice 0 -> ID servo 1 …… indice 7 -> ID servo 8
  open:   [260, 760, 260, 760, 260, 760, 260, 760]
  close:  [760, 260, 760, 260, 760, 260, 760, 260]
  middle: [451, 571, 451, 571, 451, 571, 451, 571]
  • open / close —— i due estremi della corsa meccanica. Misurati pilotando i servo singolarmente con lo strumento di debug Feetech del produttore.
  • middle —— la posizione centrale meccanica calibrata (cioè il MiddlePos nel programma dimostrativo Arduino del produttore). Nota che non è il punto medio tra open e close, ma è scostato di circa ±60 raw (±17,6°) rispetto a raw 511.

Questi sono valori di calibrazione di ciascuna mano. Le parole del produttore sono "replace values by your calibration results".

Come verificare: il pannello Servo Feedback ha una riga Current (0-1023) che mostra in tempo reale la posizione raw. Dopo aver premuto il pulsante Middle position, questa riga dovrebbe leggere 451, 571, 451, 571, ….

Riepilogo degli intervalli dei controlli ​

ControlloIntervallo
Slider apertura/chiusura (verticale)−75 … +75
Slider laterale (orizzontale)−35 … +35
Velocità1 (lenta) … 6 (veloce)

Il valore di velocità viene passato dal driver ai servo come rad/s, quindi 1–6 corrisponde approssimativamente a 57–344 °/s. Sotto carico la velocità effettiva è circa il 70% di questo valore — tienine conto quando imposti i ritardi delle sequenze.


Esecuzione della GUI (amazing_hand_gui.py) ​

Interfaccia principale AHC: controllo dito per dito, pulsanti globali, telemetria e log

L'interfaccia è divisa in quattro aree:

  • Colonna sinistra: pannello di controllo dito per dito delle quattro dita, con slider apertura/chiusura e laterale, modalità Auto/Raw, velocità, Open/Close/Center.
  • Colonna centrale: pulsanti di controllo globale (Open All / Close All / Center All / Middle position) e gestione delle pose.
  • Colonna destra: curve di telemetria e tabella di feedback Servo Feedback (posizione, carico, temperatura, tensione).
  • Parte inferiore: log di esecuzione e barra di stato, che mostra stato della connessione, avanzamento delle azioni e messaggi di errore.

Dopo l'installazione con pip è possibile chiamare direttamente:

text
amazing-hand-gui
amazing-hand-gui --port /dev/ttyUSB0

Oppure eseguire direttamente:

bash
python amazing_hand_gui.py
python amazing_hand_gui.py --port /dev/ttyUSB0

Il menu a tendina della porta elenca le porte seriali realmente presenti sulla macchina (preferisce pyserial, altrimenti legge il registro di Windows), così anche gli adattatori con numeri alti vengono mostrati. Il menu a tendina permette anche di digitare direttamente il numero di porta. Se la porta predefinita della configurazione non è inserita, la GUI parte automaticamente dalla prima porta reale; per fissare la porta passa esplicitamente --port.

Funzionalità ​

Pannello di controllo dito per dito: modalità Auto/Raw, velocità e pulsanti rapidi Open/Close/Center

  • Controllo dito per dito di apertura/chiusura e spostamento laterale tramite slider, con due modalità Auto (apertura/chiusura + laterale) e Raw (controllo diretto dell'angolo dei due servo)

    In modalità Auto i due slider sono assi di controllo e il programma esegue automaticamente la sintesi differenziale; la modalità Raw invia invece direttamente gli angoli ai due servo. I due servo di ogni dito sono affiancati con assi collineari: la rotazione nello stesso verso produce la divaricazione, quella in versi opposti produce la flessione.

  • Pulsanti rapidi Open / Close / Center per dito

  • Selezione della velocità per dito (1–6), più un menu a tendina globale per sincronizzare la velocità

  • Scorciatoie da tastiera per regolazioni precise

  • Pulsanti di posizione globale: Open All, Close All, Center All, Middle position

  • Gestione di gesti e sequenze basata su data/hand_config.yaml

  • Possibilità di eliminare direttamente dall'interfaccia i gesti salvati (pulsante 🗑 Delete)

  • Curve di telemetria dei servo in tempo reale (posizione, carico, temperatura, tensione)

  • Tabella Servo Feedback con la posizione raw in tempo reale (0–1023), utilizzabile per la verifica della calibrazione

Operazioni da tastiera ​

  • 1-4: seleziona il dito (Ring anulare, Middle medio, Pointer indice, Thumb pollice)
  • Tasti direzionali: muovono il dito selezionato
    • Su/Giù: chiudi / apri
    • Sinistra/Destra: spostamento laterale
  • Tasti modificatori:
    • Nessuno: 1° per volta (regolazione fine)
    • Shift: 5° per volta (normale)
    • Ctrl: 10° per volta (rapida)
  • Azioni rapide:
    • Q: chiude completamente il dito selezionato
    • E: apre completamente il dito selezionato
    • C: riporta al centro la posizione laterale

Pulsanti globali ​

PulsanteApertura/chiusuraLaterale
✋ Open AllTutte le dita ai valori raw openCentra
✊ Close AllTutte le dita ai valori raw closeCentra
⊙ Center AllInvariatoCentra
⊙ Middle positionTutte le dita ai valori raw middleCentra

Il menu a tendina Global Speed (1–6) applica immediatamente la velocità selezionata a tutti i controlli delle dita e sincronizza la visualizzazione degli slider di ciascun dito.

I tre pulsanti dei valori raw (Open All, Close All, Middle position) aggirano il modello degli angoli, quindi dopo l'esecuzione gli slider mostrano il valore rappresentabile più vicino, non il valore esatto. Toccando poi gli slider, la mano può scostarsi dal target raw fino a circa 0,3° — è una scelta deliberata per centrare con precisione le posizioni calibrate.

Problema noto: Center All non salta le dita in modalità Raw e sovrascrive gli angoli raw impostati manualmente. Il pulsante ⊙ Center del singolo dito, invece, no.


Esecuzione della CLI (amazing_hand_cmd.py) ​

Strumento da riga di comando indipendente, che permette di applicare gesti e riprodurre sequenze senza avviare la GUI. Legge lo stesso data/hand_config.yaml della GUI e invia letteralmente i valori di posa memorizzati — identici a quelli inviati dalla GUI.

Linux: permessi della seriale ​

L'adattatore USB-seriale si presenta di solito come /dev/ttyACM0 (Waveshare / CDC-ACM) oppure /dev/ttyUSB0 (FTDI / CH340).

Come trovarla:

bash
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
# oppure
dmesg | grep -E 'ttyACM|ttyUSB' | tail -5

Se compare Permission denied, aggiungi l'utente corrente al gruppo dialout e riconnettiti:

bash
sudo usermod -aG dialout $USER

Dopo l'installazione con pip ​

text
amazing-hand-cmd --list
amazing-hand-cmd --pose open
amazing-hand-cmd --sequence demo --loop
amazing-hand-cmd --pose open --speed 6
# quando serve, sovrascrivi la porta seriale:
amazing-hand-cmd --pose open --port /dev/ttyUSB0

Esecuzione diretta ​

bash
python amazing_hand_cmd.py --list
python amazing_hand_cmd.py --pose open
python amazing_hand_cmd.py --pose close --speed 6
python amazing_hand_cmd.py --sequence demo
python amazing_hand_cmd.py --sequence wave --loop
python amazing_hand_cmd.py --port /dev/ttyUSB0 --pose open
python amazing_hand_cmd.py --list --config /path/to/hand_config.yaml

Parametri ​

ParametroValore predefinitoDescrizione
--pose NAME–Applica il gesto con il nome specificato
--sequence NAME–Riproduce la sequenza con il nome specificato
--list–Elenca tutti i gesti e le sequenze
--loopdisattivoRiproduce la sequenza in loop fino a Ctrl+C
--speed N3Velocità dei servo 1 (lenta)… 6 (veloce)
--port PORTLinux /dev/ttyACM0
Windows COM9
Numero di porta della seriale
--baudrate N1000000Baudrate
--config PATHdata/hand_config.yamlSpecifica un altro file di configurazione
--handhand in config.yamlSpecifica quale mano usare (destra 1-8, sinistra 11-18)

All'uscita dello script (compreso Ctrl+C) la coppia di tutti i servo viene disattivata automaticamente.

La CLI non ha un parametro --config corrispondente a data/config.yaml; quel file viene sempre caricato dalla directory del progetto.


File di configurazione ​

data/config.yaml ​

SezioneScopo
serialporta seriale predefinita per piattaforma, baudrate, elenco dei baudrate opzionali
servosID dei servo corrispondenti a ogni dito
limitsintervalli angolari dei servo e dei due slider
speedsvalori predefiniti/minimi/massimi della scala di velocità 1–6
auto_extremesposizione dei servo quando lo slider laterale è al limite
raw_positionstarget raw precisi dei pulsanti di posizione globale
pathsposizione dei file di gesti/sequenze

Corrispondenza tra servo e dita ​

DitoID servoIndice nell'array di posa
Pointer indice1, 24, 5
Middle medio3, 42, 3
Ring anulare5, 60, 1
Thumb pollice7, 86, 7

L'ordine dell'array di posa è anulare, medio, indice, pollice, non per ID servo. Questo è il punto in cui è più facile sbagliarsi quando si modifica manualmente hand_config.yaml.

Il commento in cima a amazing_hand_cmd.py dice "index 0→servo1 … 7→servo8", quel commento è sbagliato; la tabella sopra riflette il comportamento reale del codice.


Gesti e sequenze ​

Pannello di gestione delle pose

Tutti i gesti e le sequenze sono salvati in data/hand_config.yaml. Se il file non esiste, la GUI lo crea automaticamente.

Salvare un gesto ​

  1. Porta la mano nella posa desiderata con gli slider o la tastiera
  2. Inserisci il nome nel campo "Name:"
  3. Fai clic su "➕ Add New" nell'area Pose Management

La velocità influisce solo sulla rapidità di movimento degli slider; il gesto salvato registra solo le 8 posizioni dei servo.

Caricare / eliminare un gesto ​

  • Dopo averlo selezionato dal menu a tendina, fai clic su ✓ Apply per far muovere la mano nella posa
  • Fai clic su 🗑 Delete a destra di Apply e, dopo la conferma, elimina definitivamente

Gestione delle sequenze ​

  1. Nel Sequence Player fai clic su "🔧 Manage" per aprire il gestore delle sequenze
  2. Saved Sequences (colonna sinistra)
  • Visualizza, esegui, modifica o elimina le sequenze esistenti
  • Doppio clic oppure clic su "▶ Execute" per eseguire una volta
  1. Sequence Builder (colonna destra)
  • Doppio clic su un gesto in "Available Poses" per aggiungerlo come passaggio
  • Per ogni passaggio è possibile impostare separatamente la velocità degli 8 servo e il ritardo; i passaggi vengono salvati nella forma "pose:s1,s2,...,s8|delay"
  • Usa ↑/↓ per cambiare l'ordine, oppure il pulsante "⏱ Delay" per inserire una pausa indipendente
  • Dopo aver inserito il nome, fai clic su "💾 Save Sequence" per salvare; con "▶ Execute" puoi prima provarla senza salvare
  1. Tornato alla finestra principale, per la riproduzione continua seleziona Loop nel Sequence Player

Editor delle sequenze

Formato dei passaggi ​

text
pose_name:speed1,speed2,...,speed8|delay
  • speed1..speed8 —— le velocità degli 8 servo (1–6) nell'ordine della posa
  • delay —— tempo di attesa fino al passaggio successivo, ad es. 0.6s. Può essere omesso; se omesso la GUI torna a un'attesa automatica fissa
  • La pausa indipendente si scrive SLEEP:1.0s (senza elenco di velocità separato da virgole)

Scelta dei ritardi. Il driver stesso è in grado di leggere se i servo si sono fermati, ma la riproduzione delle sequenze usa ritardi fissi. Si stima approssimativamente con angolo di corsa / (velocità × 57,3 × 0,7) secondi, lasciando un margine — su una mano sotto carico, un movimento superiore a circa 130° richiede più di 1,0 secondi alla velocità 3.

Esempio di formato YAML ​

text
poses:
  open:
    positions: [-35, -35, -35, -35, -35, -35, -35, -35]
  close:
    positions: [75, 75, 75, 75, 75, 75, 75, 75]
  ring_close:                 # anulare chiuso, le altre aperte
    positions: [75, 75, -35, -35, -35, -35, -35, -35]

sequences:
  demo:
    steps:
      - "open:3,3,3,3,3,3,3,3|2.0s"
      - "close:6,6,6,6,6,6,6,6|2.0s"
      - "ok:3,3,3,3,3,3,3,3|1.0s"
      - "victory:3,3,3,3,3,3,3,3|1.0s"
      - "greeting:3,3,3,3,3,3,3,3|1.5s"
      - "close:6,6,6,6,6,6,6,6|2.0s"
  wave:
    steps:
      - "open:6,6,6,6,6,6,6,6|0.8s"
      - "wave_r:5,5,5,5,5,5,5,5|0.6s"
      - "wave_l:5,5,5,5,5,5,5,5|0.6s"
      - "open:5,5,5,5,5,5,5,5|0.8s"
  finger_roll:
    steps:
      - "open:6,6,6,6,6,6,6,6|0.5s"
      - "ring_close:5,5,5,5,5,5,5,5|0.6s"
      - "open:5,5,5,5,5,5,5,5|0.5s"
      - "middle_close:5,5,5,5,5,5,5,5|0.6s"
      - "open:5,5,5,5,5,5,5,5|0.5s"

La riproduzione in loop è controllata a runtime (casella di controllo della GUI) e non viene più scritta nel YAML.


Test ​

Il progetto contiene 284 test unitari/di integrazione/di sistema e 54 test hardware.

Eseguire tutti i test (senza hardware) ​

text
pytest

Eseguire i test hardware GUI + CLI (richiede i servo collegati) ​

text
pytest tests/test_system_hardware.py --hardware --port /dev/ttyACM0
pytest tests/test_cmd_hardware.py --hardware --port /dev/ttyACM0
# oppure entrambi insieme:
pytest tests/test_system_hardware.py tests/test_cmd_hardware.py --hardware

test_system_hardware.py verifica connessione, applicazione dei gesti, lettura della telemetria, apertura/chiusura e oscillazione di un singolo dito, controllo della velocità, esecuzione delle sequenze e rilevamento del movimento.

test_cmd_hardware.py verifica end-to-end lo strato CLI: posizioni delle pose, parametri di velocità, passaggi delle sequenze, wait_for_motion, output di --list e disattivazione della coppia all'uscita.

I criteri di accettazione completi sono in Requisiti di accettazione e test.

Nota: i test non hardware verificano i valori predefiniti di fallback in hand_logic.py, che sono ancora nella scala originale −40…110. A runtime data/config.yaml li sovrascrive, quindi i test passano indipendentemente dalla calibrazione — ma questo significa anche che i test non verificano i tuoi parametri di calibrazione attuali.


Configurazione degli ID servo ​

Tutorial per configurare gli ID dei servo con il software ufficiale Feetech e la scheda driver bus seriale: https://www.robot-maker.com/forum/tutorials/article/168-brancher-et-controler-le-servomoteur-feetech-sts3032-360/

Download del software Feetech: https://github.com/Robot-Maker-SAS/FeetechServo



Telemetria e retroazione ​

  • Selezione delle metriche: posizione, carico, velocità, temperatura, tensione, indicatore di movimento.
  • Modalità del grafico: Multi-Servo (curve di più servo) e Scope (oscilloscopio a canale singolo).
  • Zoom/panoramica: Y Zoom / Pan, Time Zoom / Pan.
  • Tabella di feedback: Goal, Position, Speed, Load, Voltage, Temperature, Status, Moving.

Curve di telemetria

Tabella di feedback dei servo

Editor delle sequenze ​

  1. Nel Sequence Player fai clic su Manage.
  2. Aggiungi passaggi con Available Poses, regola la velocità per dito, il ritardo dei passaggi o inserisci una pausa.
  3. Usa ↑/↓ per cambiare l'ordine, inserisci il nome e salva; puoi anche provare prima con Execute.
  4. Torna alla finestra principale, seleziona la sequenza e fai clic su Play; abilita Loop per la riproduzione continua.

Le definizioni delle sequenze si trovano sotto la chiave sequences di data/hand_config.yaml.

Risoluzione dei problemi ​

SintomoSuggerimento
Nessuna porta seriale elencataRicollega l'adattatore USB, installa il driver o riavvia la GUI.
Pulsante Connect in grigioÈ già connesso, fai prima clic su Disconnect.
Scatti durante il ridimensionamento della finestraChiudi le finestre non necessarie; il ridimensionamento è già dotato di debounce/throttling.
La sequenza non aziona tutte le ditaControlla la velocità di ogni passaggio e assicurati che ogni posa contenga i valori di tutti gli 8 servo.
L'indicatore di blocco resta attivoControlla eventuali inceppamenti meccanici; se la differenza tra target e posizione reale è grande e non c'è movimento, scatta il rilevamento di blocco.

Documentazione di sviluppo correlata ​

Ringraziamenti ​

Progetto originale: Betatester777 Hardware e firmware di riferimento: Pollen Robotics