code to record average wind speed

I am trying to make a wind monitor which records wind speed, maximum speed and average speed. The average would be from start up. I thought that would be wind speed++ / number of sample times but am getting nothing.

I would be grateful for any help or suggestions.

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;
int rpmMaximum = 0;
int rpmAverage = 0;


void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
   lcd.print("      Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}

void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);
  
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = .9 * count;

  if ((countRpm > 10) && (countRpm < 50)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 10){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 50){
   digitalWrite (relay, HIGH);
 }
   return countRpm;
  int rpmAverage = countRpm++/currentTime;
}    
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(rpmAverage, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}
   return countRpm;
  int rpmAverage = countRpm++/currentTime;

Three problems here. First, your local variable is hiding the global variable of the same name. Not a smart thing to do.

Second, NOTHING after a return statement is ever executed.

Third, you should NOT be incrementing countRPM when computing the average.

Finally, you are NOT computing RPM. You are computing wind speed. So, name your variables appropriately.

Thank you for your response. I should have mentioned a few things.

  1. I am a complete beginner. This is my first project beyond the tutorial which came with my Arduino.
  2. I adapted this code from a previous project hub code which was counting fidget spinners rpms.

If I understand your advice, I should switch these two
return countRpm;

int rpmAverage = countRpm++/currentTime;

so that the return is at the bottom?

dillingerkt:
Thank you for your response. I should have mentioned a few things.

  1. I am a complete beginner. This is my first project beyond the tutorial which came with my Arduino.
  2. I adapted this code from a previous project hub code which was counting fidget spinners rpms.

If I understand your advice, I should switch these two
return countRpm;

int rpmAverage = countRpm++/currentTime;

so that the return is at the bottom?

You need to switch the order, but you also need to remove the "int " part of the last line, because that is creating a new variable, AND you need to remove the "++" part, because that is incorrectly incrementing the variable.

Thank you for your help. I have done those things. Sadly, I am still getting nothing for an average. After searching for other simular tasks, I tried to make a static int = num to count the loops and then divide the countRpm by the number of loops. This just gave me the mph without the average. How can I add each countRpm together from each loop to divide by the number of loops?

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;
int rpmMaximum = 0;
int rpmAverage = 0;
static int num = 0;

void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
   lcd.print("      Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}

void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);
  
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = .9 * count;

  if ((countRpm > 10) && (countRpm < 50)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 10){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 50){
   digitalWrite (relay, HIGH);
 }
  //static int num = num+1;
   rpmAverage = countRpm/currentTime;
   return countRpm;
}    
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(rpmAverage, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}

At this point, it would be much easier for you to develop the program using the serial monitor than to also worry about the LCD display manipulation. When everything is computed to your satisfaction, add in the LCD stuff.

Here is how I might average some readings together within the loop() function and display them. It has the disadvantage that the average value is displayed only every so often. There are other approaches, like smoothing using a low pass filter, that get around this problem.

int nsamples=0;
long avgRPM=0; //global variables

void loop()
{
  avgRPM = avgRPM + getRPM();
  nsamples++;

  if(nsamples > 5)  {   //take the last five data points, average and print
     Serial.print("Average RPM ");
     Serial.println(avgRPM/nsamples); //this assumes that the sensor is 1 pulse per revolution
    nsamples=0; //reset counter
    avgRPM = 0; //reset average
    }
  //other stuff here
}

try to make

int rpmAverage = 0;

float rpmAverage;

and then try to print rpmAverage * 1000; (also to serial)

   rpmAverage = countRpm/currentTime;

currentTime contains the number of milliseconds that the Arduino has been running. That hardly seems like the proper thing to divide by.

You are counting pulses from the hall effect sensor in some period of time (defined by sampleTime). Dividing the number of pulses by the interval over which the pulses were counted will give you a value that is a ratio of wind speed. The number of pulses per revolution needs to be known to give the actual wind speed. That and some formula that the device maker provides that relates revolutions to wind speed.

The average wind speed needs to take into account the total of all wind speed values in some period of time. You aren't keeping track of anything but the most recent value. You need to keep a running sum and to keep track of how many values make up that sum, so you can compute the average.

PaulS:

   rpmAverage = countRpm/currentTime;

The average wind speed needs to take into account the total of all wind speed values in some period of time. You aren’t keeping track of anything but the most recent value. You need to keep a running sum and to keep track of how many values make up that sum, so you can compute the average.

