Skip to content
1 change: 1 addition & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ static constexpr U_mm pulleyHelperMove = 10.0_mm; ///< Helper move for Load/Unlo
static constexpr U_mm cutLength = 8.0_mm;
static constexpr U_mm fsensorToNozzle = 30.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 fsensorToNozzleAvoidGrindUnload = 20.0_mm;
/// Check the state of FSensor after this amount of filament got (hopefully) pulled out while unloading.
static constexpr U_mm fsensorUnloadCheckDistance = 40.0_mm;

Expand Down
2 changes: 1 addition & 1 deletion src/logic/command_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ void CommandBase::ErrDisengagingIdler() {
void CommandBase::GoToErrDisengagingIdler(ErrorCode deferredEC) {
state = ProgressCode::ERRDisengagingIdler;
deferredErrorCode = deferredEC;
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::blink0);
ml::leds.ActiveSlotError();
mi::idler.Disengage();
}

Expand Down
8 changes: 4 additions & 4 deletions src/logic/cut_filament.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@ bool CutFilament::StepInner() {
// move selector aside - prepare the blade into active position
state = ProgressCode::PreparingBlade;
mg::globals.SetFilamentLoaded(cutSlot, mg::FilamentLoadState::AtPulley);
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
Comment thread
gudnimg marked this conversation as resolved.
ml::leds.ActiveSlotProcessing();
MoveSelector(cutSlot + 1);
}
}
break;
case ProgressCode::PreparingBlade:
if (ms::selector.Slot() == cutSlot + 1) {
state = ProgressCode::PushingFilament;
mpu::pulley.PlanMove(mg::globals.CutLength() + config::cuttingEdgeRetract, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(mg::globals.CutLength() + config::cuttingEdgeRetract, mg::globals.PulleySlowFeedrate_mm_s());
}
break;
case ProgressCode::PushingFilament:
Expand Down Expand Up @@ -123,7 +123,7 @@ bool CutFilament::StepInner() {
// revert move speed
mg::globals.SetSelectorFeedrate_mm_s(savedSelectorFeedRate_mm_s);
ms::selector.InvalidateHoming();
mpu::pulley.PlanMove(-config::cuttingEdgeRetract, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(-config::cuttingEdgeRetract, mg::globals.PulleySlowFeedrate_mm_s());
}
break;
case ProgressCode::Homing:
Expand All @@ -134,7 +134,7 @@ bool CutFilament::StepInner() {
case ProgressCode::ReturningSelector:
if (ms::selector.State() == ms::selector.Ready) {
FinishedOK();
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::on, ml::off);
ml::leds.ActiveSlotDonePrimed();
}
break;
case ProgressCode::OK:
Expand Down
2 changes: 1 addition & 1 deletion src/logic/eject_filament.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ bool EjectFilament::StepInner() {
if (mi::idler.Engaged()) {
state = ProgressCode::EjectingFilament;
mpu::pulley.InitAxis();
mpu::pulley.PlanMove(config::ejectFromCuttingEdge, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(config::ejectFromCuttingEdge, mg::globals.PulleySlowFeedrate_mm_s());
}
break;
case ProgressCode::EjectingFilament:
Expand Down
6 changes: 3 additions & 3 deletions src/logic/feed_to_bondtech.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void FeedToBondtech::Reset(uint8_t maxRetries) {
dbg_logic_P(PSTR("\nFeed to Bondtech\n\n"));
state = EngagingIdler;
this->maxRetries = maxRetries;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
ml::leds.ActiveSlotProcessing();
mi::idler.Engage(mg::globals.ActiveSlot());
}

Expand Down Expand Up @@ -78,7 +78,7 @@ bool FeedToBondtech::Step() {
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
mi::idler.PartiallyDisengage(mg::globals.ActiveSlot());
// while disengaging the idler, keep on moving with the pulley to avoid grinding while the printer is trying to grab the filament itself
mpu::pulley.PlanMove(config::fsensorToNozzleAvoidGrind, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(config::fsensorToNozzleAvoidGrind, mg::globals.PulleySlowFeedrate_mm_s());
state = PartiallyDisengagingIdler;
}
return false;
Expand All @@ -95,7 +95,7 @@ bool FeedToBondtech::Step() {
dbg_logic_P(PSTR("Feed to Bondtech --> Idler disengaged"));
dbg_logic_fP(PSTR("Pulley end steps %u"), mpu::pulley.CurrentPosition_mm());
state = OK;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
ml::leds.ActiveSlotDonePrimed();
}
return false;
case OK:
Expand Down
10 changes: 5 additions & 5 deletions src/logic/feed_to_finda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ bool FeedToFinda::Reset(bool feedPhaseLimited, bool haltAtEnd) {
state = EngagingIdler;
this->feedPhaseLimited = feedPhaseLimited;
this->haltAtEnd = haltAtEnd;
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
ml::leds.ActiveSlotProcessing();
if (ms::selector.MoveToSlot(mg::globals.ActiveSlot()) != ms::Selector::OperationResult::Accepted) {
// We can't get any FINDA readings if the selector is at the wrong spot - move it accordingly if necessary
// And prevent issuing any commands to the idler in such an error state
Expand All @@ -44,14 +44,14 @@ bool FeedToFinda::Step() {
// mpu::pulley.PlanMove(config::filamentMinLoadedToMMU, config::pulleySlowFeedrate);
// }

mpu::pulley.PlanMove(config::maximumFeedToFinda, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(config::maximumFeedToFinda, mg::globals.PulleySlowFeedrate_mm_s());
if (feedPhaseLimited) {
state = PushingFilament;
} else {
state = PushingFilamentUnlimited;
// in unlimited move we plan 2 moves at once to make the move "seamless"
// one move has already been planned above, this is the second one
mpu::pulley.PlanMove(config::maximumFeedToFinda, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(config::maximumFeedToFinda, mg::globals.PulleySlowFeedrate_mm_s());
}
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector);
mui::userInput.Clear(); // remove all buffered events if any just before we wait for some input
Expand All @@ -68,7 +68,7 @@ bool FeedToFinda::Step() {
return true; // return immediately to allow for a seamless planning of another move (like feeding to bondtech)
} else if (mm::motion.QueueEmpty()) { // all moves have been finished and FINDA didn't switch on
state = Failed;
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::blink0);
ml::leds.ActiveSlotError();
}
}
return false;
Expand All @@ -85,7 +85,7 @@ bool FeedToFinda::Step() {
return true; // return immediately to allow for a seamless planning of another move (like feeding to bondtech)
} else if (mm::motion.PlannedMoves(mm::Pulley) < 2) {
// plan another move to make the illusion of unlimited moves
mpu::pulley.PlanMove(config::maximumFeedToFinda, config::pulleySlowFeedrate);
mpu::pulley.PlanMove(config::maximumFeedToFinda, mg::globals.PulleySlowFeedrate_mm_s());
}
}
return false;
Expand Down
2 changes: 0 additions & 2 deletions src/logic/load_filament.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ void logic::LoadFilament::Reset2(bool feedPhaseLimited) {
if (!feed.Reset(feedPhaseLimited, true)) {
// selector refused to move
GoToErrDisengagingIdler(ErrorCode::FINDA_FLICKERS);
} else {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/logic/retract_from_finda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace logic {
void RetractFromFinda::Reset() {
dbg_logic_P(PSTR("\nRetract from FINDA\n\n"));
state = EngagingIdler;
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
ml::leds.ActiveSlotProcessing();
mi::idler.Engage(mg::globals.ActiveSlot());
}

Expand All @@ -33,10 +33,10 @@ bool RetractFromFinda::Step() {
state = OK;
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley);
dbg_logic_fP(PSTR("Pulley end steps %u"), mpu::pulley.CurrentPosition_mm());
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.ActiveSlotDoneEmpty();
} else { // FINDA didn't switch off
state = Failed;
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::blink0);
ml::leds.ActiveSlotError();
}
}
return false;
Expand Down
11 changes: 5 additions & 6 deletions src/logic/tool_change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ bool ToolChange::Reset(uint8_t param) {
if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::InSelector) {
dbg_logic_P(PSTR("Filament is loaded --> unload"));
state = ProgressCode::UnloadingFilament;
unl.Reset(mg::globals.ActiveSlot());
unl.Reset2(mg::globals.ActiveSlot());
} else {
mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::InSelector); // activate the correct slot, feed uses that
if (feed.Reset(true, false)) {
Expand All @@ -54,20 +54,19 @@ bool ToolChange::Reset(uint8_t param) {
return true;
}

void logic::ToolChange::GoToFeedingToBondtech() {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
void ToolChange::GoToFeedingToBondtech() {
james.Reset(3);
state = ProgressCode::FeedingToBondtech;
error = ErrorCode::RUNNING;
}

void logic::ToolChange::ToolChangeFinishedCorrectly() {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::on, ml::off);
void ToolChange::ToolChangeFinishedCorrectly() {
ml::leds.ActiveSlotDonePrimed();
mui::userInput.SetPrinterInCharge(false);
FinishedOK();
}

void logic::ToolChange::GoToFeedingToFinda() {
void ToolChange::GoToFeedingToFinda() {
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::AtPulley);
Expand Down
14 changes: 12 additions & 2 deletions src/logic/unload_filament.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,17 @@ bool UnloadFilament::Reset(uint8_t /*param*/) {
mpu::pulley.InitAxis();
state = ProgressCode::UnloadingToFinda;
error = ErrorCode::RUNNING;
skipDisengagingIdler = false;
unl.Reset(maxRetries);
ml::leds.SetAllOff();
return true;
}

bool UnloadFilament::Reset2(uint8_t param) {
bool rv = Reset(param);
skipDisengagingIdler = true;
return rv;
}

void UnloadFilament::UnloadFinishedCorrectly() {
FinishedOK();
mpu::pulley.Disable();
Expand Down Expand Up @@ -77,7 +83,11 @@ bool UnloadFilament::StepInner() {
GoToErrDisengagingIdler(ErrorCode::FINDA_DIDNT_SWITCH_OFF); // signal unloading error
} else {
state = ProgressCode::DisengagingIdler;
mi::idler.Disengage();
if (skipDisengagingIdler && ms::selector.State() == ms::Selector::Ready) {
UnloadFinishedCorrectly(); // skip disengaging the Idler - to be used inside ToolChange to speed up
} else {
mi::idler.Disengage();
}
}
}
return false;
Expand Down
6 changes: 5 additions & 1 deletion src/logic/unload_filament.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ namespace logic {
class UnloadFilament : public CommandBase {
public:
inline constexpr UnloadFilament()
: CommandBase() {}
: CommandBase()
, skipDisengagingIdler(false) {}

/// Restart the automaton
/// @param param is not used, always unloads from the active slot
bool Reset(uint8_t param) override;

bool Reset2(uint8_t param);

/// @returns true if the state machine finished its job, false otherwise
bool StepInner() override;

Expand All @@ -32,6 +35,7 @@ class UnloadFilament : public CommandBase {
UnloadToFinda unl;
FeedToFinda feed;
RetractFromFinda retract;
bool skipDisengagingIdler;
};

/// The one and only instance of UnloadFilament state machine in the FW
Expand Down
43 changes: 34 additions & 9 deletions src/logic/unload_to_finda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../modules/motion.h"
#include "../modules/permanent_storage.h"
#include "../modules/pulley.h"
#include "../modules/timebase.h"

namespace logic {

Expand All @@ -19,19 +20,40 @@ void UnloadToFinda::Reset(uint8_t maxTries) {
} else {
// FINDA is sensing the filament, plan moves to unload it
state = EngagingIdler;
mi::idler.Engage(mg::globals.ActiveSlot());
mi::idler.PartiallyDisengage(mg::globals.ActiveSlot()); // basically prepare before the active slot - saves ~1s
started_ms = mt::timebase.Millis();
ml::leds.ActiveSlotProcessing();
}
}

bool UnloadToFinda::Step() {
switch (state) {
// start by engaging the idler into intermediate position
// Then, wait for !fsensor.Pressed: that's to speed-up the pull process - unload operation will be started during the purging moves
// and as soon as the fsensor turns off, the MMU engages the idler fully and starts pulling.
// It will not wait for the extruder to finish the relieve move.
// However, such an approach breaks running the MMU on a non-reworked MK4/C1, which hasn't been officially supported, but possible (with some level of uncertainity).
case EngagingIdler:
if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::InSelector) {
state = UnloadingToFinda;
mpu::pulley.InitAxis();
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
if (!mi::idler.PartiallyDisengaged()) { // just waiting for Idler to get into the target intermediate position
return false;
}
if (mfs::fsensor.Pressed()) { // still pressed, printer didn't free the filament yet
if (mt::timebase.Elapsed(started_ms, 4000)) {
state = FailedFSensor; // fsensor didn't turn off within 4 seconds, something is seriously wrong
}
return false;
} else {
state = FailedFINDA;
// fsensor is OFF and Idler is partially engaged, engage the Idler fully and pull
if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::InSelector) {
state = UnloadingToFinda;
mpu::pulley.InitAxis();
mi::idler.Engage(mg::globals.ActiveSlot());

// slow move for the first few millimeters - help the printer relieve the filament while engaging the Idler fully
mpu::pulley.PlanMove(-config::fsensorToNozzleAvoidGrindUnload, mg::globals.PulleySlowFeedrate_mm_s(), mg::globals.PulleySlowFeedrate_mm_s());
} else {
state = FailedFINDA;
}
}
return false;
case UnloadingToFinda:
Expand All @@ -55,17 +77,20 @@ bool UnloadToFinda::Step() {
// 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);
ml::leds.ActiveSlotDoneEmpty();
} else if (!mf::finda.Pressed()) {
// detected end of filament
state = OK;
mm::motion.AbortPlannedMoves(); // stop rotating the pulley
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.ActiveSlotDoneEmpty();
} else if (/*tmc2130_read_gstat() &&*/ mm::motion.QueueEmpty()) {
// we reached the end of move queue, but the FINDA didn't switch off
// two possible causes - grinded filament or malfunctioning FINDA
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 {
state = FailedFINDA;
}
Expand Down
4 changes: 3 additions & 1 deletion src/logic/unload_to_finda.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ struct UnloadToFinda {
inline constexpr UnloadToFinda()
: state(OK)
, maxTries(3)
, unloadStart_mm(0) {}
, unloadStart_mm(0)
, started_ms(0) {}

/// Restart the automaton
/// @param maxTries maximum number of retried attempts before reporting a fail
Expand All @@ -40,6 +41,7 @@ struct UnloadToFinda {
uint8_t state;
uint8_t maxTries;
int32_t unloadStart_mm; // intentionally trying to avoid using U_mm because it is a float (reps. long double)
uint16_t started_ms; // timeout on fsensor turn off
};

} // namespace logic
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ static void setup2() {

// activate the correct LED if filament is present
if (mg::globals.FilamentLoaded() > mg::FilamentLoadState::AtPulley) {
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
ml::leds.ActiveSlotDonePrimed();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/modules/idler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Idler::OperationResult Idler::PlanMoveInner(uint8_t slot, Operation plannedOp) {
}

// already engaged or disengaged
if (currentlyEngaged == plannedMove) {
if (currentlyEngaged == plannedMove && currentSlot == plannedSlot) {
return OperationResult::Accepted;
}

Expand Down
17 changes: 17 additions & 0 deletions src/modules/leds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "leds.h"
#include "../hal/shr16.h"
#include "timebase.h"
#include "globals.h"

namespace modules {
namespace leds {
Expand Down Expand Up @@ -68,5 +69,21 @@ void LEDs::SetAllOff() {
}
}

void LEDs::ActiveSlotProcessing() {
SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
}

void LEDs::ActiveSlotError() {
SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::blink0);
}

void LEDs::ActiveSlotDoneEmpty() {
SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
}

void LEDs::ActiveSlotDonePrimed() {
SetPairButOffOthers(mg::globals.ActiveSlot(), ml::on, ml::off);
}

} // namespace leds
} // namespace modules
Loading