"Tenere memoria" dell'ultimo valore misurato

Ciao.

Ho usato una scheda arduino ed un barometro per mantenere la quota di un quadricottero, ricorrendo anche alla libreria dei controlli retroattivi (PID). Il tutto funziona molto bene e sono soddisfatto.

Il passaggio dalla modalità 'normale' alla modalità 'altitude hold', viene fatto direttamente in volo, via telecomando tramite switch.
Lo switch in posizione zero implica che arduino semplicemente passi il segnale da ricevente a cervello elettronico del velivolo.
Lo switch in posizione uno implica che arduino applichi delle correzioni proporzionalmente alla differenza tra valore misurato (dal barometro) e valore di riferimento (per ora impostato manualmente).

Ciò permette di mantenere una quota assegnata senza doversi preeoccupare, durante le manovre, di compensare con il gas

Come anticipato, il valore di quota di riferimento (in gergo "Setpoint"), è impostato manualmente (via IDE), ma vorrei fare in modo che allo sfiorare dello switch sul telecomando, arduino si ricordasse il valore ISTANTANEO di pressione letto (misurato) al momento in cui passo da una modalità all'altra. Così facendo potrei imporre al velivolo di mantenere la quota arbitraria, non fissa (da immettere manualmente).

La mia domanda è:
come posso codificare il concetto: "Prendi l'ultimo dei valori di pressione misurati".

Nota: Essendo dentro al loop principale, non posso assegnare il valore di p ad una variabile OLDVARIABLE, siccome ad ogni passaggio questo valore viene riaggiornato, a seconda di quello che legge i sensore di pressione. Dovrei quindi persuadere ARDUINO a leggere il valore di pressione e smettere di aggiornare quella variabile. COme fare?

molte grazie.
un saluto
Marco

Ciao, non sono esperto di quadricottiri o simili, quindi potrei dire ubna cosa non totalmente esatta, ma in realtà il problema è di semplice risoluzione. Nel momento in cui passi da una modalità all'altra devi memorizzare la quota attuale, per farlo ti basta una variabile booleana in più. Ovvero:

if(modalitàAltidutehold){
  if(!bAltiduteStored){
    altitudeToMaintain = currentAltitude;
    bAltiduteStored = true;
  }
  ... procedure di mantenimento altitudine...
}
else{
  //Modalità manuale
  bAltiduteStored = false;
  ... procedure navigazione manuale ...
}

Spero di essere stato sufficientemente chiaro, nel caso il problema fosse più complesso o ci fossero ancoras dubbi siamo qui :slight_smile:

Crei una variabile globale, in modalità "normale" gli assegni sempre la quota letta,
quando passi alla modalità "set hold" NON devi più fare quella parte di codice, quindi la tua nuova variabile globale rimane quella di prima.
Ovvero sei tu che nel codice devi aggiornare questa variabile globale con il valore interessato SOLO in una parte del codice.

oops, contemporeanità con @fabpolli :smiley:
ora hai due proposte di soluzione, molto simili... ma leggermente diverse.

Ciao. Grazie ad entrmbi per la risposta in quasi sincrono.

Capisco bene cosa mi state cercando di dire. In modalità manuale continua ad aggionrare il valore della pressione, poi (sando un booleano) appena passo in modalità altitude hold, smettere di aggiornare.

Fabpolli, ho provato a usare il tuo frammento di codice ma:

  1. non mi è chiaro perchè il ciclo if è a sua volta annidato dentro il ciclo che decide se si è opp no in modalitò alt hold (Io avrei messo il tuo ciclo if FUORI dal ciclo grande e solo quando selezionato altitudde hold, mettere il boelano falso). e
  2. non funziona. Ho provato anche a modificare i livelli di annidamento, ma non funziona.

Allego il mio codice main:

