Problema funzione maps Arduino.

Salve a tutti,
vi spiego il mio problema sperando che riusciate a darmi una mano.
Devo fare un controllo proporzionale della velocità di un motore in corrente continua in funzione dei gradi letti da un accelerometro MPU6050. Ho scaricato la libreria I2cdev che mi ha permesso di visualizzare correttamente i valori dei gradi convertendo quelli grezzi che mi arrivavano dal sensore.
Siccome non so implementare i PID nel mio codice, ho deciso di fare da me un controllo proporzionale sfruttando la comoda funzione maps di Arduino: in pratica, nella funzione maps ho fatto la proporzione tra i gradi letti dal giroscopio e la velocità del motore.Per cambiare il verso e regolare la velocità del motore sto utilizzando un driver BTS7960 che ho correttamente interfacciato ad Arduino.
Per ragioni di lunghezza del codice, vi condivido solo la parte iniziale del loop, che poi è quella che secondo me ci interessa.

void loop() {
  int vel;  //valore della velocità del motore                         

  float y=ypr[2] * 180/M_PI; // valore dell'angolo di Pitch/beccheggio che va da -90° fino a 90°


     if(y>=0) {// se l'angolo è positivo...
       vel=map(y, 0, 40, 50, 255);//fai la proporzione tra 0-40° da 50-255 di velocità del motore
       analogWrite(LPWM,vel);      //scrivi questo valore di velocità: il motore gira in un verso
       }
     if(y<0)  {  // se l'angolo è negativo...
       vel=map(y, 0, -40, 50, 255);//fai la proporzione tra 0-(-40°) da 50-255 di velocità del motore
       analogWrite(RPWM,vel);      //scrivi questo valore di velocità: il motore gira nell'altro verso
      }

Siccome ho bisogno che il mio motore abbia una certa coppia all'inizio per far girare un carico prima in senso orario e poi in senso antiorario, nella funzione maps ho messo che per y>=0° e y<0°, il motore inizia già con una velocità di 50, in un senso se i gradi misurati sono per y>=0° e nell'altro senso se y<0°, in modo da avere quella spinta in più all'avviamento (spero di essermi spiegato).

In LPWM ed RPWM andranno scritti i valori da 0-255 che regoleranno la velocità del motore attraverso il driver motori.

Il mio problema è questo: il valore di velocità varia sempre da 0-255 anche se ho messo 50-255, cioè a più di 0 gradi il motore non inizia con una velocità di 50 ma sempre di 0: sebbene sul monitor seriale esca scritto che il valore di velocità che viene inviato al motore è effettivamente 50, ho notato che il motore a 1° non si muove proprio, mentre a velocità 50 dovrebbe già girare (ho provato a inserire anche valori più alti all'inizio fino e 120 ma niente!). Ho notato però che se inizio già inclinato di un tot di gradi (ad esempio +5°), quella proporzione mi vale e in effetti il motore gira alla velocità dettata dalla proporzione, ma, non appena voglio cambiare inclinazione facendola diventare negativa (ad esempio -5°), nel momento in cui passo oltre gli 0° per dirigermi verso gli angoli negativi, ecco che la proporzione non vale più e diventa di nuovo da 0-255. E' come se quel valore di 0° imponesse che la proporzione deve essere per forza 0-255 se ci passo attraverso (oddio ragazzi spero di non avervi confuso le idee...). Secondo voi quale potrebbe essere il problema? E' quel valore troppo preciso di 0° che mi dà problemi e non mi fa iniziare con una velocità di 50 per gradi superiori(o inferiori) a 0°? Oppure sono io che non so usare la funzione maps? Oppure la funzione maps permette di fare proporzione solo da 0 ad un valore generico(non credo proprio...)? Ho cercato di essere il più preciso possibile, se non avete compreso qualcosa chiedete pure. Spero che qualcuno abbia un'idea su quale possa essere il problema o su come, eventualmente, poterlo aggirare.

Consiglio: prova ad eliminare l'ultimo if..ovvero, utilizza il primo if con y>=0, e per il secondo usa un ELSE (che equivale in questo caso a y<0) non è qui il problema, ma semplifichi la sintassi diciamo. Ti dico questo perché ad un mio progetto era palese che doveva andare in un certo modo, ma non c'era verso che funzionasse correttamente. Mettendo un else al posto del secondo if ho risolto il problema. Nel mio caso avevo uno sketch lungo ed ero al limite con la memoria..forse era x questo che mi era capitata sta cosa.. Cmnq ad occhio sembra corretta la logica, la funziona map non la conosco. Prova a togliere uno dei due if cosi vedi come reagisce..assicurati che le variabili che hai dichiarato accettino valori negativi! Ciao

Credo che il problema sia la funzione map che lavora con interi.

O converti semplicemente la variabile float y ad intera o meglio la converti anche in decimi di grado:

vel = map(int(y * 10), 0, 400, 50, 255);

Dacci il codice completo. Dove stampi il valore sulla seriale?
Ciao Uwe

Il problema potrebbe essere proprio il float, in più mettere else è meglio in questo caso come ti dicono sopra :wink: Comunque se pubblichi lo sketch completo è sempre meglio, mettilo come allegato.
Ciao!

Vi ringrazio delle risposte. :slight_smile: Vi allego lo sketch completo. Il codice è così lungo a causa della libreria I2cdev. A inizio loop trovate il codice che ho scritto io. In aggiunta vi è anche una variabile che legge lo stato di un pulsante buttonState : solo se è premuto il motore si muove con una certa velocità vel. Si @uwefed il valore viene stampato sulla seriale. Ho accettato il consiglio e ho cambiato l'if in else ma non ho visto cambiamenti purtroppo. Forse ho dimenticato di dirvi che il modello che sto utilizzando è Arduino Nano, non so se questo sia un dato rilevante...

MPU6050_TEST.ino (13.5 KB)

Adesso non posso dare un'occhiata allo sketch, ma cosa piu importante dell else é che la variabile y non deve essere un float :wink: O la cambi in int, oppure fai come ti ha pubblicato cyber
Ciao!

As_Needed:
Adesso non posso dare un'occhiata allo sketch, ma cosa piu importante dell else é che la variabile y non deve essere un float :wink: O la cambi in int, oppure fai come ti ha pubblicato cyber
Ciao!

Il problema è che mi serve che la velocità del motore vari con continuità... se metto che la y è un int prevedo che il motore andrà a scatti passando da, per esempio, 200 a 210 con un grado di differenza. Invece, a me serve scrivere tutti i valori da 50-255. Adesso faccio altri test e vi faccio sapere.

Nel frattempo sono riuscito ad implementare un PID in un altro programma. Al momento sto agendo solo sulla variabile P... vi faccio sapere se ho risolto in questo modo.

Ma la dichiarazione della variabile è solo per far dire al programma: questa variabile ha bisogno di n bit. Con una variabile byte occupi tutta la gamma da 0 a 255 con 4 bit..se ti basta come gamma numerica, usa byte..float è se hai bisogno di numeri con virgola...int se hai bisogno di andare in negativo...

Il problema però è anche che la funziona map deve essere usata con numeri interi. Se fai come dice giustamente cyber ovvero così:
vel = map(int(y * 10), 0, 400, 50, 255);

è un modo per avere anche i decimi di grado usando int. :wink:
Ciao!

Ok, proverò a fare come consiglia giustamente cyber. Vi aggiorno.

Ho provato a convertire la variabile scrivendo la riga di codice che mi avete consigliato ma niente purtroppo :confused: .

Allora, ho fatto altri test. Sempre stessa situazione: se il pulsante io lo tengo premuto a, per esempio, 1°, allora il motore gira effettivamente a 50 in un verso. Ora, se io continuo a tenere premuto il pulsante spostandomi contemporaneamente verso i valori negativi, allora non appena passo per 0°, il motore parte a 0 di velocità nonostante sul monitor seriale mi esca scritto che il valore inviato al ponte H sia 50. Sto letteralmente uscendo pazzo :o .

Ho fatto un altro test: ho provato solo in un verso e la funzione map rispetta la proporzione dettata!! Parte con 50. A questo punto, sono più confuso di prima dato che non capisco quale possa essere il problema...

baldursgate:
Ho fatto un altro test: ho provato solo in un verso e la funzione map rispetta la proporzione dettata!! Parte con 50. A questo punto, sono più confuso di prima dato che non capisco quale possa essere il problema...

Infatti almeno io non riesco a capire quale sia il problema, la proporzione la fa, non mi viene in mente il perché se passa da 0 fa così... Forse a qualcun'altro può venire in mente. :wink:
Ciao!

Salve ho risolto il problema... Cioè almeno per la mia applicazione questa scelta va più che bene. Praticamente non lo faccio passare per lo zero ma definisco un piccolo intervallo dove i motori stanno fermi e non fanno niente. Ecco l'inizio del loop ( in questo caso considerate il centro come 1°, valore empirico...):

void loop() {
  int vel;
  int buttonState=digitalRead(button);
  float y=ypr[2] * 180/M_PI;
  Serial.print("                    y=   ");
  Serial.println(y);
  digitalWrite(R_EN,HIGH);
  digitalWrite(L_EN,HIGH);
     
     if(buttonState==1) {
     if(y>=2.00f) {
       
      // vel=map(y, 2, 42, 40, 200);
       vel = map(int(y * 10), 50, 400, 20, 255);
       analogWrite(LPWM,vel+50);
       //Serial.print("Destra");
       }
       else analogWrite(LPWM,0);
    if(y<0.00f) {
       
      // vel=map(y, 0, -40, 40, 200); 
        vel = map(int(y * 10), -50, -400, 20, 255);
       analogWrite(RPWM,vel+50);
       }
       else analogWrite(RPWM,0);
       }
       else  {analogWrite(RPWM,0); analogWrite(LPWM,0);}
       // Serial.print("Sinistra");
       
   Serial.print("VEL=  ");
   Serial.println(vel);

Ciao e grazie per l'aiuto :slight_smile:

Di niente! Anche se sarei curioso se qualcuno sapesse il perché.. ma se dici che va bene cosi.
Ciao!