Pages: 1 [2]   Go Down
Author Topic: Increasing two different servo PWM's with different delay's  (Read 1774 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Within one continous loop

every 60 seconds - increase servoA pwm by 4
every 120 seconds - increase servoB pwm by 3
I'm really curious why you want the motor to run faster and faster, instead of a constant speed. Every clock I own has a motor that runs at a constant speed. I can't help but think I am missing something.

Hi, Increasing the PWM is not increasing the speed, it is increasing the position of the motor around the 360 degrees, for example: on the minute hand
1600pwm is midnight 1604 is one minute past 1608- two minutes past and so on.  So adding 4 to the microseconds every minute is moving the servo by one minute on the clock, every minute.

The need for a different speed on the hour hand is due to it having to only cover 1/12th of the 360 degrees in an hour.  My maths above for the hour hand were wrong however.  It is actually 3 increments every 6 minutes, not every two.

The clock is for a theatre show where there are 6 scene changes in the show. At each scene change the stage crew press a button and the time zips to the next scene time then starts ticking away until the next button is pressed, moving it on to the next scene.

I will post the full code on a seperate post for anyone who is interested. It is not perfect and probably a little messy (I still class myself as a complete newbie to all this)  It works very well at the moment and keeps proper time to within a minute which is fine for my purposes.

« Last Edit: July 12, 2012, 04:44:38 am by flotilla » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Hi, Increasing the PWM is not increasing the speed, it is increasing the position of the motor around the 360 degrees
My apologies. For some reason, I had it in my head that you were using continuous rotation servos.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My full code for community purposes and anyone who is interested.  Be gentle! I know there are probably easier ways to do this.

Code:

#include <Servo.h>
#include <SoftwareSerial.h>

Servo MinuteHand;
Servo HourHand;

// SWITCH PINS

byte setupAswitch = A0;
byte setupBswitch = A1;
byte setupCswitch = A2;
byte setupDswitch = A3;
byte setupEswitch = A4;
byte setupFswitch = A5;
byte ResetSwitch = 2;




//  SERVO PINS

int MinuteHandPin = 9;     // Control pin for servo motor
int HourHandPin = 10;

//  STORAGE VALUES

int MinutePulse; // Storage value for counting time, MinuteHand
int HourPulse; // Storage value for counting time, HourHand

long previousMillisA = 0;        // Millis Counter Store
long previousMillisB = 0;        // Millis Counter Store

long StepperAinterval = 60000; // 60 seconds break time between MINUTE movements          
long StepperBinterval = 360000; // 6 minute break time between HOUR movements

byte mode; //

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void setup() {
  Serial.begin(9600);         // connect to the serial port
  Serial.println("**********    SETTING UP CLOCK CIRCUIT    **********"); //saying how it is
  
 //  SWITCH SETUP
 pinMode      (setupAswitch, INPUT); // set up the various push switches
 digitalWrite (setupAswitch, HIGH);  // turn on internl pullup
 pinMode      (setupBswitch, INPUT);
 digitalWrite (setupBswitch, HIGH);
 pinMode      (setupCswitch, INPUT);
 digitalWrite (setupCswitch, HIGH);
 pinMode      (setupDswitch, INPUT);
 digitalWrite (setupDswitch, HIGH);
 pinMode      (setupEswitch, INPUT);
 digitalWrite (setupEswitch, HIGH);
 pinMode      (setupFswitch, INPUT);
 digitalWrite (setupFswitch, HIGH);
 pinMode      (ResetSwitch, INPUT);
 digitalWrite (ResetSwitch, HIGH);
 
 // SERVO SETUP
 MinuteHand.attach(MinuteHandPin);  //Connects servo to relevent pin
 HourHand.attach(HourHandPin);  

 // SET BOTH SERVOS TO 'MIDNIGHT'
 
 MinuteHand.writeMicroseconds(1600);  /// SET to 12.00
 HourHand.writeMicroseconds(1600);  /// SET to 12.00

 // START MILLIS TIMER
 
 //unsigned long CurrentMillisA = millis();  //Storage for Timer NOT SURE IF RIGHT ONE!!!
 
Serial.println("WAITING FOR INPUT");
}


void loop() {
  
unsigned long CurrentMillisA = millis();  //Storage for Timer
  
if ( mode == 0 && digitalRead (setupAswitch) == LOW){ mode = 1;}
if ( mode == 0 && digitalRead (setupBswitch) == LOW){ mode = 2;}
if ( mode == 0 && digitalRead (setupCswitch) == LOW){ mode = 3;}
if ( mode == 0 && digitalRead (setupDswitch) == LOW){ mode = 4;}
if ( mode == 0 && digitalRead (setupEswitch) == LOW){ mode = 5;}
if ( mode == 0 && digitalRead (setupFswitch) == LOW){ mode = 6;}

if ( mode == 0 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 1 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 2 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 3 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 4 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 5 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 6 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 7 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all

////////////////////////////////////////////////////////////////////////////////////////
////PROGRAM VARIABLES/SERVO SETUPS

switch (mode){

case 0:  // Do Nothing and Wait for input

break;

case 1:  // Set Clock start position A
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 1");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;


case 2:  // Set Clock start position B
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 2");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;


case 3:  // Set Clock start position C
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 3");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;


case 4:  // Set Clock start position D
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 4");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;

case 5:  // Set Clock start position E
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 5");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;


case 6:  // Set Clock start position F
 MinutePulse = 1600;  // sets the stored Minute value to match the time
 HourPulse = 1600;   //sets the stored Hour value to match the time set
 MinuteHand.writeMicroseconds(MinutePulse); // sets Time A min
 HourHand.writeMicroseconds(HourPulse);  // sets Time A hour
 Serial.print("HOUR PWM VALUE IS SET TO ");
 Serial.println(HourPulse);
 Serial.print("MINUTE PWM VALUE IS SET TO ");
 Serial.println(MinutePulse);
 delay (1000);
 Serial.println("TICKING 6");
 previousMillisA = 0; //Reset Millis Counter A
 previousMillisB = 0; //Reset Millis Counter B
 mode= 7;
break;


case 7: // Commence Time
 
 if (MinutePulse >= 2495) mode = 10; //servo safety to stop it over-turning
 if (HourPulse >= 2495) mode = 10;
 // Serial.println(CurrentMillisA);
 // Serial.println(CurrentMillisB);
  if(CurrentMillisA - previousMillisA > StepperAinterval) {
    previousMillisA = CurrentMillisA;
    MinutePulse = MinutePulse + 4;
    Serial.print("MINUTE PWM VALUE IS SET TO ");
    Serial.println(MinutePulse);
    MinuteHand.writeMicroseconds(MinutePulse);
  }
  if(CurrentMillisA - previousMillisB > StepperBinterval) {
    previousMillisB = CurrentMillisA;
    HourPulse = HourPulse + 2;
    Serial.print("HOUR PWM VALUE IS SET TO ");
    Serial.println(HourPulse);
    HourHand.writeMicroseconds(HourPulse);
  }

    

case 9:  //  RESET THE PROGRAM
Serial.println("RESETTING & JOGGING");
 MinuteHand.writeMicroseconds(1700); // Jogs the motor to ensure a 'midnight'
 HourHand.writeMicroseconds(1700);
 delay (1000);
 MinuteHand.writeMicroseconds(1600); // Jogs the motor
 HourHand.writeMicroseconds(1600);
MinutePulse = 1600;  // resets values
HourPulse = 1600;
Serial.print("HOUR PWM VALUE IS RESET TO MIDNIGHT");
Serial.println(HourPulse);
Serial.print("MINUTE PWM VALUE IS RESET TO MIDNIGHT");
Serial.println(MinutePulse);
delay (1000);
Serial.println("WAITING FOR INPUT");
mode = 0;
break;

case 10:  //  SERVO OVERREACH
Serial.println("******   BWEEP SERVO OVERREACH   *******");
Serial.print("SERVO OR PWM VALUE IS ");
Serial.println(HourPulse);
Serial.print("SERVO OR PWM VALUE IS ");
Serial.println(MinutePulse);
delay (3000);
Serial.println("WAITING FOR INPUT");
MinutePulse = 1600;  // resets values to midnight
HourPulse = 1600;
mode = 0;
break;


} // end switch

} // end loop
 
 
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
long StepperAinterval = 60000; // 60 seconds break time between MINUTE movements         
long StepperBinterval = 360000; // 6 minute break time between HOUR movements
These should be:
Code:
long StepperAinterval = 60000UL; // 60 seconds break time between MINUTE movements         
long StepperBinterval = 360000UL; // 6 minute break time between HOUR movements

Code:
MinuteHand.attach(MinuteHandPin);  //Connects servo to relevent pin
 HourHand.attach(HourHandPin); 
Good names. It is very easy to see what you are doing.

Code:
// SET BOTH SERVOS TO 'MIDNIGHT'
 
 MinuteHand.writeMicroseconds(1600);  /// SET to 12.00
 HourHand.writeMicroseconds(1600);  /// SET to 12.00
I'm not a fan of magic numbers. I'd do something like this:

Code:
// Set initial position for servos
#define MIDNITE 1600

Code:
// SET BOTH SERVOS TO 'MIDNIGHT'
 
 MinuteHand.writeMicroseconds(MIDNITE);  /// SET to 12.00
 HourHand.writeMicroseconds(MIDNITE);  /// SET to 12.00

That way, if you need to change the value (to 1601 or 1599, for instance), you only need to do it in one place.

Code:
if ( mode == 0 && digitalRead (setupAswitch) == LOW){ mode = 1;}
if ( mode == 0 && digitalRead (setupBswitch) == LOW){ mode = 2;}
if ( mode == 0 && digitalRead (setupCswitch) == LOW){ mode = 3;}
if ( mode == 0 && digitalRead (setupDswitch) == LOW){ mode = 4;}
if ( mode == 0 && digitalRead (setupEswitch) == LOW){ mode = 5;}
if ( mode == 0 && digitalRead (setupFswitch) == LOW){ mode = 6;}
Using a nested if test would be better:
Code:
if(mode == 0)
{
   if (digitalRead (setupAswitch) == LOW){ mode = 1;}
   if (digitalRead (setupBswitch) == LOW){ mode = 2;}
   if (digitalRead (setupCswitch) == LOW){ mode = 3;}
   if (digitalRead (setupDswitch) == LOW){ mode = 4;}
   if (digitalRead (setupEswitch) == LOW){ mode = 5;}
   if (digitalRead (setupFswitch) == LOW){ mode = 6;}
}

Code:
if ( mode == 0 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 1 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 2 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 3 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 4 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 5 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 6 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
if ( mode == 7 && digitalRead (ResetSwitch) == LOW){ mode = 9;} //reset all
Again, a little restructuring here leads to more readable code:
Code:
if(digitalRead (ResetSwitch) == LOW)
{
   if(mode > 0 && mode <= 7)
   {
      mode = 9;
   }
}
(and a lot less of it...)

I don't see how cases 2 through 6 differ from each other. Can you point out what I missed?

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Paul, that is very helpful

Code:
long StepperAinterval = 60000; // 60 seconds break time between MINUTE movements         
long StepperBinterval = 360000; // 6 minute break time between HOUR movements
These should be:
Code:
long StepperAinterval = 60000UL; // 60 seconds break time between MINUTE movements         
long StepperBinterval = 360000UL; // 6 minute break time between HOUR movements

Just wondered what the UL is for? It seems to work fine without it.

One issue I do have however is that when Case 7 starts it is not always exactly 60 seconds before the first value is written to the motor, it seems to be random as to how long after pressing the switch to the first write, I am assuming it is something to do with the millis count not being zero when the case 7 starts to run.

After the first write it does stick strictly to the right timings for each motor so it is not too much of an issue and it is never seems to be more than a minute, Just a bit annoying.

Case 1-6 are all the same because the different 'start times' have not been entered yet. When I get the timings for the show these will all be set to different start points.

Thanks again for your help
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Just wondered what the UL is for? It seems to work fine without it.
Unsigned Long. By default, literal constants are interpreted as ints. Since neither value IS an int, it is better to tell the compiler that the value isn't an int, by telling it what it is. That's what the UL on the end does.

Quote
One issue I do have however is that when Case 7 starts it is not always exactly 60 seconds before the first value is written to the motor, it seems to be random as to how long after pressing the switch to the first write, I am assuming it is something to do with the millis count not being zero when the case 7 starts to run.
Set PreviousMillsA and PreviousMillisB to CurrentMillisA, instead of 0, in the cases 2 to 6. This will ensure that nothing happens in case 7 until exactly 60 seconds has elapsed.

Quote
Case 1-6 are all the same because the different 'start times' have not been entered yet. When I get the timings for the show these will all be set to different start points.
There is a lot of duplicate code in the 6 cases. Having a series of if/else if/else statements to handle the differences (future) would shorten the code considerably.
Logged

Pages: 1 [2]   Go Up
Jump to: