Rotary Encoder Angular Velocity

Hello all,

I am currently working on a design project in which my team and I have been tasked with creating a portable 3D printed weather station that collects sensor data and displays it to an LCD screen. The weather station utilizes an Arduino Uno, two adafruit sensors, an LCD screen, and a Nidec RES20D50-201-1 rotary encoder (datasheet linked below). The two adafruit sensors read altitude, temperature, and pressure, while the rotary encoder is to be attached to an anemometer unit and in turn, calculate wind speed. This portion of the code has been giving me headaches, as it has proven difficult to incorporate the rotary encoder / angular velocity calculation routine into the master sketch. On its own, the angular velocity calculation (see below) works like a charm, the readings and calculations are done nearly instantaneously, and the results seem accurate. The calculations rely on difference calculations, utilizing the millis() and positional readings from previous / current iterations to establish a change in time and angular position. This all works great until it is implemented into the master code for the weather station, which contains additional routines that interfere with the angular velocity calculations. The interference stems from a routine that controls data output to the LCD screen, as this routine utilizes delay commands to keep displays on the screen for a few seconds before cycling to the next datum. These 4 delay commands of 3000 ms each seem to be the basis of the issue, as while the system is in delay, intermediate positional data readings are not taken, and the difference in position between iterations ends up being 1 or 2. This is an issue as now the time difference value encompasses over 12000 ms, so the calculation becomes wildly inaccurate. I have experimented with adding an oldPosition update after conducting the LCD routine or embedding the angular velocity calculations within a repeating for loop to achieve multiple successive readings, yet all alterations have deemed ineffective. It would be a huge help if somebody pointed me in the right direction as to what to do, I can figure out the code, but without direction as to what the code needs to do, I am a little lost. Thank you so much for your time and assistance, all the best to you.

Nidec RES20D50-201-1

Arduino Sketch:

#include <Encoder.h>

long oldPosition  = -999;                  // Initialization of variables to be used in calculations.
float dPos;
float dTheta;

unsigned long newTime;
unsigned long oldTime = 0;
unsigned long dt = 0;

float angularSpeed;
float linearSpeed;
float r = 0.09;

Encoder myEnc(6,7);

void setup() {
  Serial.begin(9600);
  Serial.println("Basic Encoder Test:");
}

void loop() {
  long newPosition = myEnc.read();          // The new position for the current iteration is read.
  if (newPosition != oldPosition) {         // If there has been a change in position from the previous position, if statement is excecuted.
    dPos = abs(newPosition - oldPosition);  // The difference in position between the old and new values is taken.
    oldPosition = newPosition;              // The old position is equated to the new position for the next iteration of the loop.
    newTime = millis();                     // The current millis time value is taken.
    dTheta = dPos*0.031415926535;           // The positional count data is converted into radians. With 50 pulses per revolution, and 4 counts per pulse,
                                            // there are 200 counts per revolution. This equates to 1.8 degrees, or 0.031415927 radians or arc per count.
    dt = (newTime - oldTime);               // The difference in time is taken.
    oldTime = newTime;                      // The old time value is equated to the new time value for the next iteration of the loop.
    angularSpeed = (dTheta / dt)*1000;      // The angular speed in rad/s is calculated.
    linearSpeed = r*angularSpeed;           // The linear speed is calculated in m/s.
    Serial.println(linearSpeed);            // The linear speed is printed to the serial monitor.
  }

  // delay(12000);                          // This delay commmand represents a routine in the main weather station program that encorperates 4x3000 ms
                                            // delay commands. This routine displays the linear speed data, along with 3 other additional data to an
                                            // LCD screen. The routine follows the format of display->delay->clear->display->delay->clear, in total
                                            // delaying the program 12000 ms every iteration. This appears to affect the positional reading of the 
                                            // encoder, as the intermediate changes that occur while the LCD display routine are not accounted for
                                            // while the program is in delay. I have tried to add an update block to update the oldPosition value
                                            // after the LCD routine, I have moved the routine around in order, I have tried multiple encoder reading
                                            // routines in sequence, I have tried to put the encorer reading block in a for loop, yet none of these
                                            // fixes seem to work.
  
}

That's an extensive presentation of the project.
Maybe I'll read it later. What's the initial difficulty?

These 4 delay commands of 3000 ms each seem to be the basis of the issue

Don't use delay(). There is hardly ever a need for it.

Study the blink without delay tutorial to learn a completely different programming style -- one that is generally required in any application that involves timing.

Posting hint: break up that wall of text, so that people can actually read it.

jremington:
Helpful hint: break up that wall of text, so that people can actually read it.

You did read me perfectly.... Too late late to start reading a brick sized book...

@aidanboyko, do not cross-post. Other thread removed.

I’m not sure that that rotary encoder is mechanically suitable for use as an anemometer. It looks like it is intended for use as a panel instrument so don’t expect a long life from it.

Usually, an anemometer counts complete revolutions then determines wind speed based on the number of revolutions in unit time, the length of the arms, etc. so an encoder is actually overkill, but will certainly deliver precision, high resolution results.

Anyway, for an encoder, especially when other activities are happening in the loop, you may be better off using interrupts. Here is an example: Rotary Encoder Using Arduino Hardware Interrupts
The code in the interrupt service routine should be quick to execute.

Presumably, the objective is to display the current wind speed and refresh this at a certain frequency and maybe log the values at yet another frequency. The display units would normally be linear velocity such as meters per second. Angular velocity (radians per second) is less common because the relationship to the linear wind speed depends on the physical characteristics of the anemometer.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.