Jump to content

Banner.jpg.b89429c566825f6ab32bcafbada449c9.jpg

DIY Moon Phase Dial


Gina

Recommended Posts

On 24/02/2016 at 19:59, Gina said:

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.

Since resetting the clock advances the moon phase by 12 hours erroneously I shall not be doing this twice a year but instead I think I shall wind it backwards or forwards by an hour (correcting for the time this takes).  An hour at fast speed takes 25s = 5 stepper intervals = 80 steps.  An hour's rotation is 11464 steps so to to put the clock forward would be 11464 + 80 = 11544 and back would be 11464 - 80 = 11384.

Interrupts would be disabled during this process and enabled again afterwards similarly to resetting the clock but will use a different flag variable, of course.  This action is no more difficult than resetting the clock and far less obtrusive.  It can be applied at 2am but it may need an additional flag to stop it happening again following "putting the clocks back" and 2am on said date occuring again an hour later.

Coding this action can be left for a while - I may leave the clock running for several days on test to check that the timekeeping really is correct.

Link to comment
Share on other sites

  • Replies 1.1k
  • Created
  • Last Reply

Returning to gearbox error correction, the error with the currently applied correction is estimated as 25s a year.  This is almost good enough but I think it would be nice to get it better as this can be done with a couple of extra lines of code quite easily.  (I guess almost anything would seem easy after all the trials and tribulations of recent times :D).

63.68395 v 64.0 gives an error of 1 - 63.68395 / 64 = 0.00493828125 or 1 part in 202.5.  I'm currently dropping 1 step in 13 x 16 = 208.  1 in 208 = 0.00480769230769230769230769230769 and 0.00493828125 is wanted.  Difference = 0.00013058894230769230769230769231 that's 1 in 7658.  In terms of minutes in days, that's 7658 / 60 / 24 = 5.3.  So we are still gaining a minute every 5 days if my calculations are right.  I guess the 25s a year came from the other calculation wanting a lost step every 12.6 5s intervals rather than 13.

Working out the next level of correct then gives :- 1 part in 7658.  We currently have an interval of 13 x 5s = 65s and correcting by 1 in 13 x 16 = 208.  I think that means we want 7658 / 208 for the next divisor = 36.817307692307692307692307692308.  Nearest whole number is 37 which is quite close.  When my brain has cooled down I'll calculate the resulting error :D  Meanwhile, I someone could check my calculation so far, I would very much appreciate it.  I'm quite good at getting things wrong :(

Link to comment
Share on other sites

I estimate has gained 15s which tends to agree with the predicted error of a minute in 5 days.

Here is the current ISR

void timerIsr() {
  if (!timeIsSet) { return; } // Ignore the interrupt and return while setting the clock
  fiveCount ++; // Increment interrupt count
  if (fiveCount >= 5) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount < 13 ) { 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); } 
  }
}

So we want another counter - let's call it gbCount2 which will be used to count 37. OR maybe call the gearbox counters gbCount13 and gbCount37 to make the code clearer.  Another loop required inside the 13 count loop then...

Help brain overheating... taking a break... back in a while...

Link to comment
Share on other sites

Let's see what wants doing...

Every 13 intervals we want 15 steps instead of 16 but every 37 of those we want yet another step less.  That would be 14 steps.

Two methods come to mind.  Nested loops and a single loop with the 13 step and 13 x 37 step counts using modulo and if elseif statements.  I think perhaps the latter may be easier.

13 x 37 = 481 and I think this code might work :-

    gbCount ++; // Increment gearbox count
    if (gbCount >= 481) { gbCount = 0; moveForward(14); }
    else if ((gbCount % 13) == 0) { moveForward(15); }
    else { moveForward(16); }

Looked at a switch case construct but case (% 13): isn't allowed.

switch (gbCount) {
    case 481:
      gbCount = 0;
      moveForward(14);
      break;
    case (% 13):
      moveForward(15);
      break;
    default:
      moveForward(16);
    break;
  }

 

Link to comment
Share on other sites

