Simple wind sensor


Zoltán Pásztor
 

Hi All!

Is there any reason to implement this simple wind sensor to the OCS?
https://www.thingiverse.com/thing:2523343

Is the hall sensors digital read fast enough?
What is the code for the weather.ino?

"The perimeter of the circle is 50 centimetres, thus, at a wind speed of 1 meter per second, the anemometer makes 2 full revolutions."

Thanks!


Zoltán Pásztor
 

This code is working for me. What is the method, to put this code to the weather.ino?


#include <Wire.h>
 
// An anemometer for the Arduino
int LogInterval;
int SampInterval=2; //Number of seconds in the LogInterval
 
#define WAIT_TO_START    0 // Wait for serial input in setup()
 
const byte nsamp=10;
 
// the digital pins that connect to the LEDs
//#define redLEDpin 2
#define greenLEDpin 3
#define WindPin 4
 
// Wind variables
bool SeeHigh=false;
int CntRPM=0;
unsigned long CntPeriod=0;
float RPM=0.0;
float AvPeriod=0.0;
float MPH=0.0;
float KPH=0.0;
float Twc=0.0; //Wind chill Temperature
 
// Timing counters
unsigned long StartTime; //Log Interval counter
unsigned long StartPeriod=0; // Period Start
unsigned long timeSense=0;
 
// Analog pins
int ThermPin=2; //MPC9701 thermal sensor
 
 
unsigned int ThermValue = 0;  // value coming from thermal sensor
int ThermValueAvg;
float mVout; // Temp voltage in mV
float TempC=0.0;
float TempF=0.0;
 
void error(char *str)
{
 Serial.print("error: ");
 Serial.println(str);
 while(1);
}
 
void setup(void)
{
 analogReference(EXTERNAL); //3.3V connected to AREF thru 3.3K AREF=3VDC
 int dummy=analogRead(ThermPin); //discard first analogRead
 Serial.begin(9600);
 Serial.println();
 pinMode(WindPin,INPUT);
 
#if WAIT_TO_START
Serial.println("Type any character to start");
while (!Serial.available());
#endif //WAIT_TO_START
 
Serial.println("TempF, RPM, MPH, KPH, Twc");
 
LogInterval=SampInterval*1000; //  sec between entries
StartTime=millis(); //Initialize StartTime
}
 
void loop(void)
{
// Wind calculator Look for High
if (digitalRead(WindPin)==HIGH)
   {
SeeHigh=true;
digitalWrite(greenLEDpin, LOW);
}
//Look for Low thus a High to Low transistion
else if (SeeHigh==true)
{
if (StartPeriod != 0) //Not first sampleFrt
{
 // Number of milliseconds in a revolution, added together
 CntPeriod=CntPeriod+millis()-StartPeriod;
}
StartPeriod=millis();
//Increment counter
CntRPM++;
SeeHigh=false;
digitalWrite(greenLEDpin,HIGH);
}
 
if ((millis()-StartTime)>long(LogInterval))  // Log Interval has passed
{
// Do Wind calculations for LogInterval
// RPM is calculated, Period is averaged
RPM=CntRPM*(60.0/SampInterval);
AvPeriod=CntPeriod/(CntRPM-1);
MPH=RPM*.054; //Estimate
KPH=MPH*1.609;
// Get temperature readings Average nsamps
for (byte j=0;j<nsamp;j++)
{    
ThermValue += analogRead(ThermPin);    
}    
ThermValueAvg=ThermValue/nsamp;
 
mVout=(float) ThermValueAvg*3000.0/1023.0; //3.0V = 3000mV
//TempC=(mVout-400.0)/19.5; //Ta = (Vout-400mV)/19.5mV //Original
//TempC=(mVout-580.0)/19.5; //Ta = (Vout-400mV)/19.5mV  //Modified
TempC=(mVout-490.0)/19.5; //Ta = (Vout-400mV)/19.5mV  //Modified
TempF=TempC*(9.0/5.0)+32;
 
//Wind Chill formula Twc=35.74+0.6215Tf-35.75MPH 0.16 +0.4275TfMPH 0.16
//double pow (double base, double exponent )
if ((TempF <50.0) && (MPH > 3.0))
{
Twc=35.74+0.6215*TempF-35.75*pow(MPH,0.16)+0.4275*TempF*pow(MPH,0.16);
}
else
{
Twc=TempF;
}
ThermValue=0; //Clear Buffers
 
Serial.print("$, ");
Serial.print(TempF,1);
Serial.print(", ");
Serial.print(RPM,1);
Serial.print(", ");    
Serial.print(MPH,1);
Serial.print(", ");
Serial.print(KPH,1);
Serial.print(", ");    
Serial.print(Twc,1);
 
StartTime=millis();
Serial.println();
 
StartTime = millis(); //Get StartTime for next LogInterval
// Clear variables for next LogInterval
digitalWrite(greenLEDpin, LOW);
SeeHigh=false;
CntRPM=0;
AvPeriod=0.0;
}
}


Zoltán Pásztor
 

I don't want the LED and the temperature compensation. Only the KPH value.


Howard Dutton
 

The design of that sketch is such that it can't easily coexist with other code running.

I put this stand-alone Sketch together to quickly test a better concept that would be compatible with the OCS.

Once you confirm this works I'll provide the OCS Weather.ino functions.

// sample windspeed sketch
#define AnemometerPin 18              // interrupt capable pin
// see https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
#define AnemometerSamplePeriod 5000L  // in milliseconds
#define AnemometerRPM2KPH 0.057726    // converts from RPM to KPH

volatile unsigned long anemometerTurnsCounter = 0;
unsigned long anemometerWindSpeedKPH = 0;

void setup() {
  attachInterrupt(digitalPinToInterrupt(AnemometerPin), anemometerCount, RISING);
  Serial.begin(9600);
}

void loop() {
  static unsigned long anemometerCheckTime = 0;
  long anemometerTimeElapsed = (long)(millis()-anemometerCheckTime);
  if (anemometerTimeElapsed >= AnemometerSamplePeriod) {
    anemometerCheckTime = millis();
    cli();
    long anemometerTurnsCount = anemometerTurnsCounter;
    anemometerTurnsCounter = 0;
    sei();
    // convert RPSP to RPM
    long RPM=anemometerTurnsCount * (60000L/anemometerTimeElapsed);
    anemometerWindSpeedKPH = RPM * AnemometerRPM2KPH;
    Serial.print("Windspeed in MPH = "); Serial.println(anemometerWindSpeedKPH/1.609,1);
  }
}

void anemometerCount() {
  anemometerTurnsCounter++;
}


Zoltán Pásztor
 

Yeapp, that's looks good. Thank you for your effort.
What is the formula of the RPM2KPH conversion?


Zoltán Pásztor
 

Oh, I forget. There are two magnets in the body, front of the Hall sensor, at 180 degrees. Does this not change the calculation?


Howard Dutton
 

On Sun, Dec 20, 2020 at 06:43 AM, Zoltán Pásztor wrote:
MPH=RPM*.054; //Estimate
KPH=MPH*1.609;
The formula is a simple multiplier.  I'm sure it isn't accurate and is entirely based on the example sketch you provided.

The 0.054 part someone came up with converts to RPM to MPH.  I just factored in the MPH to KPH constant... but somehow messed it up.

So AnemometerRPM2KPH is supposed to be 0.054 * 1.609 = 0.086886


Zoltán Pásztor
 

Perfect. This accuracy is enough, this is not a weather station.
Is this implementable to the Weather.ino?


Howard Dutton
 
Edited

On Sun, Dec 20, 2020 at 11:27 AM, Zoltán Pásztor wrote:
Is this implementable to the Weather.ino?
The following should work I think.  Just substitute this for the similarly named section/functions (they are just place-holders for the real thing) in Weather.ino

Naturally this logs the average wind speed over the sample period interval (5 seconds) but perhaps one would want a longer average so feel free to change that to 60 seconds or whatever.

// -----------------------------------------------------------------------------------------------------------------

// gets windspeed in kph
// this is for a cup anemometer where each rotation causes an open/close event on a switch (or hall effect transducer)
// the pin below counts the number of logic LOW to HIGH events in a given amount of time to calculate the RPM etc.

#define AnemometerPin 18              // interrupt capable pin
// see https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
#define AnemometerSamplePeriod 5000L  // in milliseconds
#define AnemometerRPM2KPH 0.086886    // converts from RPM to KPH

volatile unsigned long anemometerTurnsCounter = 0;
unsigned long anemometerWindSpeedKPH = 0;

// return (invalid) if not implemented or if there's an error
double weatherWindspeed() {
  if (!windspeedGood) return invalid;

  static unsigned long anemometerCheckTime = 0;
  long anemometerTimeElapsed = (long)(millis()-anemometerCheckTime);
  if (anemometerTimeElapsed >= AnemometerSamplePeriod) {
    anemometerCheckTime = millis();
    cli();
    long anemometerTurnsCount = anemometerTurnsCounter;
    anemometerTurnsCounter = 0;
    sei();
    // convert RPSP to RPM
    long RPM=anemometerTurnsCount * (60000L/anemometerTimeElapsed);
    anemometerWindSpeedKPH = RPM * AnemometerRPM2KPH;
  }

  if (anemometerWindSpeedKPH < 0 || anemometerWindSpeedKPH > 350) anemometerWindSpeedKPH=invalid;
  return anemometerWindSpeedKPH;
}

void anemometerCount() { anemometerTurnsCounter++; }

bool initWindspeed() {
  attachInterrupt(digitalPinToInterrupt(AnemometerPin), anemometerCount, RISING);
  return true;
}


Zoltán Pásztor
 

This is the design of the anemometer. 
https://www.thingiverse.com/thing:2523343

There is 2 magnets, so 1 revolution is 2 HIGH events. 
And here is a sentence from the creators notes:

"The perimeter of the circle is 50 centimetres, thus, at a wind speed of 1 meter per second, the anemometer makes 2 full revolutions."

I can't interpret this sentence :) , is this equal whit our calculations?


Howard Dutton
 
Edited

The # of switches is irrelevant.  I was going to change the wording in the code comments but that just makes the subject even more confusing so I'm leaving it as is.  Instead imagine the mechanics make one LOW/HIGH event per rotation, even if they don't.

I see 1M/s = 3.6KPH....

So it seems a 3.6 KPH wind gives 2 full revolutions per second and that would be 4x LOW to HIGH transitions per second.  So a pulse per second from this thing represents 3.6/4 = 0.9 KPH of wind.  And that is 60 RPM = 0.9 KPH.  For an RPM to KPH conversion it's 60 * 0.015 = 0.9.  Guess AnemometerRPM2KPH is 0.015 according to this.  So at 3.6KPH wind this thing makes four pulses per second and my code would count 20 of those events (over 5 seconds) then multiply by 12 (60000/5000 milliseconds) for 240 * 0.015 = 3.6

I'm 100% sure in the real world this thing will have fairly large errors and a better number will likely be some not insignificant % lower than 0.015.


Zoltán Pásztor
 

Well, I find this calculator: https://www.calctown.com/calculators/rpm-to-linear-velocity
So, with 80mm "anemometer arm" radius (measured at now) => 120 RPM gives 1 m/s. This is OK, because that gives the 2 revolution per second.

120 RPM = 3,6 km/h => RPM2KPH = 0,03

If I'm correct, this is my number.


Howard Dutton
 

On Sun, Dec 20, 2020 at 01:24 PM, Howard Dutton wrote:
The # of switches is irrelevant.  I was going to change the wording in the code comments but that just makes the subject even more confusing so I'm leaving it as is.  Instead imagine the mechanics make one LOW/HIGH event per rotation, even if they don't.
This is the reason it's 0.015 not 0.03.  Two switches, twice as many pulses for a given wind speed so the multiplier is 1/2 as much.


Howard Dutton
 

I added the cup anemometer example code to the OCS on github.  The example code is functionally identical to what's below (compiles to the exact same thing) but the names of variables etc. were changed from RPM to PPM (pulses per minute) in an attempt to avoid some confusion.