Introduction: Setting Up an A100LK Anemometer on an Arduino

Picture of 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.

Step 1: How It Works

Picture of 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.

Step 2: Calculating the Filter Parameters

Picture of 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.

Step 3: Calibration and Non Linearity Calculations

Picture of 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!

Step 4: Parts

Picture of 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

Step 5: Wiring Up the A100LK

Picture of 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!

Step 6: 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("");             
}

Step 7: 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?

Comments

jazzycamel (author)2016-05-23

Hi there,
Simple question: using pulseIn() are you not only measuring only the 'high' part of the square wave as opposed to the full period? If so, your frequency and thus your speed will be double the actual value. I may have missed something in your explanation though...

jazzycamel (author)jazzycamel2016-05-23

Ignore that, ive just reread the code and seen the conversion from μs to Hz is 500,000/time rather than 1,000,000. Might ne good to explain that somewhere. Also, the duty cycle of the square wave is 50% +/- 25% so you're probably better measuring edge to edge, as averaging the result won't compensate for continuously asymmetrical waveforms.

Thanks! Hopefully I've not got it out by a factor of 2, but I can check once it's up a pole in the wind.

About This Instructable

3,896views

80favorites

License:

Bio: Ugly pirate roaming the seas in search of Treasure.
More by Tecwyn Twmffat:Arduino Cell Phone 4G Signal Booster / RepeaterSimple Manual Arduino 4 Axis Stepper Motor / 16 Channel LED Power ControllerFull English Breakfast
Add instructable to: