Davis 6410 Anemometer
Application
The Davis anemometer is currently used in a simple weather station to measure wind direction and speed.
Configuration
The detailed information provided by cactus.io was used to develop the present configuration. The use of different processors and general hardware configuration did, however, necessitate some modifications to that set-up, as outlined below.
Hardware
The anemometer, together with the rain collector, is currently configured in conjunction with the Heltec CubeCell Dev-Board Plus and the 10068-BHCP power management and 100768-WS weather station sensor interface PCBs.
Langlo 'Weather Station'
The 'Weather Station' Node is currently powered by a 900mAh 14500 (AA) Li-Ion battery, supported by an 80 x 35 5.5V 70mA solar panel. The CubeCell architecture includes onboard solar panel support and battery charge management hardware, so the only additional component required in the power circuit is a reverse current protection diode on the solar panel (refer to the 10068-BHCP hardware description for details).
10068-WS + 10068-BHCP + 10068-PDS
In this configuration, the battery has retained full charge throughout the summer months here in Australia, but has yet to be tested through an extended period of overcast weather. In some of my early experiments, I did notice that once batteries were depleted to a certain level, they were never subsequently fully recharged, with the result that, over time, they ultimately ran flat. It's not yet clear whether this is a general problem, common to all processor configurations, or a 'feature' of the CubeCell [Plus] battery management system.
I'll make an appropriate note here when I've completed more extensive tests on some of the other processor configurations.
Configuration
The essential operational mechanism and configuration of the present Davis 6410 Anemometer—CubeCell Dev-Board Plus implementation is as illustrated below.
Davis Anemometer Electrical Circuit
Pin Configuration
CubeCell Plus | Davis 6410 |
---|---|
GND | GND |
Ve | VCC |
ADC3 | Direction |
GPIO8 | Speed |
Note that the above is a simplified version of the circuit, intended to illustrate the internal configuration of the Davis sensor and it's logical connection to the CubeCell Dev-Board Plus. The 10068-WS board used in the present implementation incorporates additional line protection circuitry, which includes, for example, 10kΩ pull-up resistors, on all digital lines (see 10068-WS Board Schematic). A voltage divider (provided on the ">10068-BHCP board) is also required on the Wind Direction circuit to bring the input voltage down below the 2.4V maximum supported by the CubeCell architecture.
Weather Station Node Board Stack
The anemometer is physically connected via an RJ11 socket on the 10068-WS board. The configurations of the anemometer cable and socket are illustrated below.
Davis Anemometer Cable Configuration
Software
The sketch for collecting data from the anemometer is currently specific to the Heltec CubeCell Dev-Board Plus, primarily in relation to both the interrupt mechanism and the control of power to the sensor. I have tested the application of the general principles involved with other processors (Arduino Pro Mini, ESP-12 and ESP32), but the CubeCell Plus turned out to be the easiest module to program for this application so it became the first to actually be used.
System Functions
Sleep Mode
Sleep modes and their characteristics vary between the different processor families.
In the present application, there are two considerations in relation to sleeping the processor:
- Saving the state
- Minimising power usage of both the processor and peripherals.
For details on the implementation of sleep modes on the CubeCell platform, refer to the section on CubeCell software.
Interrupts
The measurement of both wind speed and rainfall employ processor interrupts, the mechanism for which differs slightly for the different processor families.
For details on the implementation of interrups on the CubeCell platform, refer to the ">section on CubeCell software.
Measuring Wind Direction
As noted earlier, the present work is based on that described by cactus.io. One particular difference in the results is that I report my wind direction relative to true north, rather than magnetic north. The fundamental issues that need to be addressed in the code are no different, it's just a question of the reference point used.
Another consideration was the fact that the CubeCell Plus ADCs are 12 bits wide, so the range that can be mapped onto the 360° of the compass is 0..4095. To further complicate matters, the CubeCell Plus ADC input voltage is limited to 2.4V, necessitating the inclusion of a voltage divider, to bring the maximum input voltage back from 3.3V, in the input circuit.
On the basis that many inbuilt ADCs deviate from linearity near the top end of their scale, I made the decision to limit the input voltage a little further. Accordingly, using a 100kΩ/220kΩ voltage divider provides a maximum input voltage of around 2.27V, which mapped (by direct measurement, and for the purpose of calibration) to an ADC value of 3806. This value defines the upper limit of the range used in the function that maps the ADC output to the compass bearing.
According to the Australian Bureau of Meteorology, wind direction measurements are generally averaged over a 2-10 minute period. This wouldn't really be practical for my [battery-powered] application as, depending on the sampling period, it would require my node to be more or less permanently active. So my compromise is to sample the wind direction five times, at one second intervals, and report the average of those readings. The present solar/battery powered configuration reports every 60 seconds (without any decline in battery performance) and longer period averages can be calculated from this data.
Measuring Wind Speed
In the present application, wind speed and direction measurements are carried out concurrently, so the speed is reported as the average over the period used to measure the wind direction (about 5 seconds). Wind speed is derived from the number of 360° revolutions of the anemometer cups during this period, each revolution triggering an interrupt that, in turn, increments a counter.
In a 1 kph wind, the Davis 6410 anemometer cups rotate [through 360°] 1000 times per hour, so the wind speed can be calculated from the number of rotations recorded over a given time interval using the following equation (see Technical Specifications):
S | = | ( 3600000 / K ) | × ( R / T ) |
= | 3600 | × ( R / T ) |
where
- S = Wind speed (in kilometres per hour)
- K = Rotations per hour per kph = 1000
- R = Rotations recorded in time T
- T = Sample period (in milliseconds)
- 3600000 = milliseconds in 1 hour
In line with the comments on debouncing in relation to the Davis rain collector, I have not made any effort, in either hardware or software, to allow for chattering.
Testing the Configuration
The following sketch, which runs on the CubeCell Dev-Board Plus, in conjunction with the 10068-BHCP power management and 10068-WS weather station sensor interface boards, incorporates the above and can be used to verify the CubeCell Dev-Board Plus/Davis 6410 anemometer configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 210 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
#include "CubeCellPlusPins.h"// CubeCell Plus pin definitions
// Includes: //#define windDirectionPinADC3 //#define windSpeedPinGPIO8 const uint16_t reportingPeriod = 10000;// In milliseconds, but keep it low while testing uint16_t windCounter = 0; void setup () { pinMode(Vext,OUTPUT); digitalWrite(Vext,LOW);// Turn on power to connected devices Serial.begin(115200); delay(200); Serial.println("[setup] Davis Anemometer"); // Define the interrupt pin PINMODE_INPUT_PULLUP(windSpeedPin); } void loop () { measureWind(); delay(reportingPeriod); } void initialiseWindCount() { windCounter = 0; } void incrementWindCount() { windCounter++; } void measureWind() { uint32_t startTime, endTime; uint16_t rotations = 0; uint16_t windSpeed = 0; uint16_t windBearing = 0; uint16_t totalWindBearing = 0; //uint16_t bearingCalibrationOffset = 0;// See comment below uint8_t averageCount = 5; // Number of direction readings to take and average /* For the Davis 6410 anemometer, 1000 revolutions per hour = 1 kilometre per hour Our time interval is measured in milliseconds calibrationSpeed= 1// kilometres per hour calibrationRotations= 1000// rotations per hour timeUnits= 3600000// milliseconds per hour For wind speed calculations: scalingFactor = calibrationSpeed * timeUnits / calibrationRotations */ int scalingFactor = 3600; initialiseWindCount(); Serial.println("[measureWind] Begin wind sampling..."); attachInterrupt(windSpeedPin,incrementWindCount,FALLING); startTime = millis(); for (int i = 0; i < averageCount; i++) { totalWindBearing = totalWindBearing + readWindBearing(); delay(1000); } windBearing = totalWindBearing / averageCount; /* If the anemometer arm cannot be set pointing true north (see User Manual), a wind bearing calibration offset must be set according to the direction it does point and the above line of code replaced by the following lines: windBearing = bearingCalibrationOffset + totalWindBearing / averageCount; if (windBearing > 360) { windBearing = windBearing - 360; } else if (windBearing < 0) { windBearing = windBearing + 360; } */ detachInterrupt(windSpeedPin); endTime = millis(); Serial.println("[measureWind] End wind sampling"); rotations = windCounter; windSpeed = (int) (scalingFactor * rotations / (endTime - startTime)); Serial.print("[measureWind] Rotations : "); Serial.println(rotations); Serial.print("scalingFactor : "); Serial.println(scalingFactor); Serial.print("startTime : "); Serial.println(startTime); Serial.print("endTime : "); Serial.println(endTime); Serial.print("Wind Speed : "); Serial.print(windSpeed); Serial.println(" kph"); Serial.print("[measureWind] Bearing : "); Serial.print(windBearing); Serial.println(" °"); compassDirection(windBearing); } uint16_t readWindBearing() { //return adc level 0-4095; Need to calibrate to find max value for configuration uint16_t windReading = analogRead(ADC3); // Serial.print("[readWindBearing] Wind Reading "); // Serial.println( windReading ); uint16_t windBearing = myMap(windReading, 0, 3806, 0, 359); return windBearing; } uint16_t myMap(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) { if ((in_max - in_min) > (out_max - out_min)) { return (x - in_min) * (out_max - out_min+1) / (in_max - in_min + 1) + out_min; } else { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } } void compassDirection( uint16_t windBearing ) { Serial.print("[compassDirection] "); if (windBearing > 169) { if (windBearing > 259) { if (windBearing > 304) { if (windBearing > 326) { if (windBearing > 349) { Serial.print("N"); } else { // 326 < windBearing <= 349 Serial.print("NNW"); } } else { // 304 < windBearing <= 326 Serial.print("NW"); } } else { //windBearing <= 304 if ( windBearing > 281) { Serial.print("WNW"); } else { // 259 < windBearing <= 281 Serial.print("W"); } } } else { // windBearing <= 259 if ( windBearing > 214) { if ( windBearing > 236) { Serial.print("WSW"); } else { // 214 < windBearing <= 236 Serial.print("SW"); } } else { // windBearing <= ? if ( windBearing > 191) { Serial.print("SSW"); } else { // 169 < windBearing <= 191 Serial.print("S"); } } } } else { // windBearing <= 169 if ( windBearing > 79 ) { if ( windBearing > 124) { if ( windBearing > 146) { Serial.print("SSE"); } else { // 124 < windBearing <= 146 Serial.print("SE"); } } else { // 101 < windBearing <= 124 if ( windBearing > 101) { Serial.print("ESE"); } else { // 79 < windBearing <= 101 Serial.print("E"); } } } else { // windBearing <=79 if ( windBearing > 34) { if ( windBearing > 56) { Serial.print("ENE"); } else { // 34 < windBearing <= 56 Serial.print("NE"); } } else { // windBearing <= 34 if ( windBearing > 11) { Serial.print("NNE"); } else { // 349 < windBearing <= 11 Serial.print("N"); } } } } Serial.println(); } |
Weather Station Application
The Weather Station application sketch can be downloaded by clicking on the following link. The EEPROMHandler and PacketHandler libraries can be downloaded from their respective downloads pages and the CubeCell Plus pin definition file from the CubeCell Platform page. I'll provide a complete description of what's going on at some point, but for the time being you'll need to look at the descriptions under each of the relevant sensors to see what's happening in each case.
The reader may also need to refer to the section on LoRa configuration.
Place the Weather Node sketch folder in the Arduino IDE root folder (Arduino). If running on a Heltec CubeCell Plus module, as is currently configured, this sketch also requires the latest version of the Heltec [CubeCell] hardware support libraries.
Weather Node [v2.3.2] | 31-Aug-2024 | [8 KB] |
Update: 30 Nov 2022 I only recently discovered that the above will probably not be entirely compatible with the version of the gateway software that is provided elsewhere on this site. The following is a version that uses the PacketHandler library. Once the PacketHandler and the relevant support files are installed, the following sketch should compile and run on the V1 & V2 Heltec WiFi LoRa 32 boards or the ESP32-WROOM-32 board, also described elsewhere on this site.
WiFi LoRa V2 Gateway [v2.2.2] | 17-Nov-2023 | [9 KB] |
Documentation
Davis 6410 Technical Specifications | [279 KB] |
Davis 6410 User Manual | [795 KB] |