Averaging Samples

I have a conversion routine that takes a measurement, and converts it to a part number. This works wonderfully. The requirement has come up that the powers that be want three measurements taken, and the average of the three gets converted to a part number.

I have a button that's get pushed each time a measurement needs to be taken. Push it once, and the current measurement (in mm) gets saved to a variable. Push it again, and the current measurement (which may have changed) gets saved in a second variable. Push it a third time, and the third measurement is saved in a third variable, the three variables are averaged, and the resulting averaged measurement is submitted for conversion.

Push the button a fourth time and the variables are cleared and the process starts again.

The conversion routine gets entered anew for many times a second, as the user is manipulating a gear in a micrometer, and decides when to "set" a given measurement as one of the official "samples". So the part numbers being sent back have to continue regardless of if the button was pushed or not.

here is the working conversion routine:

int convert() {
mm = (float)num/1000;

float formula = round((((maxmm-(range/2.000))-mm)/jump));

int f;

f = (int)formula;

int lindy = maxl-f;

return lindy;

What's the question?

How to add the ability to take 3 samples of measurements coming through the conversion routine and submit a average to the conversion routine and save the averaged result separately. Something like pushbuttonstate++, if pushbuttonstate = 3, then mavg = (m1 + m2 + m3)/3; then mavg needs to be converted by the routine to a part number and returned. I have the general idea but assembling it is confusing me.

I can write the code to do that, but it wouldn't be copy and paste-able into your code. If you post your code, then I can see what I can do.

Producing an average of three samples instead of a single sample is easy. But I'm having trouble following how the samples would be collected in the real world. You want the user to be able to push a button to take a sample but samples should still be taken if the user doesn't push the button? How can the sketch know when to take a sample, then? You expect the user to press the same button four times for each item, but what happens if the user fumbles it, or you get switch bounce, or anything else that leaves your sketch and the user disagreeing about where they are in the sampling cycle? The sort of system I'm visualising would be a nightmare to use in practice.

Check my statistics class for easy averaging - Arduino Playground - Statistics - plus stddev min and max

Also interesting - http://arduino.cc/playground/Main/RunningAverage - ?

mm (which changes as the user moves the micrometer) is constantly converted to a part number and continuously displayed on the screen. I only want a sample taken (saved as a variable) if the button is pushed. If buttonPushed = 1, then the current value of mm needs to be saved as m1. If buttonPushed = 2, then the current value of mm needs to be saved as m2. If buttonpushed = 3, then the current value of mm needs to be saved as m3.

the part numbers of m1, m2, and m3 need to be displayed on the screen as they are taken, then the average of the three mm's displayed as a part number once all 3 have been set. Upon buttonPush = 4, all three variables are reset to zero, as is buttonPushed.

Attached is the current version of the program, which is working properly, albeit without the averaging and button functions (exceeds allowable number of characters for posting inline).

micrometer_vga_v2_4.pde (11.8 KB)

Here is a separate sketch I was playing with to see how it might be constructed. I don't have live numbers coming in on mm, nor am I converting to part numbers, this just averages three canned numbers as a test:

// this constant won't change:
const int  avgButtonPin = 6;    // connected to ground through a N.O. momentary, and to +5 through a 10k resistor.

// Variables will change:
int avgButton = 0;   // counter for the number of button presses
int avgButtonState = 0;         // current state of the button
int avgLastButtonState = 0;     // previous state of the button
int m1 = 0;
int m2 = 0;
int m3 = 0;
int mm = 0;
int mAvg = 0;



void setup() {
  // initialize the button pin as a input:
  pinMode(avgButtonPin, INPUT);
  Serial.begin(9600);
  
}


void loop() {
  // read the pushbutton input pin:
  avgButtonState = digitalRead(avgButtonPin);

  // compare the buttonState to its previous state
  if (avgButtonState != avgLastButtonState) {
    // if the state has changed, increment the counter
    if (avgButtonState == HIGH) {
      // if the current state is LOW then the button
      // went from off to on:
     
      if (avgButton == 1) {
      // m1 = mm;
       m1=100;
       avgButton++;
      }
      if (avgButton == 2) {
      // m2 = mm;
       m2=150;
       avgButton++;
      }
      if (avgButton == 3) {
      // m3 = mm;
       m3=155;
       avgButton++;
      }
      
      
      if (avgButton == 4) {
      m1 = 0;
      m2 = 0;
      m3 = 0;
      avgButton = 0;
      }
      
      mAvg=(m1+m2+m3)/3;
      Serial.print(avgButton);
      Serial.print(m1);
      Serial.print(m2);
      Serial.print(m3);
      Serial.println(mAvg);
      
   
   
    }
    delay(500);
  }
  /*


  sendDesc(15, 03, 03, 255, 255, "Reading #1"); 
  sendDesc(15, 03, 03, 255, 255, "Reading #2"); 
  sendDesc(15, 03, 03, 255, 255, "Reading #3"); 
  sendDesc(15, 03, 03, 255, 255, "Average"); 
  
  sendData(04, 03, 03, 255, 255, m1); 
  sendData(04, 03, 03, 255, 255, m2); 
  sendData(04, 03, 03, 255, 255, m3); 
  sendData(04, 03, 03, 255, 255, mAvg); 
 */
}

here's my final code, but it doesn't seem to work. The 3 samples display, and average, but are not "fixed". As the micrometer moves, the last sample taken keeps updating.

When a sample is taken, sampleState should increment by one, so that section of code should no longer execute.

The complete sketch is in the attached file:

// Take and display averages

void average(){
  avgVal = digitalRead(avgPin);      // read input value and store it in val
  delay(25);                         // 10 milliseconds is a good amount of time
  avgVal2 = digitalRead(avgPin);     // read the input again to check for bounces
  if (avgVal == avgVal2) {                 // make sure we got 2 consistant readings!
    if (avgVal != avgButtonState) {          // the button state has changed!
      if (avgVal == LOW) {                // check if the button is pressed
        if (sampleState == 0) {          // No samples
          sampleState = 1;               // Take first sample
        } else {
          if (sampleState == 1) {        // 
            sampleState = 2;             // Take second sample
          } else {
            if (sampleState == 2) {      // 
              sampleState = 3;           // Take third sample
            } else {
			  if (sampleState == 3) { //  
                sampleState = 0;           // Reset samples
              }
			}
          }
        }
      }
    }
    avgButtonState = avgVal;                 // save the new state in our variable
  }

  // Now do whatever the sampleState indicates
  if (sampleState == 0) { // all-off
  m1=0;
  m2=0;
  m3=0;
  sendText(04, 19, 03, 255, 255, "     ");
  sendText(14, 19, 03, 255, 255, "     ");
  sendText(24, 19, 03, 255, 255, "     ");
  sendText(34, 19, 03, 255, 255, "     ");
  
  }

  if (sampleState == 1) { // Sample 1
  m1=num;
  // convert m1 to samplel1 and display
  samplel1=convert();
  sendData(04, 19, 03, 255, 255, samplel1);
  }

  if (sampleState == 2) { // Sample 2
  m2=num;
  // convert m2 to samplel2 and display
  samplel2=convert();
  sendData(14, 19, 03, 255, 255, samplel2);
  }
  if (sampleState == 3)  { // Sample 3
  m3=num;
  // convert m3 to samplel3 and display
  samplel3=convert();
  sendData(24, 19, 03, 255, 255, samplel3);
  
  num=(m1+m2+m3)/3;
  // convert mAvg to sampleAvgl and display  
  sampleAvgl=convert();
  sendData(34, 19, 03, 255, 255, sampleAvgl);
  }   
}

micrometer_vga_v2_5.pde (14.5 KB)

I got it. I merged the two sections so buttonState would increment before each reading. Finished, working, I'm pleased with myself, LOL.

// Take and display averages

void average(){
  avgVal = digitalRead(avgPin);      // read input value and store it in val
  delay(25);                         // 10 milliseconds is a good amount of time
  avgVal2 = digitalRead(avgPin);     // read the input again to check for bounces
  if (avgVal == avgVal2) {                 // make sure we got 2 consistant readings!
    if (avgVal != avgButtonState) {          // the button state has changed!
      if (avgVal == LOW) {                // check if the button is pressed
        if (sampleState == 0) {          // No samples
          sampleState++;               // Take first sample
                  m1=0;
                  m2=0;
                  m3=0;
                  sendText(04, 19, 03, 255, 255, "     ");
                  sendText(14, 19, 03, 255, 255, "     ");
                  sendText(24, 19, 03, 255, 255, "     ");
                  sendText(34, 19, 03, 255, 255, "     ");
        } else {
          if (sampleState == 1) {        // 
            sampleState++;             // Take second sample
              m1=num;
              // convert m1 to samplel1 and display
              samplel1=convert();
              sendData(04, 19, 03, 255, 255, samplel1);
          } else {
            if (sampleState == 2) {      // 
              sampleState++;           // Take third sample
               m2=num;
               // convert m2 to samplel2 and display
               samplel2=convert();
               sendData(14, 19, 03, 255, 255, samplel2);

            } else {
			  if (sampleState == 3) { //  
                sampleState = 0;           // Reset samples
                  m3=num;
                  // convert m3 to samplel3 and display
                  samplel3=convert();
                  sendData(24, 19, 03, 255, 255, samplel3);
  
                   num=(m1+m2+m3)/3;
                   // convert mAvg to sampleAvgl and display  
                   sampleAvgl=convert();
                   sendData(34, 19, 03, 255, 255, sampleAvgl);

              }
			}
          }
        }
      }
    }
    avgButtonState = avgVal;                 // save the new state in our variable
  }