It turned out FINDA needs running timer to perform BlockingInit() correctly.
Therefore setup() was split into setup() (no IRQ) and setup2() (IRQ enabled).
Then, finally, the check for FINDA state became reliable upon start of the FW.
Originally, only FeedingToBondtech was reported to the printer.
With PR#173 we have this operation separated into a fast and a slow stage (for MK3S with the chimney).
It looks like the printer could benefit from knowing if the MMU is still pushing fast
or when it entered the slow stage (to prevent ramming hard the Bondtech gears)
Along with this new state being reported, we also introduce a new ErrorCode::FSENSOR_TOO_EARLY
which basically means that the fsensor triggered in the fast feeding stage.
- Check rates using the reported acceleration instead of deriving the
value from the slope.
- Simplify the tolerances when checking (use 10% for single-axis,
20% with multiple due to quantization)
- Check a broader range of values
Correctly compute both the number of steps and direction when
under/overflowing the current position by performing a relative move.
This makes a repeated PlanMove() _always_ perform the move correcly,
even when the upper-level code might require to handle the overflow
itself for measurement.
Add tests for this condition by exposing the internal CurBlockShift() to
the motion unit tests.
Do not assume any step can be merged while moving three axes at the same
time.
Use the worst case scenario involving indepedent parameters for each
axis.
This commit looks horribly complex, but the main idea is to have each of the logic::commands
report their terminal OK state in the same way. That allow for leveraging this very moment
to initiate the idle timeout.
Additionally, I wanted to hide the logic of idle mode detection, which resulted in moving the
top level logic from main.cpp into logic/idle_mode.cpp and a set of additional files to compile
in unit tests.
- circular buffer can return its count of elements (even though a better solution may be implemeted later)
- stub_motion can handle multiple planned moves
- improved load/unload filament tests
While motion queuing is safe, code that relies on the current block
needs to run with the isr disabled.
Protect AbortPlannedMoves and CurPosition from isr' interference by
using a RAII guard.
The principle has been implemented, but the TMC is not providing
the right data for some reason - homing doesn't work at all right now.
Also, after solving the physical homing, unit tests must be updated.
This PR brings the following improvements:
- unifies the error handling of TMC and Homing/Stallguard errors on all motorized modules (Idler, Selector, Pulley)
- now we distinguish between Homing and TMC errors + we have a separate handling of these two kinds into CommandBase unified for all motorized modules
- adds unit tests to verify the function
- fixes SetFINDAStateAndDebounce (didn't obey the press parameter before)
This solves a number of issues - if FINDA or FSensor failed,
the unload was never "complete" - filament was stuck in the selector
blocking it from normal operation.
Now, after all errors have been resolved, filament is explicitly FED
into FINDA and then RETRACTED to Pulley.
Both movable components now perform homing sequences transparently
whenever the logic layer invalidates the homingValid flag.
That reflects the fact, that the user may have moved the Idler or Selector
while trying to resolve a HW issue with un/loading filament.
Basic rules:
- Idler gets rehomed immediately and then moves into the target slot position
- Selector rehomes once it is possible - i.e. when filament load state
is AtPulley - then it immediately and spontanneously executes the homing
sequence and then returns to the desired state
Motivation:
- resolve startup issues (EEPROM says we have filament, but FINDA is not triggered)
- resolve accidental moves of Idler and/or Selector while
digging out stuck filament from the unit
- fix homing procedure for Idler and Selector
(homing now ends with a move to the Parking position)
- fix unit tests' startup conditions with regard to necessary
homing of Idler and Selector
TODO: still test_cut_filament fails for minor reasons
That includes:
- introduce pulley slow feedrate and fsensor-to-nozzle distance
in config necessary for slowly feeding the filament from fsensor into the nozzle.
(the constant is subject to extraction into some other config as it has to be used in the printer as well).
- update FeedToBondtech accordingly to perform a gentle push into the nozzle
after fsensor detects the filament + update its unit tests.
- slight cleanup of LoadFilament + fix its unit tests
- add FeedingToNozzle progress code, as it might be interesting
to inform the printer about this task in the future
- revert non-clean changes from RetractFromFinda - it should not disengage the idler
- revert incorrect + fix ToolChange
- clean-up UnloadFilament
because of the change of semantics of LoadFilament operation.
LoadFilament pushes the filament into FINDA and then retracts it back just to keep the
filament ready to be grabbed by the idler and pulley and loaded into the printer's nozzle.
So the selector is not blocked by the filament -> filament NOT loaded
Load filament performs feed to FINDA and retract:
- engage idler
- feed normal to FINDA with config::feedToFinda distance until FINDA triggers
- retract normal and as soon FINDA un-triggers move back to PTFE config::cuttingEdgeToFindaMidpoint
- disengage the idler
That implied introducing another substate machine - RetractFromFinda, which does the opposite
of FeedToFinda while also checking for the FINDA switching off while retracting filament.
Still, ToolChange and CutFilament need fixing with this change
This introduces a new #define UNITTEST_MOTION which is used to control
the testing scenario:
- Normal tests, we allow the stub to override the built-in definition.
- For motion tests, we stub the lower-level classes and test the
effective implementation
We also repeat the prototype of the function, which IMHO is more
readable and more flexible: we need to use inline for the real
definition, which would require even more macros otherwise.
If the queue is full and a new move is queued, panic!
Introduce a new error code QUEUE_FULL to help diagnose situations where
the queue is handled improperly: likely one of the state machines not
waiting for the previous actions to finish.
PulseGen::PlanMove returns a boolean if the queue cannot be moved.
We could extend this to Motion::PlanMove, however all moves would then
have to check for this. Having a global check such as this ensures
we never ignore such situation.
Allow to chain moves by adding one extra parameter to the PlanMove[to]
functions: ending speed.
A move will always be accelerated from the last speed towards end ending
speed. The following:
PlanMove(100._mm, 50._mm_s, 50._mm_s);
PlanMove(200._mm, 100._mm_s);
Will first move the axis 100mm, accelerating towards 50mm/s, then
accelerate again to 100mm/s. The move will for then decelerate towards a
full stop after reaching 300mm in total.
Acceleration can be changed for each segment, so that a custom
acceleration curve can be created:
SetAcceleration(10._mm_s2);
PlanMove(100._mm, 50._mm_s, 50._mm_s);
SetAcceleration(100._mm_s2);
PlanMove(100._mm, 50._mm_s, 50._mm_s);
The ending speed might not always be reached, depending on the current
acceleration settings. The new function "Rate()" will return the ending
feedrate of the last move, if necessary.
AbortPlannedMoves accepts a new "halt" parameter to control how moves
will be chanined when interrupting the current move. By default
(halt=true) the move is completely interrupted.
When halt=false is requested, a subsequent move will be chained starting
at the currently aborted velocity. This allows to chain moves in reponse
to events, for example to accelerate the pulley without stopping as soon
as the FINDA is triggered, it's sufficient to interrupt the current move
followed by a new one:
PlanMove(maximum_loading_lenght, slow_feedrate);
... wait for PINDA trigger ...
AbortPlannedMoves(true);
PlanMove(bowden_lenght, fast_feedrate);
will seamlessy continue loading and transition to the fast feedrate.
Jerk control has been simplified. It now handles only the maximal
velocity change of the last segment, which doesn't require reverse
planning.
Add a new parameter "halt" (default to true) to control the stopping
behavior:
- halt=true: no subsequent moves will be planned, motions stops abruptly
- half=false: a new move will be chained after the current one