Pages: [1] 2   Go Down
Author Topic: Arduino Pro and Anemometer (Reading Pulse Times)  (Read 2795 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using a Wind Vaned Anemometer to find the wind speed and direction. The system uses two sets of reed switches (one used for speed and one used for direction).

I am trying to print out the data to the serial monitor to confirm the data I am reading in, but am receiving nothing.

Can someone offer my some advice? I checked my syntax and I'm not sure if it is the way that it is being written or if it has to do with my timing.

When I hook up my system to the oscilloscope this is the reading that I get.


What I'm trying to do is calculate the time difference between the yellow pulses to figure out my RPM. And use the Time difference between the yellow and blue pulses to calculate phase shift to give me direction.

I referenced this other thread to give me what I have now: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265052228

Quote
//////////////////////////////////////////////////////////
//    Declaration of Variables   //
//////////////////////////////////////////////////////////
           
int analogSpeed = 0;             //Speed bus connected to analog pin 0
int analogDirection = 1;          //Direction bus connected to analog pin 1
unsigned long Speedvalue =  0;
unsigned long Directionvalue = 0;

// Variables for time
unsigned long SpeedDuration;
unsigned long DirectionDuration;
unsigned long SpeedTimePrevious;
unsigned long DirectionTimePrevious;
unsigned long DirectionTimePrevious1;
unsigned long DirectionTimePeriod;
unsigned long TimeDifference;
unsigned long Frequency;

// Variables for counting
volatile byte count;

void setup()
{
pinMode (analogSpeed, INPUT);
pinMode (analogDirection, INPUT);
Serial.begin(9600);          // Setup serial with baud rate
attachInterrupt(0, arduino_anemometer, RISING);
count = 0;
SpeedDuration = 0;
DirectionDuration = 0;
SpeedTimePrevious = 0;
DirectionTimePrevious = 0;
DirectionTimePrevious1 = 0;

TimeDifference = 0;
}

void loop()
{
///////////////////////////////////////////////////////////////////////////////////////////
// It takes about 100 microseconds to read an analog input    //
// Max reading rate is 10,000 times a second          //
/////////////////////////////////////////////////////////////////////////////////////////

//Do I want digital or analog read??

Speedvalue = analogRead(analogSpeed);       // Read the input pin at 0
Directionvalue = analogRead(analogDirection);    // Read the input pin at 1

if (count >= 1)
{
   //Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();


if (SpeedTimePrevious  >  DirectionTimePrevious)
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
}

// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;


// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 )   // Ensures that Direction must occur second
{
TimeDifference = (SpeedTimePrevious - DirectionTimePrevious);
}

count = 0;

//////////////////////////////////
//   VALUES   //
/////////////////////////////////
Speedvalue = (1492/SpeedDuration);      // Finds speed of cup rotation in
Directionvalue = 360*Frequency*TimeDifference; //Finds Angle of Wind Vein

/////////////////////////////////////////////////////////////////////////////
//   Printing SPEED, DIRECTION, TIME   //
/////////////////////////////////////////////////////////////////////////////
Serial.print("Speed: ");
Serial.println(Speedvalue, DEC);
//delay(1000);
Serial.print("Direction: ");
Serial.println(Directionvalue, DEC);
//delay(1000);
Serial.print("Time: ");
Serial.println(millis());
//delay(1000);

}

}

void arduino_anemometer()
{
count++;

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45985
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I am trying to print out the data to the serial monitor to confirm the data I am reading in, but am receiving nothing.
You are only printing a value when count is greater than 0. The count variable only gets incremented in the interrupt function. That you get nothing in the serial monitor implies that the interrupt handler is not being called, which implies that the Arduino is not receiving any signal on digital pin 2. What is connected to that pin?
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

from your code:
Quote
//Do I want digital or analog read??

As I see the pulses in the scope I would go for a digital read as it seems a nice square wave.

What is the voltage measured? You might need to boost it to get a decent level.

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You are only printing a value when count is greater than 0.
I took my printing out of the IF statement for now, but I may want to put it back there once I get the reading for the interrupt correct.

Quote
which implies that the Arduino is not receiving any signal on digital pin 2. What is connected to that pin?
You are right, I didn't connect anything to Digital Pin 2. I misread the how the interrupt function worked. I put my two inputs into Analog 0 and Analog 1.

I wanted to be able to tell when my analog signal rises so I can find the difference in time from when the signals rise relative to one another, and use that time to calculate speed and direction using RPM's and Phase Shift.

Since my signals are close to squares, could I send them through the digital pins (2,3). How would I handle the interrupt if now I have two different signals that I will need to compare?

Quote
As I see the pulses in the scope I would go for a digital read as it seems a nice square wave.

What is the voltage measured? You might need to boost it to get a decent level.
Input voltage is being regulated to 5 V, from a DC power Supply that is simulating a solar panel voltage for now.
Logged

Toronto
Offline Offline
Newbie
*
Karma: 1
Posts: 26
Arduino is teh r0xx0r
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you might want to look at some of the tachometer examples on this board, like Counting PulseIn.

I know a bit about anemometry and wind resource assessment. Are you sure your wind vane uses a reed switch? Don't think I've ever seen one of those, unless it uses several switches to indicate wind sectors.

Typical wind vanes are either:
  • linear potentiometer — linear output from 2° to 358°. Really nice ones are linear from -90° to 450° to help with direction trending.
  • Gray code — has several ttl outputs which generate a bitmap from which the wind sector can be deduced.

Reed switch anemometers are probably the easiest to read, but are quite low resolution. They work well with long cables. Other types are linear (voltage or current loop), low voltage AC (with frequency proportional to wind speed) and square wave (usually generated by a photochopper).

Since most wind data loggers (even the really expensive ones used for utility-grade work) are many times less powerful than an Arduino, I've been meaning to develop a decent logger sketch.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45985
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Since my signals are close to squares, could I send them through the digital pins (2,3). How would I handle the interrupt if now I have two different signals that I will need to compare?
The answer to the first question is yes. But, I wouldn't. I'd use 4 and 5. Or use 2 and 3, but attach interrupt handlers to the two pins (they are the external interrupt pins). Each ISR would fire on the RISING edge or the FALLING edge. In each ISR, record when the interrupt occured. In loop, look at the relative times.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Are you sure your wind vane uses a reed switch? Don't think I've ever seen one of those, unless it uses several switches to indicate wind sectors.
Yes, it does implement reed switches. Two in fact (one associated with the three cup system and one for the wind vein). You can find speed relative to one switch and seeing how fast the switch turns on and off. To find direction you have to measure the shift between the two pulses.

Quote
The answer to the first question is yes. But, I wouldn't. I'd use 4 and 5. Or use 2 and 3, but attach interrupt handlers to the two pins (they are the external interrupt pins). Each ISR would fire on the RISING edge or the FALLING edge. In each ISR, record when the interrupt occured. In loop, look at the relative times.

I guess I am just confused on how the data will be stored. If I attach my pins to 2 and 3 using and use 2 attathinterrupts instead of two

Quote
attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_anemometer, RISING);

in my loop function if digital pin 2 triggers on the rising and digital pin 3 rises while pin 2 is high, will the data I have for stored while using Pin 2 be erased?

for example...


Quote
   //Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();


if (SpeedTimePrevious  >  DirectionTimePrevious)
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
}

// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 )   // Ensures that Direction must occur second
{
TimeDifference = (SpeedTimePrevious - DirectionTimePrevious);
}

I would only want my SpeedDuration to trigger only when pin 2 rises. Does that mean I have to create a new subroutine outside of loop to account for this? Will this data be erased when pin 3 triggers with an interrupt? Can I compare the Time Difference in the loop if they are being handled in the interrupt subroutine?

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So I tried doing a simple loop.

My signal is low and for some reason count is incrementing, because the values being printed out for SpeedDuration and SpeedTimePrevious are nonzero.

Quote
setup()
{
attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_direction, RISING);
}

void loop()
{

if (count = 1)
{
   //Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
Serial.print("Speed: ");
Serial.println(SpeedDuration, DEC);
Serial.println(SpeedTimePrevious, DEC);
delay(1000);

}

Serial.print("Speed2: ");
Serial.println(DirectionTimePrevious, DEC);
delay(1000);

count=0;
directioncount=0;
}

void arduino_anemometer()
{
count++
}

void arduino_direction()
{
directioncount++
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45985
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
if (count = 1)
This is an assignment statement, not an equality test.

You would not want to test for equality, anyway. You want to do something when count > 0, not any specific value greater than 0.

Are count and directionCount volatile?

In order to get good timing data, the time the interrupt occured needs to be recorded in the ISRs. Finally, while didling with the time and count values, you really should disable interrupts, so you are not interrupted during the computations. Re-enable them when done.

And last, but not necessarily least, GET RID OF THE delay()s. You probably want to only calculate and output speed and direction once every few seconds, but don't use delay to make that happen.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So this is the data that I am getting now. (code is posted below)
Quote

Count: 0
Speed: 0
DirectionCount: 0
Speed Time: 0
Direction Time: 0
Time Difference: 0
DirectionTimePeriod: 0
Speed: 4294967295
Direction: 4294967295
Time: 2861


Count: 3
Speed: 820
DirectionCount: 3
Speed2: 11790
Speed Time: 11632
Direction Time: 11790
Time Difference: 158
DirectionTimePeriod: 820
Speed: 1312478
Direction: 69
Time: 12382


Count: 2
Speed: 821
DirectionCount: 3
Speed2: 14252
Speed Time: 14094
Direction Time: 14252
Time Difference: 158
DirectionTimePeriod: 821
Speed: 1310880
Direction: 69
Time: 14843


For some reason my direction is always 69 +/- 1 no matter the direction the wind vein points.

I'm calculating speed and direction value using
Quote
Speedvalue = (1492*3600000/SpeedDuration); 
---where 1492 is some arbitrary distance and 3600000 is to convert to hours from miliseconds
Directionvalue = 360*TimeDifference/DirectionTimePeriod;
---I decided to divide by the period of my direction signal rather than multiply by the frequency, because I would end up getting zero because of the scaling.


I'm checking the math using the tables and they match up to be 69-ish. I guess this leads to the idea that I'm not reading the rising pulses correctly. Any thoughts?

Here is my code for now:
Quote
//////////////////////////////////////////////////////////
//    Declaration of Variables   //
//////////////////////////////////////////////////////////
           
int analogSpeed = 0;             //Speed bus connected to analog pin 0
int analogDirection = 1;          //Direction bus connected to analog pin 1
unsigned long Speedvalue =  0;
unsigned long Directionvalue = 0;

// Variables for time
unsigned long SpeedDuration;
unsigned long DirectionDuration;
unsigned long SpeedTimePrevious;
unsigned long DirectionTimePrevious;
unsigned long DirectionTimePrevious1;
unsigned long DirectionTimePeriod;
unsigned long TimeDifference;
unsigned long Frequency;

// Variables for counting
volatile byte count;
volatile byte directioncount;

void setup()
{
//pinMode (analogSpeed, INPUT);
//pinMode (analogDirection, INPUT);
Serial.begin(2400);          // Setup serial with baud rate
attachInterrupt(0, arduino_anemometer, RISING);
attachInterrupt(1, arduino_direction, RISING);

count = 0;
directioncount=0;
SpeedDuration = 0;
DirectionDuration = 0;
SpeedTimePrevious = 0;
DirectionTimePrevious = 0;
DirectionTimePrevious1 = 0;

TimeDifference = 0;
}

void loop()
{
///////////////////////////////////////////////////////////////////////////////////////////
// It takes about 100 microseconds to read an analog input    //
// Max reading rate is 10,000 times a second          //
/////////////////////////////////////////////e////////////////////////////////////////////

//DO I WANT DIGITAL OR ANALOG READ?!

Speedvalue = digitalRead(analogSpeed);       // Read the input pin at 0
Directionvalue = digitalRead(analogDirection);    // Read the input pin at 1

Serial.print("Count: ");
Serial.println(count, DEC);

if (count >= 1)
{
   //Calculating Speed Duration
SpeedDuration = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
count = 0;

}

Serial.print("Speed: ");
Serial.println(SpeedDuration, DEC);
Serial.println(SpeedTimePrevious, DEC);


Serial.print("DirectionCount: ");
Serial.println(directioncount, DEC);

if ((SpeedTimePrevious  >  DirectionTimePrevious)  && (directioncount >= 1))
{
DirectionDuration = (millis() - DirectionTimePrevious);
DirectionTimePrevious = millis();
DirectionTimePeriod = (DirectionTimePrevious - DirectionTimePrevious1);
directioncount = 0;

Serial.print("Speed2: ");
Serial.println(DirectionTimePrevious, DEC);


// Calculates Frequency between DIRECTION signals
DirectionTimePrevious1 = DirectionTimePrevious;
Frequency = 1/DirectionTimePeriod;
}

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimePrevious != 0 )   // Ensures that Direction must occur second
{
TimeDifference = (DirectionTimePrevious - SpeedTimePrevious);
}
Serial.print("Speed Time: ");
Serial.println(SpeedTimePrevious, DEC);
Serial.print("Direction Time: ");
Serial.println(DirectionTimePrevious, DEC);
Serial.print("Time Difference: ");
Serial.println(TimeDifference, DEC);
Serial.print("DirectionTimePeriod: ");
Serial.println(DirectionTimePeriod, DEC);


//////////////////////////////////
//   VALUES   //
/////////////////////////////////
Speedvalue = (1492*3600000/SpeedDuration);      // Finds speed of cup rotation in
Directionvalue = 360*TimeDifference/DirectionTimePeriod; //Finds Angle of Wind Vein

/////////////////////////////////////////////////////////////////////////////
//   Printing SPEED, DIRECTION, TIME   //
/////////////////////////////////////////////////////////////////////////////
Serial.print("Speed: ");
Serial.println(Speedvalue, DEC);
Serial.print("Direction: ");
Serial.println(Directionvalue, DEC);
Serial.print("Time: ");
Serial.println(millis());



}

void arduino_anemometer()
{
count++;
}

void arduino_direction()
{
directioncount++;
}

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45985
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
Speedvalue = (1492*3600000/SpeedDuration);  
1492 and 3600000 are treated as ints. 1492 is an int, but 3600000 is not. You should have a L or UL at the end, to tell the compiler to treat the value as a long or unsigned long.

Code:
int analogSpeed = 0;             //Speed bus connected to analog pin 0
int analogDirection = 1;          //Direction bus connected to analog pin 1

Speedvalue = digitalRead(analogSpeed);       // Read the input pin at 0
Directionvalue = digitalRead(analogDirection);    // Read the input pin at 1

Are you using the digital pins, so digitalRead is appropriate, or the analog pins?
If you are using digital pins, 0 and 1 are not good choices while doing serial I/O.
If you are using analog pins, you should be using the analogRead function.
« Last Edit: March 09, 2011, 10:19:24 am by PaulS » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
1492 and 3600000 are treated as ints. 1492 is an int, but 3600000 is not. You should have a L or UL at the end, to tell the compiler to treat the value as a long or unsigned long.

Are you implying that I store the 1492*3600000 as 5371200000 in another UL variable and hash out my math in explicit UL variables?

Quote
Are you using the digital pins, so digitalRead is appropriate, or the analog pins?
If you are using digital pins, 0 and 1 are not good choices while doing serial I/O.
If you are using analog pins, you should be using the analogRead function.

Sorry those were poor name choices for variables. Since the input were square waves, I decided to have them be digital inputs. Originally they were supposed to be analog inputs at pins 0 and 1, but I changed it to digital pin 2 and 3 and forgot to change my comments/names.


On another note, I am trying out a debounce circuit on my input to help clean out my input. That could be a source of error when reading in my data.
« Last Edit: March 09, 2011, 02:27:24 pm by DynamiK » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I added a debouncing circuit (RC) to my reed switch. My voltage dropped but the results did not change at all. Anyways I thought I'd share what I was seeing on the oscilloscope and the computer.

Time between Directional signal rising


I'm getting a time that's within 700ms. (I checked over a course of 10 impulses that were printed)

Some delay was expected...but not like this...

Here are the relations that I received using the picture above
Computer DataOscilloscope Data
Speed Period: 763 ms
Time Difference: 162 ms 
Direction Period: 766 ms   
Direction: 76 degrees
Speed Period: 580 ms
Time Difference: 260 ms
Direction Period: 560 ms
Direction: 167 degrees

Again I am calculating my direction value with
Quote
Directionvalue = 360*TimeDifference/DirectionPeriod;

It makes sense that the period of the speed and the direction are the same since the rotation of the axis hits the 2 reeds at the same time.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I cleaned up the code a little bit to get rid of some redundancies in the old code.

I am noticing the following:

1. My Time Difference is always the same no matter what angle I move my anemometer.

It makes me wonder if I am even making it to that part of the code to update my software or if the program is reading my square waves correctly.

2. I have my sensor set up to a fan that gives my cups 154 rotations per minute, which give my code 308 interrupts per minute.

I read that the millis() function acts as an interrupt as well. I referr to millis() at lease 4 x in my loop function.

That mixed in with the number of interrupts I am getting, will I be able to  make it though my loop function to update my data correctly?

Another question: How much voltage does it take to trigger a rising interrupt? I have very minimal noise on my signal when it is on/off. I'm not sure if this is a problem as my timing to measure my distance between rising edges on 1 signal is off from the oscilloscope readings.

Quote
void loop()
{
Speedvalue = digitalRead(digitalSpeed);       // Read the input pin at 2
Directionvalue = digitalRead(digitalDirection);    // Read the input pin at 3

if (count >= 1)
{
   //Calculating Speed Duration
SpeedPeriod = (millis() - SpeedTimePrevious);
SpeedTimePrevious = millis();
count = 0;

}

Serial.print("Speed Period: ");
Serial.println(SpeedPeriod, DEC);

//Value of the Speed
SpeedDistance = 60000*45;                                // 4.5 ft * 60,000 ms/min * 10 scaling factor
Speedvalue = (SpeedDistance/(10*SpeedPeriod));   // Finds speed of cup rotation in ft/min
                                                        // ft * (ms/min) / ms = ft/min
                                                        //divide 10 scaling factor back out

if ((SpeedTimePrevious  >  DirectionTimeRising)  && (directioncount >= 1))
{
DirectionTimeRising = millis();
directioncount = 0;
}

// Calculates time difference between SPEED and DIRECTION signals
if (DirectionTimeRising > SpeedTimePrevious )   // Ensures that Direction must occur second
{
TimeDifference = (DirectionTimeRising - SpeedTimePrevious);
}
Serial.print("Time Difference: ");
Serial.println(TimeDifference, DEC);

//Value of Direction
Directionvalue = (360*TimeDifference)/SpeedPeriod; //Finds Angle of Wind Vein

« Last Edit: March 11, 2011, 09:11:47 pm by DynamiK » Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 48
Posts: 3393
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am wondering whether your use of Serial.print is impacting your times. I assume that the UART will buffer the text to some extent, but since you're sending around 30 characters each iteration of the loop, you may be getting delayed by that.

Also, you might get a bit more accuracy on the speed if you collect a few more interrupts (10?) before calculating the time difference
Logged

Pages: [1] 2   Go Up
Jump to: