Incremental Rotary Encoder issues

I have a project i am working on called single axis solar tracking system and i am using this rotary encoder https://diyshop.com.ua/image/cache/catalog/product/microcontroller/sensors/Encoder/ES38-06G1000BSC824/ES38-06G1000BSC824_1-650x650.jpg. The problem i having is after the tracking system have moved to its predetermined position, the rotary encoder keeps counting even though the system is not moving thereby making the whole setup unstable. i am thinking that my power source for the encoder is the problem which is a 12v adapter because the ac input is not a constant voltage, and this is my code

const byte A = 2;          // Interruption pin 2 for the rotary encoder
const byte B = 3;          // Interruption pin 3 for the rotary encoder
volatile int counter = 0;  //This variable will increase or decrease depending on the rotation of encoder
int temp, counter_copy;
int target_slope;

//Assigning the relay port to digital pins
byte RelayPin1 = 7;  // Digital pin 7
byte RelayPin2 = 8;  // Digital pin 8

// Setting the constant parameters needed to calculate inclination of platform
const int std_me = -15;
const int DaysInMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
const float Lat = 6.335;
const float Local_me = -5.6037;


// importing libraries for the rtc sensor
#include <Wire.h>
#include <Rtc_Pcf8563.h>

//init the real-time clock
Rtc_Pcf8563 rtc;


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

  // Set the relay pins as output
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);
  //Set the dc motor to off state at the start of the system
  digitalWrite(RelayPin1, HIGH);
  digitalWrite(RelayPin2, HIGH);

  // Set encoder pins as inputs
  pinMode(A, INPUT_PULLUP);
  pinMode(B, INPUT_PULLUP);

  // Setting interruptions for pin A and pin B
  attachInterrupt(digitalPinToInterrupt(A), ai0, FALLING);
  attachInterrupt(digitalPinToInterrupt(B), ai1, FALLING);
}


void loop() {
  hourlyrotation(rtc.getHour());
}

// function to determine the day of the year whose value ranges from 0 to 365 inclusive
int dayofyear(byte day, byte month) {
  if (month >= 1 && month <= 12) {
    return DaysInMonth[month - 1] + day;
  }
}

// function for determining the sign whether positive or negative attached to a value
int sign(float value) {
  if (value > 0) {
    return 1;
  } else if (value < 0) {
    return -1;
  } else {
    return 0;
  }
}


// function that calculate the hour and to position the panel to in other to get maximum radiation
void inclination() {
  int dofy = dayofyear(rtc.getDay(), rtc.getMonth());                                                                                 // Value range from 0 to 365 inclusive
  float B_ = (dofy - 1) * (360.0 / 365.0) * (PI / 180.0);                                                                             // Constant
  float equ_of_time = 229.2 * (0.000075 + 0.001868 * cos(B_) - 0.032077 * sin(B_) - 0.014615 * cos(2 * B_) - 0.04089 * sin(2 * B_));  // Value is in minutes
  float decl = 23.45 * sin((284 + dofy) * (360.0 / 365.0) * (PI / 180.0));                                                            // Declination value is in degrees
  float tcf = (equ_of_time + 4 * (std_me - Local_me)) / 1440.0;                                                                       // Time correction factor is in days
  float s_t = tcf + (rtc.getHour() / 24.0);                                                                                           // Calculating solar time is in days
  float ho_ang = (s_t - 0.5) * 360.0;                                                                                                 // Hour angle is in degrees (simplified)

  float cos_zenith = cos(Lat * (PI / 180.0)) * cos(decl * (PI / 180.0)) * cos(ho_ang * (PI / 180.0)) + sin(Lat * (PI / 180.0)) * sin(decl * (PI / 180.0));
  float sin_zenith = sqrt(1 - pow(cos_zenith, 2));
  float solar_azimuth = degrees(acos((cos_zenith * sin(radians(Lat)) - sin(radians(decl))) / (sin_zenith * cos(radians(Lat))))) * sign(ho_ang);

  int surface_azimuth = (solar_azimuth > 0) ? 90 : -90;  //azimuth is positive in the west and negative in the east

  float slope = round(degrees(atan((abs(cos(radians(surface_azimuth - solar_azimuth))) * (sin_zenith / cos_zenith)))));  // The value of slope is in degrees

  // Rearrange the slope so that angles above horizontal are positive and vice versa
  target_slope = (surface_azimuth > 0) ? -slope : slope;
}

void ai0() {
  // ai0 is activated if DigitalPin 2 is going from HIGH to LOW
  // Check pin 3 to determine the direction
  if (digitalRead(B) == HIGH) {
    counter--;
  } else if (digitalRead(B) == LOW) {
    counter++;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin 3 is going from HIGH to LOW
  // Check with pin 2 to determine the direction
  if (digitalRead(A) == HIGH) {
    counter++;
  } else if (digitalRead(A) == LOW) {
    counter--;
  }
}

void rotationdirection() {
  noInterrupts();
  counter_copy = counter;
  interrupts();
  // Send the value of counter_copy
  if (counter_copy != temp) {
    Serial.println(counter_copy);
    temp = counter_copy;
  }
  delay(1000);

  if (counter_copy < target_slope) {
    //rotate clockwise
    digitalWrite(RelayPin1, LOW);
    digitalWrite(RelayPin2, HIGH);
  } else if (counter_copy > target_slope) {
    //rotate counter clockwise
    digitalWrite(RelayPin1, HIGH);
    digitalWrite(RelayPin2, LOW);
  }
  delay(100);
  digitalWrite(RelayPin1, HIGH);
  digitalWrite(RelayPin2, HIGH);
  delay(1000);
}

//hourly rotation from 10 in the morning to 15 in the evening
void hourlyrotation(byte hourtime) {
  if (hourtime >= 10 && hourtime <= 15) {
    inclination();
    rotationdirection();
  }
}

i would appreciate any suggestions, thanks.

Please give a link to the data sheet.

Can you verify that the encoder signals show pulses even if everything should stand still? Scope shot?

Try adding lower pullup resistors.

This the what I have https://www.etekcs.com.tw/product-ES38-ES38.html

I can't. I just just use the pulse count through the serial monitor to tell that the count is changing even when the system is standing still thereby causing the whole setup to start moving.

What value do you suggest?

From the page posted:

Output Type NPN Voltage, NPN Open collector, Push pull, Line driver

Which output type does your encoder have?

It appears that you are updating the target every loop but it changes once per hour.

What if you try this:

I noticed the part number in your link in post#1 doesn’t correspond with the number at the Alibaba page it refers to. Alibaba, as are many other sellers, is not always accurate in describing the article you will receive.

So: double check the part number. Alibaba does provide a breakdown of the part number, lower in the page.

As the board is not mentioned, I assume UNO R3. A 12V supply is mentioned, I assume the barrel jack is used. I also assume the grounds are properly connected (important).

If 12V supply is within the range, use the VIN pin as output. The UNO has a diode and a capacitor between these, effectively a rectifier, easily capable of delivering 80mA over the consumption of the board itself.

If it’s stray pulses picked up in a long cable, lowering the input impedance might help. Assuming open collector outputs, use 1k resistors from the 5V pin as pull-ups instead of the internal pull-ups (typically 35k). The next trick being capacitors to the ground, but be careful, too big capacitors may make you miss real pulses.

If the problem persists, more tailor made solutions must be thought up.

The line voltage? Not "constant" because it is a.c. (alternating current) - because the line voltage varies ?

In the place where I stay, the ac source is constantly changing between 211 to 230v, it's not stable.

I find that hard to believe. Most, if not all modern switch-mode power supplies are designed to give a stable output voltage when mains voltage varies between ~100volt and ~250volt. The encoder likely has it's own 5volt regulator built-in, which gives a second layer of regulation.

Interrupts are very sensitive and fast. What does your encoder wiring look like.
As others said, external 1k pull up resistors might be required, to complement the internal ones.
If the encoder is used in a noisy (RF) environment, then also add two 10n ceramic capacitors between interrupt pins and ground, close to the Arduino.
Leo..

What's being used in this regard is not known.
Further details may yet be revealed (after much onion peeling).

As suggested, i used the 1K resistors without a capacitor and it's working very fine. I want to specially thank all those who contributed, i deeply appreciate.

Your sensor might land on the edge between 2 states and jump between both. You also need to check for rising signals.

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