Unload now rechecks the position of filament after recovery

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.
pull/143/head
D.R.racer 2022-01-14 11:57:17 +01:00 committed by DRracer
parent 8a6d962bd4
commit ea8dd7e365
12 changed files with 194 additions and 38 deletions

View File

@ -83,15 +83,17 @@ static constexpr U_mm couplerToBowden = 3.5_mm; /// 3.5_mm /// FINDA Coupler scr
// just another piece of PLA (probably having more resistance in the tubes) // just another piece of PLA (probably having more resistance in the tubes)
// and we are at least 40mm off! It looks like this really depends on the exact position // and we are at least 40mm off! It looks like this really depends on the exact position
// We'll probably need to check for stallguard while pushing the filament to avoid ginding the filament // We'll probably need to check for stallguard while pushing the filament to avoid ginding the filament
static constexpr U_mm defaultBowdenLength = 427.0_mm; /// ~427.0_mm /// Default Bowden length. @TODO Should be stored in EEPROM. 392 a 784 static constexpr U_mm defaultBowdenLength = 427.0_mm; ///< ~427.0_mm - Default Bowden length. @TODO Should be stored in EEPROM. 392 a 784
static constexpr U_mm minimumBowdenLength = 341.0_mm; /// ~341.0_mm /// Minimum bowden length. @TODO Should be stored in EEPROM. static constexpr U_mm minimumBowdenLength = 341.0_mm; ///< ~341.0_mm - Minimum bowden length. @TODO Should be stored in EEPROM.
static constexpr U_mm maximumBowdenLength = 792.0_mm; /// ~792.0_mm /// Maximum bowden length. @TODO Should be stored in EEPROM. static constexpr U_mm maximumBowdenLength = 792.0_mm; ///< ~792.0_mm - Maximum bowden length. @TODO Should be stored in EEPROM.
static constexpr U_mm feedToFinda = cuttingEdgeToFindaMidpoint + filamentMinLoadedToMMU; static constexpr U_mm feedToFinda = cuttingEdgeToFindaMidpoint + filamentMinLoadedToMMU;
static constexpr U_mm maximumFeedToFinda = feedToFinda + 20.0_mm; ///< allow for some safety margin to load to FINDA static constexpr U_mm maximumFeedToFinda = feedToFinda + 20.0_mm; ///< allow for some safety margin to load to FINDA
static constexpr U_mm pulleyHelperMove = 10.0_mm; /// Helper move for Load/Unload error states - when the MMU should slowly move the filament a bit static constexpr U_mm pulleyHelperMove = 10.0_mm; ///< Helper move for Load/Unload error states - when the MMU should slowly move the filament a bit
static constexpr U_mm cutLength = 8.0_mm; static constexpr U_mm cutLength = 8.0_mm;
static constexpr U_mm fsensorToNozzle = 20.0_mm; /// ~20mm from MK4's filament sensor through extruder gears into nozzle static constexpr U_mm fsensorToNozzle = 20.0_mm; ///< ~20mm from MK4's filament sensor through extruder gears into nozzle
static constexpr U_mm fsensorToNozzleAvoidGrind = 5.0_mm; static constexpr U_mm fsensorToNozzleAvoidGrind = 5.0_mm;
/// Check the state of FSensor after this amount of filament got (hopefully) pulled out while unloading.
static constexpr U_mm fsensorUnloadCheckDistance = 20.0_mm;
/// Begin: Pulley axis configuration /// Begin: Pulley axis configuration
static constexpr AxisConfig pulley = { static constexpr AxisConfig pulley = {

View File

@ -31,7 +31,7 @@ void UnloadFilament::Reset(uint8_t /*param*/) {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
} }
void logic::UnloadFilament::FinishedCorrectly() { void UnloadFilament::FinishedCorrectly() {
state = ProgressCode::OK; state = ProgressCode::OK;
error = ErrorCode::OK; error = ErrorCode::OK;
mm::motion.Disable(mm::Pulley); mm::motion.Disable(mm::Pulley);
@ -39,21 +39,31 @@ void logic::UnloadFilament::FinishedCorrectly() {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
} }
void UnloadFilament::GoToRetractingFromFinda() {
state = ProgressCode::RetractingFromFinda;
retract.Reset();
}
void UnloadFilament::GoToRecheckFilamentAgainstFINDA() {
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
feed.Reset(true, true);
}
bool UnloadFilament::StepInner() { bool UnloadFilament::StepInner() {
switch (state) { switch (state) {
// state 1 engage idler - will be done by the Unload to FINDA state machine // state 1 engage idler - will be done by the Unload to FINDA state machine
case ProgressCode::UnloadingToFinda: // state 2 rotate pulley as long as the FINDA is on case ProgressCode::UnloadingToFinda: // state 2 rotate pulley as long as the FINDA is on
if (unl.Step()) { if (unl.Step()) {
if (unl.State() == UnloadToFinda::Failed) { if (unl.State() == UnloadToFinda::FailedFINDA) {
// couldn't unload to FINDA, report error and wait for user to resolve it // couldn't unload to FINDA, report error and wait for user to resolve it
GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_OFF); GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_OFF);
} else if (mfs::fsensor.Pressed()) { } else if (unl.State() == UnloadToFinda::FailedFSensor) {
// fsensor still pressed - that smells bad - a piece of filament may still be present in the heatsink // fsensor still pressed - that smells bad - a piece of filament may still be present in the heatsink
// and that would cause serious problems while loading another filament // and that would cause serious problems while loading another filament
GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_OFF); GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_OFF);
} else { } else {
state = ProgressCode::RetractingFromFinda; GoToRetractingFromFinda();
retract.Reset();
} }
} }
return false; return false;
@ -83,11 +93,17 @@ bool UnloadFilament::StepInner() {
GoToErrEngagingIdler(); GoToErrEngagingIdler();
break; break;
case mui::Event::Middle: // try again the whole sequence case mui::Event::Middle: // try again the whole sequence
// First invalidate homing flags as the user may have moved the Idler or Selector accidentally
InvalidateHoming();
if (mf::finda.Pressed()) { if (mf::finda.Pressed()) {
Reset(0); Reset(0); // filament is present in FINDA (regardless of FSensor) - assume we need to pull the filament to FINDA first
} else if (!mf::finda.Pressed() && mfs::fsensor.Pressed()) {
// a piece of filament is stuck in the extruder - keep waiting for the user to fix it
} else { } else {
state = ProgressCode::DisengagingIdler; // filament is not present in FINDA and not in FSensor
mi::idler.Disengage(); // - that means the filament can still be behind FINDA and blocking the selector
// Ideally push it to FINDA and then back to verify the whole situation
GoToRecheckFilamentAgainstFINDA();
} }
break; break;
case mui::Event::Right: // problem resolved - the user pulled the fillament by hand case mui::Event::Right: // problem resolved - the user pulled the fillament by hand
@ -104,8 +120,8 @@ bool UnloadFilament::StepInner() {
error = ErrorCode::FINDA_DIDNT_SWITCH_OFF; error = ErrorCode::FINDA_DIDNT_SWITCH_OFF;
state = ProgressCode::ERRWaitingForUser; // stand still state = ProgressCode::ERRWaitingForUser; // stand still
} else { } else {
// all sensors are ok // all sensors are ok, but re-check the position of the filament against FINDA
FinishedCorrectly(); GoToRecheckFilamentAgainstFINDA();
} }
break; break;
default: default:
@ -129,6 +145,17 @@ bool UnloadFilament::StepInner() {
GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_OFF); GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_OFF);
} }
return false; return false;
case ProgressCode::FeedingToFinda:
// recovery mode - we assume the filament is somewhere between the idle position and FINDA - thus blocking the selector
if (feed.Step()) {
if (feed.State() == FeedToFinda::Failed) {
GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_ON);
} else {
state = ProgressCode::RetractingFromFinda;
retract.Reset();
}
}
break;
case ProgressCode::OK: case ProgressCode::OK:
return true; // successfully finished return true; // successfully finished
default: // we got into an unhandled state, better report it default: // we got into an unhandled state, better report it

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "command_base.h" #include "command_base.h"
#include "feed_to_finda.h"
#include "unload_to_finda.h" #include "unload_to_finda.h"
#include "retract_from_finda.h" #include "retract_from_finda.h"
@ -25,8 +26,11 @@ private:
/// Common code for a correct completion of UnloadFilament /// Common code for a correct completion of UnloadFilament
void FinishedCorrectly(); void FinishedCorrectly();
void GoToRetractingFromFinda();
void GoToRecheckFilamentAgainstFINDA();
UnloadToFinda unl; UnloadToFinda unl;
FeedToFinda feed;
RetractFromFinda retract; RetractFromFinda retract;
}; };

View File

@ -1,6 +1,7 @@
/// @file unload_to_finda.cpp /// @file unload_to_finda.cpp
#include "unload_to_finda.h" #include "unload_to_finda.h"
#include "../modules/finda.h" #include "../modules/finda.h"
#include "../modules/fsensor.h"
#include "../modules/globals.h" #include "../modules/globals.h"
#include "../modules/idler.h" #include "../modules/idler.h"
#include "../modules/leds.h" #include "../modules/leds.h"
@ -21,6 +22,11 @@ void UnloadToFinda::Reset(uint8_t maxTries) {
} }
} }
// @@TODO this may end up somewhere else as more code may need to check the distance traveled by the filament
int32_t CurrentPositionPulley_mm() {
return mm::stepsToUnit<mm::P_pos_t>(mm::P_pos_t({ mm::motion.CurPosition(mm::Pulley) }));
}
bool UnloadToFinda::Step() { bool UnloadToFinda::Step() {
switch (state) { switch (state) {
case EngagingIdler: case EngagingIdler:
@ -29,18 +35,26 @@ bool UnloadToFinda::Step() {
mm::motion.InitAxis(mm::Pulley); mm::motion.InitAxis(mm::Pulley);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0); ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
} else { } else {
state = Failed; state = FailedFINDA;
} }
return false; return false;
case UnloadingToFinda: case UnloadingToFinda:
if (mi::idler.Engaged()) { if (mi::idler.Engaged()) {
state = WaitingForFINDA; state = WaitingForFINDA;
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector);
unloadStart_mm = CurrentPositionPulley_mm();
mm::motion.PlanMove<mm::Pulley>(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, config::pulleyUnloadFeedrate); mm::motion.PlanMove<mm::Pulley>(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, config::pulleyUnloadFeedrate);
} }
return false; return false;
case WaitingForFINDA: case WaitingForFINDA: {
if (!mf::finda.Pressed()) { int32_t currentPulley_mm = CurrentPositionPulley_mm();
if ((abs(unloadStart_mm - currentPulley_mm) > config::fsensorUnloadCheckDistance.v) && mfs::fsensor.Pressed()) {
// fsensor didn't trigger within the first fsensorUnloadCheckDistance mm -> stop pulling, something failed, report an error
// This scenario should not be tried again - repeating it may cause more damage to filament + potentially more collateral damage
state = FailedFSensor;
mm::motion.AbortPlannedMoves(); // stop rotating the pulley
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
} else if (!mf::finda.Pressed()) {
// detected end of filament // detected end of filament
state = OK; state = OK;
mm::motion.AbortPlannedMoves(); // stop rotating the pulley mm::motion.AbortPlannedMoves(); // stop rotating the pulley
@ -51,12 +65,14 @@ bool UnloadToFinda::Step() {
if (--maxTries) { if (--maxTries) {
Reset(maxTries); // try again Reset(maxTries); // try again
} else { } else {
state = Failed; state = FailedFINDA;
} }
} }
}
return false; return false;
case OK: case OK:
case Failed: case FailedFINDA:
case FailedFSensor:
default: default:
return true; return true;
} }

View File

@ -18,7 +18,8 @@ struct UnloadToFinda {
UnloadingToFinda, UnloadingToFinda,
WaitingForFINDA, WaitingForFINDA,
OK, OK,
Failed FailedFINDA,
FailedFSensor
}; };
inline UnloadToFinda() inline UnloadToFinda()
: maxTries(3) {} : maxTries(3) {}
@ -36,6 +37,7 @@ struct UnloadToFinda {
private: private:
uint8_t state; uint8_t state;
uint8_t maxTries; uint8_t maxTries;
int32_t unloadStart_mm; // intentionally trying to avoid using U_mm because it is a float (reps. long double)
}; };
} // namespace logic } // namespace logic

View File

@ -112,13 +112,30 @@ static constexpr AU unitToAxisUnit(U v) {
return { (typename AU::type_t)(v.v * axisScale[AU::axis].stepsPerUnit) }; return { (typename AU::type_t)(v.v * axisScale[AU::axis].stepsPerUnit) };
} }
/// Convert an unit::Unit to a steps type (pos_t or steps_t). /// Convert an AxisUnit to unit::Unit.
/// The scaling factor is stored with the pair config::AxisConfig::uSteps and
/// config::AxisConfig::stepsPerUnit (one per-axis).
template <typename U, typename AU>
static constexpr typename U::type_t axisUnitToUnit(AU v) {
static_assert(AU::unit == U::unit, "incorrect unit type conversion");
//static_assert(U::base == axisScale[AU::axis].base, "incorrect unit base conversion");
return { (typename U::type_t)(v.v / axisScale[AU::axis].stepsPerUnit) };
}
/// Convert a unit::Unit to a steps type (pos_t or steps_t).
/// Extract the raw step count from an AxisUnit with type checking. /// Extract the raw step count from an AxisUnit with type checking.
template <typename AU, typename U> template <typename AU, typename U>
static constexpr typename AU::type_t unitToSteps(U v) { static constexpr typename AU::type_t unitToSteps(U v) {
return unitToAxisUnit<AU>(v).v; return unitToAxisUnit<AU>(v).v;
} }
/// Convert a steps type (pos_t or steps_t) to a unit::Unit.
/// Extract the raw step count from an AxisUnit with type checking.
template <typename U, typename AU>
static constexpr typename U::type_t stepsToUnit(AU pos) {
return axisUnitToUnit<U, AU>(pos);
}
// Pulley // Pulley
typedef AxisUnit<pos_t, Pulley, Lenght> P_pos_t; ///< Pulley position type (steps) typedef AxisUnit<pos_t, Pulley, Lenght> P_pos_t; ///< Pulley position type (steps)
typedef AxisUnit<steps_t, Pulley, Speed> P_speed_t; ///< Pulley speed type (steps/s) typedef AxisUnit<steps_t, Pulley, Speed> P_speed_t; ///< Pulley speed type (steps/s)

View File

@ -82,7 +82,7 @@ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t *const CDCI
hal::watchdog::Enable(hal::watchdog::configuration::compute(250)); hal::watchdog::Enable(hal::watchdog::configuration::compute(250));
} }
} }
} } // extern "C"
namespace modules { namespace modules {
namespace usb { namespace usb {

View File

@ -141,3 +141,18 @@ void SetFINDAStateAndDebounce(bool press) {
for (size_t i = 0; i < config::findaDebounceMs + 1; ++i) for (size_t i = 0; i < config::findaDebounceMs + 1; ++i)
main_loop(); main_loop();
} }
// The idea is to set fsOff and findaOff to some reasonable values (like 10 and 1000)
// for normal situations.
// For errorneous situations set fsOff or findaOff to some number higher than the number of steps
// the testing routine is allowed to do -> thus effectively blocking the corresponding moment for fsensor
// and finda switching off
bool SimulateUnloadToFINDA(uint32_t step, uint32_t fsOff, uint32_t findaOff) {
if (step == fsOff) { // make FSensor switch off
mfs::fsensor.ProcessMessage(false);
return true;
} else if (step == findaOff) { // make FINDA switch off
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
}
return mf::finda.Pressed();
}

View File

@ -27,6 +27,7 @@ void SetFINDAStateAndDebounce(bool press);
void SimulateIdlerHoming(); void SimulateIdlerHoming();
void SimulateSelectorHoming(); void SimulateSelectorHoming();
void SimulateIdlerAndSelectorHoming(); void SimulateIdlerAndSelectorHoming();
bool SimulateUnloadToFINDA(uint32_t step, uint32_t fsOff, uint32_t findaOff);
// these are recommended max steps for simulated movement of the idler and selector // these are recommended max steps for simulated movement of the idler and selector
// - roughly the amount of motion steps from one end to the other + some margin // - roughly the amount of motion steps from one end to the other + some margin

View File

@ -48,6 +48,7 @@ pos_t Motion::Position(Axis axis) const {
void Motion::SetPosition(Axis axis, pos_t x) { void Motion::SetPosition(Axis axis, pos_t x) {
axes[axis].pos = x; axes[axis].pos = x;
axisData[axis].ctrl.SetPosition(axes[axis].pos);
} }
void Motion::SetMode(Axis axis, hal::tmc2130::MotorMode mode) { void Motion::SetMode(Axis axis, hal::tmc2130::MotorMode mode) {
@ -58,6 +59,7 @@ st_timer_t Motion::Step() {
if (axes[i].pos != axes[i].targetPos) { if (axes[i].pos != axes[i].targetPos) {
int8_t dirInc = (axes[i].pos < axes[i].targetPos) ? 1 : -1; int8_t dirInc = (axes[i].pos < axes[i].targetPos) ? 1 : -1;
axes[i].pos += dirInc; axes[i].pos += dirInc;
axisData[i].ctrl.SetPosition(axes[i].pos);
} }
} }
return 0; return 0;
@ -83,6 +85,7 @@ void Motion::AbortPlannedMoves(bool halt) {
void Motion::AbortPlannedMoves(config::Axis i, bool) { void Motion::AbortPlannedMoves(config::Axis i, bool) {
axes[i].targetPos = axes[i].pos; // leave the axis where it was at the time of abort axes[i].targetPos = axes[i].pos; // leave the axis where it was at the time of abort
axisData[i].ctrl.SetPosition(axes[i].pos);
} }
void ReinitMotion() { void ReinitMotion() {

View File

@ -18,6 +18,7 @@
#include "../stubs/stub_motion.h" #include "../stubs/stub_motion.h"
using Catch::Matchers::Equals; using Catch::Matchers::Equals;
using namespace std::placeholders;
#include "../helpers/helpers.ipp" #include "../helpers/helpers.ipp"
@ -38,7 +39,7 @@ void RegularUnloadFromSlot04Init(uint8_t slot, logic::UnloadFilament &uf) {
uf.Reset(slot); uf.Reset(slot);
} }
void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf) { void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t entryIdlerSlotIndex, bool selectorShallHomeAtEnd) {
// Stage 0 - verify state just after Reset() // Stage 0 - verify state just after Reset()
// we still think we have filament loaded at this stage // we still think we have filament loaded at this stage
// idler should have been activated by the underlying automaton // idler should have been activated by the underlying automaton
@ -46,7 +47,7 @@ void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf) {
// FINDA on // FINDA on
// green LED should blink, red off // green LED should blink, red off
REQUIRE(VerifyState(uf, (mg::FilamentLoadState)(mg::FilamentLoadState::InNozzle | mg::FilamentLoadState::InSelector), REQUIRE(VerifyState(uf, (mg::FilamentLoadState)(mg::FilamentLoadState::InNozzle | mg::FilamentLoadState::InSelector),
mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); entryIdlerSlotIndex, slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
// run the automaton // run the automaton
// Stage 1 - unloading to FINDA // Stage 1 - unloading to FINDA
@ -72,6 +73,10 @@ void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf) {
// Stage 3 - idler was engaged, disengage it // Stage 3 - idler was engaged, disengage it
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps)); REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
if (selectorShallHomeAtEnd) {
SimulateSelectorHoming();
}
// filament unloaded // filament unloaded
// idler should have been disengaged // idler should have been disengaged
// no change in selector's position // no change in selector's position
@ -90,7 +95,7 @@ TEST_CASE("unload_filament::regular_unload_from_slot_0-4", "[unload_filament]")
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::UnloadFilament uf; logic::UnloadFilament uf;
RegularUnloadFromSlot04Init(slot, uf); RegularUnloadFromSlot04Init(slot, uf);
RegularUnloadFromSlot04(slot, uf); RegularUnloadFromSlot04(slot, uf, mi::Idler::IdleSlotIndex(), false);
} }
} }
@ -125,7 +130,13 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) {
// run the automaton // 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 // Stage 1 - unloading to FINDA - do NOT let it trigger - keep it pressed, the automaton should finish all moves with the pulley
// without reaching the FINDA and report an error // without reaching the FINDA and report an error
REQUIRE(WhileTopState(uf, ProgressCode::UnloadingToFinda, 500000)); REQUIRE(WhileCondition(
uf,
[&](uint32_t step) {
SimulateUnloadToFINDA(step, 10, 1'000'000);
return uf.TopLevelState() == ProgressCode::UnloadingToFinda;
},
200'000));
// we still think we have filament loaded at this stage // we still think we have filament loaded at this stage
// idler should have been activated by the underlying automaton // idler should have been activated by the underlying automaton
@ -243,6 +254,9 @@ void FindaDidntTriggerResolveTryAgain(uint8_t slot, logic::UnloadFilament &uf) {
// FINDA still on // FINDA still on
// red LED should blink, green LED should be off // 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)); REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
// Assume, the Idler homed (homing is invalidated after pressing the recovery button)
SimulateIdlerHoming();
} }
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_filament]") { TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_filament]") {
@ -250,7 +264,7 @@ TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_fil
logic::UnloadFilament uf; logic::UnloadFilament uf;
FindaDidntTriggerCommonSetup(slot, uf); FindaDidntTriggerCommonSetup(slot, uf);
FindaDidntTriggerResolveTryAgain(slot, uf); FindaDidntTriggerResolveTryAgain(slot, uf);
RegularUnloadFromSlot04(slot, uf); RegularUnloadFromSlot04(slot, uf, slot, true);
} }
} }
@ -281,6 +295,19 @@ void FailedUnloadResolveManual(uint8_t slot, logic::UnloadFilament &uf) {
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
PressButtonAndDebounce(uf, mb::Right); PressButtonAndDebounce(uf, mb::Right);
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, false, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToFinda));
// we still need to feed to FINDA and back to verify the position of the filament
SimulateIdlerHoming();
REQUIRE(WhileTopState(uf, ProgressCode::FeedingToFinda, 5000));
REQUIRE(WhileTopState(uf, ProgressCode::RetractingFromFinda, idlerEngageDisengageMaxSteps));
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
SimulateSelectorHoming();
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK)); REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
} }

