Servo Sweep between 2 bounds

I have a simple servo HS-322HD
I am having this rotate an object. What I want to do is be able to rotate at random from one place to another with a random delay, between the 2 max bounds. Basically, picture a skull rotating right a left at a neck joint. I never want it to go past the angles below as it doesn’t look right to turn the head 180 deg, plus I have physical clearance issues. (still playing with the angles to see what clears correctly)

I want that to turn as smooth as possible (slow is good) so if there is a better way to create micro stepping, please let me know. I don’t care very much for torque as it’s just a tabletop “toy”. Want it to just sit on my desk rotate left and right randomly all day.

Here is what I am mocking up in code, and it’s turning passed the limits and not very well either.
90deg is my center positioning.

I am using an old Duemilanove I hade laying around for a few years.

#include <Servo.h>

Servo myNeck;  
//Neck limits
int maxRight = 70; //45
int maxLeft = 110; //135

int angleIncrement = 1;
int incrementDelay = 15;

// delay limits
int minDelay =10000; //1 min = 60000
int maxDelay =100000; //30 min = 1800000

void setup() {
  myNeck.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  int posNew = random(maxRight,maxLeft);
    for (int pos = maxLeft; pos <= maxLeft; posNew += angleIncrement) {
    myNeck.write(posNew);
    delay(incrementDelay);
  }
  
  delay(random(minDelay, maxDelay));
  
  for (int pos = maxLeft; pos >= maxRight; posNew -= angleIncrement) {
    myNeck.write(posNew);
    delay(incrementDelay);
  }
}

Thanks a bunch!

This isn’t going to work

for (int pos = maxLeft; pos <= maxLeft; posNew += angleIncrement) {

because you are not upating pos so it will never be equal to maxleft.
Just do an ordinary FOR that goes through a number of steps and increment the position within the loop

for (byte step = 0; step < numSteps; step ++) {
    newPos += angleIncrement;
    myNeck.write(posNew);
    delay(incrementDelay);
}

…R

Slow and smooth?

Use Servo.writeMicroseconds() instead of Servo.write() This gives you about 1000 steps in the range of movement instead of 180. Servo.write() simply maps the degrees into a number of microseconds and calls Servo.writeMicroseconds()

The following 3 pairs are (roughly) equivalent: Servo.writeMicroseconds(1000) and Servo.write(0) Servo.writeMicroseconds(1500) and Servo.write(90) Servo.writeMicroseconds(2000) and Servo.write(180)

Robin2:
This isn’t going to work

for (int pos = maxLeft; pos <= maxLeft; posNew += angleIncrement) {

because you are not upating pos so it will never be equal to maxleft.
Just do an ordinary FOR that goes through a number of steps and increment the position within the loop

for (byte step = 0; step < numSteps; step ++) {

newPos += angleIncrement;
   myNeck.write(posNew);
   delay(incrementDelay);
}




...R

Thanks for a quick reply.

When I do a typical for loop like you have above I am always passed the limits I need to be. It’s 0-180 situation unless I am not understanding this correctly.

3DWarrior: Thanks for a quick reply.

When I do a typical for loop like you have above I am always passed the limits I need to be.

Then you need an explicit check for the limits. Something like

if (newPos > maxPos) {
  newPos = maxPos;
}

...R

Your linked page said: Max Travel (out of box) 201°

On same page check the range of the PWM. And use Servo.writeMicroseconds() instead of Servo.write(), as vinceherman pointed out. Not because better accuracy, but because your servo doesn't understand the degrees at all! The servo lib assumes max travel 180° instead of 201°.

The servo.write 0 to 180 "angle" is really confusing. Given the actual microsecond values it writes (540 - 2400) it just means turn the maximum amount the servo can turn. Since for different servos that maximum could be anywhere from 90 degrees to about 270 (or even 6 full turns for a winch servo) it ALWAYS needs to be calibrated for the actual servo you're using.

BTW have a look at the VarSpeedServo library https://github.com/netlabtoolkit/VarSpeedServo You don't need to mess about with sweeping the servo and controlling the sweep time yourself. Just tell it in the write() how far you want it to move and how fast (or slow). The library does it for you. I always use it for animating skeletons (o.k. I've only done two so far but that's what I used).

Steve

Awesome!

Thank you so much for the guidance and pointing towards some new material to learn. (All thou I must say everything is new at this point)

Ended up using the slipstick’s method with a VarSpeedServo library.

Here is what I have in case someone else needs this working, and it works well for what I needed.

#include <VarSpeedServo.h> 
 
VarSpeedServo myNeck;  
const int servoPin = 9; // attaches the servo on pin 9 to the servo object

//Neck limits
int maxRight = 70; //45
int maxLeft = 110; //135
int turnSpeed = 10;
int posNew = 90; 

// delay limits
int minDelay =1000; //1 min = 60000
int maxDelay =10000; //30 min = 1800000
 
void setup() { 
  myNeck.attach(servoPin);  // attaches the servo on pin 9 to the servo object
} 

void loop() {
  posNew = random(maxRight,maxLeft);
  myNeck.write(posNew,turnSpeed,true);
  delay(random(minDelay, maxDelay));
}