Setting Up an A100LK Anemometer on an Arduino
by Tecwyn Twmffat in Circuits > Sensors
7039 Views, 88 Favorites, 0 Comments
Setting Up an A100LK Anemometer on an Arduino
Anybody thinking of installing a wind generator, or even a whole flock of wind generators, would be well advised to monitor the proposed site for at least one whole year before spending a penny more on hardware. This is what the A100LK is designed for.
The first requirement is that it is accurate and calibrated to within very tight tolerances as just a few % 'off' could lose the investors many millions of dollars. My anemometer was very kindly donated to me by Vector Instruments and came with a great swathe of non linearity tables and calibration certificates which needed to be decoded within the arduino to produce super accurate results for my GPRS Weather Station, with live data displayed online at: Meusydd Weather . It also came with a recommendation to install a filter circuit to provide 'low pass filtering with a maximum cut-off frequency of 10khz on the pulsed output'. Surely it can't be any more difficult than filtering home brewed cider?
Apart from this, I've been dying to get started on version 2 of the GPRS weather station project so this was a perfect opportunity to test out my new 'Weather Station Development Board' and link up, yes, THREE arduinos via I2C and create the beginnings of a processor network that will be capable of becoming fully autonomous by the year 2040.
How It Works
The A100LK is calibrated to give out a pulsed frequency that, when divided by 10, gives out a reading in UK knots to an accuracy of no greater than + or - 1%. The device is wired up for 4.7 to 28v and so is ideal for an arduino and reading the pulses is very straight forwards. The pulsed output is basically a square wave with a maximum output of 4v which goes through our filter circuit and is then read by an arduino nano once every five seconds using the 'pulseIn' command. Nothing could be simpler - except that we've got to design the filter.
The nano then does some calculations to account for the calibration value on the A100LK test certificate and then more calculations to make the output linear. This nice linear output is achieved by writing code to query each and every value against a table of values supplied by Vector Instruments. This may sound difficult, but it is not at all so!
Lastly, the readings in UK knots need to be compiled into 'mean' averages and provide the maximum gust for a ten minute period. These readings are then displayed on a swanky full colour TFT display on the development board.
The development board itself is designed with slots for 3 arduinos - 2 nanos and a mega - and has an option for the TFT screen which is operated by one dedicated nano. The other nano is the 'Master' and can turn off the 'Slave' nano when it's not needed and can also turn on the Mega when that's needed and put it back to sleep again afterwards. The reason for the 3 arduinos is that the TFT screen is power, memory and programming space hungry so needs to be kept in it's own cage, well away from the more essential processing activities. The question to ask here is 'Why have a screen at all?' The answer is that when trying to debug a problem 'in the field' a screen would be really useful - it's not always convenient to be trying to read the serial output on a laptop - especially in bright sunlight.
Just to keep it simple, for now the A100LK is wired up to the same nano as has the TFT screen - it will be wired to the master nano at a future date.
Calculating the Filter Parameters
Using a spread sheet to display math in graphical format is really useful and we don't have to get too bogged down in the actual calculations.
I've taken the final formula from the above and created a table with voltages calculated according to whatever values of resistance and capacitance are entered. The voltages are then plotted against frequency to see which frequencies are 'cut off' from the arduino input pin.
The A100LK operates from 0 to 1500 Hz, so any frequencies above 1500 should be removed if possible. In an ideal world, the cut off would be a straight vertical line creating a 'brick wall', but for our purposes, a gentle slope will suffice.
Downloads
Calibration and Non Linearity Calculations
Near the top of the arduino code is this line:
float calibration = 1.0047; // (46.62 / 46.4)
and what it does is it takes the value from the calibration certificate (46.4) and divides it into the nominal value of (46.62) and, hey presto, the device is calibrated! The value 'calibration' is then multiplied against our actual frequency reading, divided by 10 and then corrected against data in a table:
knots = (frequency * calibration /10) + correction;
The actual value 'correction' is calculated by a series of 'if' statements:
void adjustments() { if ((frequency >=1) && (frequency <=100)) {correction = 0.20;} if ((frequency >100) && (frequency <=200)) {correction = 0.10;} if ((frequency >200) && (frequency <=300)) {correction = -0.25;} if ((frequency >300) && (frequency <=400)) {correction = -0.60;} if ((frequency >400) && (frequency <=500)) {correction = -1;} if ((frequency >500) && (frequency <=600)) {correction = -1.4;} if ((frequency >600) && (frequency <=700)) {correction = -1.75;} if ((frequency >700) && (frequency <=800)) {correction = -2;} if ((frequency >800) && (frequency <=900)) {correction = -2.20;} if ((frequency >900) && (frequency <=1000)) {correction = -2.35;} if ((frequency >1000) && (frequency <=1100)) {correction = -2.40;} if ((frequency >1100) && (frequency <=1200)) {correction = -2.50;} if ((frequency >1200) && (frequency <=1300)) {correction = -2.50;} if ((frequency >1300) && (frequency <=1400)) {correction = -2.50;} if ((frequency >1400) && (frequency <=1500)) {correction = -2.45;} if ((frequency >1500) && (frequency <=1600)) {correction = -2.40;} }
and that's it!
Parts
A100LK Anemometer from Vector Instruments
C1 Ceramic Capacitor capacitance 100nF; voltage 6.3V; package 100 mil [THT, multilayer]
J1 Piezo Speaker Part3 Arduino Nano (Rev3.0) type Arduino Nano (3.0)
R1 100Ω Resistor pin spacing 400 mil; resistance 100Ω; bands 4; tolerance ±5%; package THT
R2 100Ω Resistor pin spacing 400 mil; resistance 100Ω; bands 4; tolerance ±5%; package THT
R3 100Ω Resistor pin spacing 400 mil; resistance 100Ω; bands 4; tolerance ±5%; package THT
TFT1 1.8" TFT Display with uSD
U1 A100LK
B1 Weather station prototyping board
Wiring Up the A100LK
Previously, we worked out that a value of 200 ohms and 100nF would be good for our filter circuit, with the resistor in series and the capacitor in parallel going to ground.
Getting the nano working with the TFT screen was slightly more tricky as the standard digital pins can't be used and we have to use the ICSP connector. Fortunately, there's a nice big square hole in the weather station development board right above the connector, so after that it was just a case of identifying which pin was MOSI, MISO and SCK. Strangely, when powering from the nano USB plug, the serial monitor has to be opened for the device to work!
Code for the Nano
#include <Adafruit_GFX.h> #include <Adafruit_ST7735.h> #include <SD.h> #include <SPI.h> #if defined(__SAM3X8E__) #undef __FlashStringHelper::F(string_literal) #define F(string_literal) string_literal #endif // D4 is frequency input. // D3 is Tone. float calibration = 1.0047; // (46.62 / 46.4) #define SD_CS 4 // Chip select line for SD card #define TFT_CS 10 // Chip select line for TFT display #define TFT_DC 8 // Data/command line for TFT #define TFT_RST -1 // Reset line for TFT (or connect to +5V) Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); int frequency; int z =0; float correction =0; float knots =0; float knotsMax =0; float knotsAv =0; float runningTotal =0; void setup(void) { Serial.begin(9600); // Initialize 1.8" TFT tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab Serial.println("OK!"); tft.setRotation(3); // Rotate the TFT text tft.fillScreen(ST7735_BLACK); tft.setTextSize(5); tft.setTextColor(ST7735_RED); delay(20); tft.setCursor(20, 10); tft.print("CAT"); pinMode(4,INPUT); } void loop() { z=0; knotsMax =0; knotsAv =0; runningTotal =0; while (z<20) { z++; tone (3,500,100); frequency = 500000/pulseIn(4,HIGH,5000000); if (frequency < 0){frequency=0;} correction =0; adjustments(); knots = (frequency * calibration /10) + correction; if (knots > knotsMax){knotsMax = knots;} runningTotal = runningTotal + knots; knotsAv = runningTotal / z; printing(); delay(5000); } } void adjustments() { if ((frequency >=1) && (frequency <=100)) {correction = 0.20;} if ((frequency >100) && (frequency <=200)) {correction = 0.10;} if ((frequency >200) && (frequency <=300)) {correction = -0.25;} if ((frequency >300) && (frequency <=400)) {correction = -0.60;} if ((frequency >400) && (frequency <=500)) {correction = -1;} if ((frequency >500) && (frequency <=600)) {correction = -1.4;} if ((frequency >600) && (frequency <=700)) {correction = -1.75;} if ((frequency >700) && (frequency <=800)) {correction = -2;} if ((frequency >800) && (frequency <=900)) {correction = -2.20;} if ((frequency >900) && (frequency <=1000)) {correction = -2.35;} if ((frequency >1000) && (frequency <=1100)) {correction = -2.40;} if ((frequency >1100) && (frequency <=1200)) {correction = -2.50;} if ((frequency >1200) && (frequency <=1300)) {correction = -2.50;} if ((frequency >1300) && (frequency <=1400)) {correction = -2.50;} if ((frequency >1400) && (frequency <=1500)) {correction = -2.45;} if ((frequency >1500) && (frequency <=1600)) {correction = -2.40;} } void printing() { tft.fillScreen(ST7735_BLACK); tft.setTextSize(2); tft.setTextColor(ST7735_BLUE); delay(20); tft.setCursor(20, 10); tft.print("Windspeed"); tft.setTextSize(2); tft.setCursor(0, 50); tft.setTextColor(ST7735_YELLOW); tft.print("Frequency:"); tft.setCursor(120, 50); tft.print(frequency); tft.setCursor(0, 70); tft.print("Knots:"); tft.setCursor(80, 70); tft.print(knots); tft.setCursor(0, 90); tft.print("Max:"); tft.setCursor(80, 90); tft.print(knotsMax); tft.setCursor(0, 110); tft.print("Av:"); tft.setCursor(80, 110); tft.print(knotsAv); Serial.print("Frequency = "); Serial.println(frequency); Serial.print("Knots = "); Serial.println(knots,4); Serial.print("Max. = "); Serial.println(knotsMax,4); Serial.print("Av. = "); Serial.println(knotsAv,4); Serial.print("z = "); Serial.println(z); Serial.println(""); }
Final
So now that we've spent so much effort setting up the A100LK, all that remains is to put it somewhere high up and away from trees and buildings to get meaningful results. This will be a separate instructable, so watch this space! After monitoring the wind for 12 whole months, we can then decide whether it's feasible to invest all our money in a wind farm or not. Still, I guess I've got 12 months to start saving?