Sei servo con movimento armonico arduino

Il progetto mano biomeccanica procede su due fronti: lato software sto lavorando per ottenere sei servo con movimento armonico, cioè tutti i servo devono muoversi ciascuno indipendentemente dagli altri ma con un movimento armonico proprio.

sei servo movimento armonico

Lato meccanico Federico si sta occupando del montaggio della struttura e dell’automazione con cavi elastici, i tendini, e le minuterie necessarie al completo funzionamento.

Il collegamento dei sei servo con movimento armonico

la parte elettrica del collegamento dei sei servo con movimento armonico è molto semplice, e vale anche se vuoi collegare solo sei servo da controllare in modo non armonico 🙂

Ricorda solo che un servo può essere controllato facilmente con Arduino se utilizzi i pin PWM, che per Arduino uno sono solo sei:

sei servo con movimento armonico

nella figura hai notato che ci sono solo 7 fili che uniscono Arduino alla breadboard e che ho utilizzato un circuito su basetta millefori da me realizzato per collegare i servo.

Lo schema è il seguente:

sei servo con movimento armonico collegamenti

il terminale segnal di ogni servo è connesso ad uno dei pin PWM di arduino, mentre il positivo ed il negativo di ciascun servo è collegato direttamente alla batteria, mentre il polo negativo del circuito è comune anche ad Arduino.

La difficoltà dello sketch sei servo con movimento armonico

Se hai provato già a lavorare con i servo ti sarai reso conto che quando scrivi uno sketch per un solo servo tutto funziona alla perfezione ma appena introduci il secondo servo il grado di difficoltà cresce, ci sono alcuni concetti che ignorati portano inevitabilmente a non far funzionare lo sketch.

In questo sketch ti spiego proprio le difficoltà che ho riscontrato e che potresti incontrare aggiungendo sei servo al tuo progetto.

Prima di entrare nello specifico dello sketch è necessario chiarire il concetto di istanza di una classe o libreria arduino:

quando includi una libreria, come ad esempio la Servo.h usata in questo sketch, al suo interno è contenuta una classe servo che dispone di alcuni metodi ciascuno dei quali ha una funzione specifica.

Per utilizzare la classe Servo contenuta nel file Servo.h è necessario che tu la istanzi, ossia che tu dichiari di volerla utilizzare nello sketch e la assegni ad una variabile a tua scelta.

Dalla linea successiva dello sketch quella variabile è la tua istanza della classe Servo, per cui tutte le volte che vorrai utilizzare un metodo della classe, o oggetto, Servo dovrai far riferimento a quest’ultima.

Un esempio chiarisce più di mille parole:

/**********************************************************
 * Servo con movimento armonico e Arduino
 *
 * Data creazione 27 marzo 2013
 * Ultima modifica 07 aprile 2013
 *
 * autore: Mauro Alfieri
 * web:    mauroalfieri.it
 * tw:     @mauroalfieri
 *
/**********************************************************/

#include <Servo.h>

#define pinServoA 3
#define pinServoB 5
#define pinServoC 6
#define pinServoD 9
#define pinServoE 10
#define pinServoF 11

#define rad2grad 57.295779513
#define incremento 8
#define limitAngolo 360
#define differenza 30

float angoloA = 0;
float angoloB = 0;
float angoloC = 0;
float angoloD = 0;
float angoloE = 0;
float angoloF = 0;

float gradoA  = 0;
float gradoB  = 0;
float gradoC  = 0;
float gradoD  = 0;
float gradoE  = 0;
float gradoF  = 0;

boolean firstLoop=true;

Servo servoA;
Servo servoB;
Servo servoC;
Servo servoD;
Servo servoE;
Servo servoF;

void setup() {
  Serial.begin( 9600 );
  Serial.println( " ------------------ Avvio ------------------------" );

  servoA.attach( pinServoA );
  servoA.write( gradoA );

  servoB.attach( pinServoB );
  servoB.write( gradoB );

  servoC.attach( pinServoC );
  servoC.write( gradoC );

  servoD.attach( pinServoD );
  servoD.write( gradoD );

  servoE.attach( pinServoE );
  servoE.write( gradoE );

  servoF.attach( pinServoF );
  servoF.write( gradoF );
}

void loop() {

  if ( angoloA <= differenza &&  firstLoop == true ) { angoloB = angoloC = angoloD = angoloE = angoloF = 0; }
  if ( angoloB <= differenza &&  firstLoop == true ) { angoloC = angoloD = angoloE = angoloF = 0; }
  if ( angoloC <= differenza &&  firstLoop == true ) { angoloD = angoloE = angoloF = 0; }
  if ( angoloD <= differenza &&  firstLoop == true ) { angoloE = angoloF = 0; }
  if ( angoloE <= differenza &&  firstLoop == true ) { angoloF = 0; }

  if ( angoloA > limitAngolo ) { angoloA = 0; firstLoop = false; }
  if ( angoloB > limitAngolo ) { angoloB = 0; firstLoop = false; }
  if ( angoloC > limitAngolo ) { angoloC = 0; firstLoop = false; }
  if ( angoloD > limitAngolo ) { angoloD = 0; firstLoop = false; }
  if ( angoloE > limitAngolo ) { angoloE = 0; firstLoop = false; }
  if ( angoloF > limitAngolo ) { angoloF = 0; firstLoop = false; }

  gradoA = (( sin( (angoloA/rad2grad) ) * 80 ) + 90 );
  gradoB = (( sin( (angoloB/rad2grad) ) * 80 ) + 90 );
  gradoC = (( sin( (angoloC/rad2grad) ) * 80 ) + 90 );
  gradoD = (( sin( (angoloD/rad2grad) ) * 80 ) + 90 );
  gradoE = (( sin( (angoloE/rad2grad) ) * 80 ) + 90 );
  gradoF = (( sin( (angoloF/rad2grad) ) * 80 ) + 90 );

  Serial.print( "gradi: " );
  Serial.print( gradoA );
  Serial.print( "\t" );
  Serial.print( gradoB );
  Serial.print( "\t" );
  Serial.print( gradoC );
  Serial.print( "\t" );
  Serial.print( gradoD );
  Serial.print( "\t" );
  Serial.print( gradoE );
  Serial.print( "\t" );
  Serial.print( gradoF );
  Serial.print( "\n" );

  servoA.write( gradoA );
  servoB.write( gradoB );
  servoC.write( gradoC );
  servoD.write( gradoD );
  servoE.write( gradoE );
  servoF.write( gradoF );

  angoloA = (angoloA + incremento );
  angoloB = (angoloB + incremento );
  angoloC = (angoloC + incremento );
  angoloD = (angoloD + incremento );
  angoloE = (angoloE + incremento );
  angoloF = (angoloF + incremento );
}

soffermati subito sulle linee 15-20: per ogni servo definisci un pin a cui è collegato, chiama le definizioni dei pin da A a F;

linee 27-39: definisci due gruppi di sei variabili in cui le prime sei memorizzano l’angolo o numero progressivo su cui calcoli il sen() da passare al servo. Il secondo gruppo ti serve per memorizzare il valore di ciascun grado da passare al corrispondente servo;

linea 41: definisci una variabile di tipo booleano ( true / fasle ) denominata firstLoop il cui compito è permetterti di capire se sei al primo giro della funzione loop od ad un loop successivo;

linee 43-48: sono proprio le linee in cui definisci le sei istanze relative ai sei servo collegati. NOTA: ogni istanza ha un nome differente, questo perchè non puoi dichiarare due istanze con il medesimo nome. Da questo momento in poi nello sketch quando parlerai al servo A lo farai sempre e solo attraverso l’istanza servoA;

linee 54-55: usa subito due metodi della classe Servo applicandoli all’istanza servoA, il primo metodo è attach() e serve a definire a quale pin hai collegato il servo che chiamo A. Il secondo metodo è write() e lo troverai anche in seguito, il suo compito è permetterti di posizionare il servo al grado che desideri;

linee 57-70: esegui le stesse operazioni delle linee 54-55 per ognuno dei sei servo con movimento armonico collegati;

linee 75-79: mediante una serie di condizioni farai in modo che i servo partano in modo sfalsato l’uno rispetto all’altro, concentrati sulla prima linea la 75, questa linea dice alla sketch: fino a quando il valore dell’angoloA è minore del valore della variabile differenza in cui avrai memorizzato di quanto vuoi sfalsare gli angoli, e solo se sei al primo loop() allora imposta i valori degli ancgoli da B ad F a 0. Ecco come ottieni che i servo da B ad F partano sfalsati del valore di differenza impostato rispetto al servoA.

linee 81-86: anche queste linee sono identiche tra loro a meno delle variabili, istanze e valori definiti. In pratica sulla linea 81 dici allo sketch che se il valore dell’angoloA è maggiore del valore della definizione di limitAngolo, impostata a 360°, deve reimpostare l’angolo a 0 e la variabile boolena firstLoop a false, ossia il primo giro è compiuto. Le righe seguenti fanno la medesima cosa per tutti gli angoli successivi.

Questa sequenza di linee ti permette di controllare l’angolo di cui calcoli il sin( x ) nelle righe successive dello sketch.

Dopo il primo giro ( loop ) quando il valore dell’angoloX arriva a 360 viene azzerato e imposti la variabile firstLoop a false per dire che da questo momento i loop() sono dal secondo in poi, ecco un’immagine di quello che vedrai sul monitor seriale:

sei servo con movimento armonico serial monitor

avrai notato che all’inizio i si servo con movimento armonico partono tutti da 90° ma a valori sfalsati tra loro, quando il servoA raggiunge il valore 101° circa il servoB inizia il suo flusso, al raggiungimento del medesimo valore servoB parte il servoC e così via.

Avrai anche notato che in giallo ti ho evidenziato il passaggio del primo loop() ossia quando il valore dell’angolo viene riportato a 0, vedrai che ciclicamente tutti i servo raggiungono gli stessi valori in tempi sfalsati tra loro.

Linee 88-93: sono le linee in cui l’angoloA,B,C,D,E ed F si trasforma in un grado da applicare al servo corrispondente. Se hai letto gli articoli precedenti sul movimento armonico dei servo sai già come viene calcolato questo valore e perchè, se non lo hai fatto ti consiglio di leggerli se vuoi comprendere meglio il meccanismo che usano i sei servo con movimento armonico;

linee 109-114: applica a ciascun servo il valore in gradi calcolato alle linee 88-93;

linee 116-121: calcola per ogni angolo l’incremento del rispettivo valore.

Il video di sei servo con movimento armonico

Ecco il video che ho realizzato con 6 servo motori di marche differenti, non possiedo 6 servo tutti identici tra loro 🙂

Buon divertimento !!!

Prima di inserire un commento, per favore, leggi il regolamento

Permanent link to this article: http://www.mauroalfieri.it/elettronica/sei-servo-con-movimento-armonico-arduino.html

26 comments

Skip to comment form

  1. ciao Mauro

    i servi digitali sono supportati da Arduino?

    grassie

    ciao
    luca

    1. Ciao Luca, che io sappia si.
      Poi nello specifico devi controllare sul web se esistono delle librerie per il tuo modello.

      Ad esempio io ho trovato le librerie per i Dynamixel e pochi altri.

      Mauro

    • Giovanni on 14 Maggio 2014 at 10:46
    • Reply

    Come mai nel programma si dichiarano 6 servo ma le dita in movimento nel video sono solo 4 ?

    1. Ciao Giovanni,
      il 5° servo è per il pollice che non era ancora collegato al momento del video ed il 6° è per il polso.

        • Giorgio on 16 Agosto 2014 at 12:58
        • Reply

        Ciao mauro
        io ti consiglierei di utilizzare il 6 servo per ottenere il pollice opponibile

        1. Grazie Giorgio per il suggerimento.
          Stiamo già lavorando ad un prototipo in cui useremo 6 servo per ottenere la funzione che suggerisci, è complesso il posizionamento dei fili e dei servo 🙂 ma ci stiamo provando.

    • marino on 14 Maggio 2014 at 22:33
    • Reply

    Ciao, ho costruito un quadrupede con 8 servo, ma ho un problema riguardo la stabilità dei servo ovvero nel momento in cui si aziona una gamba quella precedente si chiude quindi cade ad un lato per il peso, come faccio a dare costantemente l’ impulso in contemporanea a tutti i servo, potrei abbinare questo codice per il moto armonico?
    Grazie in anticipo

    1. Ciao Mariano,
      interessante progetto che mi piacerebbe pubblicare una volta ultimato se ti va.
      I servo che uso io quando gli imposti un grado questo viene mantenuto fino a quando cambi l’impostazione o togli l’alimentazione al circuito.
      Potrebbero essere differenti i servo che stai usando od il peso essere troppo elevato perché il tuo robot si regga.

    • marino on 15 Maggio 2014 at 18:43
    • Reply

    ciao
    premetto che il ragno è piccolo in legno ed abbastanza leggero infatti nn sempre cade però se per esempio una zampa non è perpendicolare al pavimento si accascia su un lato, i servo sono turnigy tg9e non hanno un ingranaggio a vite infinita (e non so neanche se esistono).
    ti spiego il mio codice:
    nel setup imposto solo i pin del collegamento quindi attach()
    nel loop un codice composto da tanti write() con l’angolo in base alla sequenza di movimento che voglio dare, abbastanza brutto come codice.
    alla fine credo che per mantenere i servo sempre in posizione dovrei lasciare impostati i write nel setup con una variabile che vario da loop.. giusto??
    grazie per la pazienza, è un bel po che non uso arduino

    1. Ciao Marino,
      pur non avendo mai usato i servo che stai utilizzando sono alquanto sicuro che il metodo write() della classe servo mantenga la posizione impostata fino a quando non gli dai un nuovo angolo a cui posizionare il servo.

    • marino on 23 Maggio 2014 at 11:53
    • Reply

    ciao Mauro
    ho provato il tuo codice però il mio problema sorge nell’utilizzare 8 servo .. ho modificato il codice seguendo la logica quindi aggiungendo altre 2 variabili ecc.. da seriale i gradi li stampa correttamente però è come se arduino nn riesce ad avviarsi, ho utilizzato altre porte non pwm che solitamente funzionano lo stesso sarebbero i pin : 13, 12, 8, 4
    mentre se lo lascio il programma invariato mi funziona tranquillamente su 6 servo tra i quali uno collegato alla porta 8 che non è appunto pwm..
    sapresti dirmi se devo tener conto di non collegare un tot di porte non pwm, non capisco cosa può essere
    il mio è un arduino 2009.
    devo dire che il tuo codice da un bell’effetto al mio ragno 🙂

    ecco una foto
    http://imgur.com/jtZ2vIy

    aggiungo: ho provato con 7 servo e funziona l’ottavo non lo vuole proprio, a volte il ragno si muove ma rimane un servo spento altre volte impazzisce completamente e non esegue

    1. Ciao Marino,
      i problemi che descrivi sembrano essere legati ad un problema di alimentazione eccessiva richiesta dai servo.
      Puoi provare due strade:
      1. la adafruit produce una shield per 16 servo che ho presentato qualche settimana fa;
      2. sostituire i servo con un modello che necessità di una minor corrente assorbita.

      Come linea generale se usi dei pin digitali non PWM per controllare dei servo prova ad usare la SoftPWM che simula un PWM via software.

      Bella la foto !!!

    • marino on 24 Maggio 2014 at 10:31
    • Reply

    Ahah già poi avevu intuito che fosse l’ alimentazione in movimenro i servo consumano ancoea di piú.. Asesso sto provando a mttere qualche condensatore .. 2 da 10 v. 1000microfarad cadauno … E nn ce la fa ancora… Tralaltro il problema è solo nell’ avviamento se lascio avviare senA servo poi li attacco funziona normalmente

    1. Ciao Marino, alcuni tipi di micro servo assorbono di più dei servo standard.

    • marino on 25 Maggio 2014 at 17:04
    • Reply

    Ciao Mauro
    dopo tanti tentativi ho risolto diminuendo le variabili da 8 a 4 così mi è pure più facile controllare la direzione di movimento, ho trovato le varie combinazioni per andare avanti , indietro e destra.
    la fase successiva era quella di integrare un modulo bluetooth, ma avendolo ordinato dalla cina non mi è ancora arrivato (2 mesi) penso di automatizzarlo con un sonar che rilevi la presenza di un ostacolo così da deviare la direzione…
    comunque lo userò come progetto per l’esame di stato
    ecco un video
    https://www.youtube.com/watch?v=-8B_LVwVnjc

    1. Ciao Marino, sono contento e sicuro che farai un figurone, se vuoi accelerare i tempi devi acquistare da negozi italiani che hanno già componenti in magazzino.

      Se ti va di pubblicare tutto il progetto sul blog a tuo nome, dopo l’esame, mandami tutte le info, foto,video,sketch e una tua presentazione.

    • Davide on 28 Maggio 2014 at 16:24
    • Reply

    Ciao scusa, ho appena finito di montare un hexapod msr h01 con arduino mega. Siccome ho usato anche 18 servomotori (12 servomotori hs 645mg e 6 hs 225bb) collegati in PARALLELO che batteria posso usare per alimentarli? L’alimentazione di arduino è separata da quella dei servomotori. Poichè non arriva abbastanza corrente le gambe si muovono a scatti piccoli. Se mi potresti linkare una batteria adatta te ne sarei davvero grato 😀 grazie 😀

    1. Ciao Davide,
      devi calcolare l’assorbimento in funzione del tutto, probabilmente il produttore lo riporta sul suo sito, e decidere quanto tempo vuoi che stia in funzione.
      In base a questi parametri scegli una batteria adeguata.

    • Francesco on 19 Settembre 2014 at 17:45
    • Reply

    Ciao Mauro, devo alimentare un braccio robotico (quelli di tipo antropomorfo) con 6 servi collegati in PWM come detto da te. Ho provato ad usare i 5V di Arduino più 9V da un alimentatore esterno. Ho visto però che la scheda si surriscalda troppo e inoltre il servo che deve sopportare più carico non riesce a muoversi oltre qualche grado (facendo spesso un fischio…). Potrei aggiungere allora oltre all’alimentatore esterno di 9V una batteria da 9V (evitando quindi di usare i 5V di arduino) collegata come nel primo disegno di questo articolo? Grazie infinite per una tuo eventuale aiuto.

    1. Ciao Francesco,
      mi sembra strano che i tuoi servo possano essere alimentati a 9v, solitamente il massimo supportato sono 6v
      Ti consiglio di seguire il mio tutorial su servo con alimentazione esterna in cui è descritto nel dettaglio come collegare i servo.

    • Francesco on 22 Settembre 2014 at 12:53
    • Reply

    Grazie Mauro per la risposta. Ok, quindi uso batterie in serie da 6V per i servi e 9V l’alimentazione, come hai schematizzato tu sull’articolo da te consigliato..In questo modo quindi non devo collegare i 5V di arduino da nessuna parte, ma solo il suo GND a tutti i servo e alla batteria, giusto? Se dovessi avere problemi posso sempre contattarti?

    1. Tutto corretto Francesco.
      Si puoi commentare tutti gli articoli che desideri 🙂

    • Francesco on 28 Settembre 2014 at 16:13
    • Reply

    Ciao Mauro,
    ho collegato il tutto come suggerito (batteria da 6V e alimentatore da 9V) e grazie a te funziona (quasi) tutto perfettamente! C’è purtroppo un servo (quello che fa muovere “l’avambraccio” del robot) che purtroppo non ce la fa ad alzarsi completamente (va invece una meraviglia nel caso in cui tolgo la pinza). Volevo farti due domande: Per risolvere il problema, posso sostituire il servo con uno un po’ più potente, o è un problema di Arduino?
    La seconda, volevo sapere se tu hai mai avuto a che fare con la Cinematica Inversa di un manipolatore.
    Grazie mille come sempre, senza questo sito sarei in alto mare!

    1. Ciao Francesco, si puoi sostituire il servo con uno più potente.
      Purtroppo non ho basi o esperienza di cinematica.

    • Giuseppe on 19 Ottobre 2014 at 12:12
    • Reply

    Ciao Mauro, mi puoi spiegare come impostare la velocità dei servo nel tuo sketch, vorrei che la velocità cambiasse a seconda del valore di un sensore, si può fare?

    1. Ciao Giuseppe,
      certo, puoi, ti consiglio di leggere con attenzione questo articolo e quelli che ho dedicato ai servo in generale, troverai la risposta che cerchi.

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.