Arduinio Anemometer & Windvane

Interesting Anemometer Videos


Back to Top

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 vane, wind 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".

Back to Top

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 follows:

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 per revolution 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.

Wind Direction

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.

Wind Direction

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;  slated 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, where:

    ==> 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:

Anemometer Wiring

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:

Anemometer Wiring

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:

Anemometer Wiring