Continuous 360 Servo and accurate movement rates

Hey everyone, I'm new here and have a question about servo control. I've done two Arduino projects (specifically with ICLEDs) and this is my first project with servos.

The Use Case
The goal is to create a linear actuator powered by a servo. Why? So I would be able to move the linear actuator to a specific point (height) based on how I drive the servo. Ex: run the servo for X ms to move the linear actuator Y mm.

I have opted for a continuous servo to allow for maximum length of the linear actuator rod, and a more compact design. A 180* servo would require additional gearing (piston-style design) to achieve the same linear travel for the rod. I have avoided the idea of a screw-based linear actuator to achieve speed of linear movement.

In theory, I should be able to run the continuous servo in one direction at full speed for X ms, and then run it at full speed in the opposite direction from X ms and have the linear actuator at the same height as when it started.

The final project requires these components to be as small as possible, and I need many of them - that's why I've started with the micro servo's and 3D-printed linear actuators (the small pre-made linear actuators cost $80-100 each).

Parts

The Issue
I have coded the servo to run at different speeds in both directions without issue, the issue is with the consistency in the precision of the resting position of the linear actuator, powered by the servo.

When I run the servo for X ms in one direction, and then X ms in the opposite direction, the linear actuator does not always return to the same spot. Sometimes it is closer than others, and sometimes it is off quite a bit (5-15mm).

The project I am working on requires precision (1-2mm tolerances) for a linear actuator that can travel about 100mm

I don't think it's an issue with the 3D-printed components as things feel stable with no unwanted movement. I don't think it is my code, but perhaps I am missing some servo command or setting that affects precision? Perhaps I'm using a bad pin on the controller? Perhaps too much power (although I see people giving them 6v to achieve best performance)? Perhaps a poor servo? Perhaps the wrong type of servo? Or maybe I'm going about this the wrong way to achieve the desired outcome?

Hopefully I've provided all of the necessary information - but please let me know if I am missing anything.

Any ideas would be greatly appreciated!

Code

#include <Servo.h>

Servo servoA;

int currentHeight = 0;  // Global variable to store the current height

// Define your constants
const int MIN_HEIGHT = 0;
const int MAX_HEIGHT = 100;		// 100mm height
const int CLOSE_MAX = 1000;		// go to MIN_HEIGHT at full speedn
const int OPEN_MAX = 2000;      // go to MAX_HEIGHT at full speed
const int NEUTRAL = 1500;		// stop
const float MM_PER_SECOND = 89;  // 8.9mm/0.1s at full speed (1000 or 2000)

// clockwise is to open (180 deg, 2000 microseconds)
// counter-clockwise is to close (0 deg, 1000 microseconds)

int pos = 0;

void setup() {
  servoA.attach(D5);
  Serial.begin(9600);
}

void loop() {
  delay(2000);

  controlHeight(90);	// Set to 90mm
  delay(5000);

  controlHeight(20);	// Set to 20mm
  delay(5000);

  controlHeight(50);	// Set to 50mm
  delay(5000);

  controlHeight(0);	// Set to 0mm
  delay(5000);

}


void controlHeight(int desiredHeight) {
  
  Serial.println();
  Serial.print("Desired Height: ");
  Serial.print(desiredHeight);
  Serial.println();

  Serial.print("Current Height: ");
  Serial.print(currentHeight);
  Serial.println();

  // Calculate the delay based on the desired change in height and the speed
  int delayTime = abs(desiredHeight - currentHeight) / MM_PER_SECOND * 1000;
  
  Serial.print("Delay Calculated: ");
  Serial.print(delayTime);
  Serial.println();
  
  // Set the servo speed and direction
  if (desiredHeight > currentHeight) {
    servoA.writeMicroseconds(OPEN_MAX);
  } else if (desiredHeight < currentHeight) {
    servoA.writeMicroseconds(CLOSE_MAX);
  }

  // Wait for the linear actuator to move
  delay(delayTime);

  // Stop the servo by setting it to the neutral position
  servoA.writeMicroseconds(NEUTRAL);

  // Update the current height
  currentHeight = desiredHeight;
}

Wiring Diagram

Continuous servos are a poor choice for your project. As you have discovered, the speed cannot be accurately controlled.

Most people use stepper motors or brushed DC motors for linear actuators.

Steppers have the advantage that you don't need position feedback for extremely accurate position control, but they "forget" where they are when the power is cycled, and have to be reinitialized or "homed" at system startup.

This type of stepper linear actuator has a lead screw built into the stepper. You can salvage small versions of those out of old floppy disk drives, or CD or DVD ROMS.

With DC motor drive, you have the same problem, and also need shaft encoders to keep track of position.

Some commercial linear actuators include a linear feedback potentiometer, so you know the arm extension at all times.

1 Like

Thanks for the quick reply @jremington

I did some research into stepper motors as you mentioned and you are right - that appears to be what I am looking for - it's just a matter of finding one small enough for my project requirements.

I will see if I have any old CD/DVD ROM drives I can rip apart for a Proof Of Concept, otherwise I am looking at smaller stepper motors online for sub $20.

I'll leave this post up for the next person who might stumble upon this idea.

Thanks again

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