Eseguire istruzioni contemporaneamente utilizzando i valori percentuali

Salve a tutti,

sono Tony e sono alle prime armi con Arduino.

Ho iniziato subito a creare un piccolo braccio meccanico collegato ad una penna in grado di creare delle semplici linee.

Uno dei problemi che ho dovuto affrontare (oltre alla scelta dei servi, giochi di forza,peso,gravita ecc ecc..) e' stato quello di fare eseguire dei movimenti di due servi contemporaneamente.

La necessita' di eseguire il movimento dei due servi contemporaneamente mi serve per far si che quando il braccio si allunga in orizzontale, la penna si alzi e si allinei verticalmente al terreno in modo tale da tracciare sempre una linea dritta nello spazio x e y.

Vediamo subito un esempio:
Il seguente codice di esempio serve a far muovere il primo servo da 0 gradi fino a 180 e il secondo servo da 0 gradi fino a 90 gradi.

  for (int start1= 0; start1 <= 180; start1++) 
 {
     MyServo1.write(start1); 
     delay(20);
 } 

 for (int start2= 0; start2 <= 90; start2++) 
 {
     MyServo2.write(start2); 
     delay(20);
 }

Eseguendo il codice otterremo il movimento del primo servo e una volta completato, inziera' e terminera' il movimento del secondo servo.

Se volessimo farli muovere contemporaneamente e far si che il movimento del primo servo termini nello stesso istante del movimento del secondo servo, il codice precedente non va per niente bene.

Cercando sul forum potrete trovare molti esempi per l'utilizzo della funzione millis(), ma non sono sicuro che vada bene perche' i due servo devono eseguire movimenti diversi con gradi finali e/o di partenza anche diversi.

Aggirando altre soluzioni ho creato una funzione in grado da far muovere entrambi i servo per la stessa durata e quindi compiere entrambi i movimenti nello stesso periodo di tempo.

Ecco la mia funzione:

void Move2Servo(Servo MyServo1, Servo MyServo2, int end1, int end2)
{
   for (int i= 0; 0 <= 100; i++++) 
  {
     float degreeServo1 = (i * end1) / 100;
     MyServo1.write(int(degreeServo1)); 

     Float degreeServo2 = (i * end2) / 100;
     MyServo2.write(int(degreeServo2)); 
     delay(20);
  } 
}

Come potete vedere ha solo un ciclo sempre fisso che va da 0 a 100.
Il compito e' quello di prendere il valore percentuale del grado finale e applicarlo contemporaneamente ai due servi.
Con questa funzione ora e' possibile eseguire 2 movimenti per due servi con gradi di partenza e/o finali diversi nello stesso tempo (quindi contemporaneamente).

Spero che questa funzione puo' essere utile e magari ottimizzata.
Ha risolto il mio problema e spero possa risolverlo ad altri.

Grazie a tutti.

tony

Ti consiglio di evitare l'uso dei float e di usare la servo.writemicroseconds() per far muovere i servo, oltre a migliorare la precisione ottieni un movimento molto più fluido.
Tutti i servo funzionano con lunghezza dell'impulso di controllo compresa tra circa 500us (-90°) e circa 2500us (+90°), la posizione centrale è 1500us, usando la writemicroseconds disponi di 2000 punti su 180° invece di solo 180 punti usando la write standard.
La logica del programma rimane la stessa con la differenza che usi solo valori interi (500-2500), se ti è più comodo con la map() puoi facilmente convertire il valore in us, 500-2500, in un valore sotto forma di decimi di grado, 0-1800, oppure puoi convertirlo in millesimali, 0-1000, ovvero una percentuale con risoluzione al decimo.
Se segui questi consigli otterrai un sensibile miglioramento nella qualità dei movimenti.

astrobeed:
Ti consiglio di evitare l'uso dei float e di usare la servo.writemicroseconds() per far muovere i servo, oltre a migliorare la precisione ottieni un movimento molto più fluido.
Tutti i servo funzionano con lunghezza dell'impulso di controllo compresa tra circa 500us (-90°) e circa 2500us (+90°), la posizione centrale è 1500us, usando la writemicroseconds disponi di 2000 punti su 180° invece di solo 180 punti usando la write standard.
La logica del programma rimane la stessa con la differenza che usi solo valori interi (500-2500), se ti è più comodo con la map() puoi facilmente convertire il valore in us, 500-2500, in un valore sotto forma di decimi di grado, 0-1800, oppure puoi convertirlo in millesimali, 0-1000, ovvero una percentuale con risoluzione al decimo.
Se segui questi consigli otterrai un sensibile miglioramento nella qualità dei movimenti.

grazie mille non ero a conoscenza di questo comando.
Provero' subito e vi far' sapere come migliora :slight_smile:

Grazie!

Ora che guardavo il mio codice, come wirte io assegno comunque valori interi con il cast int().
L'utilizzo del float era solo per dare il valore percentuale per far si che le differenti gradi finali abbiano la stessa temporizzazione.

Allunghero' il ciclo a da 0 a 1000 e utilizzero la writemicroseconds() per renderlo piu fluido :slight_smile:

Infatti in questa istruzione float è inutile:

float degreeServo1 = (i * end1) / 100;                 // float=(int*int)/int

visto che tutti glie elementi coinvolti nel calcolo sono int, il compilatore fa calcoli tra interi (a 16 bit !!!) e poi solo il risultato lo pone in float. Perciò occhio che se i*end1 dovesse essere maggiore di 32767 andrebbe in overflow (ovvero ottieni un numero non voluto, nessun errore a runtime).

Anche questo, consiglio, è veramente brutto "i++++" meglio i+=2 è più leggibile

nid69ita:
Infatti in questa istruzione float è inutile:

float degreeServo1 = (i * end1) / 100;                 // float=(int*int)/int

visto che tutti glie elementi coinvolti nel calcolo sono int, il compilatore fa calcoli tra interi (a 16 bit !!!) e poi solo il risultato lo pone in float. Perciò occhio che se i*end1 dovesse essere maggiore di 32767 andrebbe in overflow (ovvero ottieni un numero non voluto, nessun errore a runtime).

Anche questo, consiglio, è veramente brutto "i++++" meglio i+=2 è più leggibile

hai ragione grazie mille!

Per il ++++ era un errore di scrittura scusatemi. Va bene il i++