Serial.print(average,3);  /Average è il nome della variabile che contiene la pressione (mediata)
     
      
      int NowH;
      boolean bAltiduteStored; //dichiara il booleano 
  
      
      
      //Depending on Position of Switch (ON or OFF), act accordingly:   
 
      if (ch6<1100) //Manual Flight  (canale sul telecomando corrispondente allo switch)
          {
            bAltiduteStored = false;
            [omiss...]
            
          }
      else  //Altitude Hold
          {
            
           if(!bAltiduteStored)
           {
              NowH = average;
              Serial.print(" *!* ");
              bAltiduteStored = true;
            }
           
             



            Setpoint=NowH; //Leggi il valore di pressione (ultimo letto), trattienilo e usalo come Setpoint (bersaglio)
            Input=average;  //average è il nome della variabile che contiene la pressione (mediata)
            
          
            AltHold.SetSampleTime(10);
            //Activate PID Loop
            //SetPoint is most recently detected pressure-altitude measurement
            
            AltHold.SetMode(AUTOMATIC);
            AltHold.Compute();
            

            
            Serial.print("\t (altide mode: on)");
            digitalWrite(led, HIGH);
            
            Serial.print("\t Setpoint:");
            Serial.print(Setpoint);
            
            Serial.print("\t Output:");
            Serial.print(Output);
            
            Serial.print("\t Now Alt:");
            Serial.print(NowH);


            int x, Thr;
            x=constrain(Output,0,60);
            Thr=map(x, 0, 60, 1175, 2000);
            
            manetta.writeMicroseconds(Thr);

            Serial.print("\t Throttle Input:");
            Serial.print(Thr);   
            
            Serial.print("\t Kp:");
            Serial.print(Kp);  
            Serial.print("\t Ki:");
            Serial.print(Ki);  
            Serial.print("\t Kd:");
            Serial.print(Kd);  
                        
            
            
          }; //qui termina la modalità altitude hold

Perchè non riesco a dirgli di smettere di registrare quando in modalità altitude hold?
GRazie. ciao
Marco

Ciao, la logica è la prima volta che entro nella sezione di mantenimento altitudine memorizzo il valore di pressione attuale. Ad ogni ciclo entrerò nel solita roma (mantenimento automatico altitudine) ma non memorizzo nuovamente il valore di pressione in modo da utilizzare il dato del primo ingresso. Detto ciò il codice che hai scritto così a logica dovrebbe essere corretto, cosa non funziona? Non mantiene l'altitudine? Vedo che hai diversi messaggi di debug in console, cosa ti fa capire che il codice non funziona (non sono pratico della cosa e quindi potrei aver letto il codice in modo non corretto) potrebbe forse errere la funzione compute di AltHold?

Ciao. GRazie per la risposta.

Ciò che non funziona è il "congelamento" (NON aggiornamento) del valore di pressione, nonostante il booleano si impostato su false.

Per debugging, stampo su terminale i valori per l'algoritmo PID, oltre che le misure di pressione e il segnale che mando poi ai motori. Noto appunto che il valore della pressione cambia, e segue quello misurato dal barometro.

Cioè il valore di p continua ad aggiornarsi.
un saluto
Marco

EUREKAAAA!!

//Parametri di Servizio

//Include LIbraries
#include <Wire.h> 
#include <Adafruit_BMP085.h>
#include <Servo.h> 
#include <Average.h> 
#include <PID_v1.h>


Adafruit_BMP085 bmp;


int ch3;             //channel used to switch the control on and off
int ch6;             //throttle input channel
int testTR=1400;     //static throttle value (used for earlier test version)
//Define PINs on Arduino Board (uno)
int PinSwitch=10;    //Switch
int PinIn=7;         // Signal enter into arduino from radio RX
int PinOut=9;        // Signal leave arduino and goes to quadcopter
int led = 13;        //Led to detect on off 


double np;

void setup() 
{
  
   if (!bmp.begin()) 
    {
	Serial.println("Could not find a valid BMP085 sensor, check wiring!");
	while (1) {}
    }
    Serial.begin(115200); // Pour a bowl of Serial
    Serial.println("");
    Serial.println("");
    Serial.println("");
    
   double p;
   p=bmp.readAltitude(102000);
   
   np=p;
}


void loop() 
  {
    
      //leggi il valore dello SWITCH su canale 6 del radiocomando
      ch6 = pulseIn(PinSwitch, HIGH, 20000);
       
      
      //preleva misura dal barometro e stampa su tarminale
      double p;
      p=bmp.readAltitude(102000);
      Serial.print("P= "); Serial.print(p);
    
    
    
      //Definisci ciclo per scrittura condizionata con un booleano 
      boolean bAltitudeStored=false;
      
    
    
     
      //Verifica posizione SWITCH
      if (ch6<1100) //Manual Flight
          {

           bAltitudeStored=false;
                 if (!bAltitudeStored)
                {
                   np=p;
                }
          }
          else //altitude hold <-----è quiche bisogna congelare il valore di p
          {
 
           bAltitudeStored=true;
           if (!bAltitudeStored)
              {
               np=p;
              }
           Serial.print(" (*)");
           Serial.print(np);
          }
      
      
      Serial.println("");
      delay(50);
  }

Il ciclo andava annidato in entrambi i casi (sia manuale che altitude hold).