Added the extra bit and re-run the sketch.  I adjusted the offset correction for the Hall sensor detection point and now have the clock setting up exactly (within 5 seconds).  I am now running the clock on test and hoping the minute hand will continue to line up with the minute marks on the exact minute or at least within a few seconds for several days :D

// Filename :- Moon_Clock_with_RTC_13 2016-02-28 1720
// Arduino test sketch for moon clock with RTC
// Hardware interrupt from RTC on pin 2
// Code included to turn stepper off between ticks
// Timing uses RTC interrupt
// Minutes driven every 5 interrupts (5s) on first stepper motor.
// Everything to do with the seconds motor has been removed
// moveBackward has been removed
//
#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 timeError = 28;  //  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 = 2000;  //  Time between steps (μs)
int mask = 0;       //  binary mask for minutes motor pins to select phase
int fiveCount = 0;  // Count interrupts for minutes stepper
int gbCount = 0;    // Counts 5s units for gearbox correction
long steps, h, units, extra ; // time set variables;
//
void setup() {
  Serial.begin (9600);     // Enable Serial Monitor via USB
  for (int i = 0; i < 4; i++) { pinMode(motorPins[i], OUTPUT); }  // set motor pins for output
  pinMode(2,INPUT_PULLUP);   //  Interrupt pin
  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(long steps) {  //  stepper motor "steps" forwards
  for (long 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);}  // 
    delayMicroseconds(delayTime);  // Allow time for motor to step
  }
}
//
void timerIsr() {
  if (!timeIsSet) { return; } // Ignore the interrupt and return while setting the clock
  fiveCount ++; // Increment interrupt count
    if (fiveCount >= 5) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount >= 481) { gbCount = 0; moveForward(14); }
    else if ((gbCount % 13) == 0) { moveForward(15); }
    else { moveForward(16); }
    for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); }
  }
}
//
void loop(){
  // Main code loop - handles time set up
  if (timeIsSet) { return; } //  break out once time is set
  Serial.println(" Setting hands to 12 o'clock");
  while ((analogRead(A6) > 500) || (analogRead(A7) > 500)) { moveForward(1); } // move fast forward until 12 o'clock sensed
  moveForward(timeError);   // correct error
  h = hour(); if (h > 12) { h = h - 12; }  // convert 24hr clock to 12hr
  units = h * 720;
  units += minute() * 12;
  units += second() / 5;
  steps = units * 16;
  extra = steps / 400;
  steps = steps + extra;
  Serial.print(" Moving hands to ");
  Serial.print(h); Serial.print(":");
  Serial.print(minute()); Serial.print(" using ");
  Serial.print(steps);
  Serial.println(" steps");
  moveForward(steps);
  timeIsSet = true;
}
// End

 

Link to comment
Share on other sites

I have decided to separate the clock and the calendar parts as the high accuracy RTC modules are only £3 and I have ordered a second one for the calendar.  This way I can use two Arduino Nanos and cut out a lot of messing about.  I appear to have the moon phase clock working and would prefer to leave this alone for a while under test and with the electrionics proved I don't want to rebuild it.  There is still work to do on it such as setting up the RGB LED string for lighting and some hardware parts for the case and the box for the electronics.

Link to comment
Share on other sites

I'm wondering whether to include the calendar section of the clock in this thread or to keep it separate.  Although it's now part of the clock I had originally thought of it as a separate unit and started a thread HERE.   And now that it's running off a separate Arduino Nano maybe separate threads are best.

56d4addb2ac3d_ClockwithCaseandCalendar01

Link to comment
Share on other sites

Yes, I think so :)  Showing about 5-10s slow now but that could be backlash in the gears.  Not yet finished of course, but that's the works, err... working :)

Link to comment
Share on other sites

I think the clock is losing slightly - it seems to be 15s slow now but I'll leave it several more days yet and see.  If it is, it will mean the gearbox correction is still not quite right though I don't know why.  Well I guess I do - my calculation must be a bit out.  If the timekeeping is off, I can add a bit of code to read the RTC when the clock is at 12 o'clock (hands enabling the Hall sensors) and adjust the correction factor. 

