fix: modules held rather than moved drift one step backwards per move - #46
Open
socquique wants to merge 3 commits into
Open
fix: modules held rather than moved drift one step backwards per move#46socquique wants to merge 3 commits into
socquique wants to merge 3 commits into
Conversation
start() re-energizes the coil pattern the rotor is resting on before a
move, but it also rewound stepNumber and left it rewound. Two consequences:
- a module that is energized and then released without stepping (every
module that is not changing character) gets the *previous* pattern
written on the next start(), which physically drags the drum one full
step backwards. In clock mode moveTo() runs once a minute, so an hour
digit that sits still for 59 of 60 updates loses ~59 steps/hour -
about 1.4 flaps on a 48-flap drum - and nothing corrects it, because a
module that never turns never passes its hall sensor.
- a module that does step wastes its first commanded step rewriting the
pattern it is already on, so position runs one step ahead of the drum
on every move.
start() now writes the holding pattern without touching stepNumber, and
step() keeps position and stepNumber in lockstep.
Also in moveTo():
- track the steps each module still owes instead of comparing positions
for equality. A mid-move magnet correction could set position past the
target, which the equality test then never matched, sending the module
round for another full revolution.
- only energize the modules that actually have to move. Holding all
eight costs ~200mA each for nothing, and that sag is what makes the
modules that *are* moving lose steps on a shared supply.
- re-test the finish condition every iteration rather than only inside
the 20ms sensor-check window.
homeToChar() passed moveTo() its arguments in the wrong order, so homing
to a character always ran at the minimum speed.
Drop checkAllFalse()/startMotors(), now unused, along with the undefined
motorPins[] declaration and the dead file-scope hasErrored. An i2c error
now clears itself once the module answers again, instead of silently
disabling that module's magnet correction forever.
Separately, in the sketch: {mm} maps to %m (month), so the default
timeFormat "{HH}:{mm}" rendered hour:month, and the renderTime fallback
"HH:mm" had no braces at all so strftime passed it through literally.
Both now use {HH}:{MM}. {SS} is documented in the settings help modal but
was never translated; added.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The early return added with the only-energize-what-moves change skipped stopMotors(), so a moveTo() that found every module already on target would leave coils energized from a previous moveTo(.., releaseMotors=false). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The PCF8575 powers up with every output high, and on this hardware high means energized, so at power-on all four coils of all eight modules are driven at once - roughly double the current a module draws while turning, on the whole display simultaneously. Nothing wrote them low until SplitFlapDisplay::init(), which setup() only reaches after mounting LittleFS, starting the web server and running connectToWifi() - and that blocks for up to 20 seconds before giving up. So every boot held the display at full stall current for seconds, longer still when the network was down. setup() now calls releaseAll() as its first act, before STARTUP_DELAY. It needs nothing but the pin and address settings out of NVS and costs one i2c write per module. Same idea as upstream PR jhoff#45, which diagnosed this against an 11 module display whose 5V rail collapsed below 3V at power-on; it was closed without merging. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
SplitFlapModule::start()re-energizes the coil the rotor is resting on before amove, but it also rewinds
stepNumberand leaves it rewound:step()leavesstepNumberpointing at the next pattern, so the rotor sits onstepNumber - 1. The firststart()writes that and nothing moves. The secondwrites
stepNumber - 2— a pattern the rotor is not on — and drags the drum onefull step backwards.
moveTo()callsstartMotors()on every module on every move, so any module thatis energized and released without stepping loses one step each time. In clock mode
moveTo()runs once a minute, and an hour digit sits still for 59 of those 60updates:
Nothing corrects it, because a module that never turns never passes its hall
sensor. Minute digits pass theirs every ~48 minutes and look fine — which is why
this shows up as "the hours drift and the minutes are OK".
Modules that do step also waste their first commanded step rewriting the pattern
they are already on, so
positionruns one step ahead of the drum per move.Changes
start()writes the holding pattern without touchingstepNumber. Coil patternsmoved to a named table so
start()andstep()cannot disagree about them.moveTo()tracks the steps each module still owes instead of comparing positionsfor equality. A mid-move magnet correction could set
positionpast the target,which the equality test then never matched, sending the module round for another
full revolution.
moveTo()only energizes modules that actually have to move. Holding all eightcosts ~200mA each for nothing, and on a shared supply that sag is what makes the
modules that are moving lose steps.
homeToChar()passedmoveTo()its arguments in the wrong order (trueasspeed), so homing to a character always ran at the minimum speed.hasErroredforever, permanently disabling that module'smagnet correction after a single transient glitch. It now clears when the module
answers again.
motorPins[]declaration and the dead file-scopehasErrored.Also here: coil current at power-on
The PCF8575 powers up with every output high, which on this hardware means all four
coils of every module are energized. Nothing wrote them low until
SplitFlapDisplay::init(), whichsetup()only reaches after mounting LittleFS,starting the web server and running
connectToWifi()— and that blocks for up to20 seconds. So every boot held the whole display at roughly double its running
current for seconds, longer when the network was down.
setup()now callsreleaseAll()first, beforeSTARTUP_DELAY. One i2c write permodule. This is the same root cause diagnosed in #45 against an 11 module display
whose 5V rail collapsed below 3V at power-on.
Testing
Verified on an 8 module ESP32-C3 display, charset 48, 2052 steps/rotation.
Reproduced the drift by cycling 26 words that differ only in the last character at
1s intervals — 60
moveTo()calls per minute, the same count the clock makes in anhour. Before, the seven idle modules visibly walked backwards; after, they hold.