Fix repeated re-homing + add more unit tests for that scenario
parent
f25f88b164
commit
bcba966a0e
|
|
@ -82,14 +82,21 @@ bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::M
|
||||||
stateBeforeModuleFailed = state;
|
stateBeforeModuleFailed = state;
|
||||||
error = ec;
|
error = ec;
|
||||||
state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen
|
state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen
|
||||||
return true;
|
}
|
||||||
} else {
|
|
||||||
|
// are we already recovering an error - that would mean we got another one
|
||||||
|
if (recoveringMovableError) {
|
||||||
|
error = ec;
|
||||||
|
state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen
|
||||||
|
}
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ProgressCode::ERRWaitingForUser: // waiting for a recovery - mask axis bits:
|
case ProgressCode::ERRWaitingForUser: // waiting for a recovery - mask axis bits:
|
||||||
if (WithoutAxisBits(ec) == ErrorCode::HOMING_FAILED) {
|
if (WithoutAxisBits(ec) == ErrorCode::HOMING_FAILED) {
|
||||||
// homing can be recovered
|
// homing can be recovered
|
||||||
mui::Event ev = mui::userInput.ConsumeEvent();
|
mui::Event ev = mui::userInput.ConsumeEvent();
|
||||||
if (ev == mui::Event::Middle) {
|
if (ev == mui::Event::Middle) {
|
||||||
|
recoveringMovableError = true;
|
||||||
m.PlanHome(); // force initiate a new homing attempt
|
m.PlanHome(); // force initiate a new homing attempt
|
||||||
state = ProgressCode::Homing;
|
state = ProgressCode::Homing;
|
||||||
error = ErrorCode::RUNNING;
|
error = ErrorCode::RUNNING;
|
||||||
|
|
@ -101,6 +108,7 @@ bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::M
|
||||||
if (m.HomingValid()) {
|
if (m.HomingValid()) {
|
||||||
// managed to recover from a homing problem
|
// managed to recover from a homing problem
|
||||||
state = stateBeforeModuleFailed;
|
state = stateBeforeModuleFailed;
|
||||||
|
recoveringMovableError = false;
|
||||||
stateBeforeModuleFailed = ProgressCode::OK;
|
stateBeforeModuleFailed = ProgressCode::OK;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +118,6 @@ bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::M
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ public:
|
||||||
inline CommandBase()
|
inline CommandBase()
|
||||||
: state(ProgressCode::OK)
|
: state(ProgressCode::OK)
|
||||||
, error(ErrorCode::OK)
|
, error(ErrorCode::OK)
|
||||||
, stateBeforeModuleFailed(ProgressCode::OK) {}
|
, stateBeforeModuleFailed(ProgressCode::OK)
|
||||||
|
, recoveringMovableError(false) {}
|
||||||
|
|
||||||
// Normally, a base class should (must) have a virtual destructor to enable correct deallocation of superstructures.
|
// Normally, a base class should (must) have a virtual destructor to enable correct deallocation of superstructures.
|
||||||
// However, in our case we don't want ANY destruction of these objects and moreover - adding a destructor like this
|
// However, in our case we don't want ANY destruction of these objects and moreover - adding a destructor like this
|
||||||
|
|
@ -110,6 +111,7 @@ protected:
|
||||||
ProgressCode state; ///< current progress state of the state machine
|
ProgressCode state; ///< current progress state of the state machine
|
||||||
ErrorCode error; ///< current error code
|
ErrorCode error; ///< current error code
|
||||||
ProgressCode stateBeforeModuleFailed; ///< saved state of the state machine before a common error happened
|
ProgressCode stateBeforeModuleFailed; ///< saved state of the state machine before a common error happened
|
||||||
|
bool recoveringMovableError;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace logic
|
} // namespace logic
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ void MovableBase::PerformHomeBack() {
|
||||||
mm::motion.SetMode(axis, mg::globals.MotorsStealth() ? mm::Stealth : mm::Normal);
|
mm::motion.SetMode(axis, mg::globals.MotorsStealth() ? mm::Stealth : mm::Normal);
|
||||||
if (!FinishHomingAndPlanMoveToParkPos()) {
|
if (!FinishHomingAndPlanMoveToParkPos()) {
|
||||||
// the measured axis' length was incorrect, something is blocking it, report an error, homing procedure terminated
|
// the measured axis' length was incorrect, something is blocking it, report an error, homing procedure terminated
|
||||||
state = HomingFailed;
|
HomeFailed();
|
||||||
} else {
|
} else {
|
||||||
homingValid = true;
|
homingValid = true;
|
||||||
// state = Ready; // not yet - we have to move to our parking position after homing the axis
|
// state = Ready; // not yet - we have to move to our parking position after homing the axis
|
||||||
|
|
@ -74,9 +74,10 @@ void MovableBase::PerformHomeBack() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovableBase::HomeFailed() {
|
void MovableBase::HomeFailed() {
|
||||||
// we ran out of planned moves but no StallGuard event has occurred - homing failed
|
// we ran out of planned moves but no StallGuard event has occurred
|
||||||
|
// or the measured length of axis was not within the accepted tolerance
|
||||||
homingValid = false;
|
homingValid = false;
|
||||||
mm::motion.SetMode(axis, mg::globals.MotorsStealth() ? mm::Stealth : mm::Normal);
|
mm::motion.Disable(axis); // disable power to the axis - allows the user to do something with the device manually
|
||||||
state = HomingFailed;
|
state = HomingFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,21 +58,35 @@ TEST_CASE("homing::successful_run", "[homing]") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelectorFailedRetry() {
|
template <typename T>
|
||||||
// prepare startup conditions
|
bool SimulateFailedHomePostfix(T &h) {
|
||||||
ForceReinitAllAutomata();
|
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5));
|
||||||
|
REQUIRE(mi::idler.HomingValid());
|
||||||
|
|
||||||
// change the startup to what we need here
|
REQUIRE(h.Error() == ErrorCode::HOMING_SELECTOR_FAILED);
|
||||||
EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley);
|
REQUIRE(h.State() == ProgressCode::ERRWaitingForUser);
|
||||||
|
REQUIRE_FALSE(mm::motion.Enabled(mm::Selector));
|
||||||
|
|
||||||
// set FINDA OFF + debounce
|
// do a few steps before pushing the button
|
||||||
SetFINDAStateAndDebounce(false);
|
WhileTopState(h, ProgressCode::ERRWaitingForUser, 5);
|
||||||
|
|
||||||
logic::Home h;
|
REQUIRE_FALSE(mm::motion.Enabled(mm::Selector));
|
||||||
REQUIRE(VerifyState(h, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
||||||
|
|
||||||
h.Reset(0);
|
PressButtonAndDebounce(h, mb::Middle);
|
||||||
REQUIRE(VerifyState(h, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::Homing));
|
|
||||||
|
// it shall start homing again
|
||||||
|
REQUIRE(h.Error() == ErrorCode::RUNNING);
|
||||||
|
REQUIRE(h.State() == ProgressCode::Homing);
|
||||||
|
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||||
|
REQUIRE(mm::motion.Enabled(mm::Selector));
|
||||||
|
|
||||||
|
ClearButtons(h);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool SimulateFailedHomeFirstTime(T &h) {
|
||||||
REQUIRE_FALSE(mi::idler.HomingValid());
|
REQUIRE_FALSE(mi::idler.HomingValid());
|
||||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||||
|
|
||||||
|
|
@ -115,28 +129,71 @@ bool SelectorFailedRetry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now the Selector shall perform a move into their parking positions
|
|
||||||
while (ms::selector.State() != mm::MovableBase::HomingFailed)
|
while (ms::selector.State() != mm::MovableBase::HomingFailed)
|
||||||
main_loop();
|
main_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5));
|
return SimulateFailedHomePostfix(h);
|
||||||
REQUIRE(mi::idler.HomingValid());
|
}
|
||||||
|
|
||||||
// cannot check the whole environment easily, the selector's and idler's positions are elsewhere
|
template <typename T>
|
||||||
REQUIRE(h.Error() == ErrorCode::HOMING_SELECTOR_FAILED);
|
bool SimulateFailedHomeSelectorRepeated(T &h) {
|
||||||
REQUIRE(h.State() == ProgressCode::ERRWaitingForUser);
|
// we leave Idler aside in this case
|
||||||
|
|
||||||
// do a few steps before pushing the button
|
|
||||||
WhileTopState(h, ProgressCode::ERRWaitingForUser, 5);
|
|
||||||
|
|
||||||
PressButtonAndDebounce(h, mb::Middle);
|
|
||||||
|
|
||||||
// it shall start homing again
|
|
||||||
REQUIRE(h.Error() == ErrorCode::RUNNING);
|
|
||||||
REQUIRE(h.State() == ProgressCode::Homing);
|
|
||||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||||
|
|
||||||
|
{
|
||||||
|
// do 5 steps until we trigger the simulated stallguard
|
||||||
|
for (uint8_t i = 0; i < 5; ++i) {
|
||||||
|
main_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
mm::TriggerStallGuard(mm::Selector);
|
||||||
|
main_loop();
|
||||||
|
mm::motion.StallGuardReset(mm::Selector);
|
||||||
|
}
|
||||||
|
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||||
|
uint32_t selectorTriggerShort = selectorSteps / 2;
|
||||||
|
uint32_t maxSteps = selectorTriggerShort + 1;
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||||
|
main_loop();
|
||||||
|
|
||||||
|
if (i == selectorTriggerShort) {
|
||||||
|
mm::TriggerStallGuard(mm::Selector);
|
||||||
|
} else {
|
||||||
|
mm::motion.StallGuardReset(mm::Selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ms::selector.State() != mm::MovableBase::HomingFailed)
|
||||||
|
main_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SimulateFailedHomePostfix(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectorFailedRetry() {
|
||||||
|
// prepare startup conditions
|
||||||
|
ForceReinitAllAutomata();
|
||||||
|
|
||||||
|
// change the startup to what we need here
|
||||||
|
EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley);
|
||||||
|
|
||||||
|
// set FINDA OFF + debounce
|
||||||
|
SetFINDAStateAndDebounce(false);
|
||||||
|
|
||||||
|
logic::Home h;
|
||||||
|
REQUIRE(VerifyState(h, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
||||||
|
|
||||||
|
h.Reset(0);
|
||||||
|
REQUIRE(VerifyState(h, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::Homing));
|
||||||
|
|
||||||
|
REQUIRE(SimulateFailedHomeFirstTime(h));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 5; ++i) {
|
||||||
|
REQUIRE(SimulateFailedHomeSelectorRepeated(h));
|
||||||
|
}
|
||||||
|
|
||||||
SimulateSelectorHoming();
|
SimulateSelectorHoming();
|
||||||
|
|
||||||
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5000));
|
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5000));
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ AxisSim axes[3] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Motion::InitAxis(Axis axis) {
|
bool Motion::InitAxis(Axis axis) {
|
||||||
axes[axis].enabled = true;
|
SetEnabled(axis, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Motion::SetEnabled(Axis axis, bool enabled) {
|
void Motion::SetEnabled(Axis axis, bool enabled) {
|
||||||
axes[axis].enabled = enabled;
|
axisData[axis].enabled = axes[axis].enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Motion::StallGuard(Axis axis) {
|
bool Motion::StallGuard(Axis axis) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue