Jump to content

Banner.jpg.b83b14cd4142fe10848741bb2a14c66b.jpg

DIY Moon Phase Dial


Gina

Recommended Posts

How on earth can the timing be so far out??? :(  I've checked the main calculation so many times in different ways.  This assumes the gearbox on the stepper motor is at least nearly what it's specified to be.  There are a couple of ways I can test this.  I can take one of these stepper motors and put a pointer on the shaft then send 2038 steps to it which should make it turn exactly 360°.  Or I could send the number of steps to the clock minutes motor to turn the minutes hand 360°. 

If we take the number of steps for a revolution of the motor shaft as 2038 then we will want 2038 x 45 / 8 steps to turn the minute hand by one revolution.  That works out at 11463.75 steps. 11464 to the nearest step.

Link to comment
Share on other sites

  • Replies 1.1k
  • Created
  • Last Reply

I have produced a cut-down sketch which will turn the hands to 12 o'clock (including the correction of a fraction of a minute) then send 11464 steps to rotate the minute hand 360° so the clock should read exactly 1:00.  Let's see what happens.

// Filename :- Moon_Clock_Testing_02 - 2016-02-28 1820
//
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 = 2000;  //  Time between steps (μs)
int mask = 0;       //  binary mask for minutes motor pins to select phase
//
void setup() {
  for (int i = 0; i < 4; i++) { pinMode(motorPins[i], OUTPUT); }  // set motor pins for output
}
//
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 loop(){
  // Main code loop - handles time set up
  if (timeIsSet) { return; } //  break out once time is set
  while ((analogRead(A6) > 500) || (analogRead(A7) > 500)) { moveForward(1); } // move fast forward until 12 o'clock sensed
  moveForward(timeError);   // correct error
  moveForward(11464);
  timeIsSet = true;
}
// End

Confirmed - clock reading 1:00 :)

Link to comment
Share on other sites

3 hours ago, woodblock said:
3 hours ago, woodblock said:

Hi Gina,

I don't understand how the clock works so I'm probably barking up the wrong tree but doesn't that fivecount go 0,1,2,3,4,5,6/0,1,2,3,4,5,6/0 so that is 6 counts per cycle not 5. Would that make the clock run slow? If it was counting clock pulses then your time would be out by a factor of 6/5

Cheers

Steve

 

Hi Gina,

I don't understand how the clock works so I'm probably barking up the wrong tree but doesn't that fivecount go 0,1,2,3,4,5,6/0,1,2,3,4,5,6/0 so that is 6 counts per cycle not 5. Would that make the clock run slow? If it was counting clock pulses then your time would be out by a factor of 6/5

Cheers

Steve

 

Yes, whatever the value of 'steps' the loop will execute steps+1 times.

Link to comment
Share on other sites

The count goes 0, 1, 2, 3, 4, 5=0, 1, 2, 3, 4, 5=0, 1, 2, 3, 4, 5=0, 1...
The count goes 0, 1, 2,  3, 4, 5.....1, 2, 3, 4, 5.......1, 2, 3, 4, 5

I make that a count of 5 but maybe I'm wrong.  If the count were 6 rather than 5 the error would be 20% rather than 11% surely?

Link to comment
Share on other sites

The rotation angle corresponds to one hour within 5s as I can see a difference of 5s.  This confirms that the accuracy of motor, gears and my calculations is within 5 in 3600 = 0.14%.  So no reason for the 11% timekeeping error has yet been found - I have eliminated all the gears and calculations AFAICS.

The interrupt is supposed to occur with a period of exactly one second (accuracy better than a minute a century).  I have already shown that the processor is well ready by the time subsequent interrupts arrive so shouldn't lose any.  As I see it the only thing left to point a finger at is the RTC 1Hz square wave.  The RTC shows the right time in hours, minutes and seconds.

Link to comment
Share on other sites

In this loop it will execute steps+1 times. If steps is 5 then i will be

5,4,3,2,1,0

before it exits as It is a while loop. 

 and i will be reinitialised to the value of steps on every call. Or am I talking about the wrong piece of code?

for (long i = steps; i >= 0; i--) 
Link to comment
Share on other sites

No it was the ISR fivecount that was in doubt.

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

OTOH the piece of code you quoted does seem to be wrong :(   But if it executes steps+1 iterations, that would mean stepping the motor 17 times instead of 16 and cause the clock to gain not loose.  :icon_scratch:

My bwain hurts bwian :(

So

for (long i = steps; i >= 0; i--) {

should be

for (long i = steps - 1; i >= 0; i--) {

I'm getting confused but I'll try that :D

Link to comment
Share on other sites

18 minutes ago, Gina said:

No it was the ISR fivecount that was in doubt.


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

OTOH the piece of code you quoted does seem to be wrong :(   But if it executes steps+1 iterations, that would mean stepping the motor 17 times instead of 16 and cause the clock to gain not loose.  :icon_scratch:

My bwain hurts bwian :(

So


for (long i = steps; i >= 0; i--) {

should be


for (long i = steps - 1; i >= 0; i--) {

I'm getting confused but I'll try that :D

Or just:

for (long i = steps; i > 0; i-- )

 

 

Link to comment
Share on other sites

Hmmm... seems to have got the gallops - 8:28 real time and clock says 8:49 :eek:

Here's the sketch

// Filename :- Moon_Clock_with_RTC_12 - 2016-02-28 1915
// 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 = 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 = 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 = 1;
    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); } 
  }
}
//
void loop(){
  // Main code loop - handles time set up
  if (timeIsSet) { return; } //  break out once time is set
  Serial.print(" RTC Time is ");
  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

Looking around the 28BYJ-48 steppers appear to have a maximum stepping rate in the 100s of hertz - I think you are trying to step them too quickly and are dropping steps. 2ms plus code execution time is unlikely to be more than 3ms between steps and I suspect you need 5-10 ms to be on the safe side. That mention of the seconds stepper vibrating but not roitating sent me on this track.

I suggest seeing what happens with delayTime set to 10000 or 5000 instead of 2000.

Link to comment
Share on other sites

I don't think I'm having a problem with stepper speed since it works correctly even at fast speed.  The accuracy is better than 0.14% in turning the hands by an hour and still within 5s when setting the time 8 hours forward.  In fact I've been thinking I might do even better by using half stepping with 2 coils on at a time rather than one.  I did a test when I was experimenting - I found 1ms too short but 1.5ms was fine so I allowed some margin by using 2ms.

Link to comment
Share on other sites

It sounds like this is not the problem but in the original code it said "if fivecount>5 then fivecount=0."

So fivecount has to reach 6 before it gets reset to 0. It would count five interrupt intervals if it said "greater than or equal to" 5

Also the modified version where you have "if fivecount=5 then fivecount=1" would only count four interrupt intervals not five like this 1,2,3,4,(5/1),2,3,4,(5/1),2,3,4,(5/1) if you count the number of intervals from 2 until the next 2 then there are only 4 steps.

It seems to make sense because you said that when you tried the one above then the time went very fast so that loop has an effect on the way the clock runs. The lower the count the faster the clock runs.

Perhaps I should shut up.

Cheers

Steve

 

Link to comment
Share on other sites

Don't worry Steve - you were right, there was a time when I had "if fivecount>5 then fivecount=0." whereas previously I had "if fivecount>4 then fivecount=0." a senior moment :D  Anyway, I think I might have it right now - the clock seems to be keeping time.  I'll leave it running overnight and see what it says in the morning.

Here's the sketch I'm running now.

// Filename :- Moon_Clock_with_RTC_12 - 2016-02-28 1915
// 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 = 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 = 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 < 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); } 
  }
}
//
void loop(){
  // Main code loop - handles time set up
  if (timeIsSet) { return; } //  break out once time is set
  Serial.print(" RTC Time is ");
  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 estimate that the clock is about 20s fast ATM but if that is just a fixed offset, I can correct it.  What matters is that the clock remains this same amount fast over days, weeks and months.  The stepper motor gearbox correction I'm applying should correct this to within a minute in months.  Then I shall probably arrange to correct this remaining error every few months.

Another possibility would be to check the timekeeping every time the clock reached 12 o'clock by sensing the hands and then checking the exact time from the RTC.  The difference could then be applied to correct the time by adding or dropping a few steps from the stepper motor.

Link to comment
Share on other sites

On this day when man makes a clock correction for Earth's period of rotation round the sun I think I may move on to the next level of adjustment of my clock to correct for the stepper gearbox :)

I could make this automatic by reading the RTC time at 12 o'clock and adjusting the correction or I could just add one more level of correction to get to better than a minute a decade and leave it at that.  After all, I can always reset the clock and the electric company may well do that for me more often than that :D

One thing I might also attend to is that every time the clock is reset the hands turn by a total of 12 hours and the moon phase is advanced.  At first I thought this might be solved by running the hands back to 12 o'clock and then forward to the right time but it won't be if the time is after 6 o'clock - the time needs to change by 6 hours or so for the moon phase advance.  ATM I can't think of any relatively easy way to allow for this.  All I can think of is a servo to lift the moon phase pauls and stop the advance.

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.