QS-FS01 Anemometer Wind Sensor

Picked up one of these from aliexpress. In my infinite wisdom, i selected the pulse model (its digital, should be more accurate, how hard can it be to just count pulses?).

well, all the tutorials online are for the analog one where wind speed corresponds to a voltage. guess i should of checked for tutorials before i ordered it....

Anyway, it seems like i have it partially working, 5v goes in, ground goes in,, and a signal wire gives me 5v back and drops to 0v every time it turns. did a quick sample code job with pulseIn and it sometimes reads right, sometimes reads garbage, so presumable I need a pullup or pulldown resistor. grabbed a 4.7k resistor tried it both as a pullup and a pulldown on the signal wire, no luck though. either way, the resistor just zero's the readings out.

label on the sensor seems to match the manual for the pulse version.

manual for the sensor can be found here:
http://chinaplccenter.com/support/pdf/sensor/QS-FS-en.pdf

current testing code:

define windspeed_PIN 4

long getWindSpeed () {
  unsigned long duration1 = pulseIn(windspeed_PIN, HIGH, 1000000);
  unsigned long duration2 = pulseIn(windspeed_PIN, LOW, 500000);
  //add to get full pulse duration, although not consecutive, should be accurate enough
  unsigned long duration = duration1 + duration2;
  float windspeed = 0;
  //error checking
  if (duration1=0) duration=0;
  Serial.println(duration);
  //dont return garbage when sensor moving too slow for reading, return 0 instead
  if (duration>0) windspeed = (1000000/duration)*0.88*3.6;

  return windspeed;
}


void setup() {
  Serial.begin(9600);
  pinMode(windspeed_PIN, INPUT);
}

void loop() {
  Serial.print (getWindSpeed()); Serial.println ("kph");
  delay(500);
}

pulled out my ladder and opened it up, looks like its just a hall sensor and already has a pull up resistor in it. issue must be in my code for the bad readings.

IMG_20170422_120106 (Small).jpg

IMG_20170422_120208 (Small).jpg

There's dozens of post like your's, go to the search box at the top of the page and type "anemometer". :slight_smile:

Here is how I measure the rotational speed of a pulse type anemometer (1 pulse per revolution), using simple input polling:

   unsigned long start, revtime;
   while (digitalRead(anem_input) == LOW); //wait for input to go high
   start=millis(); //reset timer
   while (digitalRead(anem_input) == HIGH); //wait for it to go low again
   while (digitalRead(anem_input) == LOW); //wait for next high
   revtime = millis()-start; //time for one revolution

Of course, the processor can't do anything else while it is polling the input, but that is all my particular setup needs to do, except to send data out the serial port once every minute.

perfect, thanks jremington! that helped a bunch.

While waits for the next pinchange, and could lock up your loop on a windless day.
Maybe better to record millis() when the pin changes, or has changed several times.
This page might help.

Leo..

could lock up your loop on a windless day

Yes, that does happen, but then you know that the wind velocity is zero (fine for my application).

It is easy enough to build a timeout into the while loop, for example:

   unsigned long timeout=millis(); //start timeout timer
   while (digitalRead(anem_input) == HIGH && (millis() - timeout < 3000UL) ); //wait for it to go low again, but not wait longer than 3 seconds

thanks to jremington's code I managed to get my sensor up and running. i then had an issue with the readings jumping around given it was only one pulse and needed some smoothing/averaging, so i then started counting the number of pulses in a given time, but the code was doing this on demand when it was served to a webpage query and was too slow. I also ran into what Wawa mentioned with windless days. I then moved over to figuring out interrupts, found out after much time that not all digital pins are equal, had some serious issues with loosing decimals, some issues with compiling errors (constants than needed to be unsigned longs) and finally have it working reasonable well now.

for future reference for anybody hopefully this helps. it is a cut and paste out of my weather station code and i haven't tested it on its own (it works great in my weather station)

thanks again for the help!

#define windspeed_PIN 3 //must be an interrupt pin
//predefine variables as global to accomidate interupt
float windspeedPulses = 0;
unsigned long windspeedLastTime = millis();
float windspeedInterval = 120000; //average reading over 120 seconds
float windspeedKPH = 0;

void windspeedInterrupt() {
  windspeedPulses++;
  if (millis() > (windspeedLastTime + windspeedInterval)) {
    windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
    windspeedPulses = 0;
    windspeedLastTime = millis();
  }
  //Serial.println(F("Windspeed interrupt."));
}

void setup() {
  Serial.begin(9600);

  //setup windspeed/anemometer pin
  pinMode(windspeed_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(windspeed_PIN), windspeedInterrupt, RISING);


}

void loop() {
  //periocially check if windspeed interrupt hasnt been called incase wind speed is 0
  //don't call too often or this will skew low wind speeds
  if (millis() > (windspeedLastTime + (180UL * 1000))) {
    //if not signifiant number of pulses, zero out, else, force an interrupt
    if (windspeedPulses < 12) {
      windspeedPulses = 0;
      windspeedLastTime = millis();
      windspeedKPH = 0;
    }
    else {
      windspeedInterrupt();
    }
  }

  Serial.print(F("Windspeed: ")); Serial.print(windspeedKPH); Serial.println(F(" kph"));
  delay(1000);
}

There are a couple of potential problems.

(1) variables used in both interrupt routines and elsewhere must be declared "volatile". Otherwise the compiler may optimize your code and it will mysteriously stop working

(2) never print within an interrupt (now commented out), as printing depends on interrupts and they are turned off in an interrupt routine.

(3) It is not a good idea to call windspeedInterrupt from the main loop. This can lock up your program if a genuine interrupt occurs. The interrupt should simply set a flag variable that it has been called (again declared volatile) which the main loop can check and reset.

thanks for the pointers!

#define windspeed_PIN 3 //must be an interrupt pin
//predefine variables as global to accomidate interupt
//variable used outside windspeedInterrupt function must be volatile
//https://www.arduino.cc/en/reference/volatile
volatile float windspeedPulses = 0;
volatile unsigned long windspeedLastTime = millis();
volatile float windspeedKPH = 0;
volatile float windspeedInterval = 120000; //average reading over 120 seconds

void windspeedInterrupt() {
  windspeedPulses++;
  if (millis() > (windspeedLastTime + windspeedInterval)) {
    windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
    windspeedPulses = 0;
    windspeedLastTime = millis();
  }
}

void setup() {
  Serial.begin(9600);

  //setup windspeed/anemometer pin
  pinMode(windspeed_PIN, INPUT);
  //https://www.arduino.cc/en/Reference/AttachInterrupt
  attachInterrupt(digitalPinToInterrupt(windspeed_PIN), windspeedInterrupt, RISING);
}

void loop() {
  //periocially check if windspeed interrupt hasnt been called incase wind speed is 0
  //don't call too often or this will skew low wind speeds, using 150% of interval
  if (millis() > (windspeedLastTime + (windspeedInterval * 1.5 * 1000))) {
    //if there hasn't been a signifiant number of pulses, zero out windspeed variable and reset
    if (windspeedPulses < 12) {
      windspeedKPH = 0;
      windspeedPulses = 0;
      windspeedLastTime = millis();
    }
    //else there has been enough pulses to be significant, therefore calculate a new speed and reset
    else {
      windspeedKPH = (windspeedPulses / ((millis() - windspeedLastTime) / 1000)) * 0.88 * 3.6;
      windspeedPulses = 0;
      windspeedLastTime = millis();
    }
  }

  //For debugging, windspeedPulses should increase if wired correctly and interrupt is being called
  //do not call serial.print from within interrupt loop
  //Serial.print(F("windspeedPulses: ")); Serial.println(windspeedPulses);
  //display windpseed
  Serial.print(F("Windspeed: ")); Serial.print(windspeedKPH); Serial.println(F(" kph"));
  delay(1000);
}