problema calcoli e variabili

Buonasera a tutti.

Sto cercando di realizzare un controllo PID sulla velocità in uscita di un motore cc.

Appena iniziato a scrivere il codice ho riscontrato subito un problema a livello di calcolo software.

Il seguente codice serve proprio a chiarire il problema riscontrato nel codice originale:

float t=0,t0=0,dt=0;
float vr;
float vt=10.2;
float kp=5,ki=2;
float err=0.0,It=0.0,Pid=0;
int np0=5;
void setup()
{
  Serial.begin(9600);  // input/output

}


void loop()
{
t=millis();
dt=(t-t0)/1000;
vr=((np0)*3.1416)/(dt*5.0);
 //vr=2.1;
  err=vt-vr;
  
  It=It+err*dt;
  
  Pid=(kp*err)+(ki*It);

    Serial.print("; dt= ");
  Serial.print(dt);
    Serial.print("; vr= ");
  Serial.print(vr);

    Serial.print("; Err= ");
  Serial.print(err);

    Serial.print("; It= ");
  Serial.print(It);
    Serial.print("; Pid= ");
  Serial.println(Pid);

   
 t0=t;
delay(500);
}

nel main loop vengono eseguiti dei calcoli su tempi (dt) e velocità (vr e vt) ed i risultati vengono inviati al monitor seriale. Tuttavia i risultati dei calcoli sono diversi a seconda che Vr sia calcolata dalla formula o che sia impostata ad un valore fisso decommentando la riga vr=2.1.

In pratica, facendo girare il codice con il monitor seriale acceso il valre di "Pid" rimane a zero, se si utilizza la variabile "Vr" calcolata dalla espressione matematica, mentre si incrementa (come vorrei) se si impone Vr ad un valore fisso, ad esempio 2.1. Qualcuno può darmi una mano a comprendere?

Ringrazio e saluto

Prima di tutto, essendo il tuo primo post, ti consiglio di presentarti QUI (spiegando quali conoscenze hai di elettronica e di programmazione) e di leggere con attenzione il REGOLAMENTO ...

... poi, attenzione a come definisci le variabili ... la prima che mi salta all'occhio è t (ed anche t0 e dt) che tu hai definito float mentre, essendo usata con millis() deve essere definita unsigned long.

Guglielmo

Grazie Guglielmo di avermi risposto e di avermi consigliato le buone maniere, sono novizio un po’ in tutto…

…non capisco tuttavia in cosa sto sbagliando nel mio sketch e neppure i tuoi consigli:

dunque, ho definito le variabili t,t0,e dt come “float” poichè i reali contengono al loro interno anche gli interi, poi, volendo il valore di “dt” (delta tempo) in secondi questo può assumere anche valori < 1 e quindi non intero di tipo long. Per questo motivo ho pensato che nel grande (float) ci stesse anche il piccolo (unsigned long), in cosa sto sbagliando?
Comunque ho provato a definire i valori t,t0 e dt come tu consigli ma il risultato è ancora peggiore perchè adesso esce tutto zero, anche i valori di Vr e di err che prima mi calcolava in modo corretto!

Puoi aiutarmi a venirne a capo?

Ringrazio e saluto
Luca

Devo subito correggermi in quanto ho visto che millis() deve necessariamente lavorare con unsigned long per non generare errori di calcolo.Quindi definisco t e t0 unsigned long e dt come float ma il comportamento del codice rimane apparentemente incomprensibile.

Saluti

ciao

Dichiarando t e t0 unsigned long e dt float ottengo questo:

; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan

e mi sono chiesto: ma perchè dt è uguale a 0.00? Nella formula dt = (t - t0) / 1000; ho un numero intero 500 (t-t0) diviso un altro numero intero (1000) e quindi il risultato 0 ci stà. Di conseguenza la formula vr = ((np0) * 3.1416) / (dt * 5.0); mi da una divisione per 0 e mi risulta che non sia possibile

allora ho modificato così:

 dt = (t - t0) / 1000.0;

con questo risultato:

; dt= 0.00; vr= inf; Err= inf; It= nan; Pid= nan
; dt= 0.50; vr= 6.28; Err= 3.92; It= nan; Pid= nan
; dt= 0.50; vr= 6.26; Err= 3.94; It= nan; Pid= nan
; dt= 0.50; vr= 6.27; Err= 3.93; It= nan; Pid= nan
; dt= 0.50; vr= 6.27; Err= 3.93; It= nan; Pid= nan
; dt= 0.50; vr= 6.26; Err= 3.94; It= nan; Pid= nan
; dt= 0.50; vr= 6.26; Err= 3.94; It= nan; Pid= nan
; dt= 0.50; vr= 6.26; Err= 3.94; It= nan; Pid= nan
; dt= 0.50; vr= 6.26; Err= 3.94; It= nan; Pid= nan

Un miglioramento: dt non vale più 0 (a parte il primo) e vr e Err "danno i numeri" E fino a quì le cose che ho capito. :confused: :confused: Non mi chiedere perchè ma se aggiungi un bel

delay(1000);

prima del Serial.begin ottieni questo:

; dt= 1.00; vr= 3.14; Err= 7.06; It= 7.05; Pid= 49.37
; dt= 0.50; vr= 6.25; Err= 3.95; It= 9.04; Pid= 37.85
; dt= 0.50; vr= 6.27; Err= 3.93; It= 11.01; Pid= 41.66
; dt= 0.50; vr= 6.25; Err= 3.95; It= 12.99; Pid= 45.76
; dt= 0.50; vr= 6.26; Err= 3.94; It= 14.97; Pid= 49.66
; dt= 0.50; vr= 6.25; Err= 3.95; It= 16.96; Pid= 53.70
; dt= 0.50; vr= 6.26; Err= 3.94; It= 18.94; Pid= 57.59
; dt= 0.50; vr= 6.26; Err= 3.94; It= 20.92; Pid= 61.55
; dt= 0.50; vr= 6.25; Err= 3.95; It= 22.91; Pid= 65.59
; dt= 0.50; vr= 6.26; Err= 3.94; It= 24.89; Pid= 69.49
; dt= 0.50; vr= 6.25; Err= 3.95; It= 26.88; Pid= 73.53
; dt= 0.50; vr= 6.27; Err= 3.93; It= 28.85; Pid= 77.34
; dt= 0.50; vr= 6.25; Err= 3.95; It= 30.83; Pid= 81.44

Non so se è quello che volevi ma almeno i numeri si muovono

Ma non ho ancora capito perchè... :'( :'(

ciao pippo72

Grazie tante pippo72

forse nel funzionamento aleatorio delle varie formule tu hai trovato la combinazione giusta di piccole modifiche per far funzionare il tutto!

Da quello che dici (proverò appena posso) se divido un intero (t-t0) per un altro intero 1000 il risultato è un intero, e quindi il giusto valore di 0.5 mi si approssima a “0”, che messo in una variabile dt definita come float diventa “0.0”.
Invece dividendo l’ intero (t-t0) per un intero con la virgola (e quindi un float) 1000.0 il risultato è un float non approssimato all’unità che messo in una variabile float viene correttamente visualizzato…

Possibile???

il fatto poi che aggiungendo un delay nel setup faccia funzionare tutto il resto proprio non me lo spiego!!!
sembra che il risultato di un calcolo dipenda pure dall’umidità della stanza!!!Maledetta ignoranza…la mia ovviamente…

se qualcuno volesse aggiungere qualcosa sarei grato.

Grazie ancora pippo!

La fregatura principale è che ti serve un PID e non un più semplice blink, per PID + ignoranza = fegato spappolato.

Comunque la libreria PID di arduino non è sufficiente per le tue necessità? In ogni caso pid o non pid i calcoli in C possono fare girare le palle al principiante. Colmare questa ignoranza se hai due giorni di tempo ci riesci anche svagandoti di tanto in tanto. Se puoi/vuoi cerca un libro sul C (in questo contesto il C++ si comporta come il C) e comincia dall'inizio con i tipi di dato e con gli operatori, il cast implicito e quello esplicito.

PS: Vai sicuramente più spedito nell'apprendimento se usi un compilatore IDE per il PC, ti compili i pochi esempi proposti e te li tienei li presenti come memoria storica, perché anche dopo tanta confidenza con il C capita sempre un calcolo che fornisce dati inaspettati.

Ciao.

Grazie Mauro

non fai altro che confermare ciò che sospettavo ..... l'ignoranza va colmata con lo studio! Prima di comprare un libro cercherò su internet qualche "scorciatoia" ossia qualcosa di più approfondito su l'argomento:

i tipi di dato e con gli operatori, il cast implicito e quello esplicito.

Non riuscendo a risolvere, ahimè studierò!!

Saluti