Anemometer/Windvane

N8MDP Weather Station


Anemometer / Wind Vane

Thunderstorm


 

Table of Contents

 

    ==>What is an Anemometer and Wind Vane?

 

    ==>Wiring the Anemometer / Wind Vane to the Arduino Uno

 

    ==>Calibrating Wind Direction of the Wind Vane

 

    ==>Arduino Sketch to display wind direction and compass point

 

    ==>How to measure wind speed with the Anemometer

 

    ==>Arduino Sketch to display windspeed

 

    ==>Arduino Sketch to display windspeed and direction

 

What is an Anemometer and Wind Vane

 

An Anemometer is a weather sensor device used to measure wind speed. From Wikipedia, an anemometer is a device used for measuring the speed of wind, and is also a common weather station instrument. The term is derived from the Greek word anemos, which means wind, and is used to describe any wind speed measurement instrument used in meteorology. A weather vanewind vane, or weathercock is an instrument for showing the direction of the wind. It is typically used as an architectural ornament to the highest point of a building. The word vane comes from the Old English word fana meaning "flag".

 

Interesting Anemometer Videos

 

 

Wiring the Anemometer / WindVane to the Arduino Uno

One of the best sites that I visited that showed how to hook up the Davis Anemometer / Windvane was at cactus.io in Australia. I used their approach to wire up my sensor to the Arduino Uno/Ethernet Shield.

 

The anemometer/windvane has an RJ-11 jack on it, similar to a telephone jack. Fortunately, I had some spare telephone wall plates that I used to wire up to the Arduino, saving the trouble of cutting the wire. The overall wiring looks as folows:

 

Anemometer Wiring

The colors of the wires on the anemometer jack were different than what was shown in the above illustration. So I had to map the colors of the RJ-11 plug on the sensor cable to the wall plate colors as follows:

 

RJ-11 Plug Color Wire Wall Plate Wire Color
Yellow Power Black
Blue Wind Direction Red
Red Ground Green
Black Wind Speed Yellow
Wall Plate

 

As you noticed in the above Arduino wiring diagram, there are two connections to the Arduino. The Wind speed circuit is connected to a digital pin (digital Pin 2) and the wind direction circuit is connected to an analog pin (Analog Pin 4).

 

The wind speed circuit is a switch that is activated once perrevolution of the wind cups. In this hookup, we are using a 4.7K pullup resistor. This will pull the pin 2 to 5V when the switch is open. If we don't use a pullup resistor, the circuit voltage could float and cause false triggers on the input. When the mercury switch on the wind cups close, pin 2 will be pulled to GND for a short duration while the magnet passes the switch. We use this pulse on pin 2 of the Arduino to detect every time the wind cups goes through one revolution. I'll discuss later how to measure the wind speed. For now, let's start with detecting the wind direction.

 

The Davis wind vane has a 20k linear potentiometer attached to it. The output from the wind direction circuit is connected to an analog pin on the Arduino. As we move the wind vane around we should get a reading between 0 and 1023. The Arduino has a 10 bit A to D converter which gives us the range of 0 to 1023. This would also correspond to a voltage of 0 to 5V. In the software, we will need to convert the 0 to 1023 to a 0 to 360 range to give us the wind direction.

 

The potentiometer in the wind vane has a dead band that will result in the value 0 on the analog pin. The diagram below shows the dead band for the Davis anemometer/windvane I'm using for testing. In this image we are looking down over the top of the wind vane. The anemometer is resting on the cups.

 

Wind Direction

 

The wind vane is calibrated from the factory to be 0 when the vane is lined up along the length of the support bar pointing away from the mounting bracket.

 

Typically speaking, there are 8 compass points between 0° and 359°. These 8 compass points fall within a range of 45°. Below is a table showing how I set up the 8 compass points and the angular range I used:

 

Compass Point
Angular Range
North (N)
337.5° to 22.5°
NorthEast (NE)
22.5° to 67.5°
East (E)
67.5° to 112.5°
SouthWest (SE)
112.5° to 157.5°
South (S)
157.5° to 202.5°
SouthWest (SW)
202.5° to 247.5°
West (W)
247.5° to 292.5°
NorthWest (NW)
292.5° to 337.5°

 

In my Arduino Sketch, I use this to give me not only the wind direction in degrees but also the compass point direction.

 

This could easily be increased to 16 compass points if you want to include NNE, SSW, WNW, etc, if you wanted to do that. But keep in mind that means more code in the Arduino sketch.

 

Back to Top

 

Calibrating Wind Direction

 

The simplest way to set up the anemometer for wind direction calibration is to have the mounting arm pointing directly to north on the compass. This means the direction that is obtained by converting the analog input value to a direction value will line up correctly with North. However if you are unable to point the mounting arm to magnetic north then we need to apply an offset to our wind direction calculation to correct the wind direction reading.

 

Davis Wind Direction Offset

To determine the offset to apply we need to point the wind vane to magnetic north. Using a compass we can determine the angle offset from the wind vane to the support bar. The 0 to 1023 output value from the wind vane stays relative the metal support bar. We then translate the 0 - 1023 value to a 0 - 360 value it is still relative to the support bar. However our magnetic north heading is now 40 degrees to the left of the support bar.

 

In the situation in the diagram above we need to add 40 to the translated wind direction so that our direction reading is now showing the calibrated wind direction. In the sketch we now need to supply the offset value. To do this change the value on line 5 to #define Offset 40. In the situation below we need to subtract -45 from the wind direction. We need to set the offset on line 5 to #define Offset -45.

Davis Wind Direction Offset

If the magnetic north heading relative to the support bar is between 0 to 180 then we subtract the offset from the Direction output to get the adjusted wind direction. If the magnetic north heading relative to the support bar is between 181 to 360 then we add the offset to the Direction output to get the adjusted wind direction.

 

This is not the only way to calibrate the wind direction but it works for the way we calculate wind direction in the software.

 

Back to Top

 

The Arduino Wind Direction Sketch

 

The following Arduino sketch reads the values on the Analog input pin. converts the raw A/D to a compass value and then displays the direction.

 

Davis Wind Direction Sketch       (Download Sketch)
// Arduino sketch to display wind direction using a Davis Anemometer / Wind Vane

int VaneValue;      // raw analog value from wind vane 
int Direction;      // translated 0 - 360 direction 
int CalDirection;   // converted value with offset applied 
int LastValue;      // last direction value

#define Offset 0; 

void setup() 
{ 
  LastValue = 0; 
  Serial.begin(9600); 
  Serial.println("Vane Value\tDirection\tHeading"); 
} 

void loop() 
{ 
  delay(1000);                                    // wait for a second
  VaneValue = analogRead(A4);                     // Read the analog value from the A/D converter
  Direction = map(VaneValue, 0, 1023, 0, 359);    // Map the A/D value into the compass range
  CalDirection = Direction + Offset;              // Add an offset if the anemometer/windvane arm is not pointing North

  if(CalDirection > 360)                          // Calculate for a calibrated anemometer/windvane arm 
    CalDirection = CalDirection - 360; 
  
  if(CalDirection < 0) 
    CalDirection = CalDirection + 360; 
  
  // Only update the display if change greater than 2 degrees. Otherwise skip until a change is detected.
  if(abs(CalDirection - LastValue) > 2) 
  { 
    Serial.print(VaneValue); Serial.print("\t\t"); 
    Serial.print(CalDirection); Serial.print("\t\t"); 
    getHeading(CalDirection);                     // Get the compass heading to display
    LastValue = CalDirection;                     // Set the LastValue variable to dtermine of direct changed > 2 degrees 
  }
} 

// Converts compass direction to heading 
void getHeading(int direction) { 
  if(direction > 337 and direction <= 22) 
    Serial.println("N"); 
  else if (direction > 22 and direction <= 67) 
    Serial.println("NE"); 
  else if (direction > 67 and direction <= 112) 
    Serial.println("E"); 
  else if (direction > 112 and direction <= 157) 
    Serial.println("SE"); 
  else if (direction > 157 and direction <= 202) 
    Serial.println("S"); 
  else if (direction > 202 and direction <= 247) 
    Serial.println("SW"); 
  else if (direction > 247 and direction <= 292) 
    Serial.println("W"); 
  else if (direction > 292 and direction <= 337) 
    Serial.println("NW"); 
  else 
    Serial.println("N"); 
}

 

The output in the Arduino serial monitor should look like the following:

 

Wind Direction Output

 

Back to Top

 

How to measure wind speed with the Anemometer

 

The wind cups of the anemometer assembly have a reed switch mounted inside near the shaft. This switch is activated once per revolution of the cups. To calculate the wind speed, a formula must be used to convert the number of times the switch activates per period of time to miles per hour.

 

According to the Davis Anemometer technical document that came with my weather station, 1 mile per hour is equal to 1600 revolutions per hour.

 

Using the formula V = P(2.25/T) we can calculate the speed in miles per hour.

  • V is speed in miles per hour
  • P is number of pulses per sample period (same as Wind Speed Sample Period on the data sheet)
  • T is the sample period in seconds

 

In the Arduino sketch, we are using the formula as provided by Davis to calculate the instantaneous wind speed in miles per hour.

 

Due to the random nature of switch activations on pin 2 (sometimes referred to switch bounce), a hardware interrupt on digital input pin 2 is used, which generates an interrupt on the falling edge of the pulse (5V dropping to ground and back to 5V when the switch is closed by the anemometer). The interrupt service routine (ISR) that is executed on the interrupt increments a counter.

 

Since the Davis spec states that the wind speed sample period is 2.25 seconds, it's safe to use a delay of 3 seconds to get an average sample for the wind speed. Even though the delay will halt the loop code for that period of time, the interrupt handler called "Rotation" is still executed. This will be the sample period (T) used in the calculation. The calculation is performed in the main loop.

 

Note: Code in Interrupt Service Routines should be kept to a minimum.

 

Back to Top

 

The Arduino Wind Speed Sketch

 

Davis Wind Speed Sketch 1        (Download Sketch)
// Arduino sketch to display wind speed using a Davis Anemometer / Wind Vane

#include  

#define WindSensorPin (2)                   // The pin location of the anemometer sensor 

volatile unsigned long Rotations;           // cup rotation counter used in interrupt routine 
volatile unsigned long ContactBounceTime;   // Timer to avoid contact bounce in interrupt routine 

float WindSpeed;                            // speed miles per hour 

void setup() { 
    Serial.begin(9600); 
    
    pinMode(WindSensorPin, INPUT); 
    attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);   // Set up the interupt
    
    Serial.println("Davis Wind Speed Test"); 
    Serial.println("Rotations\tMPH"); 
} 

void loop() { 
    Rotations = 0;                              // Set Rotations count to 0 ready for calculations 
    
    sei();                                      // Enables interrupts 
    delay (3000);                               // Wait 3 seconds to average 
    cli();                                      // Disable interrupts 
    
    // convert to mp/h using the formula V=P(2.25/T) 
    // V = P(2.25/3) = P * 0.75 
    WindSpeed = Rotations * 0.75; 
    
    Serial.print(Rotations); Serial.print("\t\t"); 
    Serial.println(WindSpeed); 
} 

// This is the function that the interrupt calls to increment the rotation count 
void isr_rotation () { 

    if ((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact. 
    Rotations++; 
    ContactBounceTime = millis(); 
  } 
}
 

 

The output should look like the following:

 

Wind Speed Output

 

 

If you want to add more flare to the output, you can use the windspeed to determine a particular wind strength string that will related to the wind speed. For example, in the next sketch, I added a wind strength function using the following criteria (source: Wikipedia):

 

 

Wind Speed (MPH) Wind Speed (Knots) Wind Strength
Beaufort Number
<1 MPH <1 knot Calm
0
1 - 3 MPH 1 - 3 knots Light Air
1
4 - 7 MPH 4 - 6 knots Light Breeze
2
8 - 12 MPH 7 - 10 knots Gentle Breeze
3
13 - 18 MPH 11 - 16 knots Moderate Breeze
4
19 - 24 MPH 17 - 21 knots Fresh Breeze
5
25 - 31 MPH 22 - 27 knots Strong Breeze
6
32 - 38 MPH 28 - 33 knots Near Gale
7
39 - 46 MPH 34 - 40 knots Gale
8
47 - 54 MPH 41 - 47 knots Strong Gale
9
55 - 63 MPH 48 - 55 knots Storm
10
64 - 72 MPH 56 - 63 knots Violent Storm
11
>72 MPH >63 knots Hurricane Force
12

 

Davis Wind Speed Sketch 2        (Download Sketch)
// Arduino sketch to display wind speed using a Davis Anemometer / Wind Vane

#include  

#define WindSensorPin (2)                   // The pin location of the anemometer sensor 

volatile unsigned long Rotations;           // cup rotation counter used in interrupt routine 
volatile unsigned long ContactBounceTime;   // Timer to avoid contact bounce in interrupt routine 

float WindSpeed;                            // speed miles per hour 

void setup() { 
    Serial.begin(9600); 
    
    pinMode(WindSensorPin, INPUT); 
    attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING);   // Set up the interupt
    
    Serial.println("Davis Wind Speed Test"); 
    Serial.println("Rotations\tMPH\tWind Strength"); 
} 

void loop() { 
    Rotations = 0;                              // Set Rotations count to 0 ready for calculations 
    
    sei();                                      // Enables interrupts 
    delay (3000);                               // Wait 3 seconds to average 
    cli();                                      // Disable interrupts 
    
    // convert to mp/h using the formula V=P(2.25/T) 
    // V = P(2.25/3) = P * 0.75 
    WindSpeed = Rotations * 0.75; 
    
    Serial.print(Rotations); Serial.print("\t\t"); 
    Serial.print(WindSpeed); Serial.print("\t");
    getWindStrength(WindSpeed); 
} 

// This is the function that the interrupt calls to increment the rotation count 
void isr_rotation () { 

    if ((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact. 
    Rotations++; 
    ContactBounceTime = millis(); 
  } 
}

// converts wind speed to wind strength 
void getWindStrength(float speed) { 

  if(speed < 1) 
    Serial.println("Calm"); 
  else if(speed >= 1 && speed < 4) 
    Serial.println("Light Air"); 
  else if(speed >= 4 && speed < 8) 
    Serial.println("Light Breeze"); 
  else if(speed >= 8 && speed < 13) 
    Serial.println("Gentle Breeze"); 
  else if(speed >= 13 && speed < 19) 
    Serial.println("Moderate Breeze"); 
  else if(speed >= 19 && speed < 25) 
    Serial.println("Fresh Breeze"); 
  else if(speed >= 25 && speed < 32) 
    Serial.println("Strong Breeze"); 
  else if(speed >= 32 && speed < 39) 
    Serial.println("Near Gale"); 
  else if(speed >= 39 && speed < 47) 
    Serial.println("Gale"); 
  else if(speed >= 47 && speed < 55) 
    Serial.println("Severe Gale"); 
  else if(speed >= 55 && speed < 64) 
    Serial.println("Storm"); 
  else if(speed >= 64 && speed < 72) 
    Serial.println("Violent Storm"); 
  else 
    Serial.println("Hurricane Force"); 
}
 

 

The output should look like the following:

 

Wind Speed Output 2

 

This should give you enough information to use the David Anemometer / Wind Vane

 

Back to Top

 

The Arduino Wind Speed and Direction Sketch

 

Finally, I took some of the code used on the wind direction and wind speed sketch to create a combined program that does both. Using basic math, you can also display the wind speed in knots or km/hr. We can also display the window direction by degrees or direction based on the wind vane position.

 

In this revised sketch, I will use a timer interrupt that will generate an interrupt when the 0.5 second timer is triggered. The interrupt service routine called "isr_timer" will execute and this will be used to create a 2.5 second sample period.

 

I used the TimerOne library to provide the timer interrupt functionality. You can download this library from several sources including the arduino website.

 

Make sure that the variables WindSensorPin (line 2), WindVanePin (line 3) and VaneOffset (line 4) match your configuration.

 

Davis Wind Speed / Direction Sketch        (Download Sketch)
// Arduino sketch to display both Wind Speed and Direction

#include "TimerOne.h"                     // Timer Interrupt set to 2 second for read sensors 
#include  

#define WindSensorPin (2)                 // The pin location of the anemometer sensor 
#define WindVanePin (A4)                  // The pin the wind vane sensor is connected to 
#define VaneOffset -180;                  // define the anemometer offset from magnetic north 

int VaneValue;                            // raw analog value from wind vane 
int Direction;                            // translated 0 - 360 direction 
int CalDirection;                         // converted value with offset applied 
int LastValue;                            // last direction value 

volatile bool IsSampleRequired;           // this is set true every 2.5s. Get wind speed 
volatile unsigned int TimerCount;         // used to determine 2.5sec timer count 
volatile unsigned long Rotations;         // cup rotation counter used in interrupt routine 
volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in isr 

float WindSpeed; // speed miles per hour 

void setup() { 

  LastValue = 0; 
  
  IsSampleRequired = false; 
  
  TimerCount = 0; 
  Rotations = 0;                          // Set Rotations to 0 ready for calculations 
  
  Serial.begin(9600); 
  
  pinMode(WindSensorPin, INPUT); 
  attachInterrupt(digitalPinToInterrupt(WindSensorPin), isr_rotation, FALLING); 
  
  Serial.println("Davis Anemometer Test"); 
  Serial.println("Speed (MPH)\tKnots\tDirection\tStrength"); 
  
  // Setup the timer interupt 
  Timer1.initialize(500000);              // Timer interrupt every 2.5 seconds 
  Timer1.attachInterrupt(isr_timer); 
} 

void loop() { 

  getWindDirection(); 
  
  // Only update the display if change greater than 2 degrees. 
  if(abs(CalDirection - LastValue) > 2) { 
    LastValue = CalDirection; 
  } 
  
  if(IsSampleRequired) { 
    // convert to mp/h using the formula V=P(2.25/T) 
    // V = P(2.25/2.5) = P * 0.9 
    WindSpeed = Rotations * 0.9; 
    Rotations = 0; // Reset count for next sample 
  
    IsSampleRequired = false; 
  
    Serial.print(WindSpeed); Serial.print("\t\t"); 
    Serial.print(getKnots(WindSpeed)); Serial.print("\t"); 
    Serial.print(CalDirection); 
    getHeading(CalDirection); Serial.print("\t\t"); 
    getWindStrength(WindSpeed); 
  } 
} 

// isr handler for timer interrupt 
void isr_timer() { 

  TimerCount++; 
  
  if(TimerCount == 6) 
  { 
    IsSampleRequired = true; 
    TimerCount = 0; 
  } 
} 

// This is the function that the interrupt calls to increment the rotation count 
void isr_rotation() { 

  if((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact. 
    Rotations++; 
    ContactBounceTime = millis(); 
} 
} 

// Convert MPH to Knots 
float getKnots(float speed) { 
  return speed * 0.868976; 
} 

// Get Wind Direction 
void getWindDirection() { 

  VaneValue = analogRead(WindVanePin); 
  Direction = map(VaneValue, 0, 1023, 0, 359); 
  CalDirection = Direction + VaneOffset; 
  
  if(CalDirection > 360) 
    CalDirection = CalDirection - 360; 
  
  if(CalDirection < 0) 
    CalDirection = CalDirection + 360; 

} 

// Converts compass direction to heading 
void getHeading(int direction) { 
  if(direction > 337 and direction <= 22) 
    Serial.print(" N"); 
  else if (direction > 22 and direction <= 67) 
    Serial.print(" NE"); 
  else if (direction > 67 and direction <= 112) 
    Serial.print(" E"); 
  else if (direction > 112 and direction <= 157) 
    Serial.print(" SE"); 
  else if (direction > 157 and direction <= 202) 
    Serial.print(" S"); 
  else if (direction > 202 and direction <= 247) 
    Serial.print(" SW"); 
  else if (direction > 247 and direction <= 292) 
    Serial.print(" W"); 
  else if (direction > 292 and direction <= 337) 
    Serial.print(" NW"); 
  else 
    Serial.print(" N"); 
} 

// converts wind speed to wind strength 
void getWindStrength(float speed) { 

  if(speed < 1) 
    Serial.println("Calm"); 
  else if(speed >= 1 && speed < 4) 
    Serial.println("Light Air"); 
  else if(speed >= 4 && speed < 8) 
    Serial.println("Light Breeze"); 
  else if(speed >= 8 && speed < 13) 
    Serial.println("Gentle Breeze"); 
  else if(speed >= 13 && speed < 19) 
    Serial.println("Moderate Breeze"); 
  else if(speed >= 19 && speed < 25) 
    Serial.println("Fresh Breeze"); 
  else if(speed >= 25 && speed < 32) 
    Serial.println("Strong Breeze"); 
  else if(speed >= 32 && speed < 39) 
    Serial.println("Near Gale"); 
  else if(speed >= 39 && speed < 47) 
    Serial.println("Gale"); 
  else if(speed >= 47 && speed < 55) 
    Serial.println("Severe Gale"); 
  else if(speed >= 55 && speed < 64) 
    Serial.println("Storm"); 
  else if(speed >= 64 && speed < 72) 
    Serial.println("Violent Storm"); 
  else 
    Serial.println("Hurricane Force"); 
}

 

The output should look like the following

 

Windspeed Direction Output

 

Back to Top


© 2018, Jonathan Tucker N8MDP. All Rights Reserved. Powered by cPanel.