Arduino UNO + PCA9685 + FEETECH FS5106R – Continuous Rotation Servo Issue

Setup:

I have connected a FEETECH FS5106R Continuous Rotation Servo to an Adafruit 16-Channel PWM/Servo Shield, which is mounted on an Arduino UNO R3. The servo is powered by an external 5V power supply.

Issue:

The servo rotates correctly using the Adafruit PWM Servo Driver Library, but when I try to stop it by sending 1500 μs PWM, it keeps making a buzzing noise and does not completely stop. It seems to be receiving a very small movement signal instead of fully stopping.

I bought the servo from AliExpress, and it does not have a potentiometer for manual adjustment of the neutral position.

I tested different STOP values (1480-1520 μs) to find the correct neutral position, but the buzzing remains.

Question:

  • How can I precisely stop the continuous rotation servo when using the PCA9685?
  • Is there a better way to fine-tune the neutral position?
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // Standard PCA9685 address

const uint8_t SERVO_CHANNEL = 0; // Channel where the servo is connected
const uint16_t STOP_PWM = 1500;  // Stopping the servo
const uint16_t FORWARD_PWM = 1700; // Rotation in one direction
const uint16_t BACKWARD_PWM = 1300; // Rotation in the opposite direction

void setup() {
    Serial.begin(9600);
    pwm.begin();
    pwm.setPWMFreq(50);  // 50 Hz is the standard for servos
    delay(10);
}

void loop() {
    Serial.println("Moving forward...");
    pwm.writeMicroseconds(SERVO_CHANNEL, FORWARD_PWM);
    delay(2000);

    Serial.println("Stopping...");
    pwm.writeMicroseconds(SERVO_CHANNEL, STOP_PWM);
    delay(1000);

    Serial.println("Moving backward...");
    pwm.writeMicroseconds(SERVO_CHANNEL, BACKWARD_PWM);
    delay(2000);

    Serial.println("Stopping...");
    pwm.writeMicroseconds(SERVO_CHANNEL, STOP_PWM);
    delay(1000);
}

I suspect this is normal for continuous rotation servos. Maybe some other kind of motor would have been a better choice, such as a DC motor with gearbox or a stepper motor. Tell the forum more about the application.

There might be better solutions, but since I currently only have these components available, I would like to find a solution using what I have. The deadline is approaching soon, so I need to resolve this as quickly as possible. Any help or suggestions would be greatly appreciated!

Here’s a YouTube video that demonstrates what I’m trying to achieve:

I have tested adjusting the neutral position using code, incrementing the PWM value by 1 μs at a time (from 1480 to 1520 μs), but the servo did not stop at any value. It kept moving continuously. Since my unit does not have a potentiometer for manual adjustment, or I am unable to find it, I cannot fine-tune it physically.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // Standard PCA9685 address

const uint8_t SERVO_CHANNEL = 0;
uint16_t testNeutral = 1480;  // Starting test value

void setup() {
    Serial.begin(9600);
    pwm.begin();
    pwm.setPWMFreq(50);  // 50 Hz is the standard for servos
    delay(10);
}

void loop() {
    Serial.print("Testing neutral value: ");
    Serial.println(testNeutral);

    pwm.writeMicroseconds(SERVO_CHANNEL, testNeutral);
    delay(3000); // Wait 3 seconds to see if the servo stops

    testNeutral += 1;  // Increase test value in steps of 1
    if (testNeutral > 1520) {
        testNeutral = 1480; // Restart the test range
    }
}

Will there be any load on the servo when it is at its stopped position ?

No, it only pushes the Pusher left or right.

Once the servo reaches the position at which you want it to stop can you stop sending a PWM signal to it ?

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // Standard PCA9685 address

const uint8_t SERVO_CHANNEL = 0;
const uint16_t STOP_PWM = 1500;   // Stopping the servo
const uint16_t FORWARD_PWM = 1700; // Moving forward
const uint16_t BACKWARD_PWM = 1300; // Moving backward

void setup() {
    Serial.begin(9600);
    pwm.begin();
    pwm.setPWMFreq(50);  // Standard servo frequency
    delay(10);
}

void loop() {
    Serial.println("Moving forward...");
    pwm.writeMicroseconds(SERVO_CHANNEL, FORWARD_PWM);
    delay(2000);

    Serial.println("Stopping with PWM...");
    pwm.writeMicroseconds(SERVO_CHANNEL, STOP_PWM); // Ensure it stops properly
    delay(500);

    Serial.println("Disabling PWM...");
    pwm.setPWM(SERVO_CHANNEL, 0, 0); // Stop sending PWM signal
    delay(1000);

    Serial.println("Moving backward...");
    pwm.writeMicroseconds(SERVO_CHANNEL, BACKWARD_PWM);
    delay(2000);

    Serial.println("Stopping with PWM...");
    pwm.writeMicroseconds(SERVO_CHANNEL, STOP_PWM); // Ensure it stops properly
    delay(500);

    Serial.println("Disabling PWM...");
    pwm.setPWM(SERVO_CHANNEL, 0, 0); // Stop sending PWM signal
    delay(1000);
}

Yes, it stops, but it continues rotating in the same direction.

It can't both be stopped and rotating so I don't understand what you are saying

I attached the code with comments; it should rotate for 2 seconds in one direction, then 2 seconds in the other direction, now without using the neutral position.

As I mentioned, it rotates 2 seconds CW, stops, and then continues CW again.

The purpose is to open and close the lock on a box.

It looks like it's okay now and works without the neutral position.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);  // Standard PCA9685 address

const uint8_t SERVO_CHANNEL = 0;
const uint16_t STOP_PWM = 1500;      // Stopping the servo
const uint16_t FORWARD_PWM = 1700;   // Moving forward
const uint16_t BACKWARD_PWM = 1300;  // Moving backward

void setup() {
  Serial.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(50);  // Standard servo frequency
  delay(10);
}

void loop() {
  Serial.println("Moving forward...");
  pwm.writeMicroseconds(SERVO_CHANNEL, FORWARD_PWM);
  delay(1000);

  Serial.println("Disabling PWM...");
  pwm.setPWM(SERVO_CHANNEL, 0, 0);  // Stop sending PWM signal
  delay(1000);

  Serial.println("Moving backward...");
  pwm.writeMicroseconds(SERVO_CHANNEL, BACKWARD_PWM);
  delay(1000);

  Serial.println("Disabling PWM...");
  pwm.setPWM(SERVO_CHANNEL, 0, 0);  // Stop sending PWM signal
  delay(1000);
}

I'm coming back here again because the code still doesn't work properly. After several openings and closings of the "lock", I notice a shift in the Pusher from its neutral position. How can I return the Pusher to the exact neutral position after opening the lock? I have no experience with Continuous Rotation Servos. The way I tried to solve it isn't good (even though I set a slightly longer delay when closing).

In the FS5106R servo motor specifications, it says the Neutral Position is 1500(±9)μs. I wasn't able to apply that successfully.

SERVO_CHANNEL = 0
STOP_PWM = 1500
FORWARD_PWM = 1700
BACKWARD_PWM = 1300

OPEN
pwm.writeMicroseconds(SERVO_CHANNEL, FORWARD_PWM)
delay(800)
"Disabling PWM"
pwm.setPWM(SERVO_CHANNEL, 0, 0)

CLOSE
pwm.writeMicroseconds(SERVO_CHANNEL, BACKWARD_PWM);
delay(817)
"Disabling PWM"
pwm.setPWM(SERVO_CHANNEL, 0, 0)

This is only pseudocode.

You can't unless there is feedback of its position or a physical barrier to make it stop at the right place

FS5106R.pdf (451.9 KB)

Isn’t there a risk that a physical barrier will break it if it keeps rotating?

Yes

There is a possible solution to that if you can measure the current drawn by the servo. This will rise dramatically when the servo stalls at its end position but there is still the danger of damage

Could you incorporate an end stop switch into the mechanism to detect the return to its home position ?

I don't think I'm skilled enough to be able to do that. But what about the neutral position mentioned in the specifications np= 1500(±9)μs? I thought I could still solve it somehow through code.

The Devil is in the detail

Note that the neutral position is ±9μs, not exactly 1500μs. You could try adjusting the neutral position in the code by using a different value for STOP_PWM but be prepared to be disappointed if it is still not consistent due to mechanical factors such as backlash/slop along with changes in voltage over time

I tried to handle it in code by waiting for it to stop, but without success. I tested with ±50 μs around the neutral value, but it didn’t work.

Consider adding a limit switch