Verify Cut filament state machine + update unit tests
parent
75fe7b20b5
commit
974c1ba6db
|
|
@ -19,10 +19,11 @@ namespace mg = modules::globals;
|
||||||
|
|
||||||
void CutFilament::Reset(uint8_t param) {
|
void CutFilament::Reset(uint8_t param) {
|
||||||
error = ErrorCode::OK;
|
error = ErrorCode::OK;
|
||||||
|
cutSlot = param;
|
||||||
|
|
||||||
if (mg::globals.FilamentLoaded()) {
|
if (mg::globals.FilamentLoaded()) {
|
||||||
state = ProgressCode::UnloadingFilament;
|
state = ProgressCode::UnloadingFilament;
|
||||||
unl.Reset(mg::globals.ActiveSlot());
|
unl.Reset(cutSlot);
|
||||||
} else {
|
} else {
|
||||||
SelectFilamentSlot();
|
SelectFilamentSlot();
|
||||||
}
|
}
|
||||||
|
|
@ -30,9 +31,8 @@ void CutFilament::Reset(uint8_t param) {
|
||||||
|
|
||||||
void CutFilament::SelectFilamentSlot() {
|
void CutFilament::SelectFilamentSlot() {
|
||||||
state = ProgressCode::SelectingFilamentSlot;
|
state = ProgressCode::SelectingFilamentSlot;
|
||||||
uint8_t newFilamentSlot = mg::globals.ActiveSlot() + 1; // move 1 slot aside
|
mi::idler.Engage(cutSlot);
|
||||||
mi::idler.Engage(newFilamentSlot); //@@TODO does this make sense?
|
ms::selector.MoveToSlot(cutSlot);
|
||||||
ms::selector.MoveToSlot(newFilamentSlot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CutFilament::Step() {
|
bool CutFilament::Step() {
|
||||||
|
|
@ -46,34 +46,32 @@ bool CutFilament::Step() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::SelectingFilamentSlot:
|
case ProgressCode::SelectingFilamentSlot:
|
||||||
if (mm::motion.QueueEmpty()) { // idler and selector finished their moves
|
if (mi::idler.Engaged() && ms::selector.Slot() == cutSlot) { // idler and selector finished their moves
|
||||||
feed.Reset(true);
|
feed.Reset(true);
|
||||||
state = ProgressCode::FeedingToFinda;
|
state = ProgressCode::FeedingToFinda;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::FeedingToFinda: // @@TODO this state will be reused for repeated cutting of filament ... probably there will be multiple attempts, not sure
|
case ProgressCode::FeedingToFinda: // @@TODO this state will be reused for repeated cutting of filament ... probably there will be multiple attempts, not sure
|
||||||
//@@TODO - this is not correct - when the active slot is +1, the FINDA cannot detect the incoming filament - we can only pray that the filament moves
|
|
||||||
//idler should hold slot 0, while the selector is at slot 1
|
|
||||||
if (feed.Step()) {
|
if (feed.Step()) {
|
||||||
if (feed.State() == FeedToFinda::Failed) {
|
if (feed.State() == FeedToFinda::Failed) {
|
||||||
// @@TODO
|
// @@TODO
|
||||||
} else {
|
} else {
|
||||||
// move selector aside - prepare the blade into active position
|
// unload back to the pulley
|
||||||
state = ProgressCode::PreparingBlade;
|
state = ProgressCode::UnloadingToPulley;
|
||||||
ms::selector.MoveToSlot(mg::globals.ActiveSlot());
|
mm::motion.PlanMove(mm::Pulley, -400, 1000); // @@TODO constants
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::PreparingBlade:
|
case ProgressCode::UnloadingToPulley:
|
||||||
if (mm::motion.QueueEmpty()) {
|
if (mm::motion.QueueEmpty()) { // idler and selector finished their moves
|
||||||
state = ProgressCode::EngagingIdler;
|
// move selector aside - prepare the blade into active position
|
||||||
mi::idler.Engage(mg::globals.ActiveSlot());
|
state = ProgressCode::PreparingBlade;
|
||||||
|
ms::selector.MoveToSlot(cutSlot + 1);
|
||||||
}
|
}
|
||||||
break;
|
case ProgressCode::PreparingBlade:
|
||||||
case ProgressCode::EngagingIdler:
|
if (ms::selector.Slot() == cutSlot + 1) {
|
||||||
if (mi::idler.Engaged()) {
|
|
||||||
state = ProgressCode::PushingFilament;
|
state = ProgressCode::PushingFilament;
|
||||||
mm::motion.PlanMove(cutStepsPre, 0, 0, 1500, 0, 0); //@@TODO
|
mm::motion.PlanMove(mm::Pulley, 400, 1000); // @@TODO constants
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::PushingFilament:
|
case ProgressCode::PushingFilament:
|
||||||
|
|
@ -83,17 +81,19 @@ bool CutFilament::Step() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::PerformingCut:
|
case ProgressCode::PerformingCut:
|
||||||
if (mm::motion.QueueEmpty()) { // this may not be necessary if we want the selector and pulley move at once
|
if (ms::selector.Slot() == 0) { // this may not be necessary if we want the selector and pulley move at once
|
||||||
state = ProgressCode::ReturningSelector;
|
state = ProgressCode::ReturningSelector;
|
||||||
ms::selector.MoveToSlot(mg::globals.ActiveSlot()); // return selector back
|
ms::selector.MoveToSlot(5); // move selector to the other end of its axis to cleanup
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::ReturningSelector:
|
case ProgressCode::ReturningSelector:
|
||||||
if (mm::motion.QueueEmpty()) { // selector returned to position, feed the filament back to FINDA
|
if (ms::selector.Slot() == 5) { // selector returned to position, feed the filament back to FINDA
|
||||||
state = ProgressCode::FeedingToFinda;
|
state = ProgressCode::OK;
|
||||||
feed.Reset(true);
|
feed.Reset(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ProgressCode::OK:
|
||||||
|
return true;
|
||||||
default: // we got into an unhandled state, better report it
|
default: // we got into an unhandled state, better report it
|
||||||
state = ProgressCode::ERRInternal;
|
state = ProgressCode::ERRInternal;
|
||||||
error = ErrorCode::INTERNAL;
|
error = ErrorCode::INTERNAL;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ private:
|
||||||
constexpr static const uint16_t cutStepsPost = 150;
|
constexpr static const uint16_t cutStepsPost = 150;
|
||||||
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
|
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
|
||||||
FeedToFinda feed;
|
FeedToFinda feed;
|
||||||
|
uint8_t cutSlot;
|
||||||
|
|
||||||
void SelectFilamentSlot();
|
void SelectFilamentSlot();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ enum class ProgressCode : uint_fast8_t {
|
||||||
EngagingIdler,
|
EngagingIdler,
|
||||||
DisengagingIdler,
|
DisengagingIdler,
|
||||||
UnloadingToFinda,
|
UnloadingToFinda,
|
||||||
|
UnloadingToPulley,
|
||||||
FeedingToFinda,
|
FeedingToFinda,
|
||||||
FeedingToBondtech,
|
FeedingToBondtech,
|
||||||
AvoidingGrind,
|
AvoidingGrind,
|
||||||
|
|
|
||||||
|
|
@ -27,30 +27,29 @@ namespace mb = modules::buttons;
|
||||||
namespace mg = modules::globals;
|
namespace mg = modules::globals;
|
||||||
namespace ms = modules::selector;
|
namespace ms = modules::selector;
|
||||||
|
|
||||||
|
#include "../helpers/helpers.ipp"
|
||||||
|
|
||||||
TEST_CASE("cut_filament::cut0", "[cut_filament]") {
|
TEST_CASE("cut_filament::cut0", "[cut_filament]") {
|
||||||
using namespace logic;
|
uint8_t cutSlot = 0;
|
||||||
|
|
||||||
ForceReinitAllAutomata();
|
ForceReinitAllAutomata();
|
||||||
|
|
||||||
CutFilament cf;
|
logic::CutFilament cf;
|
||||||
|
|
||||||
|
EnsureActiveSlotIndex(cutSlot);
|
||||||
|
|
||||||
// restart the automaton
|
// restart the automaton
|
||||||
cf.Reset(0);
|
cf.Reset(cutSlot);
|
||||||
|
|
||||||
main_loop();
|
// check initial conditions
|
||||||
|
REQUIRE(VerifyState(cf, false, 5, cutSlot, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::SelectingFilamentSlot));
|
||||||
// it should have instructed the selector and idler to move to slot 1
|
|
||||||
// check if the idler and selector have the right command
|
|
||||||
CHECK(modules::motion::axes[modules::motion::Idler].targetPos == mi::Idler::SlotPosition(0));
|
|
||||||
CHECK(modules::motion::axes[modules::motion::Selector].targetPos == ms::Selector::SlotPosition(0));
|
|
||||||
|
|
||||||
// now cycle at most some number of cycles (to be determined yet) and then verify, that the idler and selector reached their target positions
|
// now cycle at most some number of cycles (to be determined yet) and then verify, that the idler and selector reached their target positions
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::SelectingFilamentSlot, 5000));
|
REQUIRE(WhileTopState(cf, ProgressCode::SelectingFilamentSlot, 5000));
|
||||||
|
|
||||||
CHECK(modules::motion::axes[modules::motion::Idler].pos == mi::Idler::SlotPosition(0));
|
|
||||||
CHECK(modules::motion::axes[modules::motion::Selector].pos == ms::Selector::SlotPosition(0));
|
|
||||||
|
|
||||||
// idler and selector reached their target positions and the CF automaton will start feeding to FINDA as the next step
|
// idler and selector reached their target positions and the CF automaton will start feeding to FINDA as the next step
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::FeedingToFinda);
|
REQUIRE(VerifyState(cf, false, cutSlot, cutSlot, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::FeedingToFinda));
|
||||||
|
|
||||||
// prepare for simulated finda trigger
|
// prepare for simulated finda trigger
|
||||||
REQUIRE(WhileCondition(
|
REQUIRE(WhileCondition(
|
||||||
cf,
|
cf,
|
||||||
|
|
@ -60,29 +59,35 @@ TEST_CASE("cut_filament::cut0", "[cut_filament]") {
|
||||||
}
|
}
|
||||||
return cf.TopLevelState() == ProgressCode::FeedingToFinda; }, 5000));
|
return cf.TopLevelState() == ProgressCode::FeedingToFinda; }, 5000));
|
||||||
|
|
||||||
// filament fed into FINDA, cutting...
|
// filament fed to FINDA
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::PreparingBlade);
|
//@@TODO filament loaded flag - decide whether the filament loaded flag means really loaded into the printer or just a piece of filament
|
||||||
|
// stuck out of the pulley to prevent movement of the selector
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, cutSlot, true, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::UnloadingToPulley));
|
||||||
|
|
||||||
|
// pull it back to the pulley + simulate FINDA depress
|
||||||
|
REQUIRE(WhileCondition(
|
||||||
|
cf,
|
||||||
|
[&](int step) -> bool {
|
||||||
|
if( step == 100 ){ // simulate FINDA trigger - will get depressed in 100 steps
|
||||||
|
hal::adc::SetADC(1, 0);
|
||||||
|
}
|
||||||
|
return cf.TopLevelState() == ProgressCode::UnloadingToPulley; }, 5000));
|
||||||
|
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, cutSlot, false, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::PreparingBlade));
|
||||||
|
|
||||||
|
// now move the selector aside, prepare for cutting
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::PreparingBlade, 5000));
|
REQUIRE(WhileTopState(cf, ProgressCode::PreparingBlade, 5000));
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, cutSlot + 1, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::PushingFilament));
|
||||||
|
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::EngagingIdler);
|
// pushing filament a bit for a cut
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::EngagingIdler, 5000));
|
|
||||||
|
|
||||||
// the idler should be at the active slot @@TODO
|
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::PushingFilament);
|
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::PushingFilament, 5000));
|
REQUIRE(WhileTopState(cf, ProgressCode::PushingFilament, 5000));
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, cutSlot + 1, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::PerformingCut));
|
||||||
|
|
||||||
// filament pushed - performing cut
|
// cutting
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::PerformingCut);
|
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::PerformingCut, 5000));
|
REQUIRE(WhileTopState(cf, ProgressCode::PerformingCut, 5000));
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, 0, false, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::ReturningSelector));
|
||||||
|
|
||||||
// returning selector
|
// moving selector to the other end of its axis
|
||||||
REQUIRE(cf.TopLevelState() == ProgressCode::ReturningSelector);
|
|
||||||
REQUIRE(WhileTopState(cf, ProgressCode::ReturningSelector, 5000));
|
REQUIRE(WhileTopState(cf, ProgressCode::ReturningSelector, 5000));
|
||||||
|
REQUIRE(VerifyState(cf, /*true*/ false, cutSlot, 5, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
||||||
// the next states are still @@TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// comments:
|
|
||||||
// The tricky part of the whole state machine are the edge cases - filament not loaded, stall guards etc.
|
|
||||||
// ... all the external influence we can get on the real HW
|
|
||||||
// But the good news is we can simulate them all in the unit test and thus ensure proper handling
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue