Averaging sensor data inside a Millis loop

Hi everyone,

What i would like to do is, blink an LED while 5seconds of pressure data is gathered and averaged for use later on in the code. Currently i have the LED code working nicely, and can get the two functions running in series but not parallel. Im clearly not implementing the pressure reading and count correctly. To make it work, i need to know how many times the data was counted during the time period so that i can average by (sum of pressure readings)/ (number of pressure readings). The question is , Have i done this right?
The code keeps falling over at sumPressure += ms5611.readPressure();

Note the code only runs once for 5 seconds in the setup loop, hence the uint32_t period = 5000L wrapper loop.

Happy to sample every barometerLED interval, so stuck it in that part of the code.

    // ===Initialise Barometer====
float sumPressure = 0;
const int NumMeasurements = 100 ;
const int count = 0;

    
  uint32_t period = 5000L;       // approx 5 seconds  Used to set test lopp for period of time
// flash barometerLED while not armed for flight
for( uint32_t tStart = millis();  (millis()-tStart) < period;  ){{
      currentMillis = millis();    
      
   
      

      
  if (barometerLED_State == LOW) {
    if (currentMillis - previousbaroLED_Millis >= barometerLED_Interval) {
       barometerLED_State = HIGH;
       previousbaroLED_Millis += barometerLED_Interval; 
       sumPressure += ms5611.readPressure();
       count == count +1;
    }
    
  }
  else {
    if (currentMillis - previousbaroLED_Millis >= blinkDuration) {
       barometerLED_State = LOW;
       previousbaroLED_Millis += blinkDuration;
       
    } 
  } 
   
}
digitalWrite(barometerLED, barometerLED_State);
referencePressure = sumPressure / count ; //NumMeasurements;

Serial.println( referencePressure);
Serial.println( count);
}
count == count +1;

Oops

const int count Oops

The code keeps falling over at

What does that mean?

Thanks!
count is now an int, and count = count+1 but the count function sort of works, it counts 1,1,2,2,3,34,4,5,5,6,67,7,7,7,7,8,8,8,8,8....
Not the way i was hoping it would count!
if i move the count function to the top, it counts 16,000 times. That's a lot of samples and a bit over the top. I only need every 200ms for the five seconds. The blink duration is a variable currently set at 200Ms.

"The code keeps falling over at.." means the code crashes at : sumPressure += ms5611.readPressure();

if i comment it out, it works.

