Giroscopio con servo

Salve,
Ho creato un piccolo progetto dove il servo è comandato dal giroscopio quando quest'ultimo si muove su asse Yaw, e fin qui sono riuscito a realizzare il tutto con varie ricerche sia sul Vs sito che sul web, quindi ho realizzato sia hardware ed anche il codice che desideravo, tutto funziona.
Adesso vi chiedo aiuto poiché ho bisogno della seguente modifica:

  • vorrei che il servo iniziasse a muoversi dopo che il giroscopio abbia effettua esempio 45° quindi diciamo che se muovessi il giroscopio da 0 a 45° il servo non risponde, non appena abbia superato il 45° inizia a muoversi
  • vorrei che il servo una volta che ha compiuto i suoi 180° tornasse indietro nella posizione di partenza (0°).
    Spero di aver esposto con chiarezza la problematica e se potete aiutarmi nella modifica/aggiunta del codice.
    Grazie in anticipo :wave:
#include <Wire.h>
#include <MPU6050.h>
#include <Servo.h>

MPU6050 mpu;
Servo ServoZ;

// Timers
unsigned long timer = 0;
float timeStep = 0.01;

// Pitch, Roll and Yaw values
float pitch = 0;
float roll = 0;
float yaw = 0;


void setup() 
{
  Serial.begin(115200);
  ServoZ.attach(9);

  // Initialize MPU6050
  while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  {
    Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
    delay(500);
  }
  
  // Calibrate gyroscope. The calibration must be at rest.
  // If you don't want calibrate, comment this line.
  mpu.calibrateGyro();

  // Set threshold sensivty. Default 3.
  // If you don't want use threshold, comment this line or set 0.
  mpu.setThreshold(3);
}

void loop()
{
  timer = millis();

  // Read normalized values
  Vector norm = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + norm.YAxis * timeStep;
  roll = roll + norm.XAxis * timeStep;
  yaw = yaw + norm.ZAxis * timeStep;

  ServoZ.write(yaw);


  // Output raw
  Serial.print(" Pitch = ");
  Serial.print(pitch);
  Serial.print(" Roll = ");
  Serial.print(roll);  
  Serial.print(" Yaw = ");
  Serial.println(yaw);

  // Wait to full timeStep period
  delay((timeStep*5000) - (millis() - timer));
}

Attendiamo che tu faccia quanto ti ho richiesto QUI.

Guglielmo

1 Like

Curiosità... Dove hai trovato quell'uso così "creativo" di millis?

Fatto :slightly_smiling_face:

in una libreria di jarzebski su Github

Mi pare di capire che yaw è la variabile da tenere sotto controllo.

if (yaw > 45) {
    ServoZ.write(180);
} else {
    ServoZ.write(0);
}

Fintato che yaw è maggiore di 45 il servo resta nella posizione 180, quando yaw è == o < di 45 va in posizione 0,

Il delay alla fine introduce un ritardo che al massimo è di 50ms, che influenza la reattività.

Ciao.

Ciao ti ringrazio per la risposta, ho provato e va abbastanza bene, però il servo dopo che ha compiuto i 180° non ritorna a zero in automatico ma solo se riporto il giroscopio al di sotto dei 45°, a me piacerebbe che ritorna a zero in automatico, è fattibile? ho provato io ma non ne ho le capacità facendo vari tentativi :man_facepalming:

mmm... non so se può funzionare:

if (yaw > 45) {
    ServoZ.write(180);
} 

// il resto del codice di prima a seguire l'ultima parte
  // Wait to full timeStep period
  delay((timeStep*5000) - (millis() - timer));
  ServoZ.write(0);
}

Credo proprio non possa funzionare. Dopo essere tornato a zero cosa accade se yaw è ancora > di 45, perché al momento torna a 180 e dopo circa 50ms (o meno) va a zero.

Ciao.

Purtroppo non va ma ti ringrazio ugualmente, secondo me perché probabilmente è tutto legato al giroscopio...
Da ignorante secondo me dovrebbe essere tradotto in codice:

  • Se Yaw è maggiore di 45° porta il Servo a 180° (come già mi ha scritto tu il codice)
  • Quando il Servo ha raggiunto i 180° portalo al punto di partenza cioè a zero.
  1. Ok, ma cosa accade dopo che raggiunge la posizione a 0?
    Deve restare a zero?

Non c'è modo di chiedere al servo la sua posizione all'istante T.
Potresti usare un pulsante fine corsa.
Ma resta sempre il punto 1.

Non saprei, dipende se il servo muove il giroscopio.
Se puoi scendi nei dettagli.
Ciao.

Mi piacerebbe che Quando il servo ritorna a zero e da questo punto ricalibra il giroscopio cosi da riportare Yaw a 0° cosi da iniziare di nuovo il ciclo.
Cmq è il giroscopio che muove il servo.
Quindi riepilogando:

  • Se Yaw è maggiore di 45° porta il Servo a 180° (come già mi ha scritto tu il codice)
  • Quando il Servo ha raggiunto i 180° portarlo al punto di partenza cioè a zero.
  • Ricalibra il giroscopio in modo che Yaw è di nuovo su 0°
  • Inizia di nuovo il ciclo da capo.

Non so se è accettabile. dopo il comando servo(0) la cpu si ferma per 100ms, quando trascorsi, chiama: mpu.calibrateGyro();, che dovrebbe ricalibrare il giroscopio.

void loop()
{
  timer = millis();

  // Read normalized values
  Vector norm = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + norm.YAxis * timeStep;
  roll = roll + norm.XAxis * timeStep;
  yaw = yaw + norm.ZAxis * timeStep;
  
   if (yaw > 45) {
       ServoZ.write(180);
       delay(100);    // 100ms nella speranza che il servo non ci impieghi più tempo.
       ServoZ.write(0);
       delay(100);
       mpu.calibrateGyro();
   }

  // Output raw
  Serial.print(" Pitch = ");
  Serial.print(pitch);
  Serial.print(" Roll = ");
  Serial.print(roll);  
  Serial.print(" Yaw = ");
  Serial.println(yaw);

  // Wait to full timeStep period
  delay((timeStep*5000) - (millis() - timer));
}

PS: non l'avevi detto che volevi calibrare il gyro?

Ciao.


Ho fatto qualche piccola modifica "Servo.write (yaw < 45" perché altrimenti il servo si muoveva già da prima, adesso risolto, però non mi fa ripartire il giroscopio, si impalla dopo aver fatto il suo lavoro normalmente.

Non si muove prima, invece stampa 600ms dopo avere ruotato il gyro a poco più di 45°. :wink:

ServoZ.write(yaw < 45) viene valutato così:
Se yaw è minore di 45 il risultato della espressione è vera (true):
ServoZ.write(1) 
Se yaw è => (uguale o maggiore di)i 45 viene valutata falsa (false).
ServoZ.write(0) 
true equivale a 1.
false equivale a 0.

Forse è dovuto a:mpu.calibrateGyro();
Non mi intendo tanto di giroscopi.

bool enable = false;

void loop()
{
  timer = millis();

  // Read normalized values
  Vector norm = mpu.readNormalizeGyro();

  // Calculate Pitch, Roll and Yaw
  pitch = pitch + norm.YAxis * timeStep;
  roll = roll + norm.XAxis * timeStep;
  yaw = yaw + norm.ZAxis * timeStep;
  
   if (enable == true && yaw > 45) {
       ServoZ.write(180);
       delay(100);    // 100ms nella speranza che il servo non ci impieghi più tempo.
       ServoZ.write(0);
       delay(100);
       enable = false;  // da questo momento enable == false.
   } else if (yaw < 1)  {
       // altrimenti se yaw < 1 enable = true.
       enable = true;
   }

  // Output raw
  Serial.print(" Pitch = ");
  Serial.print(pitch);
  Serial.print(" Roll = ");
  Serial.print(roll);  
  Serial.print(" Yaw = ");
  Serial.println(yaw);

  // Wait to full timeStep period
  delay((timeStep*5000) - (millis() - timer));
}

Ciao.

Bene....magari per risolvere il problema di ricominciare il ciclo ho pensato ad un pulsante di reset, faccio prima una ricerca prima di scocciare qui.... Grazie ancora vi aggiorno

leggevo un pò in giro del "do while", potrebbe fare al mio caso?
" la condizione di ripetizione viene verificata solo DOPO aver eseguito il corpo del ciclo"
sembra adatto per la mia esigenza... :thinking:

Escludo che il do while possa cambiare le cose.
Ma scusa cosa non va nell'ultimo skech che ho allegato.
Il servo va a 180, dopo 100ms torna a 0.
Da questo momento per avere lo stesso comportamento devi girare il gyro in modo che il valore di yaw sia minore di 1.
Adesso se muovi il gyro e superi 45 accade la stessa cosa e così all'infinito.

Ciao.

Nella modifica che mi hai scritto succede che il servo si posiziona a 45° e non da 0° e quando con il giroscopio raggiungo i 45° al monitor seriale, il servo fa solo un cenno di muoversi e basta, poi l'asse Yaw si blocca a zero sul monitor e non cambia valore.
Invece quello dello screenshot che ti ho allegato precedentemente fa il suo lavoro benissimo anche se probabilmente è scritto piu rudimentale.
Il problema resta come ripartire da zero lo sketch da codice prima di arrivare al tasto reset esterno

Lo avevo detto che di giroscopi non ne capisco nulla.

bool enable = false;

void loop()
{
  timer = millis();

  // Read normalized values
  Vector norm = mpu.readNormalizeGyro();
   
  Serial.print("ZAxis = ");
  Serial.println(norm.ZAxis);
  
   if (enable == true &&  norm.ZAxis > 45) {
       ServoZ.write(180);
       delay(500);    // 500ms nella speranza che il servo non ci impieghi più tempo.
       ServoZ.write(0);
       delay(500);
       enable = false;  // da questo momento enable == false.
   } else if ( norm.ZAxis < 5)  {
       // altrimenti se  norm.ZAxis < 5 gradi enable = true.
       enable = true;
   }  

  
  delay(500);
}

Così dovrebbe funzionare.

Ciao.

Provato, mi piace come lavora.... solo la sensibilità del giroscopio è troppo elevata, appena lo tocco subito attiva il servo. Su quali parametri posso agire? Grazie ancora