If I do it right, this will gradually regulate the timekeeping until the hands agree with the RTC.  Keeping the adjustment to just a little at a time will constitute a low-pass filter in the control loop and add stability.  To retain the regulation over a power cut I can save the value to the EEPROM.  Of course, I can calculate the error from the time error over several days and set the correction to a better value to start with but this will still be a bit out and automatic correction can save me from keep doing it manually.

Link to comment
Share on other sites

Having slept on this I think I have the answer.  There will still be a residual error after applying that last correction since we are only going to the nearest whole number.  It will need another correction or maybe two or three to get to the one part in a million accuracy we need.  Just as the earth's rotation round the sun has several levels of correction.

Link to comment
Share on other sites

Here's another possible route to accuracy. Take a reading from the RTC and set counters to zero. Keep a count of the elapsed time as sent to the dial, then after a suitable period (the count goes beyond a specific value) check the RTC, which will be very slightly fast compared to the dial. Reset the counter and add in any missing whole seconds.

If you are losing 15 seconds a day and you aim to check the RTC every 3600 seconds, you will never be more than a second out unless something interferes with the radio signal.

Make the seconds counter a long and you won't have to worry if the radio signal goes down for an extended period.

I would not be surprised if commercial mechanical clocks don't use an approach like this as they sync at least once a day.

You could also do a 'sense check' with the RTC every time the hands pass the hall sensors.

Link to comment
Share on other sites

Thank you Neil :)  I think the steps sent to the dial/hands will be exactly right as that was calculated by me.  The problem is that the number of steps is not quite right due to the stepper gearbox ratio.  I can calculate what I would expect the remaining error to be (but my poor old brain is beginning to struggle with all this - good job Windows has a nice high accuracy calculator :D )  To get to the required accuracy of around one part in a million will need much better accuracy than one step in 481 intervals (1 in 481 x 16 = 7696).

In practice at noon today the clock was about 15s slow..

On 29/02/2016 at 19:07, Gina said:

7:00:00pm and clock spot on 7 o'clock :)

Time lapsed = 2 days less 7 hours = 24 - 7 = 17 hours.  That's 15s in 17 x 3600s = 61200 or 1 in 4080.

Hmmmm... I seem to have got something wrong - looks to me like the error is twice as bad as it should be.  That is according to absolute Greenwich time rather than the RTC but I don't think the RTC can be that far out. No, I've got things wrong.  Um... No... that 7696 is the correction, not the error - isn't it?  Oh gawd I dunno...

I'm thinking that, rather than keep "straining my brain" with complicated calculations I should go empirical rather than absolute and adjust the correction factor to match the error actually found as nearly as I can and then set up the automatic correction adjustment with enough "clout" to work but not become unstable.

The clock has not yet had sufficient running time to get anywhere near close to accurate.  It's only 3 time intervals out - when it gets to a minute it might be time to work out the next correction stage.  That will be a week at least.  Patience Gina - just leave it to accumulate a meaningful error and get on with other things :D

BTW - I'm not using the radio time code receiver - just the RTC.  But if the RTC doesn't prove accurate enough I might alter the design and use the receiver.

Link to comment
Share on other sites

While I'm waiting for sufficient error to accumulate I can design the framework for the next correction level or two :D  eg. if the next correction were add a step in 4000 time intervals - which I think is a step in 4000 x 16 = 64,000 - would give the following code.  Adding extra levels is now simple once the appropriate correction is worked out (the hard bit). 

void timerIsr() {
  if (!timeIsSet) { return; } // Ignore the interrupt and return while setting the clock
  fiveCount ++; // Increment interrupt count
    if (fiveCount >= 5) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount >= 4000) { gbCount = 0; moveForward(17); }
    else if ((gbCount % 481) == 0) { moveForward(14); }
    else if ((gbCount % 13) == 0) { moveForward(15); }
    else { moveForward(16); }
  }
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); }
}

 

Link to comment
Share on other sites

I think that once the timekeeping gets to better than 5s in 12 hours, the RTC could be read at 12 o'clock and either a drive spurt (tick) added or the next one skipped.  This would mean that the time is reset every 12 o'clock and the time would never be more than one tick of 5s out.  If the clock is losing a few seconds in 12 hours we add an extra 16 steps in addition to the regular set whereas if it's gaining we drop the scheduled burst.

Case 1. losing :- The seconds should read between 55 and 59 and if less than 55 we want to send an extra 16 steps to the motor.  To be absolutely correct we should exclude seconds=0.

Case 2. gaining :- The seconds should be between 0 and 4 and if 5 or greater we want to skip the next "tick".

Link to comment
Share on other sites

2016-03-02 2000 clock 20s slow.  Elapsed time since start of test = 49 hours.  Proportional time error is 20s in 49h = 1 in 8820.  To correct for this requires an extra step every 8820 steps which is 551 time intervals.  But we're already dropping a step every 481 intervals so according to that the error could be corrected by increasing the 481 substantially.  Strange that I was so far out!  Am I going completely off the rails???

I think sufficient time has elapsed to see that the timekeeping is substantially out.  Comparing the current apparent error number of 551 with the running correction of 481 it seems to me that the second correction is causing more error that it's correcting.  This second level correction was calculated from the theoretical gearbox error and is clearly wrong.  I come back to thinking that an emperical correction would be better.  I therefore propose to remove the second level correction altogether and see what that gives.

The ISR is now :-

void timerIsr() {
  if (!timeIsSet) { return; } // Ignore the interrupt and return while setting the clock
  fiveCount ++; // Increment interrupt count
    if (fiveCount >= 5) { fiveCount = 0;
    gbCount ++; // Increment gearbox count
    if (gbCount >= 13) { gbCount = 0; moveForward(15); }
    else { moveForward(16); }
  }
  for (int i = 3; i >= 0; i--) { digitalWrite(motorPins[i], 0); }
}

 

Link to comment
Share on other sites

New clock test run just started.  Current date-time is 2016-03-02 2100 and clock is dead on the mark. 

Stepper motor gearbox correction is one step dropped every 13 time intervals.  Second level correction has been removed.  Total correction is 1 in 13 x 16 steps = 208 so we are sending 207 steps versus 208.

To estimate the timekeeping error I reckon I can get within a couple of seconds.  The minute hand moves in quite definite steps and I can see exactly when it reaches the middle of the mark on the dial.  Then I glance over to the digital clock on the wall and read the seconds. I reckon that takes a second or so.

Link to comment
Share on other sites

Gina well done, there must have been times you must have thought you'd never see this stage.  I admire your tenacity, it's paid off. You have a lovely and unique clock there.

 

Jim

Link to comment
Share on other sites

At 2016-03-03 0900 the clock read 8:59 (within a second or so) that's one whole minute slow!!!  Much more than I expected.

 

Link to comment
Share on other sites

I'm not sure my brain is awake yet :D  I'll see if I can grind out a calculation...  One minute in 12 hours is... um... 1 in 60x12=720.  Yes, that's right :)  720 steps occur in 720/16 groups of 16 steps aka one interval of 5s.  720/16=45.  The correction for that would be +1 step in 45 intervals.  This is odd because the calculated theoretical count was 12.65 and using 13 should under-correct for the gearbox ratio being under 64:1 and therefore giving a faster rotation than if it were 64:1 exactly.  I would have expected the clock to be 1m fast, not slow.  Or is my thinking upside down?

I'm beginning to wonder if I would be better working in one second intervals rather than 5s intervals.  The reason for using 5s intervals was this resulted in whole numbers of steps.  But that was only with a gearbox ratio of exactly 64:1 and now it isn't, there's no real reason for the 5s pre-count (fiveCount). 

The clock would require 3.2 steps per second for 64:1.  This is gearbox ratio / 20 steps per second.  We can use the real ratio and apply correction steps accordingly.  I know this will mean all new calculations but the old calculations seem to be way out so new ones are needed anyway.

I'm going to give this a rest now for a few hours and do something completely different.  Watercolour painting I think - a complete rest from brain damage :D

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.