Arduino + Servomotori

Ciao a tutti, ho acquistato un piccolo servo standard, precisamente il Futaba S3003 (le specifiche si trovano qui http://www.futaba-rc.com/servos/servos.html). Ho eseguito i collegamenti in questo modo, dopo aver alimentato arduino esternamente (e cambiato lo switch ovviamente): cavo nero del motore: +5V, cavo rosso del motore: GND, cavo bianco del motore: pin 9 (PWM0)... Credo che sia tutto giusto in quanto il motorino appena alimento la scheda si assesta... Ho scritto uno sketch per provare a afr girare il motore, chenneso', di 90 gradi... Lo sketch e' questo:

int servoPin = 9;

void setup() {
  pinMode(servoPin, OUTPUT);
}

void loop() {

  analogWrite(servoPin, 90);
  delay(500); //Per sicurezza, per mantenere in sync il motore
  analogWrite(servoPin, 0);
  delay(500);

}

Il risultato e' che il motore gira, ma non di 90 gradi! ad occhio saranno una decina... Ora io credo di essere stato un po' ingenuo a credere che un valore intero passato alla analogWrite fosse poi considerato dal motore come i gradi di cui girare... (mi sono ispirato alla documentazione di wiring... credo che guardero' come funziona dentro la classe Servo)! Ho provato ad eseguire del codice trovato qui http://www.tigoe.net/pcomp/code/archives/arduino/000741.shtml (opportunamente modificato), ma il risultato e' lo stesso, gira di un pelo... Qualche delucidazione in merito? Mi manca qualche conoscenza di base sui servo?

Grazie e ciao

Corrado

ciao corrado,
non ho nessuna esperienza con servomotori...devo ancora procurarmene uno
( a proposito tu dove lo hai pescato?)

comunque per quel poco che vedo il problema potrebbe risidere nel fatto che usi il pwm
e sostanzialmente gli dai due comandi opposti in brevissimo tempo
cioè non fa neanche in tempo ad iniziare il movimento verso i 90° che già gli dici di tornare indietro :slight_smile:

se noti l'esempio che fa tom igoe, invece di un ANALOGWRITE (impulso analogico in uscita) come il tuo
usa DIGITALWRITE ( un impulso digitale in uscita) e quindi ha senso accendere e spegnere velocemente il segnale in uscita
per crearsi una frequenza personalizzata.

hai due alternative:
1- usa il pwm con analogWrite ma aumenta i tempi di attesa (prova 1-2 secondi = 1000 2000 ms)
non so se però questo funzionerà...credo di si, ma non ne sono certo al 100%

2- sostituisci analogWrite con digitalWrite come nell'esempio di tom igoe
digitalWrite(servoPin, HIGH); // Turn the motor on
delayMicroseconds(pulse); // Length of the pulse sets the motor position
digitalWrite(servoPin, LOW); // Turn the motor off
delay(20); // 20 millisecond delay is needed between pulses

spero ti aiuti
ciao
b.

Mhhh sinceramente pensavo ::slight_smile: che il tempo dato fosse sufficiente, ho provato con un valore piu' alto ma non migliora... Per quanto riguarda il codice che utilizza la digitalWrite, ho un dubbio. La funzione mi mette a HIGH il pin, attende un tot, e poi mette a LOW il pin, che si traduce in: il motore inizia a girare, continua a farlo per un certo tot, e poi si ferma (ma riparte subito perche' ricomincia il ciclo). Non riesco a intravedere il modo per comandarlo, per dirgli "posizionati ad un certo angolo"! Ok mi metto a ragionare..

Grazie per l'aiuto!

Vi faccio sapere, ma ogni idea e' gradita

Corrado

Ok da quello che ho capito il servo si apetta un impulso lungo tra i mille e 2000 microsecondi che equivalgono alla posizione iniziale e alla finale... quindi per settare il motore nella posizione intermedia bisogna teoricamente mandare un impulso di 1,5 millisecondi. Ho scritto questo codice per testare:

int servoPin = 9;
int pulse = 950;

void setup() {
  pinMode(servoPin, OUTPUT);
}

void loop() {

  pulse += 50;
  if(pulse > 2000)
    pulse = 1000;
  digitalWrite(servoPin, HIGH);
  delayMicroseconds(pulse);
  digitalWrite(servoPin, LOW);
  delay(1000);

}

Quindi inizia con un impulso di mille microsecodni e lo aumenta fino a 2000, quindi il motorino dovrebbe girare (a step lunghi un secondo) dalla posizione iniziale a quella finale, per poi ricominciare quando si superano i 2000 microsecondi.

Volete vedere il risultato? anche perche' a parole non riesco a descriverlo.

www.art3ch.org/corrado/motore.avi (2.5 Mb).

Cosa non ho ancora capito... :cry: Sospetto che sia ancora un problema di timings, magari il motore ci mette troppo tempo a tornare in posizione ed inizia a sfasare.

Un saluto

in teoria funziona mentre in pratica no:)

dovresti mandare un certo numero di impulsi della stessa lunghezza

metti un for loop che ripete lo stesso impulso 10 volte cosi il servo non si confonde :slight_smile:

se vuoi del codice di riferimento qui trovi del un esempio per i servo

converti il codice in modo che non usi numeri con la virgola e vedrai che funziona
(i numeri con la virgola incasinano arduino, e' un problema del compilatore)

massimo

Esatto! e' proprio quello che ho provato a fare, e sono arrivato a questa conclusione... Vi faccio un esempio pratico. Supponiamo che il motore sia in posizione iniziale, quindi ha ricevuto un impulso lungo 1000 microsecondi. Voglio farlo spostare in posizione finale, quindi devo inviargli un treno di segnali lunghi 2000 microsecondi. Solo che devo continuare a farlo finche' non raggiunge la posizione! E qui entra in gioco il for... ho pensato che l'indice del for (e quindi "per quanto tempo" continuare a spedirgli segnali lunghi 2000 microsecondi) deve essere in funzione di quanta strada deve percorrere diciamo... e di conseguenza e' in funzione della posizione attuale e della velocita' di rotazione del motore... a naso non mi sembra un conto tanto semplice (contando che questo significa anche tenere traccia della posizione corrente del motore, che complica un po' le cose). Secondo me tutti questi conti se li fa la classe Servo delle API di wiring, ma quando rilasciano il codice?? uff... carta e penna, ho capito!

Vi tengo aggiornati...

Ciau

Ciao di arduino non so niente, però ho già programmato servocomandi.
Il tuo codice non funziona perchè non tieni in considerazione il funzionamento del servo.
E' vero che devi mandare un impuso che va da 1ms a 2ms per settare la posizione del servo (1,5ms il servo è in posizione centrale), però il circuito di feedback del servo ha bisogno di una pausa tra un impulso e l'altro compresa tra 10ms e 40ms (solitamente si usano 20ms). Tu tra un impulso e l'altro fai passare 1 secondo..
Il loop per il controllo del servo deve ripetersi ogni 20ms in pratica (nessuna eccezione), poi sta a te via software farlo rimanere per un secondo in una determinata posizione, ma tanto per essere chiari, in quel secondo tu devi fare un "refresh" della posizione ogni 20ms. Spero di essere stato abbastanza chiaro.
In soldoni questo è richiesto perchè il servo altro non è che un semplice motoriduttore DC con un circuito di feedback (di controllo) che permette (tramite un potenziometro) di calcolare la posizione del servo. Come saprai un motore DC non è fatto per rimanere fermo in una posizione fissa (per quello ci sono i motori passo passo), quindi devi costantemente regolare la posizione per farlo rimanere "fermo".
Tieni in considerazione che a causa dello sforzo necessario è sconsigliabile far rimanere fermi i servo (questo accade solitamente per quelli economici) troppo a lungo specie se non sono a vuoto, altrimenti potrebbero bruciarsi.
Tornando all'esempio che hai citato, se ci fai caso è anche scritto "pulse the servo again if the refresh time (20 ms) have passed", e anche nell'esempio postato da Massimo Banzi era abbastanza evidente (c'è un delay esplicito di 20ms). Ovviamente tu non l'hai notato perchè non ne eri a conoscenza.
Riassumendo puoi modicare l'esempio che hai postato tu lasciando invariata la parte dove si genera l'impulso e cambiando solo la parte iniziale (dove si legge la posizione da un ingresso analogico), facendo in modo di incrementare la posizione di un certo valore ogni secondo.
Tiene presente che facendo così il servo si muoverà sempre alla massima velocità.
Se vuoi anche regolare la velocità le cose si complicano un po', in pratica devi incrementare la posizione poco alla volta, e non impostare direttamente la posizione desiderata.
Spero di esserti stato utile.

Ottimo S3003!!! Ne ho usati decine (Ma sugli aeromodelli, non con Arduino).
Comunque, per pilotare un servo, e' decisamente piu' pratico usare la libreria per i servocomandi.
http://www.arduino.cc/playground/ComponentLib/Servo

Certo che rispondere a un thread vecchio di tre anni... Mah...
Che dite, mi vergogno un pochetto?

lol