Yes, I understand (I think). So:
totRPM = countRpm + totRPM // keeps a running count of all the totals

num++ // keeps a running count of number of measurements

AvgRPM = totRPM/num

Am I getting warmer? It still doesn’t work but I feel like I’m getting closer.

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;
int rpmMaximum = 0;
int rpmAverage = 0;
static int num = 0;
static int totRPM = 0;
int avgRPM = 0;
//long avgRPM = 0; //global variable
void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
   lcd.print("      Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}

void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);
  
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = .9 * count;

  if ((countRpm > 10) && (countRpm < 50)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 10){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 50){
   digitalWrite (relay, HIGH);
   
       totRPM = countRpm + totRPM;
       num++;
       avgRPM = totRPM/num;
 
 // avgRPM = avgRPM + getRPM();  // new
//  num++;                       //new

//  if(num > 5)
//    Serial.print("Average RPM  ");
//    Serial.print(avgRPM/num);
 //   num=0;
 //   avgRPM=0;
 }  
  //static int num = num+1;
  // rpmAverage = countRpm/currentTime;
   return countRpm;
}    
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(avgRPM, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}

Am I getting warmer?

Smoking hot.

static int num = 0;
static int totRPM = 0;

Global variables don't really need to be static. Static means something different for global variables, related to file level visibility. Since you only have one file, static means nothing.

It still doesn't work but

...I'm not going to tell you what num is, what totRPM is, what avgRPM is, or what "it doesn't work" means.

I am happy to know I’m moving in the correct direction. Thank you!

I removed the static from the int.

Is the code

totRPM = countRpm + totRPM;
num=num + 1;
avgRPM = totRPM/num;

correct but in the wrong location, incorrect but in the correct location, or both?

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;
int rpmMaximum = 0;
int rpmAverage = 0;
int num = 0;
int totRPM = 0;
int avgRPM = 0;
//long avgRPM = 0; //global variable
void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
   lcd.print("      Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}

void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);
  
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = .9 * count;

  if ((countRpm > 10) && (countRpm < 50)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 10){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 50){
   digitalWrite (relay, HIGH);
  
   
       totRPM = countRpm + totRPM;
       num=num + 1;
       avgRPM = totRPM/num;
  
 // avgRPM = avgRPM + getRPM();  // new
//  num++;                       //new

//  if(num > 5)
//    Serial.print("Average RPM  ");
//    Serial.print(avgRPM/num);
 //   num=0;
 //   avgRPM=0;
 }  
  //static int num = num+1;
  // rpmAverage = countRpm/currentTime;
   return countRpm;
}    
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(avgRPM, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}

correct but in the wrong location, incorrect but in the correct location, or both?

I'm going to leave that for you to determine. Let me ask a different question, first. Why do you have Serial.begin() in setup()?

There isn't much point in setting up the serial port if you never use it.

Of course, you SHOULD use the serial port, to debug your program. If the value in averageRPM is wrong, that is because the values used in the calculation are wrong OR the wrong operations are performed. Which is it? The only way to know that is to print the input values, the intermediate values, and the final result (with meaningful identifiers). If the initial values are garbage, then the intermediate and final values will be, to. If the initial values are good, but the final value is not, then somewhere in between, something happened that wasn't correct.

Debugging blindly is the hardest possible way to do it. Debugging with facts is so much easier. And facts are remarkably easy to come by.

I used a sketch for counting rpms on a fidget spinner as a template to start with. The serial.begin() was left from that.

When I changed the sketch by adding int in front of the totRPM and moving it out of the bracket

int totRPM = countRpm + totRPM;
num=num + 1;
avgRPM = totRPM / num;

I get a number for avgRPM but it drops to zero quickly, implying one of the values is not adding. When I add int to the num=num +1, the average equals the current mph. So, I suspect the formula is correct but Im not identifying the code properly or something simple like that.

I hear what you are saying about the serial print. I just haven’t learned to do that yet. This is my first stab at programming in 35 years. Last time was Fortran.

I know you are right, and if I figure how to print the values on the serial, I will get some answers. Thanks for your help.

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;            //P=rpm * 9 (2.5/T)
int rpmMaximum = 0;
int rpmAverage = 0;
int num = 0;
int totRPM = 0;
int avgRPM = 0;
//long avgRPM = 0; //global variable
void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
   lcd.print("      Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}
         
void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);

   
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = .9 * count;
 
  if ((countRpm > 10) && (countRpm < 50)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 10){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 50){
   digitalWrite (relay, HIGH);
  
  }  
   int   totRPM = countRpm + totRPM;
         num=num + 1;
         avgRPM = totRPM / num;
  
 // avgRPM = avgRPM + getRPM();  // new
//  num++;                       //new

//  if(num > 5)
//    Serial.print("Average RPM  ");
//    Serial.print(avgRPM/num);
 //   num=0;
 //   avgRPM=0;
// }  
  //static int num = num+1;
  // rpmAverage = countRpm/currentTime;
   return countRpm;
 

  
}
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(avgRPM, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}

Got it!

Thanks again for your guidance.

Putting the int in front of totRPM means that you create a completely new local version of totRPM starting from 0 every time that function gets called, instead of adding anything into the original global version of totRPM. I'm pretty sure that isn't what you should be doing. Same with num if you tried adding int to that.

Using a few serial.print() commands immediately before your averaging routine to show you what values of totRPM, countRPM and num you are working with would soon show you. The examples on the reference pages for serial.print -Serial.print() - Arduino Reference and serial.println() Serial.println() - Arduino Reference will give you the idea.

Steve

I have run into a snag. I was hoping to track the average wind speed over a long period of time. However, after a short period of time the average starts to drop until eventually it reads zero. I am wondering if this means that I have run out of RAM? If so, can I add an SD card reader to increase memory or is there a better solution?

. I am wondering if this means that I have run out of RAM?

Yes it does.
Or maybe it doesn't .

How the Hell are we supposed to know?

Most likely, there is an error in your present code, which you forgot to post.

Opps. Here is my present code

#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
const int hallSensorPin = 2;                      // connect the hall effect sensor on pin 2
const int relay = 4;                              // connect relay negative to pin 4
const unsigned long sampleTime = 2500;            //P=rpm * 9 (2.5/T)
int rpmMaximum = 0;
int rpmAverage = 0;
int num = 0;
int totRPM = 0;
int avgRPM = 0;
void setup() 
{
  pinMode(hallSensorPin,INPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  Serial.begin(9600);
   lcd.begin(16, 2);
  lcd.print("Initializing");
  delay(1000);
  lcd.clear();
  lcd.print("    Welcome"); 
  for (int positionCounter = 0; positionCounter < 21; positionCounter++) {
    lcd.scrollDisplayLeft();
    delay(350);
  }
    delay(100);
  lcd.clear();
}
         
void loop() 
{
  delay(100);
  int rpm = getRPM();
  if (rpm > rpmMaximum) rpmMaximum = rpm;
    lcd.clear();
  displayRPM(rpm);

   
}
int getRPM()
{
  int count = 0;
  boolean countFlag = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime)
  {
    if (digitalRead(hallSensorPin) == HIGH){
      countFlag = HIGH;
    }
    if (digitalRead(hallSensorPin) == LOW && countFlag == HIGH){
      count++;
      countFlag=LOW;
    }
    currentTime = millis() - startTime;
  }
  int countRpm = 1.3 * count;
 
  if ((countRpm > 12) && (countRpm < 65)){
   digitalWrite (relay, LOW);
 }
  if (countRpm <= 9){
   digitalWrite (relay, HIGH);
 }  
  if (countRpm >= 65){
   digitalWrite (relay, HIGH);
  
  }  
         totRPM = countRpm + totRPM;
         num=num + 1;
         avgRPM = totRPM / num;
  
 
   return countRpm;
 

  
}
void displayRPM(int rpm) 

{
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(rpm,DEC);
  lcd.setCursor(4,0);
  lcd.print("MPH");
  lcd.setCursor(9,0);
  lcd.print(rpmMaximum, DEC);
  lcd.setCursor(13,0);
  lcd.print("MAX");
  lcd.setCursor(0,1);
  lcd.print(avgRPM, DEC);  
  lcd.setCursor(4,1); 
  lcd.print("Average MPH");
}
int getRPM()

Given what this function actually does, it should be called getRPMAndDiddleWithRelay(). Or, what it actually does should be changed.

         totRPM = countRpm + totRPM;
         num=num + 1;
         avgRPM = totRPM / num;

What is going to happen when totRPM overflows? When num overflows? When num increases to 0 again?

However, after a short period of time the average starts to drop until eventually it reads zero. I am wondering if this means that I have run out of RAM?

"Facts" like "a short period of time" are useless. We need real facts, like what is the value in countRpm when the above calculations happen. What is the value of millis() when things go pear-shaped? What is the value of num when that happens?