Change the semantics of load filament

Load filament performs feed to FINDA and retract:
- engage idler
- feed normal to FINDA with config::feedToFinda distance until FINDA triggers
- retract normal and as soon FINDA un-triggers move back to PTFE config::cuttingEdgeToFindaMidpoint
- disengage the idler

That implied introducing another substate machine - RetractFromFinda, which does the opposite
of FeedToFinda while also checking for the FINDA switching off while retracting filament.

Still, ToolChange and CutFilament need fixing with this change
pull/126/head
D.R.racer 2021-09-27 08:43:56 +02:00 committed by DRracer
parent 01b2280ea6
commit 6426295e32
11 changed files with 119 additions and 50 deletions

View File

@ -7,6 +7,7 @@ target_sources(
feed_to_finda.cpp
load_filament.cpp
no_command.cpp
retract_from_finda.cpp
set_mode.cpp
tool_change.cpp
unload_filament.cpp

View File

@ -32,29 +32,14 @@ bool FeedToFinda::Step() {
if (mf::finda.Pressed() || (feedPhaseLimited && mui::userInput.AnyEvent())) { // @@TODO probably also a command from the printer
mm::motion.AbortPlannedMoves(); // stop pushing filament
// FINDA triggered - that means it works and detected the filament tip
state = UnloadBackToPTFE;
mm::motion.PlanMove<mm::Pulley>(-config::cuttingEdgeToFindaMidpoint, config::pulleyFeedrate);
state = OK;
} else if (mm::motion.QueueEmpty()) { // all moves have been finished and FINDA didn't switch on
state = Failed;
// @@TODO - shall we disengage the idler?
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0);
}
}
return false;
case UnloadBackToPTFE:
if (mm::motion.QueueEmpty()) { // all moves have been finished
state = DisengagingIdler;
mi::idler.Disengage();
}
return false;
case DisengagingIdler:
if (!mi::idler.Engaged()) {
state = OK;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
}
// @@TODO FINDA must be reported as OFF again as we are pulling the filament from it - is this correct?
return false;
case OK:
case Failed:
default:

View File

@ -51,20 +51,22 @@ bool LoadFilament::StepInner() {
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0); // signal loading error
} else {
state = ProgressCode::FeedingToBondtech;
james.Reset(config::feedToBondtechMaxRetries);
state = ProgressCode::RetractingFromFinda;
retract.Reset();
}
}
break;
case ProgressCode::FeedingToBondtech:
if (james.Step()) { // No, Mr. Bond, I expect you to FEED
switch (james.State()) {
case FeedToBondtech::Failed:
case FeedToBondtech::OK:
mm::motion.Disable(mm::Pulley);
case ProgressCode::RetractingFromFinda:
if (retract.Step()) {
if (retract.State() == RetractFromFinda::Failed) {
state = ProgressCode::ERRDisengagingIdler;
error = ErrorCode::FINDA_DIDNT_SWITCH_OFF;
mi::idler.Disengage();
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0); // signal loading error
} else {
state = ProgressCode::DisengagingIdler;
mi::idler.Disengage();
}
}
break;

View File

@ -2,7 +2,7 @@
#include <stdint.h>
#include "command_base.h"
#include "feed_to_finda.h"
#include "feed_to_bondtech.h"
#include "retract_from_finda.h"
namespace logic {
@ -21,7 +21,7 @@ public:
private:
FeedToFinda feed;
FeedToBondtech james; // bond ;)
RetractFromFinda retract;
};
/// The one and only instance of LoadFilament state machine in the FW

View File

@ -33,4 +33,5 @@ enum class ProgressCode : uint_fast8_t {
ReturningSelector, // P21
ParkingSelector, // P22
EjectingFilament, // P23
RetractingFromFinda, // P24
};

View File

@ -0,0 +1,42 @@
#include "retract_from_finda.h"
#include "../modules/finda.h"
#include "../modules/globals.h"
#include "../modules/idler.h"
#include "../modules/leds.h"
#include "../modules/motion.h"
namespace logic {
void RetractFromFinda::Reset() {
state = EngagingIdler;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
mi::idler.Engage(mg::globals.ActiveSlot());
}
bool RetractFromFinda::Step() {
switch (state) {
case EngagingIdler:
if (mi::idler.Engaged()) {
state = UnloadBackToPTFE;
mm::motion.PlanMove<mm::Pulley>(-config::cuttingEdgeToFindaMidpoint, config::pulleyFeedrate);
}
return false;
case UnloadBackToPTFE:
if (mm::motion.QueueEmpty()) { // all moves have been finished
if (!mf::finda.Pressed()) { // FINDA switched off correctly
state = OK;
} else { // FINDA didn't switch off
state = Failed;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0);
}
}
return false;
case OK:
case Failed:
default:
return true;
}
}
} // namespace logic

