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
}
}
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
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.
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.
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.
(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.
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...
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.
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.
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.
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.