Trouble getting a servo to move when a second servo is at a given position

Hi,

This is the first time posting so I hope I do everything correct.

I have two servos. I need one servo to start moving but the second servo doesn't start until the first servo is at 90. Both servos should then be doing sweeps. I just can't think of how to do it. Have posted the code but there is something I just can't figure out to get it running.

#include <Servo.h>


Servo servo1;  // create servo object to control a servo
Servo servo2;  // create servo object to control a servo

int servo1Position = 0;     // the current angle of the servo - starting at 0.
int servo1Interval = 80; // millisecs between servo moves
int servo2Position = 0;
int servo2Interval = 20;
int servo1Degrees = 1;       // amount servo moves at each step
int servo2Degrees = 1;       //    will be changed to negative value for movement in the other direction

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousServoMillis = 0; // the time when the servo was last moved

void setup() {

  servo1.write(servo1Position); // sets the initial position
  servo1.attach(8);
  servo2.write(servo2Position); // sets the initial position
  servo2.attach(9);

  Serial.begin(9600);
}

void loop () {
  currentMillis = millis();//   this is equivalent to noting the time from a clock
  
  servoSweep();
 
  Serial.println(servo1Position);  
  Serial.println(servo2Position);
  }

void servoSweep() {

     // this is similar to the servo sweep example except that it uses millis() rather than delay()

     // nothing happens unless the interval has expired
     // the value of currentMillis was set in loop()
 
 if (currentMillis - previousServoMillis >= servo1Interval) {
       // its time for another move
   previousServoMillis += servo1Interval;
   
   servo1Position = servo1Position + servo1Degrees; // servoDegrees might be negative

    
  if ((servo1Position >= 180) || (servo1Position <= 0))  {
         // if the servo is at either extreme change the sign of the degrees to make it move the other way
     servo1Degrees = - servo1Degrees; // reverse direction
         // and update the position to ensure it is within range
     servo1Position = servo1Position + servo1Degrees;
   }
    {
   servo1.write(servo1Position);
       // and record the time when the move happened
    }
 
 // make the servo move to the next position
 if (servo1Position >= 90){
        servo2Position = servo2Position + servo2Degrees;  
 servo2.write(servo2Position);
 
 }

if (currentMillis - previousServoMillis >= servo2Interval) {
       // its time for another move
   previousServoMillis += servo2Interval; }

 if ((servo2Position >= 180) || (servo2Position <= 0))  {
         // if the servo is at either extreme change the sign of the degrees to make it move the other way
     servo2Degrees = - servo2Degrees; // reverse direction
         // and update the position to ensure it is within range
   
   }
 }
  }

What does this do for you?

if (currentMillis - previousServoMillis >= servo2Interval)
{
// its time for another move
previousServoMillis += servo2Interval;
}

Suggest you place { and } on separate lines.

Format your sketches with CTRL T

larryd:
What does this do for you?

if (currentMillis - previousServoMillis >= servo2Interval)
{
// its time for another move
previousServoMillis += servo2Interval;
}

Suggest you place { and } on separate lines.

It should a) determine if the time interval time interval between servo2 moves has been clocked and if so, b) update the time.

Re brackets on seperate lines, does that make a difference to the code or is it more for ease of reading the code?

Thanks

Braces on separate lines make things line up so you can easily see what’s being done.

CTRL T Formats your code.

if (currentMillis - previousServoMillis >= servo2Interval)
{
// its time for another move
previousServoMillis += servo2Interval;
}

The above, as it stands, does ‘nothing’ for you.

if (currentMillis - previousServoMillis >= servo2Interval)
{
// its time for another move
previousServoMillis += servo2Interval;

// put stuff here that you want to do every ‘servo2Interval’ ms. <———<<<<

}

Thanks for the CTRL T tip . I did not know that.

I see what you mean with the coding. Have changed it so now have both servos running simultaneously at different speeds but am still stumped as to how to get servo 2 to start its first sweep when servo 1 is at 90 degree. Any ideas appreciated.

#include <Servo.h>


Servo servo1;  // create servo object to control a servo
Servo servo2;  // create servo object to control a servo

int servo1Position = 20;     // the current angle of the servo - starting at 0.
int servo1Interval = 20; // millisecs between servo moves
int servo2Position = 20;
int servo2Interval = 200;
int servo1Degrees = 1;       // amount servo moves at each step
int servo2Degrees = 1;       //    will be changed to negative value for movement in the other direction

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousServo1Millis = 0;
unsigned long previousServo2Millis = 0;// the time when the servo was last moved

void setup() {

  servo1.write(servo1Position); // sets the initial position
  servo1.attach(8);
  servo2.write(servo2Position); // sets the initial position
  servo2.attach(9);

  Serial.begin(9600);
}

void loop () {
  currentMillis = millis();//   this is equivalent to noting the time from a clock

  servo1Sweep();
  servo2Sweep();

  Serial.println(servo1Position);
  Serial.println(servo2Position);
}

void servo1Sweep()
{

  // this is similar to the servo sweep example except that it uses millis() rather than delay()

  // nothing happens unless the interval has expired
  // the value of currentMillis was set in loop()

  if (currentMillis - previousServo1Millis >= servo1Interval) {
    // its time for another move
    previousServo1Millis += servo1Interval;

    servo1Position = servo1Position + servo1Degrees; // servoDegrees might be negative


    if ((servo1Position >= 150) || (servo1Position <= 20))  {
      // if the servo is at either extreme change the sign of the degrees to make it move the other way
      servo1Degrees = - servo1Degrees; // reverse direction
      // and update the position to ensure it is within range
      servo1Position = servo1Position + servo1Degrees;
    }
    {
      servo1.write(servo1Position);
      // and record the time when the move happened
    }
  }
}

// make the servo move to the next position

void servo2Sweep()
{
  if (currentMillis - previousServo2Millis >= servo2Interval)
  {
    // its time for another move
    previousServo2Millis += servo2Interval;
    servo2Position = servo2Position + servo2Degrees;
  }


  if ((servo2Position >= 150) || (servo2Position <= 20))  {
    // if the servo is at either extreme change the sign of the degrees to make it move the other way
    servo2Degrees = - servo2Degrees; // reverse direction
    // and update the position to ensure it is within range
    servo2Position = servo2Position + servo2Degrees;
  }
  {
    servo2.write(servo2Position);
  }
}

You may need two timers.
unsigned long previousServoMillis_1 = 0;
unsigned long previousServoMillis_2 = 0;

When the first servo is at 90° set an ‘enableFlag’ to true, if you need the 2nd timer, make previousServoMillis_2 = millis()

When the enableFlag = true, you check to see if the second timer has expired, and/or you just do your stuff.

At some point you make enabledFlag = false, you decide.

I agree with a flag. And if I've got this right then I think it covers what you want.

int sweepDegrees = 270; // change this to desired sweep range of degrees
int servo2Offset = -90; // set servo 2 offset in degrees

const int sweepFactor = sweepDegrees / 180;

bool released = false;
/* 
Start at 179 because first loop will increment.
It's + 1 - 180, so 179 means start at 0 degrees.
*/
int sweep1 = 179; 
int sweep2;
  
loop () {
  sweep1 = (sweep1 + 1) % 360;
  sweep2 = (sweep1 + 360 + servo2Offset * sweepFactor) % 360;
  // sweep3 = (sweep1 + 360 + servo3Offset * sweepFactor) % 360; // etc

  int angle1 = abs(sweep1 - 180) * sweepFactor;  
  // move servo 1

  if(angle1 - servo2Offset >= 0) released = true; // some condition to release servo 2

  if(released) {  
    int angle2 = abs(sweep2 - 180) * sweepFactor;
    // move servo 2
  }
}

Can you not just start servo1 at 90?

int servo1Position = 90;     // the current angle of the servo - starting at 90.

If not, another option would be to do the first 90 degrees of servo1 sweep in setup():

  for ( ; servo1Position <= 90; servo1Position++)
  {
    servo1.write(servo1Position);
    delay(servo1Interval);
  }

You will also need separate timers for the two sweeps.

johnwasser:
Can you not just start servo1 at 90?

int servo1Position = 90;     // the current angle of the servo - starting at 90.

If not, another option would be to do the first 90 degrees of servo1 sweep in setup():

  for ( ; servo1Position <= 90; servo1Position++)

{
    servo1.write(servo1Position);
    delay(servo1Interval);
  }




You will also need separate timers for the two sweeps.

No. The situation is the servos operate fingers in a hand. I imagine the hand is resting on the table, finger tips down, and you start drumming your fingers on the table. You don't start with fingers raised. Yes, I wish I could have just offset the start position, it would have been an easy fix.

Assuming you’re using ‘standard’ RC servos...

Sadly, the Arduino has no idea where each servo is while it’s in motion, unless you make incremental small angular steps in your code.
Then - you know when the servo has been told to go to 91-degrees, and can start servo #2

A more sophisticated approach would be to bring the feedback loop out of the RC servo, either with wires to an analog input, or a completely separate ‘servo’ using a separate DC servo’-motor and encoder - which provides you with complete control & positioning in real-time.

Thanks for all the replies. There's some new commands I've not used before so will sepnd some time over the next few days wrapping myhead around it.
And yes, they are RC servos.

And yes, they are RC servos.

And how are they powered? It is generally not acceptable to run two servos off the Arduino’s 5V output, you need an external power supply and good decoupling circuits between each motor.

lastchancename:
A more sophisticated approach would be to bring the feedback loop out of the RC servo

... like these ones from adafruit.

Hadn't seen those off the shelf - niiice!!!

lastchancename:
Hadn't seen those off the shelf - niiice!!!

There's not only the adafruit ones: OP here says this one has feedback although I only see 3 wires in the photo and in the mechanical drawing. Maybe there's a "special".

Grumpy_Mike:
And how are they powered? It is generally not acceptable to run two servos off the Arduino’s 5V output, you need an external power supply and good decoupling circuits between each motor.

The projects are school based. When trialling coding we use up to 5 servo's on 1 arduino with no load however when hooked up to the fingers (loaded) we use separate power supplies that we purchased as our normal laboratory power supplies are rectified but not smoothed so caused havoc. I have not come across the concept of decoupling circuits but upon reading up on the topic they make a lot of sense so will bear them in mind for future work. Thanks

The projects are school based.

Oh well that changes the laws of Physics doesn't it. :slight_smile: Even with no load on start up each servo could take up to 1A. This is called the stall current.

I have not come across the concept of decoupling circuits but upon reading up on the topic they make a lot of sense

See the last circuit of:-http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html
That is what I always use on each servo.