View File

@ -0,0 +1,36 @@
#pragma once
#include <stdint.h>
namespace logic {
/// @brief Retract filament from FINDA to PTFE
///
/// Continuously pull filament by a fixed length (originally 600 steps) + verify FINDA is switched OFF
struct RetractFromFinda {
/// internal states of the state machine
enum {
EngagingIdler,
UnloadBackToPTFE,
OK,
Failed
};
inline RetractFromFinda()
: state(OK) {}
/// Restart the automaton
void Reset();
/// @returns true if the state machine finished its job, false otherwise
bool Step();
/// This method may be used to check the result of the automaton
/// @returns OK if everything went OK and FINDA triggered
/// @returns Failed if the FINDA didn't trigger
inline uint8_t State() const { return state; }
private:
uint8_t state;
};
} // namespace logic

View File

@ -63,26 +63,26 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
1500));
// From now on the FINDA is reported as ON
// unloading back to PTFE
REQUIRE(ff.State() == FeedToFinda::UnloadBackToPTFE);
REQUIRE(WhileCondition(
ff,
[&](int) { return ff.State() == FeedToFinda::UnloadBackToPTFE; },
5000));
// // unloading back to PTFE
// REQUIRE(ff.State() == FeedToFinda::UnloadBackToPTFE);
// REQUIRE(WhileCondition(
// ff,
// [&](int) { return ff.State() == FeedToFinda::UnloadBackToPTFE; },
// 5000));
// disengaging idler
REQUIRE(ff.State() == FeedToFinda::DisengagingIdler);
REQUIRE(WhileCondition(
ff,
[&](int) { return mi::idler.Engaged(); },
5000));
// // disengaging idler
// REQUIRE(ff.State() == FeedToFinda::DisengagingIdler);
// REQUIRE(WhileCondition(
// ff,
// [&](int) { return mi::idler.Engaged(); },
// 5000));
CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5).v); // @@TODO constants
// CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5).v); // @@TODO constants
CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0).v);
// state machine finished ok, the green LED should be on
// state machine finished ok, the green LED should be blinking
REQUIRE(ff.State() == FeedToFinda::OK);
REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::off);
REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0);
REQUIRE(ff.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true
}

View File

@ -5,6 +5,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/modules/buttons.cpp
${CMAKE_SOURCE_DIR}/src/modules/debouncer.cpp
${CMAKE_SOURCE_DIR}/src/modules/finda.cpp

View File

@ -57,23 +57,23 @@ void LoadFilamentSuccessful(uint8_t slot, logic::LoadFilament &lf) {
}
return lf.TopLevelState() == ProgressCode::FeedingToFinda; },
5000));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToBondtech));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda));
// Stage 3 - feeding to bondtech
// we'll make a fsensor switch during the process
// Stage 3 - retracting from finda
// we'll assume the finda is working correctly here
REQUIRE(WhileCondition(
lf,
[&](int step) -> bool {
if(step == 100){ // on 100th step make fsensor trigger
mfs::fsensor.ProcessMessage(true);
if(step == 50){ // on 50th step make FINDA trigger
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
}
return lf.TopLevelState() == ProgressCode::FeedingToBondtech; },
return lf.TopLevelState() == ProgressCode::RetractingFromFinda; },
5000));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::DisengagingIdler));
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::DisengagingIdler));
// Stage 4 - disengaging idler
REQUIRE(WhileTopState(lf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
REQUIRE(VerifyState(lf, true, mi::Idler::IdleSlotIndex(), slot, true, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
REQUIRE(VerifyState(lf, true, mi::Idler::IdleSlotIndex(), slot, false, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK));
}
TEST_CASE("load_filament::regular_load_to_slot_0-4", "[load_filament]") {

View File

@ -5,6 +5,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp