Wind Data Logging
A friend of mine wanted to find out which way the wind generally blows in his garden, as he is planning to install a pond and the wind direction would influence where he placed certain equipment.
So we decided on wind speed and direction sensors, logging the data to SD card over a period of days/weeks. After some quick research on SD cards, it turns out they are rather easy to interface with Arduino via SPI; the only issue being that SD cards’ logic is 3.3v.
I ordered an SD card breakout board (cheap at a few pound) and while waiting for it to arrive, made my own crude version; SD card power supplied from the Arduino’s 3.3v and resistor pair voltage dividers for the data lines.
The wind speed sensor simply closed it’s contacts twice per rotation. The direction sensor was a little more complicated, at eight equally spaced positions different resistances were measured across it’s two connections.
So the plan was to connect the speed sensor to one of the Arduino’s digital pins (one with interrupt capability) utilising internal pull-up resistor, and the direction sensor to one of the analog pins so that we can effectively convert the resistance to an analog value. Notice the 0.1 microfarad decoupling cap across the speed sensor for de-bounce.
See this schematic I put together.
I used a spare micro-SD card adaptor as a ‘socket’ by soldering some header pins to it. While testing, I temporarily hooked up an LCD display to make it a little easier to see what was going on.
How it works:
Upon power-up, a random filename is created ready for data to be recorded into. e.g. XXXX-1.CSV
The wind speed sensor is connected to pin 2 of the Arduino, which can be utilised as an interrupt. Every time the speed sensor makes half a turn, the interrupt function runs.
On each run, the wind speed counter is incremented, and the position logged.
Once per minute, the average speed over that minute is calculated, along with the most common direction recorded. These values are then written to the current .CSV file on the SD card.
Every 6 hours a new file is created, XXXX-2.CSV then XXXX-3.CSV etc. Each holding 360 entries. We decided to do this in case of data-loss, at least we would only lose 6 hours and not the entire week for example. The reason for the random filename, was incase power was lost and then regained for some reason, we didn’t want the files to become overwritten (better safe than sorry eh).
Once it was confirmed working, I wrote it to a 5v Arduino mini pro, and connected it all up with the micro SD card board. One option would have been to use a 3.3v Arduino mini pro, negating the use for a proper SD card board and it’s 3.3v regulated logic level conversion. Anyway, it works and does the job.
Here’s some charts compiled by my friend from the data collected in the first week (click to enlarge):
Here you can download the xlsx file my friend used to create the above charts : Wind.xlsx
Find the code below.
– Wayne
// ================================================= //
// WIND SENSOR LOGGER PROGRAM //
// ================================================= //
// Date: 05 Jan 2015 //
// Author: Wayne K Jones / www.warmcat.uk //
// Free for non-commercial use, however please give //
// credit to the author. //
// ================================================= //
#include <SD.h>
int directionPin = A0; // for wind direction
const int chipSelect = 10;
int rpmcount;
int rpm;
unsigned long timeold;
long randNum;
int moo=0;
int foo=0;
int n = 0; //1
int ne = 0; //2
int e = 0; //3
int se = 0; //4
int s = 0; //5
int sw = 0; //6
int w = 0; //7
int nw = 0; //8
int mostdir = 0;
int mostdircount = 0;
float dir = 0;
File logFile;
String filenamePrefix = "";
void setup() {
Serial.begin(9600);
//Random filename generation //
randomSeed(analogRead(1)); //use Analog 1 for random seed
randNum = random(1000,9999);
filenamePrefix = filenamePrefix + randNum + "-";
// ========================= //
attachInterrupt(0, rpm_int, FALLING); //pin 2
digitalWrite(2,HIGH);
rpmcount =0;
rpm =0;
timeold =0;
Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to output, even if you don't use it:
pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
}
void loop() {
if (millis() - timeold == 60000) { //update every minute
detachInterrupt(0); //pause interrupts
rpm = rpmcount * 0.5;
//reset time and rpm count
timeold = millis();
rpmcount = 0;
mostdir = 0; //zero most used direction
mostdircount = 0; //and the count of said direction
// work out which direction variable has largest value
if (mostdircount < n) { mostdir = 1; mostdircount = n; }
if (mostdircount < ne) { mostdir = 2; mostdircount = ne; }
if (mostdircount < e) { mostdir = 3; mostdircount = e; }
if (mostdircount < se) { mostdir = 4; mostdircount = se; }
if (mostdircount < s) { mostdir = 5; mostdircount = s; }
if (mostdircount < sw) { mostdir = 6; mostdircount = sw; }
if (mostdircount < w) { mostdir = 7; mostdircount = w; }
if (mostdircount < nw) { mostdir = 8; mostdircount = nw; }
String data = ""; //initialise data string
switch (mostdir) {
case 0:
data = data + "-"; //no wind
break;
case 1:
data = data + "N"; //add N wind dir to data string
break;
case 2:
data = data + "NE";
break;
case 3:
data = data + "E";
break;
case 4:
data = data + "SE";
break;
case 5:
data = data + "S";
break;
case 6:
data = data + "SW";
break;
case 7:
data = data + "W";
break;
case 8:
data = data + "NW";
break;
}
data = data + "," + rpm; //add rpm to data string
Serial.println(data);
if (moo % 360 == 0) {
//every 360 moos (every 6 hours) increment foo (which creates a new file)
foo++;
}
moo++; //moo increments every time this if statement runs
String filename = ""; //initialse filename string
filename = filenamePrefix + foo + ".csv "; //create filename from random number, foo, and extension
// so we get XXXX-Y.csv ... XXXX being the randomly created number every time arduino power cycled.
// Y being 'foo' which increments every hour
//convert filename string to char array
char filenameCharArray[filename.length()];
filename.toCharArray(filenameCharArray, filename.length());
logFile = SD.open(filenameCharArray, FILE_WRITE); //create or open file
if (logFile) {
// if the file opened okay, write to it:
Serial.print("Writing to ");
Serial.println(filenameCharArray);
logFile.println(data);
// close the file:
logFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.print("error opening ");
Serial.println(filenameCharArray);
}
//Clear counts for next time
n = 0; //1
ne = 0; //2
e = 0; //3
se = 0; //4
s = 0; //5
sw = 0; //6
w = 0; //7
nw = 0; //8
attachInterrupt(0, rpm_int, FALLING);
}
}
void rpm_int() { //our interrupt every time wind sensor 1/2 turn
rpmcount++;
dir = analogRead(directionPin); //increment variable of current direction
if ((dir > 61) && (dir < 93)) n++;
if ((dir > 123) && (dir < 195)) ne++;
if ((dir > 240) && (dir < 290)) e++;
if ((dir > 596) && (dir < 632)) se++;
if ((dir > 930) && (dir < 950)) s++;
if ((dir > 820) && (dir < 891)) sw++;
if ((dir > 700) && (dir < 790)) w++;
if ((dir > 400) && (dir < 470)) nw++;
}
Any up date on how the project went?
How did your friend sort the data so it could be used?
Hey Mark 🙂
The CSV files opened into a spreadsheet, my friend then performed some kind of weird “excel magic” and then out popped the nice charts. I’ve updated the blog with the charts and the xls file for download.