Distinguish fast and slow feed stage

Originally, only FeedingToBondtech was reported to the printer.
With PR#173 we have this operation separated into a fast and a slow stage (for MK3S with the chimney).
It looks like the printer could benefit from knowing if the MMU is still pushing fast
or when it entered the slow stage (to prevent ramming hard the Bondtech gears)

Along with this new state being reported, we also introduce a new ErrorCode::FSENSOR_TOO_EARLY
which basically means that the fsensor triggered in the fast feeding stage.
pull/176/head
D.R.racer 2022-05-21 13:47:03 +02:00 committed by DRracer
parent d830a92fee
commit fbb46e5951
7 changed files with 62 additions and 13 deletions

View File

@ -41,6 +41,11 @@ enum class ErrorCode : uint_fast16_t {
FINDA_VS_EEPROM_DISREPANCY = 0x8008, ///< E32776 FINDA is pressed but we have no such record in EEPROM - this can only happen at the start of the MMU and can be resolved by issuing an Unload command FINDA_VS_EEPROM_DISREPANCY = 0x8008, ///< E32776 FINDA is pressed but we have no such record in EEPROM - this can only happen at the start of the MMU and can be resolved by issuing an Unload command
FSENSOR_TOO_EARLY = 0x8009, ///< E32777 FSensor triggered while doing FastFeedToBondtech - that means either:
///< - the PTFE is too short
///< - a piece of filament was left inside - pushed in front of the loaded filament causing the fsensor trigger too early
///< - fsensor is faulty producing bogus triggers
QUEUE_FULL = 0x802b, ///< E32811 internal logic error - attempt to move with a full queue QUEUE_FULL = 0x802b, ///< E32811 internal logic error - attempt to move with a full queue
VERSION_MISMATCH = 0x802c, ///< E32812 internal error of the printer - incompatible version of the MMU FW VERSION_MISMATCH = 0x802c, ///< E32812 internal error of the printer - incompatible version of the MMU FW

View File

@ -34,7 +34,7 @@ bool FeedToBondtech::Step() {
if (mi::idler.Engaged()) { if (mi::idler.Engaged()) {
dbg_logic_P(PSTR("Feed to Bondtech --> Idler engaged")); dbg_logic_P(PSTR("Feed to Bondtech --> Idler engaged"));
dbg_logic_fP(PSTR("Pulley start steps %u"), mpu::pulley.CurrentPosition_mm()); dbg_logic_fP(PSTR("Pulley start steps %u"), mpu::pulley.CurrentPosition_mm());
state = PushingFilamentToFSensor; state = PushingFilamentFast;
mpu::pulley.InitAxis(); mpu::pulley.InitAxis();
// plan a fast move while in the safe minimal length // plan a fast move while in the safe minimal length
mpu::pulley.PlanMove(config::minimumBowdenLength, config::pulleyLoadFeedrate, config::pulleySlowFeedrate); mpu::pulley.PlanMove(config::minimumBowdenLength, config::pulleyLoadFeedrate, config::pulleySlowFeedrate);
@ -42,14 +42,26 @@ bool FeedToBondtech::Step() {
mpu::pulley.PlanMove(config::maximumBowdenLength - config::minimumBowdenLength, config::pulleySlowFeedrate, config::pulleySlowFeedrate); mpu::pulley.PlanMove(config::maximumBowdenLength - config::minimumBowdenLength, config::pulleySlowFeedrate, config::pulleySlowFeedrate);
} }
return false; return false;
case PushingFilamentFast:
if (mfs::fsensor.Pressed()) {
// Safety precaution - if the fsensor triggers while pushing the filament fast, we must stop pushing immediately
// With a correctly set-up MMU this shouldn't happen
mm::motion.AbortPlannedMoves(); // stop pushing filament
state = FSensorTooEarly;
} else if (mm::motion.PlannedMoves(mm::Pulley) == 1) {
// a bit of a hack - the fast (already planned) move has finished, doing the slow part
// -> just switch to FeedingToFSensor
state = PushingFilamentToFSensor;
}
return false;
case PushingFilamentToFSensor: case PushingFilamentToFSensor:
//dbg_logic_P(PSTR("Feed to Bondtech --> Pushing")); //dbg_logic_P(PSTR("Feed to Bondtech --> Pushing"));
if (mfs::fsensor.Pressed()) { if (mfs::fsensor.Pressed()) {
mm::motion.AbortPlannedMoves(); // stop pushing filament mm::motion.AbortPlannedMoves(); // stop pushing filament
GoToPushToNozzle(); GoToPushToNozzle();
} else if (mm::motion.StallGuard(mm::Pulley)) { // } else if (mm::motion.StallGuard(mm::Pulley)) {
// stall guard occurred during movement - the filament got stuck // // stall guard occurred during movement - the filament got stuck
state = Failed; // @@TODO may be even report why it failed // state = PulleyStalled;
} else if (mm::motion.QueueEmpty()) { // all moves have been finished and the fsensor didn't switch on } else if (mm::motion.QueueEmpty()) { // all moves have been finished and the fsensor didn't switch on
state = Failed; state = Failed;
} }
@ -76,6 +88,8 @@ bool FeedToBondtech::Step() {
dbg_logic_P(PSTR("Feed to Bondtech OK")); dbg_logic_P(PSTR("Feed to Bondtech OK"));
return true; return true;
case Failed: case Failed:
case FSensorTooEarly:
// case PulleyStalled:
dbg_logic_P(PSTR("Feed to Bondtech FAILED")); dbg_logic_P(PSTR("Feed to Bondtech FAILED"));
return true; return true;
default: default:

View File

@ -14,11 +14,14 @@ struct FeedToBondtech {
/// internal states of the state machine /// internal states of the state machine
enum { enum {
EngagingIdler, EngagingIdler,
PushingFilamentFast,
PushingFilamentToFSensor, PushingFilamentToFSensor,
PushingFilamentIntoNozzle, PushingFilamentIntoNozzle,
DisengagingIdler, DisengagingIdler,
OK, OK,
Failed Failed,
FSensorTooEarly,
// PulleyStalled
}; };
inline FeedToBondtech() inline FeedToBondtech()

View File

@ -39,5 +39,7 @@ enum class ProgressCode : uint_fast8_t {
Homing, // P26 Homing, // P26
MovingSelector, // P27 MovingSelector, // P27
FeedingToFSensor, // P28
Empty = 0xff // dummy empty state Empty = 0xff // dummy empty state
}; };

View File

@ -81,9 +81,14 @@ bool ToolChange::StepInner() {
break; break;
case ProgressCode::FeedingToBondtech: case ProgressCode::FeedingToBondtech:
if (james.Step()) { if (james.Step()) {
if (james.State() == FeedToBondtech::Failed) { switch (james.State()) {
case FeedToBondtech::Failed:
GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_ON); // signal loading error GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_ON); // signal loading error
} else { break;
case FeedToBondtech::FSensorTooEarly:
GoToErrDisengagingIdler(ErrorCode::FSENSOR_TOO_EARLY); // signal loading error
break;
default:
ToolChangeFinishedCorrectly(); ToolChangeFinishedCorrectly();
} }
} }
@ -163,6 +168,15 @@ ProgressCode ToolChange::State() const {
switch (state) { switch (state) {
case ProgressCode::UnloadingFilament: case ProgressCode::UnloadingFilament:
return unl.State(); // report sub-automaton states properly return unl.State(); // report sub-automaton states properly
case ProgressCode::FeedingToBondtech:
// only process the important states
switch (james.State()) {
case FeedToBondtech::PushingFilamentToFSensor:
return ProgressCode::FeedingToFSensor;
case FeedToBondtech::PushingFilamentIntoNozzle:
return ProgressCode::FeedingToNozzle;
}
// [[fallthrough]] // everything else is reported as FeedingToBondtech
default: default:
return state; return state;
} }

View File

@ -52,14 +52,21 @@ TEST_CASE("feed_to_bondtech::feed_phase_unlimited", "[feed_to_bondtech]") {
CHECK(mm::axes[mm::Pulley].enabled); CHECK(mm::axes[mm::Pulley].enabled);
// idler engaged, selector in position, we'll start pushing filament // idler engaged, selector in position, we'll start pushing filament
REQUIRE(fb.State() == FeedToBondtech::PushingFilamentToFSensor); REQUIRE(fb.State() == FeedToBondtech::PushingFilamentFast);
// at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test) // at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test)
REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0); REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0);
// fast load - no fsensor trigger
REQUIRE(WhileCondition(
fb,
[&](uint32_t) { return fb.State() == FeedToBondtech::PushingFilamentFast; },
mm::unitToSteps<mm::P_pos_t>(config::minimumBowdenLength) + 2));
// slow load - expecting fsensor trigger
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
fb, fb,
[&](uint32_t step) { [&](uint32_t step) {
if( step == 1000 ){ if( step == 100 ){
mfs::fsensor.ProcessMessage(true); mfs::fsensor.ProcessMessage(true);
} }
return fb.State() == FeedToBondtech::PushingFilamentToFSensor; }, return fb.State() == FeedToBondtech::PushingFilamentToFSensor; },

View File

@ -42,15 +42,17 @@ void FeedingToFinda(logic::ToolChange &tc, uint8_t toSlot, uint32_t triggerAt =
} }
void FeedingToBondtech(logic::ToolChange &tc, uint8_t toSlot) { void FeedingToBondtech(logic::ToolChange &tc, uint8_t toSlot) {
// james is feeding // james is feeding fast and then slowly
// FSensor must not trigger too early
REQUIRE_FALSE(mfs::fsensor.Pressed());
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
tc, tc,
[&](uint32_t step) -> bool { [&](uint32_t step) -> bool {
if(step == 2000){ // on 2000th step make filament sensor trigger if(step == mm::unitToSteps<mm::P_pos_t>(config::minimumBowdenLength)+10){ // on the correct step make filament sensor trigger
mfs::fsensor.ProcessMessage(true); mfs::fsensor.ProcessMessage(true);
} }
return tc.TopLevelState() == ProgressCode::FeedingToBondtech; }, return tc.TopLevelState() == ProgressCode::FeedingToBondtech; },
20000UL)); mm::unitToSteps<mm::P_pos_t>(config::minimumBowdenLength) + 10000));
REQUIRE(VerifyState(tc, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), toSlot, true, false, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK)); REQUIRE(VerifyState(tc, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), toSlot, true, false, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK));
} }
@ -73,7 +75,9 @@ void ToolChange(logic::ToolChange &tc, uint8_t fromSlot, uint8_t toSlot) {
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
tc, tc,
[&](uint32_t step) -> bool { [&](uint32_t step) -> bool {
if(step == 2000){ // on 2000th step make FINDA trigger if(step == 20){ // on 20th step make FSensor switch off
mfs::fsensor.ProcessMessage(false);
} else if(step == mm::unitToSteps<mm::P_pos_t>(config::minimumBowdenLength)){ // on 2000th step make FINDA trigger
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
} }
return tc.TopLevelState() == ProgressCode::UnloadingFilament; }, return tc.TopLevelState() == ProgressCode::UnloadingFilament; },