View File

@ -1,5 +1,7 @@
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include <functional>
#include "../../../../src/modules/buttons.h" #include "../../../../src/modules/buttons.h"
#include "../../../../src/modules/finda.h" #include "../../../../src/modules/finda.h"
#include "../../../../src/modules/fsensor.h" #include "../../../../src/modules/fsensor.h"
@ -18,6 +20,7 @@
#include "../stubs/stub_motion.h" #include "../stubs/stub_motion.h"
using Catch::Matchers::Equals; using Catch::Matchers::Equals;
using namespace std::placeholders;
namespace ha = hal::adc; namespace ha = hal::adc;
@ -27,6 +30,8 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
// we need finda ON // we need finda ON
SetFINDAStateAndDebounce(true); SetFINDAStateAndDebounce(true);
// fsensor should be ON
mfs::fsensor.ProcessMessage(true);
// and MMU "thinks" it has the filament loaded // and MMU "thinks" it has the filament loaded
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
@ -51,11 +56,7 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
// now pulling the filament until finda triggers // now pulling the filament until finda triggers
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 1000), 1100));
REQUIRE(WhileCondition(
ff,
[&](uint32_t) { return mf::finda.Pressed(); },
50000));
REQUIRE(ff.State() == logic::UnloadToFinda::OK); REQUIRE(ff.State() == logic::UnloadToFinda::OK);
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
@ -81,6 +82,8 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
// we need finda ON // we need finda ON
SetFINDAStateAndDebounce(true); SetFINDAStateAndDebounce(true);
// fsensor should be ON
mfs::fsensor.ProcessMessage(true);
// and MMU "thinks" it has the filament loaded // and MMU "thinks" it has the filament loaded
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
@ -107,11 +110,50 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA); REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
// no changes to FINDA during unload - we'll pretend it never triggers // no changes to FINDA during unload - we'll pretend it never triggers
REQUIRE_FALSE(WhileCondition( // but set FSensor correctly
ff, REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 150000), 50000));
[&](uint32_t) { return mf::finda.Pressed(); },
50000));
REQUIRE(ff.State() == logic::UnloadToFinda::Failed); REQUIRE(ff.State() == logic::UnloadToFinda::FailedFINDA);
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
}
TEST_CASE("unload_to_finda::unload_without_FSensor_trigger", "[unload_to_finda]") {
ForceReinitAllAutomata();
EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley);
// we need finda ON
SetFINDAStateAndDebounce(true);
// fsensor should be ON
mfs::fsensor.ProcessMessage(true);
// and MMU "thinks" it has the filament loaded
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
logic::UnloadToFinda ff;
// restart the automaton - just 1 attempt
ff.Reset(1);
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
// it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v);
CHECK(mm::axes[mm::Idler].enabled == true);
// engaging idler
REQUIRE(WhileCondition(
ff,
[&](uint32_t) { return !mi::idler.Engaged(); },
5000));
// now pulling the filament until finda triggers
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
// 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(ff.State() == logic::UnloadToFinda::FailedFSensor);
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector); REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
} }