for( uint32_t tStart = millis();  (millis()-tStart) < period;  ){{

What's that?

Please post your updated code; all of it.

for( uint32_t tStart = millis(); (millis()-tStart) < period; )

Its basically a millis loop to wrap around the main Millis function to make it run in the setup() . Long story short, i dont want to run this loop in the Main() as i only want it to run once to create the the baseline reference pressure.

updated code ( with sumpressure commented out ):

  // ===Initialise Barometer====
float sumPressure = 0;
int count = 0;

    
  uint32_t period = 5000L;       // approx 5 seconds  Used to set test lopp for period of time
// flash barometerLED while not armed for flight
for( uint32_t tStart = millis();  (millis()-tStart) < period;  ){{
      currentMillis = millis();       
      //sumPressure += ms5611.readPressure();
      count = count +1;
      
  if (barometerLED_State == LOW) {
    if (currentMillis - previousbaroLED_Millis >= barometerLED_Interval) {
       barometerLED_State = HIGH;
       previousbaroLED_Millis += barometerLED_Interval; 

    }
    
  }
  else {
    if (currentMillis - previousbaroLED_Millis >= blinkDuration) {
       barometerLED_State = LOW;
       previousbaroLED_Millis += blinkDuration;
       count = count +1;
    } 
  } 
   
}
digitalWrite(barometerLED, barometerLED_State);
referencePressure = sumPressure / count ; //NumMeasurements;

Serial.println( referencePressure);
Serial.println( count);
}

roweng:
for( uint32_t tStart = millis(); (millis()-tStart) < period; )

Its basically a millis loop to wrap around the main Millis function to make it run in the setup() . Long story short, i dont want to run this loop in the Main() as i only want it to run once to create the the baseline reference pressure.

It's very difficult to know what is going on as you have not posted the complete program.

If you want to create a timed loop in setup() then you could do it like this

bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
  // other code in this loop
}

...R

Heres the code stripped down to look at the important bit:

Currently i have the LED blink for 5 seconds in the setup loop. Perfect.
But what I want to do is, during this 5 second period, take a barometer reading every say, 0.2 seconds, record the sum of baro readings, and the number of baro readings ( should be 5sec/ 0.2 sec = 25 readings)

so that i can determine an average pressure at the end of this time period. Getting confused as to how i count every n times through the loop.

//=======Include Libraries===============
//libraries here
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor
#include <Kalman.h> // single state Kalman Filter
//=============LED Setup=================
const byte powerLED = 3;
const byte barometerLED = 5;
byte barometerLED_State = LOW;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long previouspowerLED_Millis = 0;
const int blinkDuration = 200; // number of millisecs that Led's are on - all three leds use this

//============= Millis() timing  Setup=============

unsigned long prevLedCMillis;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED

//=============Pressure sensor Setup===== GY-63
const int elapsedTime = 100;

MS5611 ms5611;

double referencePressure;
unsigned long prevMillis;
const int pause = 10;

void setup() {

   // ===Initialise LED's====

  pinMode(barometerLED, OUTPUT);

  
  // power on, delay then turn off showing power is on and state is ready to proceed

  digitalWrite(barometerLED, HIGH);
  delay(2000);
  
  digitalWrite(barometerLED, LOW);


  
  // ===Initialise Barometer====
float sumPressure = 0;
int newcount;
int count1 =0;
int countZero =0;
int count =0;

    
  uint32_t period = 5000L;       // approx 5 seconds  Used to set test lopp for period of time
// flash barometerLED while determining average pressure


for( uint32_t tStart = millis();  (millis()-tStart) < period;  ){{      
  if (barometerLED_State == LOW) {
    if (currentMillis - previousbaroLED_Millis >= barometerLED_Interval) {
       barometerLED_State = HIGH;
       previousbaroLED_Millis += barometerLED_Interval; 

    }
    
  }
  else {
    if (currentMillis - previousbaroLED_Millis >= blinkDuration) {
       barometerLED_State = LOW;
       previousbaroLED_Millis += blinkDuration;
       
    } 
  } 
   
}
digitalWrite(barometerLED, barometerLED_State);
referencePressure = sumPressure / count ; //NumMeasurements;

Serial.println( referencePressure);
Serial.println( count1);
}

}

void loop() {
  // put your main code here, to run repeatedly:

}

referencePressure = sumPressure / count ; Zero divided zero?

Heres the latest iteration.

Problems:

It doesnt sum the sumPressure readings
It doesnt incriment the newcount every 10000 readings.

I understand what i want to to do, but im struggling to get the code to do it!

//=======Include Libraries===============
//libraries here
#include "I2Cdev.h"
#include <Servo.h>
#include "MPU6050_6Axis_MotionApps20.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor
#include <Kalman.h> // single state Kalman Filter
//=============LED Setup=================
const byte powerLED = 3;
const byte barometerLED = 5;
byte barometerLED_State = LOW;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long previouspowerLED_Millis = 0;
const int blinkDuration = 200; // number of millisecs that Led's are on - all three leds use this

//============= Millis() timing  Setup=============

unsigned long prevLedCMillis;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED

//=============Pressure sensor Setup===== GY-63
const int elapsedTime = 100;
float filteredAltitude;
// initial values Kalman myfilter(1.025,32,1023,0);//suggested initial values for high noise filtering
Kalman myFilter(1.0125,20,1023,0); 

MS5611 ms5611;

double referencePressure;
unsigned long prevMillis;
const int pause = 10;

void setup() {

   // ===Initialise LED's====

  pinMode(barometerLED, OUTPUT);

  
  // power on, delay then turn off showing power is on and state is ready to proceed

  digitalWrite(barometerLED, HIGH);
  delay(2000);
  
  digitalWrite(barometerLED, LOW);


  
  // ===Initialise Barometer====
float sumPressure = 0;
int newcount;
int count1 =0;
int countZero =0;
int count =0;
Serial.begin(9600);
 
  // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
    
  uint32_t period = 5000L;       // approx 5 seconds  Used to set test lopp for period of time
// flash barometerLED while not armed for flight
for( uint32_t tStart = millis();  (millis()-tStart) < period;  ){{      
  count = countZero + 1;
  countZero = count;
  if (count >= 10000){
    sumPressure += ms5611.readPressure();
    newcount = count1 + 1;
    
    
  }
  
  if (barometerLED_State == LOW) {
    if (currentMillis - previousbaroLED_Millis >= barometerLED_Interval) {
       barometerLED_State = HIGH;
       previousbaroLED_Millis += barometerLED_Interval;       
        
    }
    
  }
  else {
    if (currentMillis - previousbaroLED_Millis >= blinkDuration) {
       barometerLED_State = LOW;
       previousbaroLED_Millis += blinkDuration;
       
    } 
  } 
   
}
digitalWrite(barometerLED, barometerLED_State);
referencePressure = sumPressure / count ; //NumMeasurements;
Serial.println("--");
Serial.println( referencePressure);
Serial.println( sumPressure);
Serial.println( count);
Serial.println( newcount);
}

}

void loop() {
  // put your main code here, to run repeatedly:

}

roweng:
I understand what i want to to do, but im struggling to get the code to do it!

Have you considered Reply #5 ?

...R

Yes- Im just thinking it over. I can see how to insert the blinking LED into it, but not how to take samples every n iterations through the loop and how to count the nth iteration. Im trying to research more on this part of the problem. If i understand that, then i may have achance of merging the two bits of code.

roweng:
Yes- Im just thinking it over. I can see how to insert the blinking LED into it, but not how to take samples every n iterations through the loop and how to count the nth iteration.

The WHILE loop will repeat so quickly that counting the iterations is not very practical.

Perhaps you want a time interval between the samples?

...R

Robin2:
Perhaps you want a time interval between the samples?

Good question, because running wild has a undefined number of samples. Since the samples are added to a float, there is no more accuracy at some point.

roweng, please tell us why you want the average and why you came up with the 5 seconds.

  1. When removing noise, there is no need to sample for 5 seconds. Just a few samples, 5 to 1000, will remove the high-frequency noise. The total value can be a unsigned long to get more accuracy.

  2. When removing the mains 50Hz or 60Hz, it can be hard. The first thing to do is make a shielded and good circuit and perhaps a 100nF capacitor to the analog input and GND. Then a few seconds with enough samples should work. For example 3 to 10 seconds with 40 to 1000 samples per second. The millis-timer should stay in sync with time, so it should be a little different than the Blink-Without-Delay.

  3. When the pressure is changing and you want the average of the pressure, then a few samples 10 to 100 over a few seconds is enough. The pressure change is a slow process, unless a oscillating air pump is turned on. Those oscillations can travel a long way through air tubes. Then it is better to use a damper and a pressure sensor behind the damper.

(the numbers that I mention is just a guess to give a rough idea how many I'm talking about)

Answering the second part first:

Ive been doing some development on the side with manual averaging of the pressure running through a simple 1D Kalman filter ( using Kalman.h) and using a counter loop, and found that a reading every 0.5 seconds or less over about 5 seconds gave me good results for the initial pressure when determining relative altitude. But the reality is the intervals will be set up as variables so that i can keep on tuning on real life.

The end application is altitude measurement.

I saw counting iterations of a loop as a possible solution,but i'm very rusty at the is coding game. Infact this project has been fantastic in getting my knowledge up, even though its a bit above my ability. And there nothing like having a project you believe in, in order to focus and understand coding!

I can see now that yes, probably a time interval solution is probably better, and especially as i have millis already running, it should just be another layer on top of what i have. MAybe i should restructure my code to the answer5 structure, and then use a simpler blink structure and intertwine the averaging calculations. My mind wants to use a while averaging, do blinking approach, but i get the feeling thats a bit outdated?!

Ill get into the new approach and see how i go.

So playing around, i can get my measurements and count right, but i dont understand why i'm getting lots of measurements for each interval? As the duration is 5000, and the measurement period is 1000, im expecting 5 pressure measurements and a count of 1-5 displayed. Instead i get 1111111111,2222222,....

I appreciate i can achieve the count by dividing period/ read duration, but thats no fun! also, i dont need lots of readings for each interval, just one. What am i missing please?

// test of modified baro + blinking code using time interval
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor

int period = 5000;
byte barometerLED_State = LOW;
const byte barometerLED = 5;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long prevMillis =0;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED
const int blinkDuration = 200;
const int readDuration = 1000;
double referencePressure;
double pressure;

int count = 0;

MS5611 ms5611;

void setup() {

Serial.begin(9600);
pinMode(barometerLED, OUTPUT);

   // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
  
bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
    currentMillis = millis();

    if (currentMillis - prevMillis >= readDuration){
        count = count +1;
        referencePressure += ms5611.readPressure();
        pressure = ms5611.readPressure(); // debugging: reference pressure
      prevMillis = currentMillis;
    }
  double average = referencePressure/count;
  
    Serial.println(count);
    Serial.println(referencePressure);
    Serial.println(pressure);
    Serial.println(average);
}

};



void loop() {
  // put your main code here, to run repeatedly:

}

You are calculating averages and printing them every pass through a loop. Move one curly bracket to include them in the interval update.

You have a bunch of code in setup() that should be in the loop() function.

OK, thats sort of worked thanks. When i check the count, its still counting every pass through the interval. How do i set it so that it just counts once for each time interval please?

ie currently: 1,1,1,1,1,1,1,1...,2,2,2,2,2,2,2....,3,3,3,3,3.... etc

want: 1,2,3,4,5.

but the average looks right.

For selfish reasons, i need this to run inside the setup loop for now. In a future build, i can see it moving to loop(), but for now it needs to be in setup.

// test of modified baro + blinking code using time interval
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor

int period = 5000;
byte barometerLED_State = LOW;
const byte barometerLED = 5;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long prevMillis =0;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED
const int blinkDuration = 200;
const int readDuration = 1000;
double referencePressure;
double pressure;

int count = 0;

MS5611 ms5611;

void setup() {

Serial.begin(9600);
pinMode(barometerLED, OUTPUT);

   // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
  
bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
    currentMillis = millis();

    if (currentMillis - prevMillis >= readDuration){
        count = count +1;
        referencePressure += ms5611.readPressure();
        pressure = ms5611.readPressure(); // debugging: reference pressure
      prevMillis = currentMillis;
    }
    Serial.println(count); // debug check
}
  double average = referencePressure/count;
  
    Serial.println(count);
    Serial.println(referencePressure);
    Serial.println(pressure);
    Serial.println(average);


};

Ok, I think I've almost got it!

Problem now is it counts to count +1, so it counts to 6 instead of 5. its one step ahead of the loop, which is not right. How do i fix that?

// test of modified baro + blinking code using time interval
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor

int period = 5000;
byte barometerLED_State = LOW;
const byte barometerLED = 5;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long prevMillis =0;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED
const int blinkDuration = 200;
const int readDuration = 1000;
double referencePressure;
double pressure;

int count = 0;
int newcount = 0;


MS5611 ms5611;

void setup() {

Serial.begin(9600);
pinMode(barometerLED, OUTPUT);

   // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
  
bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
    currentMillis = millis();

    if (currentMillis - prevMillis >= readDuration){
         count = count +1;
        referencePressure += ms5611.readPressure();
        pressure = ms5611.readPressure(); // debugging: reference pressure
        
      prevMillis = currentMillis;
      
    }
    //Serial.println(count); // debug check
   
    
    if (newcount == count){
            newcount = newcount +1;
            Serial.println(newcount); // debug check
         }
}
  double average = referencePressure/count;

  
  
    Serial.println(count);
    Serial.println(referencePressure);
    Serial.println(pressure);
    Serial.println(average);


};



void loop() {
  // put your main code here, to run repeatedly:

}

fixed :slight_smile: :

// test of modified baro + blinking code using time interval
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor

int period = 5000;
byte barometerLED_State = LOW;
const byte barometerLED = 5;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long prevMillis =0;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED
const int blinkDuration = 200;
const int readDuration = 1000;
double referencePressure;
double pressure;

int count = 0;
int newcount = 0;


MS5611 ms5611;

void setup() {

Serial.begin(9600);
pinMode(barometerLED, OUTPUT);

   // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
  
bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
    currentMillis = millis();

    if (currentMillis - prevMillis >= readDuration){
         count = count +1;
        referencePressure += ms5611.readPressure();
        pressure = ms5611.readPressure(); // debugging: reference pressure
        
      prevMillis = currentMillis;
      
    }
    //Serial.println(count); // debug check
   
    
    if (newcount == count-1){
            newcount = newcount +1;
            Serial.println(newcount); // debug check
            Serial.println(pressure); // debug check
         }
}
  double average = referencePressure/count;

  
    Serial.print ("No. of samples: ");
    Serial.println(count);
    Serial.print("Instantaneous Pressure: ");
    Serial.println(pressure);
    Serial.print("Average Pressure: ");
    Serial.println(average);


};



void loop() {
  // put your main code here, to run repeatedly:

}

Now, to add the blinking LED, is it better to try and intertwine it into the existing timing loop, or run it as a standalone in series?

Right, A unique problem because i need to determine the average pressure inside setup(). I have used an array to get the average pressure into the loop() function.
But now the relative altitude (calculated) is returning garbage! What have i missed please?

// // test of modified baro + blinking code using time interval
// time interval, blinking and pressure readings work. This is included in main code:
#include "I2Cdev.h"
#include <Wire.h>
#include <MS5611.h> // GY63 MS5611 pressure sensor
#include <Kalman.h> // single state Kalman Filter

int period = 5000; // duration of reference sampling 
byte barometerLED_State = LOW;
const byte barometerLED = 5;
const int barometerLED_Interval = 300; // number of millisecs between blinks
unsigned long prevMillis =0;
unsigned long currentMillis;
unsigned long previousbaroLED_Millis = 0; //used in baro setup blinking LED
const int blinkDuration = 100;
const int readDuration = 1000;  // time between each pressure sample
double referencePressure;
double pressure;
double pressure1;

int count = 0;
int newcount = 0;
int avePress[0];

float filteredAltitude;
// initial values Kalman myfilter(1.025,32,1023,0);//suggested initial values for high noise filtering
Kalman myFilter(1.0125,20,1023,0);


MS5611 ms5611;

void setup() {

Serial.begin(9600);
pinMode(barometerLED, OUTPUT);

   // Initialize MS5611 sensor
  Serial.println("Initialize MS5611 Sensor");
   while(!ms5611.begin())
  {
    Serial.println("Could not find a valid MS5611 sensor, check wiring!");
    delay(500);
  }
  
bool loopFinished = false;
unsigned long loopStartTime = millis();
while (loopFinished == false) {
   if (millis() - loopStartTime >= period) {
      loopFinished = true;
   }
    currentMillis = millis();

    if (currentMillis - prevMillis >= readDuration){
         count = count +1;
        referencePressure += ms5611.readPressure();
        
      prevMillis = currentMillis;
      
    }
  
   pressure = ms5611.readPressure(); // debugging: reference pressure
    
    if (newcount == count-1){
            newcount = newcount +1;
            Serial.println(newcount); // debug check
            Serial.println(pressure); // debug check
         }
         
   { // blink
     
      currentMillis = millis();       
     
        if (barometerLED_State == LOW) {
          if (currentMillis - previousbaroLED_Millis >= barometerLED_Interval) {
             barometerLED_State = HIGH;
             previousbaroLED_Millis += barometerLED_Interval; 
      
          }
          
        }
        else {
          if (currentMillis - previousbaroLED_Millis >= blinkDuration) {
             barometerLED_State = LOW;
             previousbaroLED_Millis += blinkDuration;
          } 
        } 
         
      digitalWrite(barometerLED, barometerLED_State);
   } // blink
}

  double average = referencePressure/count;

  
    Serial.print ("No. of samples: ");
    Serial.println(count);
    Serial.print("Instantaneous Pressure: ");
    Serial.println(pressure);
    Serial.print("Average Pressure: ");
    Serial.println(average);
 
  avePress[0] = average;   



};

double newAlt;  // debug -playing around 


void loop() {
 // playing around with calculating relative altitude using calculated ave pressure and sensor provided alt
// current eqn for rel altitude is:
//   float relativeAltitude = ms5611.getAltitude(realPressure, referencePressure);
// want to change this so that it reads the avePress[0]  and current pressure, realTemperature using :
// https://keisan.casio.com/has10/SpecExec.cgi?path=06000000.Science%252F02100100.Earth%2520science%252F12000300.Altitude%2520from%2520atmospheric%2520pressure%252Fdefault.xml&charset=utf-8
long realTemperature = ms5611.readTemperature();

newAlt = ((pow(( avePress[0] / ms5611.readPressure() ), 1/5.257) - 1.0) * (realTemperature + 273.15)) / 0.0065;


//newAlt = getAltitude;
Serial.println(avePress[0]);  // debug
 Serial.println(newAlt);
}