clocksync: Rework multi-mcu adjust to better handle long moves

The multi-mcu clock syncing code relies on the ability to periodically
update the mcu clock adjustments.  If a series of very long moves are
submitted then it is possible the adjustments could become unstable.
For example, if an adjustment is made to reduce a clock error over the
next couple of seconds, but it is applied to a longer period because
the next move lasts many seconds, then this would result in a bigger
adjustment for the following move, which would result in an even
bigger error when that move lasts many seconds.  This can repeat until
the system destabilizes.

Check for cases where the print_time is far in the future of the
current estimated print time and average over a longer period in that
case.  That should reduce the possibility of the adjustment code
becoming unstable.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-02-19 22:13:28 -05:00
parent 97f7735c6a
commit 02ae2ab984
1 changed files with 19 additions and 11 deletions

View File

@ -165,6 +165,7 @@ class SecondarySync(ClockSync):
ClockSync.__init__(self, reactor) ClockSync.__init__(self, reactor)
self.main_sync = main_sync self.main_sync = main_sync
self.clock_adj = (0., 1.) self.clock_adj = (0., 1.)
self.last_sync_time = 0.
def connect(self, serial): def connect(self, serial):
ClockSync.connect(self, serial) ClockSync.connect(self, serial)
self.clock_adj = (0., self.mcu_freq) self.clock_adj = (0., self.mcu_freq)
@ -195,18 +196,25 @@ class SecondarySync(ClockSync):
adjusted_offset, adjusted_freq = self.clock_adj adjusted_offset, adjusted_freq = self.clock_adj
return "%s adj=%d" % (ClockSync.stats(self, eventtime), adjusted_freq) return "%s adj=%d" % (ClockSync.stats(self, eventtime), adjusted_freq)
def calibrate_clock(self, print_time, eventtime): def calibrate_clock(self, print_time, eventtime):
# Calculate: est_print_time = main_sync.estimatated_print_time()
ser_time, ser_clock, ser_freq = self.main_sync.clock_est ser_time, ser_clock, ser_freq = self.main_sync.clock_est
main_mcu_freq = self.main_sync.mcu_freq main_mcu_freq = self.main_sync.mcu_freq
est_main_clock = (eventtime - ser_time) * ser_freq + ser_clock
main_clock = (eventtime - ser_time) * ser_freq + ser_clock est_print_time = est_main_clock / main_mcu_freq
print_time = max(print_time, main_clock / main_mcu_freq) # Determine sync1_print_time and sync2_print_time
main_sync_clock = (print_time + 4.) * main_mcu_freq sync1_print_time = max(print_time, est_print_time)
sync_time = ser_time + (main_sync_clock - ser_clock) / ser_freq sync2_print_time = max(sync1_print_time + 4., self.last_sync_time,
2.5 * (print_time - est_print_time))
print_clock = self.print_time_to_clock(print_time) # Calc sync2_sys_time (inverse of main_sync.estimatated_print_time)
sync_clock = self.get_clock(sync_time) sync2_main_clock = sync2_print_time * main_mcu_freq
adjusted_freq = .25 * (sync_clock - print_clock) sync2_sys_time = ser_time + (sync2_main_clock - ser_clock) / ser_freq
adjusted_offset = print_time - print_clock / adjusted_freq # Adjust freq so estimated print_time will match at sync2_print_time
sync1_clock = self.print_time_to_clock(sync1_print_time)
sync2_clock = self.get_clock(sync2_sys_time)
adjusted_freq = ((sync2_clock - sync1_clock)
/ (sync2_print_time - sync1_print_time))
adjusted_offset = sync1_print_time - sync1_clock / adjusted_freq
# Apply new values
self.clock_adj = (adjusted_offset, adjusted_freq) self.clock_adj = (adjusted_offset, adjusted_freq)
self.last_sync_time = sync2_print_time
return self.clock_adj return self.clock_adj