timing a movement for a watch winder

Hello everyone,

I'm not sure this is the right section to post this question to, but the other ones seemed rather irrelevant. I'm making a watch winder for a friend of mine using arduino.
I use a Tower Pro servo which I modified for continuous movement by removing the mechanical stop and soldering the potentiometer in 90 degree position. Although it's a little underpowered for this application it seems adequate.

It might seem a little silly but I'm new to embedded electronics but here is the problem;

I need the servo to run for a set period of time after the arduino is connected to the power, then stop, then run again in a loop without user input. Since the pot is fixed I cannot measure turns it has made and use a "for loop" to count the turns to find out roughly the time the servo needs to pause. The run-stop structure is as follows: 10 * (run 30 min stop 15 min) then stop for 990 minutes. (thus having a 24 hour cycle)

I use servo library to run the servo but don't know how to stop it and restart it automatically...

Any ideas?

void loop()
{
for (int i=0; i<10; i++)
{
startMotion();
delay(30L60L1000L); // 30 seconds
stopMotion();
delay(15L60L1000L); // 15 seconds
}
delay(990L60L1000L); // 990 seconds
}

Thanks for the reply but since the servo never reaches the position (since it's pot is fixed) when I write delays in between it is forever stuck on the first movement... Is there a command to execute a function for a set period of time?

The code I wrote is as follows;

{
for (int i=0; i<10; i++)
{

myservo.write(100);
delay(30L60L1000L); // 30 seconds
myservo.write(92); //this is the position in which the servo stops
delay(15L60L1000L); // 15 seconds
}
delay(990L60L1000L); // 990 seconds
}

Maybe I didn't get something?

30L * 60L * 1000L = 30 minutes * 60 seconds per minute * 1000 milliseconds per second.

Seems like your error is there xD.

Well as I have said before the program never gets to the delay part... No matter how long or short the delay maybe writing a position to the servo means it will turn indefinitely since the encoder is not working any more due to the modifications made on the servo. Is there a way to control the servo with another code perhaps? Like digitalwrite? I know that I need to send a pulsating signal to tell the servo to do something but don't know how to send it in any other way then using the servo library.

OR; tell the servo to try to write a position for sometime - stop - continue...

You really need to post all of your code. We have no idea what the rest of the code is doing from the snippets you've posted.

The servos should be started moving using the Servo::writeMicroseconds() method.

There are interactions between the Servo library and PWM on certain pins, depending on which board you have. The PWM pins you are using, if any, are in the code you haven't posted.

Interrupt usage can cause the delay() function to not work. Are you using interrupts? We can't tell, since you haven't posted all of your code.

Well as I have said before the program never gets to the delay part.

How do you KNOW that the program hasn't gotten to the DoNothingPeriod() function (aka delay())?

#include <Servo.h>

Servo myservo;

int pos = 0;

void setup()
{
myservo.attach(9);
}

void loop()
{
for (int i=0; i<10; i++)
{

myservo.write(100);
delay(30L60L1000L); // 30 seconds
myservo.write(92); //this is the position in which the servo stops
delay(15L60L1000L); // 15 seconds
}
delay(990L60L1000L); // 990 seconds
}

this is the whole code... The board is an Arduino Uno, + to 5V Gnd to Gnd and the signal pin goes to digital 9.

I don't "know" that it doesn't get to that part it's just common sense but it may be wrong...

From what I gather I need to be able to send the signal for a set period of time then stop. With the servowrite() function it tries to set the servo to a certain position without any success.

I use a Tower Pro servo which I modified for continuous movement by removing the mechanical stop and soldering the potentiometer in 90 degree position. Although it's a little underpowered for this application it seems adequate.

The thing you have now is not a servo. Please stop referring to it as such. What you now have is a variable speed, bi-directional electric motor.

You can make a servo move to a specific position, and stop, using the Servo::write() function. You can NOT make a variable speed, bi-directional electric motor move to a specific position, and stop, using ANY Servo function. You CAN make the servo move in one direction, or the other, or stop, by using Servo::writeMicroseconds() with the appropriate value as the argument. Typically, values less than 1500 move the no-longer-a-servo one way, and values greater than 1500 move it the other way, while 1500 causes it to stop. The exact value where it stops needs to be determined experimentally. The range of values that cause movement, and the speed of that movement, also needs to be determined experimentally.

OK, I know that it is no longer a servo but the common way of referring to bi-directional, variable speed motors that are made from servos is 'continuous rotation servo' so I used the incorrect term...

Using the servo library alone I now know that it is impossible to stop the motor once the command to move it is given. However is there a library for timing events which can be used for this purpose. Pseudocode example below:

#the time is defined as the time since the program started to run, the unit is hours

if (12.00<time <13.00)
{
write servo(500);
}
else
{
stop the once-a-servo and return to the beginning of the scope
}

Seems to be some confusion between seconds and minutes, but this should help accelerate testing:

#include <Servo.h> 
 
Servo myservo;  

//#define DEBUG   // uncomment this line to run the sketch at 10x speed.

#ifdef DEBUG
  #define ONE_SECOND (100L)
#else
  #define ONE_SECOND (1000L)
#endif

#define ONE_MINUTE (ONE_SECOND * 60L)
#define ONE_HOUR   (ONE_MINUTE * 60L)
 
void setup() 
{ 
  myservo.attach(9);
} 
 
 
void loop() 
{ 
   for (int i=0; i<10; i++) {
     myservo.write(100); 
     delay(30L * ONE_MINUTE);
     myservo.write(92); 
     delay(15L * ONE_MINUTE);
   }
   delay(990L * ONE_MINUTE);
}

Thank you good sir,

I don't have the Arduino with me right now but I'll try as soon as I get home. Still I don't think this will work but it takes a minute to test, my guess is it will try to write the position indefinitely. The problem I suppose is that I'm trying to use a servo library to control something that no longer has the most important feature of a servo (namely, the ability to know it's motor position). But there doesn't seem to be a library for these modified once-a-servos (or OAS, if you will) and obviously a dc motor control code won't work since the thing that tells a servo to move is the pulsating signal that is transmitted through the Orange/White cable.

With an external sensor I would be able to stop the motor like

if (photocell receives light)
{
write servo (130)
}
else
{
stop
}

But since it needs to be tied to time and not an external sensor the problem still exists. Well... it might not and I might have been confused about the time, in that case thanks for the advice and code.

BTW if I can get this to work I will use this example to make picture drawing robots.

Using the servo library alone I now know that it is impossible to stop the motor once the command to move it is given.

This is not at all correct. By calling Servo::writeMicroseconds() with the correct value, the no-longer-a-servo will stop.

Please stop trying to use Servo.write(). That method is used ONLY for servos, which you do NOT have.

OP, please clarify: What is your issue?

myservo.write(100); <-- this code on a modified servo will set it to rotate in one direction relatively slowly.
myservo.write(180); <-- this code will set it to rotate in the same direction faster
myservo.write(92); <-- this code will stop the rotation (exact value needs to be tested empirically, but it should be near 90)

Your issue is one of these two (I can't tell which from your posts):

a) Modified Servo starts moving, doesn't stop
Reason: You aren't waiting for half an hour, which is how long the first delay is in code. It won't stop until you tell it to with myservo.write(92)
b) Modified Servo doesn't start moving
Reason: You have power supply issues, or your modified servo is broken.

General statements: You NO LONGER have ANY position feedback on your servo, unless you get around to ADDING an encoder or infinite-turn potentiometer to the output shaft. The ONLY WAY to control position in your case is to guesstimate the amount of time it takes to travel theta degrees at a set speed, then wait that long and hope the servo's in the right place.

electricBunny:
Using the servo library alone I now know that it is impossible to stop the motor once the command to move it is given.

This is false. Where did you get that from? Setting the desired 'angle' back to wherever the servo's internal potentiometer is glued will stop the motor.

electricBunny:
However is there a library for timing events which can be used for this purpose. Pseudocode example below:
#the time is defined as the time since the program started to run, the unit is hours

if (12.00<time <13.00)
{
write servo(500);
}
else
{
stop the once-a-servo and return to the beginning of the scope
}

This is going to tell the servo to move at maximum speed (500 is more than the servo's write command will take) in one direction, for an hour. I'm not sure what you're trying to get at here - running it in one direction for x hours is not going to give you position control.

On a modified servo, the |setAngle - centerPoint| is approximately proportional to the speed that the motor will move at. If setAngle < centerPoint, it will turn one way, and if setAngle > centerPoint, it will turn the other. If setAngle == centerPoint, it will stop. It WILL try to write the position indefinitely - but since it can't actually get there, it will simply keep rotating.

There isn't a point to make another library for these modified servos - the commands are the same and the signals are the same. The only difference is what the output of the servo will be.

If you have problems stopping an ex-servo (I've found they sometimes drift), you could try a detach, but two things to be aware of:

  1. There will be no holding torque, except for that due the gearing
  2. you'll need to attach it again before moving.
#include <Servo.h> 
 
Servo myservo;  
 
int pos = 0;   
 
void setup() 
{ 
} 
 
 
void loop() 
{ 
   for (int i=0; i<10; i++)
        {
       
        myservo.write(100);    // Pre-set the motor speed
        myservo.attach(9);     // Attach the servo to start the motor spinning
        delay(30L*60L*1000L);  // Wait 30 minutes
        myservo.write(92);    //  Set the motor speed to zero (between forward and backward)
        myservo.detach();     // Stop sending pulses to the servo
        delay(15L*60L*1000L);  // Wait for 15 minutes before running again
        }
   delay(990L*60L*1000L);  // Wait for 990 minutes
}

Thanks everyone, I think I got what I needed the last code seemes to be a very elegant solution. I still cannot try the code for external reasons but it will most likely work as intended with that last code John Wasser has posted.

Case is very likely to be closed...

Another choice is to remove the electronics from the "continuous rotation servo" and connect a small H-bridge directly to the motor. This will reduce the "servo" to acting as a DC gearmotor. You will have better control of the speed and be assured that it will come to a full stop. You could also add an optical sensor for a "home" position and use that to stop the rotation at a known position.