This project documents how to make a windvane to sense the wind direction. It was designed for an autonomous sailboat but could be used in other applications. The structure is mostly 3D printed and uses a gopro mount to attach to the hull. The main sensor is a magnetic encoder that outputs an analog voltage in the 0-5V range. For my application I used a voltage divider to bring that down to 0-2.5V because my autopilot is based on 3.3V logic. I also have an arduino program to output the vane angle as NMEA 0183 serial data; I don’t use this on my boat but it is a standard digital interface that might be helpful for others.
Encoder and Earlier Attempts
The heart of this sensor is the magnetic encoder model P3022. You can find it on amazon and other places, but Marlin P. Jones has good deals so I get them there. It is very low-friction and has a nice analog output so it’s super easy to use. I wish there was a 3.3V version, the 5V output is too much for most modern microcontrollers, but the output power is sufficient to drive a voltage divider without significant loading error as far as I can tell.
I spent some time designing a vane around a less-integrated sensor, the AS5600 (affiliate link). This is a nice sensor, and much cheaper than the P3022, but you need to integrate your own magnet and bearings. I found that to 3D print an accurate axle, it needed to be pretty big, which required a large, heavy bearing. My designs using a 1/8 inch (3mm) shaft and small bearing were too wobbly to be reliable. I think a brass shaft would have worked, or maybe a design with 2 bearings, but unless you need to make a large quantity I think the simplicity of the integrated sensor pays for itself.
Vane Design
I drew up a design for the vane to 3D print. I had a few ideas to implement:
- Covers that overlap to keep water from coming in (unless you spray upwards)
- Base is a standard GoPro mount because these are easy to find and stick on, and makes the vane easily removable for transport.
- I used a fiberglass tube from Tap Plastics for the strut, it’s much lighter than PVC pipe or something 3D printed.
- In order to keep the balance weight low, I made the vane’s tail from a foam take-out container rather than printing it.
- I printed 1/4-20 threads into the end of the vane to add an adjustable balance weight. Balancing the vane is important to keep the angle from changing if the vane is tilted. The threads printed okay but I had to clean them out, and I also had to cut the vane tip shorter because the nut was too heavy otherwise.
- I printed it in PETG for the good hot day tolerance compared to PLA
Assembly
Parts & Materials List
- Electronics
- P3022 sensor (amazon affiliate link)
- Hookup Wire. I used this waterproof connector (affiliate link) to make the vane removable but had to extend it.
- Resistors for voltage divider (if needed) (affiliate link)
- Arduino Nano for NMEA output (if needed) (affiliate link)
- 3D Printed Parts: STL files available on Thingiverse
- Cup
- Cap
- Base
- Vane
- Other Parts
- Strut 0.414 in OD epoxy tube from Tap Plastics
- Tail from takeout container foam
- E6000 Glue (affiliate link)
- 5 Minute Epoxy Glue (affiliate link)
Build Steps
Wire up the sensor. Make sure the wires are long enough! Don’t put a connector on the ends of the wires until you’ve fished them through the strut.
Mount the sensor into the cup. I wrapped a few wraps of electrical tape around the sensor to make it a tight fit in the cup. I added a little bit of E6000 to the top to keep it from spinning but didn’t use so much glue that it won’t come apart if needed. Ideally the “dead zone” between 0-5V should line up with head-to-wind on your sailboat since you won’t be sailing that way anyway. In practice the dead zone is pretty small so it will probably work fine with an offset added in the software.
Test fit the cap. I had to drill it out a little so it wouldn’t drag on the bearing. I didn’t glue the cap on, it seems pretty tight, but I would recommend glue before any offshore sailing just to be more watertight.
Cut the strut to the right length. Your choice! Drill a hole in the bottom of the strut for the wire to exit. The hole should be above the base piece or you will have to drill that too. I angled the hole down so the wire comes out without a sharp bend (drill perpendicular, then put a hand drill in and rotate the bit).
Run the wires out the hole and glue the cup and base to the strut with some E6000 or epoxy. I used E6000 to seal around the wires and a zip tie for strain relief. Make sure that the sensor is level before gluing and tape the pieces down so they won’t spin while the glue dries!
Cut a tail for the vane. Bigger is better as long as it won’t bump into anything when it rotates. I used foam from a takeout container but a meat tray or something similar could work too– lighter is better. Sand the edges and any texture off so it looks nice. Glue to the vane with 5 minute epoxy- E6000 will dissolve foam so do not use it here!
Mount the vane on the sensor, it should press fit but use glue as needed– if it spins the angles will be wrong! Balance the sensor so that it won’t swing when tilted using a 1/4-20 nut or whatever is handy. I had to clean up the threads with a thread-cutter first but maybe your printer works better than mine. I also had to cut/glue the vane shaft to make it shorter to put the threads in the right place with the nut I used. Then I cut it too short (because I forgot about the weight of the plastic removed) and had to add a washer. Maybe I should put threads on the whole front of the vane to give more adjustment range…
Voltage Divider
A common circuit to reduce voltages is the voltage divider. I used two 10KΩ resistors to cut the output in half. That is more reduction than needed for a 3.3V circuit. I could not find any specification on the max current the sensor can supply, so I used large resistors to be sure it would be okay, even though this could cause a loading error when attached to the ADC. Seems fine though. Maybe something like 6kΩ and 4kΩ (or 3kΩ and 2kΩ?) arranged to give a gain of 0.6 would be better for resolution and loading considerations.
NMEA 0183 Output
I wrote an arduino code to take the analog input and output a serial NMEA windvane sentence (SDMVW). It’s a modification of my speed/depth sensor code project, simplified by eliminating the calibration routine over serial (constants are hard-coded) and obviously sending the new sentence. This sentence also could send wind speed but there’s no data for that so far.
I’ve tested the code on arduino nano (old style) and uno, but it should work on anything with serial and analog-digital conversion if you update the parameters (and the ADC resolution if it’s not 10 bit). Note that since the sensor is 5V you should use it on a 5V arduino unless you include a voltage divider to reduce the sensor voltage. If you do use a 5V arduino you will need to convert the TTL serial voltage (voltage divider or logic shifter) to work with most 3.3V flight controllers (Pixhawk etc.) The USB-serial found on Arduinos makes this work really well for PC or Raspberry Pi connections.
// This code is a NMEA 0183 wind direction instrument
// Mike Holden mholden@csum.edu
// began 3/17/10 as speed/depth nmea sender https://www.holdentechnology.com/2017/09/02/nmea-0183-speedometer/
// Changes:
// 05/02/10 added factory reset to program eeprom initially (instead of commenting in/out stuff)
// put checksum in eeprom to tell if it's been programmed.
// fixed up calibration routine to work better
// 05/17/10 Added fix so missing pulses make speed go to zero.
// 05/24/12 updated for arduino 1.0
// hacked 3/2020 for wind sensor
// 01/03/2020 cleaned up for wind sensor
// Hardware:
int LEDPin = 13; // there should be an LED on 13 already
long baud;
int deg, degtenths;
float wind_dxn;
float print_time = 0;
char nmeastring[50] = "$VWVHW,,T,,M,0.00,N,0.00,K*";
int jj;
char checksum=0xAA;
// Popular Adjustments:
#define BAUD 4800 // serial port baud rate
#define PRINTDT 10 // ms between serial output (set to 1000 for 1 Hz output)
#define MAXVOLTS 3.3 // max voltage expected from vane (5 or less)
#define MINVOLTS 0.0 // min voltage expected from vane (0 or more)
#define DEGOFF -160.0 // Zero point for vane adjust
// given a voltage V, the angle is determined by:
// Angle = DEGOFF + 360*(V-MINVOLTS)/(MAXVOLTS-MINVOLTS)
// This equation is then wrapped to 0-360 degrees
// The setup() method runs once, when the sketch starts
void setup() {
// initialize the digital pin as an output:
pinMode(LEDPin, OUTPUT);
// dt_char= 20000/(float)baud; // ms between output characters; minimum ~10/baud*1000
Serial.begin(BAUD);
Serial.println("\n\r-----------------------------");
Serial.println(" www.holdentechnology.com");
Serial.println(" meh...surement system model W");
Serial.println("-----------------------------\n\r");
digitalWrite(LEDPin, HIGH); // set the LED on
delay(1000); // wait for a second
digitalWrite(LEDPin, LOW); // set the LED off
delay(1000); // wait for a second
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void loop()
{
//MWV - Wind Speed and Angle
// 1 2 3 4 5
// | | | | |
// $--MWV,x.x,a,x.x,a,a*hh<CR><LF>
//Field Number:
//1.Wind Angle, 0 to 359 degrees
//2. Reference, R = Relative, T = True
//3. Wind Speed
//4. Wind Speed Units, K/M/
//5. Status, A = Data Valid, V = Invalid
//6. Checksum
//Example: $WIMWV,214.8,R,0.1,K,A*28
// make NMEA speed string
// read voltage as 10 bit int (0-1023), convert to 0-360 degrees
// See parameter defs above
wind_dxn = ((float)analogRead(A0))*5.0/1023.0; // volts input
wind_dxn = (wind_dxn - MINVOLTS)*360.0/(MAXVOLTS-MINVOLTS);
wind_dxn += DEGOFF; // correct offset
if (wind_dxn < 0) wind_dxn+=360.0; // correct wrap
if (wind_dxn > 360) wind_dxn-=360.0; // correct wrap
// wind_dxn = 180*cos(float(millis())*1.0/10000.0)+180; //HACK!!! fake data
deg = (int) wind_dxn; // gets around lack of floating point in arduino's sprintf
degtenths = wind_dxn*100 - deg*100;
sprintf(nmeastring,"$SDMWV,%3d.%02d,R,0.0,K,A*",deg,degtenths);
// checksum math (see NMEA0183 references)
checksum = 0;
jj=1;
while (nmeastring[jj+1]!=0)
{
checksum ^= nmeastring[jj];
jj++;
}
// Print NMEA sentence.
// periodically send the string + checksum
if (millis() > print_time)
{
print_time = (float)millis() + PRINTDT;
//Serial.println("$GPRMC,200258,A,3754.4088,N,12223.0474,W,4.9,266.5,300712,15.1,E,D*3F"); // HACK!!! for testing
Serial.print(nmeastring);
if (checksum < 0x10) Serial.print('0');
Serial.println(checksum,HEX);
}
} // end of loop
Code language: Arduino (arduino)
Hello, first of all, I am a mechanic, electronics are a hobby of mine, I am from Belgium and I have build a wind direction vane with the AS5600. Test with a AS5600 test program works 100%.
But here it comes. My knowledge of arduino is not so good. In Your article there is something about a prototype with AS5600. So maybe there is a sketch for arduino with the AS5600. Is there a possibility to send me the sketch? I find nothing on the internet and my project is stranded over the software. If you respond, I will send you fotos os the mechanical side of my project.
Please excuse me for my poor English .
Your sincerely
Thierry
Hi! Sorry I missed this comment! I think I used the PWM output of the AS5600 so in the arduino the pulseIn function did the work for me.
int sensorValue = pulseIn(7,HIGH);