From f4274d1b1605bdec721f87462d5f0f3e17decae5 Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Wed, 12 Apr 2023 08:06:17 +0200 Subject: [PATCH] Update unit tests to handle UnloadingFromFSensor --- src/logic/unload_filament.cpp | 2 +- src/logic/unload_to_finda.cpp | 23 +++++++---- .../logic/failing_tmc/test_failing_tmc.cpp | 2 +- tests/unit/logic/helpers/helpers.ipp | 11 ++++-- .../logic/tool_change/test_tool_change.cpp | 4 +- .../unload_filament/test_unload_filament.cpp | 23 +++++------ .../unload_to_finda/test_unload_to_finda.cpp | 39 ++++++++++++++----- 7 files changed, 67 insertions(+), 37 deletions(-) diff --git a/src/logic/unload_filament.cpp b/src/logic/unload_filament.cpp index b8bbecf..a6be01a 100644 --- a/src/logic/unload_filament.cpp +++ b/src/logic/unload_filament.cpp @@ -28,8 +28,8 @@ bool UnloadFilament::Reset(uint8_t /*param*/) { mpu::pulley.InitAxis(); state = ProgressCode::UnloadingToFinda; error = ErrorCode::RUNNING; - unl.Reset(maxRetries); ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); + unl.Reset(maxRetries); return true; } diff --git a/src/logic/unload_to_finda.cpp b/src/logic/unload_to_finda.cpp index d7e3247..01a5f24 100644 --- a/src/logic/unload_to_finda.cpp +++ b/src/logic/unload_to_finda.cpp @@ -18,11 +18,9 @@ void UnloadToFinda::Reset(uint8_t maxTries) { state = OK; // FINDA is already off, we assume the fillament is not there, i.e. already unloaded } else { // FINDA is sensing the filament, plan moves to unload it - state = EngagingIdler; mi::idler.Engage(mg::globals.ActiveSlot()); if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::InSelector) { - state = UnloadingFromFSensor; - mpu::pulley.InitAxis(); + state = EngagingIdler; ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0); } else { state = FailedFINDA; @@ -38,12 +36,16 @@ bool UnloadToFinda::Step() { mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector); unloadStart_mm = mpu::pulley.CurrentPosition_mm(); // plan both moves to keep the unload smooth + mpu::pulley.InitAxis(); mpu::pulley.PlanMove(-mg::globals.FSensorUnloadCheck_mm(), mg::globals.PulleySlowFeedrate_mm_s()); - mpu::pulley.PlanMove(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, mg::globals.PulleyUnloadFeedrate_mm_s()); + mpu::pulley.PlanMove(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU // standard lenght where FINDA is expected to trigger + + mg::globals.FSensorUnloadCheck_mm(), // but subtract the slow unload phase distance + mg::globals.PulleyUnloadFeedrate_mm_s()); } return false; - case UnloadingFromFSensor: - if ((abs(unloadStart_mm - mpu::pulley.CurrentPosition_mm()) > mm::truncatedUnit(mg::globals.FSensorUnloadCheck_mm()))) { + case UnloadingFromFSensor: { + int32_t mpucp = mpu::pulley.CurrentPosition_mm(); + if ((abs(unloadStart_mm - mpucp) > mm::truncatedUnit(mg::globals.FSensorUnloadCheck_mm()))) { // passed the slow unload distance, check fsensor if (mfs::fsensor.Pressed()) { // fsensor didn't trigger within the first fsensorUnloadCheckDistance mm -> stop pulling, something failed, report an error @@ -51,19 +53,24 @@ bool UnloadToFinda::Step() { state = FailedFSensor; mm::motion.AbortPlannedMoves(); // stop rotating the pulley ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off); + return false; // avoid falling into WaitingForFINDA } else { // fsensor turned correctly off, seamlessly transfer to fast unloading -> waiting for FINDA // the move has already been planned when idler engaged state = WaitingForFINDA; + // in this case we can safely fall into the WaitingForFINDA state as well } } - return false; + } + [[fallthrough]]; // while UnloadingFromFSensor also check for FINDA switch off + // if that happens, filament has either broken (its tip reached finda before fsensor switched off) + // or there is some other problem. case WaitingForFINDA: { if (!mf::finda.Pressed()) { // detected end of filament state = OK; mm::motion.AbortPlannedMoves(); // stop rotating the pulley - ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off); + // ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off); } else if (/*tmc2130_read_gstat() &&*/ mm::motion.QueueEmpty()) { // we reached the end of move queue, but the FINDA didn't switch off // two possible causes - grinded filament or malfunctioning FINDA diff --git a/tests/unit/logic/failing_tmc/test_failing_tmc.cpp b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp index 7b998fb..8375fe5 100644 --- a/tests/unit/logic/failing_tmc/test_failing_tmc.cpp +++ b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp @@ -54,7 +54,7 @@ void FailingMovableUnload(hal::tmc2130::ErrorFlags ef, ErrorCode ec, config::Axi // UnloadFilament starts by engaging the idler (through the UnloadToFinda state machine) uf.Reset(0); - REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), 0, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); + REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), 0, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); REQUIRE(WhileCondition( uf, diff --git a/tests/unit/logic/helpers/helpers.ipp b/tests/unit/logic/helpers/helpers.ipp index 0760f78..8e74808 100644 --- a/tests/unit/logic/helpers/helpers.ipp +++ b/tests/unit/logic/helpers/helpers.ipp @@ -116,15 +116,18 @@ bool VerifyState(SM &uf, mg::FilamentLoadState fls, uint8_t idlerSlotIndex, uint bool findaPressed, bool pulleyEnabled, ml::Mode greenLEDMode, ml::Mode redLEDMode, ErrorCode err, ProgressCode topLevelProgress) { CHECKED_ELSE(VerifyEnvironmentState(fls, idlerSlotIndex, selectorSlotIndex, findaPressed, pulleyEnabled, greenLEDMode, redLEDMode)) { + WARN("VerifyEnvironmentState failed"); return false; } CHECKED_ELSE(uf.Error() == err) { + WARN("uf.Error() != err"); return false; } auto tls = uf.TopLevelState(); CHECKED_ELSE(tls == topLevelProgress) { - return false; + WARN("tls == topLevelProgress"); + return false; } return true; } @@ -181,10 +184,12 @@ bool VerifyState2(SM &uf, mg::FilamentLoadState fls, uint8_t idlerSlotIndex, uin } CHECKED_ELSE(uf.Error() == err) { - return false; + WARN("uf.Error() != err"); + return false; } CHECKED_ELSE(uf.TopLevelState() == topLevelProgress) { - return false; + WARN("tls == topLevelProgress"); + return false; } return true; } diff --git a/tests/unit/logic/tool_change/test_tool_change.cpp b/tests/unit/logic/tool_change/test_tool_change.cpp index c2ef04b..7b12b1b 100644 --- a/tests/unit/logic/tool_change/test_tool_change.cpp +++ b/tests/unit/logic/tool_change/test_tool_change.cpp @@ -309,7 +309,7 @@ void ToolChangeFailFSensor(logic::ToolChange &tc, uint8_t fromSlot, uint8_t toSl // restart the automaton tc.Reset(toSlot); - REQUIRE(VerifyState(tc, mg::FilamentLoadState::InNozzle, mi::idler.IdleSlotIndex(), fromSlot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingFilament)); + REQUIRE(VerifyState(tc, mg::FilamentLoadState::InNozzle, mi::idler.IdleSlotIndex(), fromSlot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingFilament)); // simulate unload to finda but fail the fsensor test REQUIRE(WhileCondition(tc, std::bind(SimulateUnloadToFINDA, _1, 500'000, 10'000), 200'000)); REQUIRE(VerifyState(tc, mg::FilamentLoadState::InSelector, mi::idler.IdleSlotIndex(), fromSlot, false, false, ml::off, ml::blink0, ErrorCode::FSENSOR_DIDNT_SWITCH_OFF, ProgressCode::UnloadingFilament)); @@ -498,7 +498,7 @@ void ToolChangeFSENSOR_TOO_EARLY(logic::ToolChange &tc, uint8_t slot) { // make AutoRetry PressButtonAndDebounce(tc, mb::Middle, true); - REQUIRE(VerifyState(tc, mg::FilamentLoadState::InSelector, mi::idler.IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingFilament)); + REQUIRE(VerifyState(tc, mg::FilamentLoadState::InSelector, mi::idler.IdleSlotIndex(), slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingFilament)); SimulateIdlerHoming(tc); diff --git a/tests/unit/logic/unload_filament/test_unload_filament.cpp b/tests/unit/logic/unload_filament/test_unload_filament.cpp index 3d4c96c..fe28d41 100644 --- a/tests/unit/logic/unload_filament/test_unload_filament.cpp +++ b/tests/unit/logic/unload_filament/test_unload_filament.cpp @@ -57,14 +57,12 @@ void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t en // run the automaton // Stage 1 - unloading to FINDA - REQUIRE(WhileCondition( - uf, - [&](uint32_t step) -> bool { - if(step == 100){ // on 100th step make FINDA trigger - hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); - } - return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, - 50000)); + REQUIRE(WhileCondition(uf, + std::bind(SimulateUnloadToFINDA, _1, + mm::unitToSteps(mg::globals.FSensorUnloadCheck_mm()) / 4, // make fsensor trigger roughly in the first 1/4 of the check distance + mm::unitToSteps(config::minimumBowdenLength)), + 200'000)); + uf.Step(); // make UnloadFilament do one more step to transfer to the correct state after finda pressed // we still think we have filament loaded at this stage // idler should have been activated by the underlying automaton @@ -102,7 +100,7 @@ TEST_CASE("unload_filament::regular_unload_from_slot_0-4", "[unload_filament]") for (uint8_t slot = 0; slot < config::toolCount; ++slot) { logic::UnloadFilament uf; RegularUnloadFromSlot04Init(slot, uf); - RegularUnloadFromSlot04(slot, uf, mi::Idler::IdleSlotIndex(), false, ml::off); + RegularUnloadFromSlot04(slot, uf, mi::Idler::IdleSlotIndex(), false, ml::blink0); } } @@ -132,7 +130,7 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) { // FINDA triggered off // green LED should be off // no error so far - REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); + REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); // run the automaton // Stage 1 - unloading to FINDA - do NOT let it trigger - keep it pressed, the automaton should finish all moves with the pulley @@ -164,7 +162,6 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) { REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRWaitingForUser)); } - void FindaDidntTriggerResolveTryAgain(uint8_t slot, logic::UnloadFilament &uf) { // Stage 3 - the user has to do something // there are 3 options: @@ -179,8 +176,8 @@ void FindaDidntTriggerResolveTryAgain(uint8_t slot, logic::UnloadFilament &uf) { // idler should have been disengaged // no change in selector's position // FINDA still on - // red LED should blink, green LED should be off - REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); + // red LED should be off, green LED should be blinking + REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); ClearButtons(uf); diff --git a/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp b/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp index c9e066c..0fd3bbb 100644 --- a/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp +++ b/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp @@ -58,7 +58,10 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") { // now pulling the filament until finda triggers REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingFromFSensor); - REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 1000), 1100)); + REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, + mm::unitToSteps(mg::globals.FSensorUnloadCheck_mm()) / 4, // make fsensor trigger roughly in the first 1/4 of the check distance + mm::unitToSteps(config::minimumBowdenLength)), + 200'000)); REQUIRE(ff.State() == logic::UnloadToFinda::OK); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); @@ -109,11 +112,16 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") 5000)); // now pulling the filament until finda triggers - REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); + REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingFromFSensor); // no changes to FINDA during unload - we'll pretend it never triggers // but set FSensor correctly - REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 150000), 50000)); + REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, + mm::unitToSteps(mg::globals.FSensorUnloadCheck_mm()) / 4, // make fsensor trigger roughly in the first 1/4 of the check distance + mm::unitToSteps(config::maximumBowdenLength * 2) // set finda trigger beyond the total allowed number of steps (i.e. not trigger) + ), + mm::unitToSteps(config::maximumBowdenLength) // limit the number of loops to max bowden length steps + )); REQUIRE(ff.State() == logic::UnloadToFinda::FailedFINDA); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); @@ -150,11 +158,16 @@ TEST_CASE("unload_to_finda::unload_without_FSensor_trigger", "[unload_to_finda]" 5000)); // now pulling the filament until finda triggers - REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); + REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingFromFSensor); // no changes to FSensor during unload - we'll pretend it never triggers // but set FINDA correctly - REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 150000, 10000), 50000)); + REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, + mm::unitToSteps(config::maximumBowdenLength * 2), // no changes to FSensor during unload - we'll pretend it never triggers + mm::unitToSteps(config::minimumBowdenLength) // trigger finda roughly at the expected distance (should never reach though) + ), + mm::unitToSteps(config::maximumBowdenLength) // limit the number of loops to max bowden length steps + )); REQUIRE(ff.State() == logic::UnloadToFinda::FailedFSensor); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); @@ -191,14 +204,20 @@ TEST_CASE("unload_to_finda::unload_repeated", "[unload_to_finda]") { 5000)); // now pulling the filament until finda triggers - REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); + REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingFromFSensor); // no changes to FINDA during unload - we'll pretend it never triggers // but set FSensor correctly // In this case it is vital to correctly compute the amount of steps // to make the unload state machine restart after the 1st attempt - uint32_t unlSteps = 1 + mm::unitToSteps(config::defaultBowdenLength + config::feedToFinda + config::filamentMinLoadedToMMU); - REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 150000), unlSteps)); + uint32_t unlSteps = 2 + mm::unitToSteps(config::defaultBowdenLength + config::feedToFinda + config::filamentMinLoadedToMMU - mg::globals.FSensorUnloadCheck_mm()); + REQUIRE_FALSE(WhileCondition( + ff, + std::bind(SimulateUnloadToFINDA, _1, + mm::unitToSteps(mg::globals.FSensorUnloadCheck_mm()) / 4, // make fsensor trigger roughly in the first 1/4 of the check distance + mm::unitToSteps(config::maximumBowdenLength * 2) // do not allow finda to trigger within the specified range + ), + unlSteps)); main_loop(); ff.Step(); @@ -219,7 +238,9 @@ TEST_CASE("unload_to_finda::unload_repeated", "[unload_to_finda]") { ff.Step(); } - REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); + // technically we are in the WaitingForFINDA state, but we want to tell the printer to rotate the E-motor after each unload retry + // -> therefore we check for the UnloadingFromFSensor state + REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingFromFSensor); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); // now turn FINDA off - shall respond immediately