Controlling initial servo movement when calibrating PIR

I have rigged up an Arduino Nano with PIR and servo to turn the head of a plastic owl. The servo movement was way too fast at first, but I was able to slow it down in the code. But that very first servo movement (after plugging into power and after the approximately 30-second PIR initialization) the servo turns 90 degrees and back to center at a very fast speed. Is there a way to slow that initial servo movement down?

Here's my code:

//# include <ESP32Servo.h> // ESP32 Servo library
# include <Servo.h>
int pirPin = 2;//digital pin connected to the PIR's output
int pirPos = 10;   //connects to the PIR's 5V pin
int ledPin = 12;
int calibrationTime = 30;

Servo myservo; //creates a servo object

int pos = 90; //variable to store servo position

// -----------------------------------------------------------------------------
void setup (){
    myservo.attach (9);//attaches servo to pin 9
    Serial.begin (9600);//begins serial communication
    pinMode (pirPin, INPUT);
    pinMode (pirPos, OUTPUT);
    pinMode (ledPin, OUTPUT); // LED light
    digitalWrite (pirPos, HIGH);
    digitalWrite (ledPin, HIGH); //***

    //give the sensor time to calibrate
    Serial.println ("calibrating sensor ");
    for (int i = 0; i < calibrationTime; i++){
        Serial.print (calibrationTime - i);
        Serial.print ("-");
        delay (800); // gives time for PIR to settle down before reading
    }
    // digitalWrite (ledPin, LOW); //prevents initial whiplash servo movement - DELETE this
    Serial.println ();
    Serial.println ("done");

    while (digitalRead(pirPin) == HIGH) {
        delay (500);
        Serial.print (".");
    }
    Serial.print ("SENSOR ACTIVE");
}

// -----------------------------------------------------------------------------
bool
move (
    int           target,
    unsigned long dly )
{
    static int pos;

    if ((target - pos) > 0)
        myservo.write (++pos);
    else if ((target - pos) < 0)
        myservo.write (--pos);
    delay (dly);

    return target == pos;
}

// -----------------------------------------------------------------------------
unsigned long dly;

void loop ()
{
    if (HIGH == digitalRead(pirPin))  {     // active 
        digitalWrite (ledPin, HIGH);        // on
        if (move (pos, dly))  {             // new pos/dly once reached
            delay(1000);                // waits for a second //***
            pos = random (180); //random position from 0-180
            Serial.println (pos);
            dly = 25; //was //random (12, 40); // more realistic to have one speed
        }
    }
    else  {
        digitalWrite (ledPin, LOW);     // low
        delay(100);
        move (90, 0); // return to center position
    }
}

You have two different variables named pos in your sketch, each with their own scope and value

As a start I suggest that you rename one or both of them so it is clear which one is being referred to in each part of your code

As an aside, if you want the servo to start in any position other than 90 then write that value to the servo before attach()ing it

Sorry, I have avoided using RC servos for a long time, so I am a bit rusty with them.

I used to run into this issue, with them, as the servos will try to jump to whatever your first
position is, often assuming centered with something lime 1500us.

Most of these servos do not provide any mechanism to retrieve their current positions. There are some digital servos that do have some form of proprietary mechanism for this, but that is not the norm. This is one of the reasons I went to using other servos, mostly dynamixel servos by Robotis...

But back when I used them. We tried to always have some known home position that we made sure we positioned the robots in that position before. There was usually also a command (which may be a button on the remote), that we would press to put the robot into that position before we turned it off. Positions like: Lynxmotion Phoenix

With an Arm like:
image
We would have the arm rotated to be centered on the board, and the arm sort of pushed back where the two U brackets are as close to horizontal as they go with arm more or less resting as far down as it goes.

Then figure out what those positions are, and use those as the initial positions to tell the servos at start up time.

With smarter servos, the code typically does a query of their current positions, without the
torque turned on. It then tells it to move slowly to the desired starting point.

Good luck

The variable pos is initially declared to be an integer with value of 90. But later in the sketch it becomes a random number between 0 and 180. I'm not seeing where there are two variables with the same name. Can you help me figure this out?

Regarding home position, I want the servo to go to position 90 after the PIR is triggered, so that the owl head is always facing straight ahead. I believe I have accomplished that with this sketch.

Which of the two different pos variables do you mean ?

int pos = 90;  //variable to store servo position

or

    static int pos;

I changed pos to new pos in the function so that it reads:

bool
move (
    int           target,
    unsigned long dly )
{
    static int newpos;

    if ((target - newpos) > 0)
        myservo.write (++newpos);
    else if ((target - newpos) < 0)
        myservo.write (--newpos);
    delay (dly);

    return target == newpos;

But apparently there's no way to override that initial sweep after first initialization?

If you don't want the servo to "jerk" to the default 90° position at startup, save the current position at shutdown in EEPROM and restore that position before attach on next startup.

https://docs.arduino.cc/learn/built-in-libraries/eeprom/

(Most of these servos do not provide any mechanism to retrieve their current position)

Yes they do, that is how they operate.
An internal pot generates a pulse, that pulse is compared to the incoming pulse and drives the servo gear motor appropriately.

The important word is in bold

???....meaning just what exactly?

Meaning as I said earlier: Most of these servos do not provide any mechanism to retrieve their current position.

The servos themself may know where they are at and what the new position that has
been requested. But most have no mechanism to allow them to communicate this
to a host.

As I mentioned, Some RC servos have setup their own way to do so.
For example: BasicMicro (was known for part of the time as Orion Robotics) had
their own servos similar to the Hitec servo with their own controller board inside the
servo. If the host sent it a specific short pulse, and then switched their IO pin to input,
the servo would return a pulse that informed the host its current position. I know some
other digital RC servos dis something similar.

But without that, the host never knows the true position of the servo. Most code simply assumes that the servo is at the last position requested. But if for example there is an obstruction, the servo might not make it there...

Other servos, like I mentioned Dynamixels or Lynxmotion new servos or ... often use a
different communication, typically some form of serial, and they usually includes commands to the servos to retrieve information from the servos, such as their position, speed, temperature, etc. Likewise several of these servos have additional smarts, like you can tell them to go from their current position, to a new position and get there in some specific time frame, or at some specific speed. Also you can restrict the torque level...

They don't communicate their position because they do not have to.

A certain signal is sent out and as long as the servo runs to that same pulse position, job done.

The Op is trying to get a servo to a certain position at startup and I believe the answer was given way back in the first couple of replies.

My trick is to only attach the servo right before it's going to be used and then detach it when the movement is done. Rinse and repeat in some function you call at the appropriate time. Plus, it saves wear and tear on the servo.

The downside is that as soon as you detach, the thing attached to the servo horn goes limp. Since you're using a rotating owl head (Hallowe'en? Gnarly...), it shouldn't be a problem.

For those about to Haunt,
I salute you! :saluting_face:

Servos have an internal pot and unless suitably modified you cannot read a value from it and hence determine the current servo position

The Op is trying to get a servo to a certain position at startup and I believe the answer was given way back in the first couple of replies.

If the answer is saving servo position to EEPROM, that's probably beyond my level of understanding. Or at least too much work for something that isn't really a big deal.

Basically when I power up the Arduino, the servo goes through an initialization and then does a fast twitch or two before settling down to LOW state. And from that point on it works perfectly. And after moving to various random positions, the servo returns to the 90 position.

This is actually the second owl I've made. Strangely, the first one doesn't do the initial powerup twitch. Unfortunately, I've been tweaking the code for this second owl and not sure which sketch is currently loaded on that first owl. Otherwise the two owl projects are very nearly identical. The first owl uses an Arduino Nano ESP32 and the second uses an Arduino Nano (not the ESP32), so I had to make a couple of adjustments in the code (mainly to change the servo library because the ESP32 requires a different library. But the servos are the same model (Micro servo - TowerPro SG92R). So not sure how I got the first servo to stop the powerup switch unless it has something to do with the Arduino boards.

Does anyone want to see video of my owl?

Maybe investigate servo.detach()?

Some servos might sleep without a signal, and if yours is one, you might be able to play tricks with attach/detach to have a softer start. Or if you can switch the power to the servo on and off, you could use that to slow the movement.

Sure! Would be fun to see.

The other approach is sort of a manual process. That is manually align the owl such that it is in its initial position, before you turn it on.

Here's the owl. Most of the electronics are actually inside its hollow body. I'm still playing around with the speed of the servo, but slow is much better than fast.