UnloadToFinda: update unit tests
parent
3bf5a1a0dc
commit
9aa9e0cc2b
|
|
@ -87,7 +87,10 @@ bool UnloadToFinda::Step() {
|
||||||
// we reached the end of move queue, but the FINDA didn't switch off
|
// we reached the end of move queue, but the FINDA didn't switch off
|
||||||
// two possible causes - grinded filament or malfunctioning FINDA
|
// two possible causes - grinded filament or malfunctioning FINDA
|
||||||
if (--maxTries) {
|
if (--maxTries) {
|
||||||
Reset(maxTries); // try again
|
// Ideally, the Idler shall rehome and then try again.
|
||||||
|
// That would auto-resolve errors caused by slipped or misaligned Idler
|
||||||
|
mi::idler.InvalidateHoming();
|
||||||
|
Reset(maxTries);
|
||||||
} else {
|
} else {
|
||||||
state = FailedFINDA;
|
state = FailedFINDA;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,19 +79,27 @@ void ForceReinitAllAutomata() {
|
||||||
mg::globals.Init();
|
mg::globals.Init();
|
||||||
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley);
|
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley);
|
||||||
}
|
}
|
||||||
|
void HomeIdler() {
|
||||||
|
logic::NoCommand nc; // just a dummy instance which has an empty Step()
|
||||||
|
SimulateIdlerHoming(nc);
|
||||||
|
SimulateIdlerWaitForHomingValid(nc);
|
||||||
|
SimulateIdlerMoveToParkingPosition(nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HomeSelector() {
|
||||||
|
logic::NoCommand nc; // just a dummy instance which has an empty Step()
|
||||||
|
SimulateSelectorHoming(nc);
|
||||||
|
SimulateSelectorWaitForHomingValid(nc);
|
||||||
|
SimulateSelectorWaitForReadyState(nc);
|
||||||
|
}
|
||||||
|
|
||||||
void HomeIdlerAndSelector() {
|
void HomeIdlerAndSelector() {
|
||||||
mi::idler.InvalidateHoming();
|
mi::idler.InvalidateHoming();
|
||||||
ms::selector.InvalidateHoming();
|
ms::selector.InvalidateHoming();
|
||||||
logic::NoCommand nc; // just a dummy instance which has an empty Step()
|
|
||||||
|
|
||||||
SimulateIdlerHoming(nc);
|
HomeIdler();
|
||||||
SimulateIdlerWaitForHomingValid(nc);
|
|
||||||
SimulateIdlerMoveToParkingPosition(nc);
|
|
||||||
|
|
||||||
SimulateSelectorHoming(nc);
|
HomeSelector();
|
||||||
SimulateSelectorWaitForHomingValid(nc);
|
|
||||||
SimulateSelectorWaitForReadyState(nc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EnsureActiveSlotIndex(uint8_t slot, mg::FilamentLoadState loadState) {
|
bool EnsureActiveSlotIndex(uint8_t slot, mg::FilamentLoadState loadState) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../../src/logic/command_base.h"
|
#include "../../../../src/logic/command_base.h"
|
||||||
#include "../../../../src/modules/globals.h"
|
#include "../../../../src/modules/globals.h"
|
||||||
|
#include "../../../../src/modules/idler.h"
|
||||||
|
|
||||||
extern void main_loop();
|
extern void main_loop();
|
||||||
extern void ForceReinitAllAutomata();
|
extern void ForceReinitAllAutomata();
|
||||||
|
|
@ -44,3 +45,21 @@ static constexpr uint32_t selectorMoveMaxSteps = 40000UL;
|
||||||
void HomeIdlerAndSelector();
|
void HomeIdlerAndSelector();
|
||||||
|
|
||||||
void SimulateErrDisengagingIdler(logic::CommandBase &cb, ErrorCode deferredEC);
|
void SimulateErrDisengagingIdler(logic::CommandBase &cb, ErrorCode deferredEC);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool SimulateEngageIdlerFully(T &cb) {
|
||||||
|
return WhileCondition(
|
||||||
|
cb,
|
||||||
|
[&](uint32_t) { return !mi::idler.Engaged(); },
|
||||||
|
5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool SimulateEngageIdlerPartially(T &cb) {
|
||||||
|
return WhileCondition(
|
||||||
|
cb,
|
||||||
|
[&](uint32_t) { return !mi::idler.PartiallyDisengaged(); },
|
||||||
|
5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HomeIdler();
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,12 @@
|
||||||
#include "../../../../src/modules/motion.h"
|
#include "../../../../src/modules/motion.h"
|
||||||
#include "../../../../src/modules/permanent_storage.h"
|
#include "../../../../src/modules/permanent_storage.h"
|
||||||
#include "../../../../src/modules/selector.h"
|
#include "../../../../src/modules/selector.h"
|
||||||
|
#include "../../../../src/modules/timebase.h"
|
||||||
|
|
||||||
#include "../../../../src/logic/unload_to_finda.h"
|
#include "../../../../src/logic/unload_to_finda.h"
|
||||||
|
|
||||||
#include "../../modules/stubs/stub_adc.h"
|
#include "../../modules/stubs/stub_adc.h"
|
||||||
|
#include "../../modules/stubs/stub_timebase.h"
|
||||||
|
|
||||||
#include "../stubs/main_loop_stub.h"
|
#include "../stubs/main_loop_stub.h"
|
||||||
#include "../stubs/stub_motion.h"
|
#include "../stubs/stub_motion.h"
|
||||||
|
|
@ -24,7 +26,7 @@ using namespace std::placeholders;
|
||||||
|
|
||||||
namespace ha = hal::adc;
|
namespace ha = hal::adc;
|
||||||
|
|
||||||
TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
|
void UnloadToFindaCommonSetup(logic::UnloadToFinda &ff, uint8_t retryAttempts) {
|
||||||
ForceReinitAllAutomata();
|
ForceReinitAllAutomata();
|
||||||
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
||||||
|
|
||||||
|
|
@ -35,10 +37,8 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
|
||||||
// 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);
|
||||||
|
|
||||||
logic::UnloadToFinda ff;
|
|
||||||
|
|
||||||
// restart the automaton - just 1 attempt
|
// restart the automaton - just 1 attempt
|
||||||
ff.Reset(1);
|
ff.Reset(retryAttempts);
|
||||||
|
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
|
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
|
||||||
|
|
||||||
|
|
@ -47,12 +47,10 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::IntermediateSlotPosition(0).v);
|
CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::IntermediateSlotPosition(0).v);
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
|
CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
|
||||||
|
|
||||||
// engaging idler partially
|
REQUIRE(SimulateEngageIdlerPartially(ff));
|
||||||
REQUIRE(WhileCondition(
|
}
|
||||||
ff,
|
|
||||||
[&](uint32_t) { return !mi::idler.PartiallyDisengaged(); },
|
|
||||||
5000));
|
|
||||||
|
|
||||||
|
void UnloadToFindaCommonTurnOffFSensor(logic::UnloadToFinda &ff) {
|
||||||
// turn off fsensor - the printer freed the filament from the gears
|
// turn off fsensor - the printer freed the filament from the gears
|
||||||
SetFSensorStateAndDebounce(false);
|
SetFSensorStateAndDebounce(false);
|
||||||
|
|
||||||
|
|
@ -63,14 +61,17 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
|
||||||
CHECK(mm::axes[mm::Pulley].enabled == true);
|
CHECK(mm::axes[mm::Pulley].enabled == true);
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
|
CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
|
||||||
|
|
||||||
// engaging idler fully
|
REQUIRE(SimulateEngageIdlerFully(ff));
|
||||||
REQUIRE(WhileCondition(
|
|
||||||
ff,
|
|
||||||
[&](uint32_t) { return !mi::idler.Engaged(); },
|
|
||||||
5000));
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
|
||||||
|
logic::UnloadToFinda ff;
|
||||||
|
UnloadToFindaCommonSetup(ff, 1);
|
||||||
|
UnloadToFindaCommonTurnOffFSensor(ff);
|
||||||
|
|
||||||
REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 1000), 1100));
|
REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 1000), 1100));
|
||||||
|
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::OK);
|
REQUIRE(ff.State() == logic::UnloadToFinda::OK);
|
||||||
|
|
@ -92,37 +93,9 @@ TEST_CASE("unload_to_finda::no_sense_FINDA_upon_start", "[unload_to_finda]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") {
|
TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") {
|
||||||
ForceReinitAllAutomata();
|
|
||||||
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
|
||||||
|
|
||||||
// we need finda ON
|
|
||||||
SetFINDAStateAndDebounce(true);
|
|
||||||
// fsensor should be ON
|
|
||||||
SetFSensorStateAndDebounce(true);
|
|
||||||
// and MMU "thinks" it has the filament loaded
|
|
||||||
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
|
|
||||||
|
|
||||||
logic::UnloadToFinda ff;
|
logic::UnloadToFinda ff;
|
||||||
|
UnloadToFindaCommonSetup(ff, 1);
|
||||||
// restart the automaton - just 1 attempt
|
UnloadToFindaCommonTurnOffFSensor(ff);
|
||||||
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::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
|
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Selector) == 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 FINDA during unload - we'll pretend it never triggers
|
// no changes to FINDA during unload - we'll pretend it never triggers
|
||||||
// but set FSensor correctly
|
// but set FSensor correctly
|
||||||
|
|
@ -134,96 +107,67 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("unload_to_finda::unload_without_FSensor_trigger", "[unload_to_finda]") {
|
TEST_CASE("unload_to_finda::unload_without_FSensor_trigger", "[unload_to_finda]") {
|
||||||
ForceReinitAllAutomata();
|
|
||||||
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
|
||||||
|
|
||||||
// we need finda ON
|
|
||||||
SetFINDAStateAndDebounce(true);
|
|
||||||
// fsensor should be ON
|
|
||||||
SetFSensorStateAndDebounce(true);
|
|
||||||
// and MMU "thinks" it has the filament loaded
|
|
||||||
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
|
|
||||||
|
|
||||||
logic::UnloadToFinda ff;
|
logic::UnloadToFinda ff;
|
||||||
|
UnloadToFindaCommonSetup(ff, 1);
|
||||||
// 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::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
|
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Selector) == 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
|
// no changes to FSensor during unload - we'll pretend it never triggers
|
||||||
// but set FINDA correctly
|
// time-out in 4 seconds
|
||||||
REQUIRE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 150000, 10000), 50000));
|
mt::IncMillis(4000);
|
||||||
|
|
||||||
|
main_loop();
|
||||||
|
ff.Step();
|
||||||
|
|
||||||
|
// no pulling actually starts, because the fsensor didn't turn off and the time-out elapsed
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::FailedFSensor);
|
REQUIRE(ff.State() == logic::UnloadToFinda::FailedFSensor);
|
||||||
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
|
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InNozzle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("unload_to_finda::unload_repeated", "[unload_to_finda]") {
|
TEST_CASE("unload_to_finda::unload_repeated", "[unload_to_finda]") {
|
||||||
ForceReinitAllAutomata();
|
|
||||||
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
|
||||||
|
|
||||||
// we need finda ON
|
|
||||||
SetFINDAStateAndDebounce(true);
|
|
||||||
// fsensor should be ON
|
|
||||||
SetFSensorStateAndDebounce(true);
|
|
||||||
// and MMU "thinks" it has the filament loaded
|
|
||||||
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
|
|
||||||
|
|
||||||
logic::UnloadToFinda ff;
|
logic::UnloadToFinda ff;
|
||||||
|
UnloadToFindaCommonSetup(ff, 2);
|
||||||
|
|
||||||
// restart the automaton - 2 attempts
|
UnloadToFindaCommonTurnOffFSensor(ff);
|
||||||
ff.Reset(2);
|
|
||||||
|
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
|
// remember raw Pulley pos for tweaking the steps below
|
||||||
|
// because a 20mm (config::fsensorToNozzleAvoidGrindUnload)
|
||||||
// it should have instructed the selector and idler to move to slot 1
|
// move is being executed while the Idler is fully engaging
|
||||||
// check if the idler and selector have the right command
|
// It is roughly -90 steps
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
|
// int32_t pulleySteppedAlready = mm::axes[config::Pulley].pos;
|
||||||
CHECK(mm::AxisNearestTargetPos(mm::Selector) == 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 FINDA during unload - we'll pretend it never triggers
|
// no changes to FINDA during unload - we'll pretend it never triggers
|
||||||
// but set FSensor correctly
|
// but set FSensor correctly
|
||||||
// In this case it is vital to correctly compute the amount of steps
|
// In this case it is vital to correctly compute the amount of steps
|
||||||
// to make the unload state machine restart after the 1st attempt
|
// to make the unload state machine restart after the 1st attempt
|
||||||
uint32_t unlSteps = 1 + mm::unitToSteps<mm::P_pos_t>(config::maximumBowdenLength + config::feedToFinda + config::filamentMinLoadedToMMU);
|
// The number of steps must be more than what the state machine expects for FINDA to trigger.
|
||||||
|
uint32_t unlSteps = 1 + mm::unitToSteps<mm::P_pos_t>(
|
||||||
|
// standard fast move distance
|
||||||
|
config::maximumBowdenLength + config::feedToFinda + config::filamentMinLoadedToMMU
|
||||||
|
// slow start move distance
|
||||||
|
+ config::fsensorToNozzleAvoidGrindUnload);
|
||||||
|
// compensation
|
||||||
|
// + pulleySteppedAlready;
|
||||||
REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 150000), unlSteps));
|
REQUIRE_FALSE(WhileCondition(ff, std::bind(SimulateUnloadToFINDA, _1, 10, 150000), unlSteps));
|
||||||
|
|
||||||
main_loop();
|
main_loop();
|
||||||
ff.Step();
|
ff.Step();
|
||||||
|
|
||||||
|
REQUIRE_FALSE(mi::idler.HomingValid());
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
|
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
|
||||||
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
|
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
|
||||||
|
|
||||||
|
HomeIdler();
|
||||||
|
|
||||||
|
main_loop();
|
||||||
|
ff.Step();
|
||||||
|
REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingToFinda);
|
||||||
|
|
||||||
|
SimulateEngageIdlerPartially(ff);
|
||||||
|
|
||||||
main_loop();
|
main_loop();
|
||||||
ff.Step();
|
ff.Step();
|
||||||
|
|
||||||
REQUIRE(ff.State() == logic::UnloadToFinda::UnloadingToFinda);
|
SimulateEngageIdlerFully(ff);
|
||||||
|
|
||||||
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
|
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::InSelector);
|
||||||
|
|
||||||
// make arbitrary amount of steps
|
// make arbitrary amount of steps
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue