Rotary Encoder and Servo interference

I'm trying to build a system in which a rotary encoder and a servo work together connected to the same Arduino (Uno). Each component and code work well when connected on its own to the Arduino.
However, the encoder data becomes very unstable (wrong range and not consistent) when working alongside the servo.

I'm using the Simplified Example code on this page to read the encoder data
And the most basic servo sweep example to move the servo.
I also tried using the Adafruit TiCoServo Library as my guess is the core of the problem is within the interrupts.

What is the best approach to using servos and rotary encoders in the same system, running off the same Arduino?

Would something like a PCA9685 could help?

Here is my code:

//#include <Servo.h>
#include <Adafruit_TiCoServo.h>

// Servo config
Adafruit_TiCoServo myservo;  // create servo object to control a servo
int servoPin = 9;
int servoEncoderPin = A0;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor
int pos = 0;    // variable to store the servo position

// Encoder config
int val;
int encoder0PinA = 3;
int encoder0PinB = 4;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;

void setup() {
  Serial.begin (9600);
  
  // servo setup
  myservo.attach(servoPin);
  
  // encoder setup
  pinMode (encoder0PinA, INPUT);
  pinMode (encoder0PinB, INPUT);

}

void loop() {
  // sweep servo
  for (pos = 0; pos <= 100; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    sensorValue = analogRead(servoEncoderPin);
    get_encoder_value();
    // Serial.println(sensorValue);
    // Serial.print(" "); 
    Serial.println(encoder0Pos);
    delay(50);                       // waits 15ms for the servo to reach the position
  }
  // Serial.println("stop!");
  delay(1000);
  
  for (pos = 100; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    sensorValue = analogRead(servoEncoderPin);
    get_encoder_value();    
    // Serial.println(sensorValue);    
    // Serial.print(" "); 
    Serial.println(encoder0Pos);
    delay(50);                       // waits 15ms for the servo to reach the position
  }
  // Serial.println("stop!");  
  delay(1000);
  
}

void get_encoder_value(){

  n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      encoder0Pos--;
    } else {
      encoder0Pos++;
    }
  }
  encoder0PinALast = n;

}

Do you have any filtering on the rotary encoder pins?
Such as

Rotary encoder filter.JPG

Rotary encoder filter.JPG

no, will try adding!

Do you know the exact model of encoder you have and whether or not the output is open collector or one of the other available outputs? You may need pullups or pull downs on the outputs.

You can not read the encoder with digitalRead() polling techniques when you use delay() in your code inside the for loop which is moving the servo. You will not be able to follow the state of the changing pins during the delay().

You could consider interrupt techniques an encoder library like Encoder.h which is available through the library manager. You then accumulate the changing encoder counts in the background.

What is the best approach to using servos and rotary encoders in the same system, running off the same Arduino?

Why do you need an encoder with a Servo? Are you trying to set the target position of the servo with the encoder? Are you trying to control the movement with the encoder instead of the servo's internal positional feedback?

Do you need the encoder position before and after the move, or do you need the output while the servo is actually moving?

Please explain more about what you are trying to achieve.

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