Jump to content

Banner.jpg.b89429c566825f6ab32bcafbada449c9.jpg

DIY Moon Phase Dial


Gina

Recommended Posts

Looking at the error that would result from just setting the time, the extra time would be 5m in 12 hours .  ie. 5m in 720mm or one part in 144.  This needs correcting as I don't want the clock to be a few minutes slow after setting the time.  So, as before when I divided by 50 for the extra, I can now divide by 144 to do the new correction with the new gears.

Link to comment
Share on other sites

  • Replies 1.1k
  • Created
  • Last Reply
19 hours ago, Gina said:

Now to re-calculate the timings v steps for running the clock normally.  Minutes motor pinion is 8t and minutes wheel 45t. 

Taking the required timing gives the following :-

  1. Stepper motor does 2048 steps per revolution. 
  2. Minutes wheel does one revolution per hour = 60m = 3600s. 
  3. Steps per second = 2048 / 3600 = 128 / 225.
  4. In terms of the actual gears this is 16 x 8 and 5 x 45.
  5. That's 16 steps every 5s.

I’ve used a 28BYJ-48 stepper motor in a project some time ago with dubious results. An investigation at the time confirmed that the gear ratio is in fact not precisely 1:64. See this. It solved my problem.

Link to comment
Share on other sites

1 hour ago, Icosahedron said:

I’ve used a 28BYJ-48 stepper motor in a project some time ago with dubious results. An investigation at the time confirmed that the gear ratio is in fact not precisely 1:64. See this. It solved my problem.

Thanks for that link, some useful info in there.

ChrisH

Link to comment
Share on other sites

Oh bu**er!!!! :(  Back to square one!!! Drat I going to have to "take up full time off-grid spoon whittling" :(  And here I am watching a new print of the minutes wheel, pinion and tube because I made it wrong before with the wrong size tube - the minute hand didn't fit :(  I've done a re-calibration of the UP printer - it was a mile out - the Z axis was 2mm out in 40mm - now that's bad!.

Thank you for pointing this out BTW I'm very much indebted to you :)  I would have been tearing my hair out wondering why my clock didn't keep time.

Gear ratio 63.68395:1 instead of 64:1 :(

Quote

Manufacturer specifies 64:1. Some patient and diligent people on the Arduino forums have disassembled the gear train of these little motors and determined that the exact gear ratio is in fact 63.68395:1. My observations confirm their findings. These means that in the recommended half-step mode we will have:64 steps per motor rotation x 63.684 gear ratio = 4076 steps per full revolution (approximately).

Well, "approximately" isn't good enough for a clock! :(

It looks like I am going to have to completely redesign this clock if it is to keep time.  If I could get it accurate enough to be within a minute in 12 hours, or rather a tad slow so that I could read the RTC and advance the clock a little to correct the time.  This would be complicated and I don't like it :(

Maybe I could do away with 28BYJ-48 stepper motors altogether.  Two alternatives come to mind - ungeared steppers and micro servo motors used with a ratchet device.

Looking at the quoted figures for the gear ratio and comparing this with the approximation given, the error is 63.68395 to 63.684 = 0.00005 in about 64 = 0.00000078125.  I calculate this to be 24.6375 seconds a year. ie. less than half a minute a year and since I shall be resetting the clock twice a year for GMT/BST change this would not matter.

The error if I did nothing and used 64 as the gear ratio is 64.0 - 63.68395 = 0.31605 or 0.3 in 64 = 0.00493828125.  That works out at about 7m in 24h which is not on.  But the "approximate" ratio which apparently gives 4076 half-steps instead of 4096 (or 2038 instead of 2048 steps), would be adequate if I could work out the gear ratios :rolleyes2:

Link to comment
Share on other sites

23 hours ago, Gina said:

I now have the clock running fine at full speed with the new minutes motor pinion and wheel/gear.  Proper design with plenty of clearance has meant that the gears no longer bind.  I have allowed a millimetre of play between the teeth with teeth about 4mm deep.  The teeth drive well without any tendency to jam.  I have also redesigned and made new seconds gears.

That's really good news Gina, one problem solved at least.

 

Jim

Link to comment
Share on other sites

2 hours ago, Icosahedron said:

I’ve used a 28BYJ-48 stepper motor in a project some time ago with dubious results. An investigation at the time confirmed that the gear ratio is in fact not precisely 1:64. See this. It solved my problem.

LOL! I have a couple of these 'in stock' now I know why they are so cheap!

Link to comment
Share on other sites

Well, I'm going to try new calculations.  Instead of 2048 steps per revolution of the output shaft of the stepper motor we have 2038.  Let's see how 2038 factorises.  2038 = 2 x 1019.  1019 seems to be prime :(  There is no way I can make a gear with 1019 teeth so doing it by gearing is not possible.  Presumably this is as close as we can get - we are dealing with small variations here.

An alternative is to vary the number of steps rather than keep a fixed number at a fixed interval.  With the gear ratio being slightly less than 64, the clock will gain by default so a step would need taking off every so many intervals.  Taking the gears as already done, the normal timing is 16 steps every 5 seconds so the principle is to send 15 steps to the motor instead of 16 every so often.  The clock would be running slightly slow every so often.  The speed ratio if 15/16 = 0.9375.  We want a reduction of 2038/2048 = 0.9951171875.

Putting this another way, for each 15/16 period the proportional reduction is 1 - 0.9375 = 0.0625.  The required reduction is 1 - 0.9951171875 = 0.0048828125.  Now I reckon that if we apply the lost step every x intervals then x = 0.0625 / 0.0048828125 = 12.8.  But let's take the true value of 0.00493828125 and we get 0.0625 / 0.00493828125 = 12.656... 

Now, I see that the difference between the two values is about 0.14 and to make the correction 13 instead of 12.656 is about 3x as much and therefore the error involved would be of the order of 3x the 25s a year I calculated in another post above.  I calculate the resulting error as around 70s a year and this would be corrrected every six months or so by the hour change.  (As long as I make the hour change by updating the clock to the RTC.)

Conclusion :- Applying a dropped step every 13 periods of 5s would result in the clock remaining within a minute of correct time, with the remaining error being corrected by the "changing the clock" for GMT/BST twice a year.

PHEW!!! :D

Link to comment
Share on other sites

It seems I can overcome the problem of the gearbox on the stepper motor being different from specification, in code - but producing a decent minutes wheel and pinion with a drive tube for the minute hand where the gear plane is at right angles to the tube is quite another matter.  I have a feeling that this is going to have to wait until I get my home made "Pilot" 3D printer working properly - I fear the little overworked UP Plus 2 printer is finally "past it" :(

Link to comment
Share on other sites

Well I could but if I use the current gearing the clock would gain so would need running backwards.  If I ran it forwards it would go all the way round and advance the moon phase when it shouldn't.  I'm not sure that arranging to run the clock back to the right time from the RTC would be any easier than counting to 13 and dropping a step.

Link to comment
Share on other sites

Hi Gina,

I don't know much about clocks but it seems to me that the answer might be to accept the gear ratio as is and then get the accuracy by setting the pulse rate to the step motor. If you use Accelstepper, you can get very accurate pulse frequencies. Obviously it depends on the Arduino clock frequency being stable but provided it is you could tweak the pulse rate until you get the accuracy you want.

Regards, Hugh

Link to comment
Share on other sites

I intend to do just that Hugh :)  Well almost - I'm running the stepper motor directly from the Arduino via ULN2003A drivers.  Also, I'm using an extremely accurate RTC module producing a 1Hz square wave that I'm using as an interrupt to the Arduino rather than the internal Timer1. 

For the clock timing I have the stepper motor driving the minutes wheel with a gear ratio of 8:45 which means I use 16 steps every 5 seconds (count 5 from the interrupt).  Above, I have calculated that if I drop a step (from 16 to 15) every 13 bursts (ie. every 13 x 5s = 65s) I can get an accuracy of about a minute in a year.  RTC timed clock resetting for BST and GMT takes care of that error.

Link to comment
Share on other sites

I think I've patched up the minutes tube by cutting off the old smaller tube and gluing on a larger one whilst its supported by the seconds axle.  Now just waiting for the glue to set.

Link to comment
Share on other sites

The minute hand tube is done and the clock reassembled.  The new Hall sensor position is fine and I timed how long it took for the clock to advance by 12 hours and it was 4m 55s which agrees well with my estimate of 5m :)  The clock now sets itself to 12 o'clock on power up.  Next, the number of steps needed to set the time from the RTC is calculated and the extra time taken to set the time allowed for.

Here is the modified code to calculate the number of steps needed to set the time with the new minutes drive gearing.  16 steps per 5s unit and a correction of 1 in 144 for the time it takes to turn the hands.

int h, units, steps, extra ;

  h = hour();
  if (h > 12) { h = h - 12; }  // convert 24hr clock to 12hr
  units = h * 720 + ( minutes() * 12 ) + (seconds() / 5));
  steps = units * 16;
  extra = steps / 144;
  steps = steps + extra;
 

 

Link to comment
Share on other sites

Next job is to allow for the strange gearbox ratio for normal running.  For each 1 second interrupt the seconds motor is advanced appropriately to turn the second hand one second, then a count is used to determine if a minute drive interval has arrived.  On the first 4 of each 5 interrupts just the second hand is advanced and the motors turned off but on the fifth the minutes motor is sent either 15 or 16 steps in addition to advancing seconds and then turning the motors off.

To allow for the gearbox correction, another counter is used to count 13.  On the first 12 counts, the motor is sent 16 steps but on the 13th it is sent only 15 steps.  Other actions are the same.

Link to comment
Share on other sites

Here is the code to set the clock to 12 o'clock when the power is applied.  One thing wants pointing out - because the minute hand Hall sensor detects the magnetic field a little before the exact minute position, the minute hand need moving forward by a few steps to put the minute hand exactly on the 12 o'clock position.  This is set in the timeError in the first line of code and implemented once the clock has reached the sensing position.

// Arduino test sketch for moon clock to test the Hall sensors
// 
//
int timeError = 50;  //  Amount of time setting error to be corrected
boolean timeIsSet = false;
int motorPins[] = {3, 4, 5, 6};  // motor pins for the minutes stepper
int delayTime = 2;  //  Time between steps (ms)
int mask = 0;        //  binary mask for motor pins to select phase
//
void setup() {
  Serial.begin (9600);     // Enable Serial Monitor via USB
  for (int i = 0; i < 4; i++) { pinMode(motorPins[i], OUTPUT); } // set the motor pins for output
}
//
void moveForward() {  //  move one stepper motor phase forwards
  if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
  mask>>=1;  // binary shift phase mask one position right
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
  delay(delayTime);  // Allow time for motor to step
}
//
void moveBackward() {  //  move one stepper motor phase backwards
  if ((mask == 0) || (mask == 1)) { mask = 16; }
  mask>>=1; for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[3-i], mask>>i&0x01); } delay(delayTime);}
//
void loop() {
  if (timeIsSet) { return; } //  break out once time is set
  while ((analogRead(A6) > 500) || (analogRead(A7) > 500)) { moveForward(); }
  for (int i = timeError; i >= 0; i--) {  moveForward(); }  // correct error
  timeIsSet = true;
}
// End

 

Link to comment
Share on other sites

Some simplification can be applied to the code by putting the step count inside the moveForward procedure.

This is the current procedure code :-

void moveForward() {  //  move one stepper motor phase forwards
  if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
  mask>>=1;  // binary shift phase mask one position right
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
  delay(delayTime);  // Allow time for motor to step
}

And an example of calling this in a loop is :-

for (int i = timeError; i >= 0; i--) {  moveForward(); }

With the number of steps passed as a parameter, this call becomes simply :-

moveForward(timeError); 

Putting the for loop inside the procedure gives :-

void moveForward(int steps) {  //  stepper motor "steps" forwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delay(delayTime);  // Allow time for motor to step
  }
}

Here is the alteration applied to the code that sets the clock to 12 o'clock at startup.  Tested and working :(

// Arduino test sketch for moon clock to test the Hall sensors
// 
//
int timeError = 50;  //  Amount of time setting error to be corrected
boolean timeIsSet = false;
int motorPins[] = {3, 4, 5, 6};  // motor pins for the minutes stepper
int delayTime = 2;  //  Time between steps (ms)
int mask = 0;        //  binary mask for motor pins to select phase
//int i;              //  General integer used for counting
//
void setup() {
  Serial.begin (9600);     // Enable Serial Monitor via USB
  for (int i = 0; i < 4; i++) {
    pinMode(motorPins[i], OUTPUT);  // set the motor pins for output
  }
}
//
void moveForward(int steps) {  //  stepper motor "steps" forwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delay(delayTime);  // Allow time for motor to step
  }
}//
void moveBackward(int steps) {  //  move one stepper motor phase backwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[3 - i], mask>>i&0x01);}  // 
    delay(delayTime);  // Allow time for motor to step
  }
}//
void loop() {
  if (timeIsSet) { return; } //  break out once time is set
  while ((analogRead(A6) > 500) || (analogRead(A7) > 500)) { moveForward(1); }
  moveForward(timeError);   // correct error
  timeIsSet = true;
}
// End

 

Link to comment
Share on other sites

The above paves the way to applying the gearbox correction to the ISR.

  1. increment gearboxCount
  2. if (gearboxCount < 12)   moveForward(16)
  3. else moveForward(15) and set gearboxCount = 0  ready for next time.

Applying this to the ISR :-

void timerIsr() { 
  moveForwardSecs(secSteps);
  fiveCount ++; // Increment interrupt count
  if (fiveCount > 4) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount < 12 ) { moveForward(16); } else { moveForward(15); gbCount = 0; }
//  Disable all motor pins to turn current off 
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); digitalWrite(motorPins2[i], 0);} 
}

 

Link to comment
Share on other sites

Actually, I've taken these in the wrong order really - the order should be :-

  1. Set clock to 12 o'clock
  2. Calculate steps required to set correct time from RTC and do it
  3. Set clock running from interrupt derived from RTC
Link to comment
Share on other sites

Oh well, since I've done it, here's Part 3 :D  Not tested yet though other than compiled.

// Filename :- Moon_Clock_with_RTC_03 - 2016-02-25 2210
// Arduino test sketch for moon clock with RTC v03
// Hardware interrupt from RTC on pin 2
// Code included to turn stepper off between ticks
// Timing uses RTC interrupt
// Second stepper motor drive added to drive seconds hand. 
// Minutes driven every 5 interrupts (5s) on first stepper motor.
//
#include <DS3232RTC.h>    //http://github.com/JChristensen/DS3232RTC
#include <Time.h>         //http://www.arduino.cc/playground/Code/Time  
#include <Wire.h>         //http://arduino.cc/en/Reference/Wire (included with Arduino IDE)
//
int motorPins[] = {3, 4, 5, 6};  // motor pins for the minutes stepper
int motorPins2[] = {A0, A1, A2, A3};  // motor pins for the seconds stepper
int secSteps = 64;  // motor steps for seconds
int delayTime = 2;
int count = 0;
int mask = 0; //  binary mask for motor pins to select phase
int mask2 = 0; //  binary mask for motor pins to select phase
int fiveCount = 0; // Count interrupts for minutes stepper
int gbCount = 0; // Counts 5s units for gearbox correction
//
void setup() {
  for (int i = 0; i < 4; i++) {
    pinMode(motorPins[i], OUTPUT);  // set the motor pins for output
    pinMode(motorPins2[i], OUTPUT);  // set the motor pins for output
  }
    pinMode(2,INPUT_PULLUP);     
    Serial.begin(9600);
    RTC.set(now());
    setSyncProvider(RTC.get);   // the function to get the time from the RTC
    if(timeStatus() != timeSet) 
        Serial.println("Unable to sync with the RTC");
    else
        Serial.println("RTC has set the system time");
     
    RTC.squareWave(SQWAVE_1_HZ);    //1 Hz square wave            
  
    attachInterrupt(digitalPinToInterrupt(2), timerIsr, FALLING);
}
//
void moveForward(int steps) {  //  stepper motor "steps" forwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], mask>>i&0x01);}  // 
    delay(delayTime);  // Allow time for motor to step
  }
}//
void moveBackward(int steps) {  //  move one stepper motor phase backwards
  for (int i = steps; i >= 0; i--) {
    if ((mask == 0) || (mask == 1)) { mask = 16;}  // set/reset phase mask
    mask>>=1;  // binary shift phase mask one position right
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[3 - i], mask>>i&0x01);}  // 
    delay(delayTime);  // Allow time for motor to step
  }
}//
//
void timerIsr() { 
//  moveForwardSecs(secSteps);
  fiveCount ++; // Increment interrupt count
  if (fiveCount > 4) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount < 12 ) { moveForward(16); } else { moveForward(15); gbCount = 0; }
//  Disable all motor pins to turn current off 
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); digitalWrite(motorPins2[i], 0);} 
  }}

//
void loop()
{
  // Main code loop
  // TODO: Put start-up & time setting code here
}
// End

 

Link to comment
Share on other sites

I think I have most of the bones of Part 2 if I can find it :)

The first step of setting the RTC to computer system time is already in Part 3.  This sets the RTC to the time at compile time so it's important that compile and upload follow straight on (just hit the upload button and the sketch is compiled first anyway). 

Part 2 calculates the number of steps to set the clock to the right time and send that number of steps to the minutes stepper motor.  All the startup code from Parts 1 & 2 goes in void loop()

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.