Avoid trying to unload filament when not loaded

however, it looks like the EEPROM is not updated correctly, needs more testing
pull/134/head
D.R.racer 2021-10-15 10:16:13 +02:00 committed by DRracer
parent 04348b2d86
commit 9438253106
22 changed files with 97 additions and 51 deletions

View File

@ -19,6 +19,7 @@
namespace config {
static constexpr const uint8_t toolCount = 5U; ///< Max number of extruders/tools/slots
static_assert(toolCount < 15, "Up to 14 valid slots (+1 parking) is supported in EEPROM storage");
// Printer's filament sensor setup
static constexpr const uint16_t fsensorDebounceMs = 10;

View File

@ -69,7 +69,7 @@ bool CutFilament::StepInner() {
if (mm::motion.QueueEmpty()) { // idler and selector finished their moves
// move selector aside - prepare the blade into active position
state = ProgressCode::PreparingBlade;
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::AtPulley);
mg::globals.SetFilamentLoaded(cutSlot, mg::FilamentLoadState::AtPulley);
ms::selector.MoveToSlot(cutSlot + 1);
}
case ProgressCode::PreparingBlade:

View File

@ -66,7 +66,7 @@ bool EjectFilament::StepInner() {
case ProgressCode::DisengagingIdler:
if (!mi::idler.Engaged()) { // idler disengaged
mm::motion.Disable(mm::Pulley);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::NotLoaded);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::NotLoaded);
state = ProgressCode::OK;
error = ErrorCode::OK;
}

View File

@ -35,7 +35,7 @@ bool FeedToBondtech::Step() {
//dbg_logic_P(PSTR("Feed to Bondtech --> Pushing"));
if (mfs::fsensor.Pressed()) {
mm::motion.AbortPlannedMoves(); // stop pushing filament
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InFSensor);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InFSensor);
// plan a slow move to help push filament into the nozzle
//@@TODO the speed in mm/s must correspond to printer's feeding speed!
mm::motion.PlanMove<mm::Pulley>(config::fsensorToNozzle, config::pulleySlowFeedrate);
@ -49,7 +49,7 @@ bool FeedToBondtech::Step() {
return false;
case PushingFilamentIntoNozzle:
if (mm::motion.QueueEmpty()) {
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
mi::idler.Disengage();
// while disengaging the idler, keep on moving with the pulley to avoid grinding while the printer is trying to grab the filament itself
mm::motion.PlanMove<mm::Pulley>(config::fsensorToNozzleAvoidGrind, config::pulleySlowFeedrate);

View File

@ -29,11 +29,12 @@ bool FeedToFinda::Step() {
dbg_logic_fP(PSTR("Pulley start steps %u"), mm::motion.CurPosition(mm::Pulley));
state = PushingFilament;
mm::motion.InitAxis(mm::Pulley);
if (mg::globals.FilamentLoaded() == mg::FilamentLoadState::NotLoaded) { // feed slowly filament to PTFE
mm::motion.PlanMove<mm::Pulley>(config::filamentMinLoadedToMMU, config::pulleySlowFeedrate);
}
// @@TODO this may never happen as load filament always assumes the filament is at least at the pulley
// if (mg::globals.FilamentLoaded() == mg::FilamentLoadState::NotLoaded) { // feed slowly filament to PTFE
// mm::motion.PlanMove<mm::Pulley>(config::filamentMinLoadedToMMU, config::pulleySlowFeedrate);
// }
mm::motion.PlanMove<mm::Pulley>(config::feedToFinda, config::pulleyFeedrate);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InSelector);
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
}
return false;
@ -41,7 +42,7 @@ 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
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InSelector);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector);
dbg_logic_P(PSTR("Feed to Finda --> Idler disengaged"));
dbg_logic_fP(PSTR("Pulley end steps %u"), mm::motion.CurPosition(mm::Pulley));
state = OK;

View File

@ -21,7 +21,7 @@ void LoadFilament::Reset(uint8_t param) {
dbg_logic_P(PSTR("Load Filament"));
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
mg::globals.SetActiveSlot(param);
mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet
feed.Reset(true);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);

View File

@ -30,7 +30,7 @@ bool RetractFromFinda::Step() {
if (mm::motion.QueueEmpty()) { // all moves have been finished
if (!mf::finda.Pressed()) { // FINDA switched off correctly while the move was performed
state = OK;
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::AtPulley);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley);
dbg_logic_fP(PSTR("Pulley end steps %u"), mm::motion.CurPosition(mm::Pulley));
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
} else { // FINDA didn't switch off

View File

@ -38,7 +38,7 @@ void ToolChange::Reset(uint8_t param) {
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
dbg_logic_P(PSTR("Filament is not loaded --> load"));
mg::globals.SetActiveSlot(plannedSlot);
mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::InSelector);
feed.Reset(true);
}
}
@ -52,7 +52,7 @@ bool ToolChange::StepInner() {
// There is no way the UnloadFilament to finish in an error state
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
mg::globals.SetActiveSlot(plannedSlot);
mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::AtPulley);
feed.Reset(true);
}
break;

View File

@ -14,6 +14,13 @@ namespace logic {
UnloadFilament unloadFilament;
void UnloadFilament::Reset(uint8_t /*param*/) {
if (!mf::finda.Pressed() && mg::globals.FilamentLoaded() < mg::FilamentLoadState::InSelector) {
// it looks like we have nothing in the PTFE tube, at least FINDA doesn't sense anything
// so the filament has been probably already unloaded - terminate with OK or report an error?
return;
}
// unloads filament from extruder - filament is above Bondtech gears
mm::motion.InitAxis(mm::Pulley);
state = ProgressCode::UnloadingToFinda;
@ -59,7 +66,7 @@ bool UnloadFilament::StepInner() {
state = ProgressCode::OK;
error = ErrorCode::OK;
mm::motion.Disable(mm::Pulley);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::AtPulley); // filament unloaded
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley); // filament unloaded
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);
}

View File

@ -35,7 +35,7 @@ bool UnloadToFinda::Step() {
case UnloadingToFinda:
if (mi::idler.Engaged()) {
state = WaitingForFINDA;
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InSelector);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector);
mm::motion.PlanMove<mm::Pulley>(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, config::pulleyFeedrate); // @@TODO constants
}
return false;

View File

@ -1,5 +1,6 @@
/// @file globals.cpp
#include "globals.h"
#include "../config/config.h"
#include "permanent_storage.h"
namespace modules {
@ -9,7 +10,14 @@ Globals globals;
void Globals::Init() {
mps::FilamentLoaded::get(activeSlot); //@@TODO check for errors
// @@TODO where to obtain information whether a slot is loaded with a filament?
if (activeSlot < config::toolCount) {
// some valid slot has been recorded in EEPROM - we have some filament loaded in the selector or even in the nozzle
filamentLoaded = FilamentLoadState::InNozzle; // let's assume the filament is down to the nozzle as a worst case scenario
} else {
// the filament is not present in the selector - we can move the selector freely
filamentLoaded = FilamentLoadState::AtPulley;
}
}
uint8_t Globals::ActiveSlot() const {
@ -18,15 +26,28 @@ uint8_t Globals::ActiveSlot() const {
void Globals::SetActiveSlot(uint8_t newActiveSlot) {
activeSlot = newActiveSlot;
mps::FilamentLoaded::set(activeSlot);
}
FilamentLoadState Globals::FilamentLoaded() const {
return filamentLoaded;
}
void Globals::SetFilamentLoaded(FilamentLoadState newFilamentLoaded) {
void Globals::SetFilamentLoaded(uint8_t slot, FilamentLoadState newFilamentLoaded) {
filamentLoaded = newFilamentLoaded;
SetActiveSlot(slot);
switch (newFilamentLoaded) {
case FilamentLoadState::NotLoaded:
case FilamentLoadState::AtPulley:
// Clear the active slot (basically sets the active slot to config::toolCount)
mps::FilamentLoaded::set(config::toolCount);
break;
case FilamentLoadState::InSelector:
case FilamentLoadState::InFSensor:
case FilamentLoadState::InNozzle:
// Record a valid active slot
mps::FilamentLoaded::set(slot);
break;
}
}
uint16_t Globals::DriveErrors() const {

View File

@ -28,28 +28,22 @@ static_assert(
"incorrect order of Slot Filament Load States");
/// Globals keep track of global state variables in the firmware.
/// So far only Active slot and Filament loaded variables are used.
class Globals {
public:
/// Initializes the global storage hive - basically looks into EEPROM to gather information.
void Init();
/// @returns active filament slot on the MMU unit
/// @returns active filament slot on the MMU unit. This value basically means there is some piece of filament blocking the selector from moving freely.
/// Slots are numbered 0-4
uint8_t ActiveSlot() const;
/// Sets the active slot, usually after some command/operation.
/// Also updates the EEPROM records accordingly
/// @param newActiveSlot the new slot index to set
void SetActiveSlot(uint8_t newActiveSlot);
/// @returns true if filament is considered as loaded
FilamentLoadState FilamentLoaded() const;
/// Sets the filament loaded flag value, usually after some command/operation.
/// Also updates the EEPROM records accordingly
/// @param newFilamentLoaded new state
void SetFilamentLoaded(FilamentLoadState newFilamentLoaded);
void SetFilamentLoaded(uint8_t slot, FilamentLoadState newFilamentLoaded);
/// @returns the total number of MMU errors so far
/// Errors are stored in the EEPROM
@ -68,6 +62,11 @@ public:
bool MotorsStealth() const { return stealthMode; }
private:
/// Sets the active slot, usually after some command/operation.
/// Also updates the EEPROM records accordingly
/// @param newActiveSlot the new slot index to set
void SetActiveSlot(uint8_t newActiveSlot);
uint8_t activeSlot;
FilamentLoadState filamentLoaded;
bool stealthMode;

View File

@ -228,7 +228,7 @@ bool FilamentLoaded::get(uint8_t &filament) {
return false;
const uint8_t rawFilament = ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilament[index]));
filament = 0x0f & rawFilament;
if (filament > 4)
if (filament >= config::toolCount)
return false;
const uint8_t status = getStatus();
if (!(status == KeyFront1

View File

@ -24,7 +24,7 @@ using Catch::Matchers::Equals;
void CutSlot(logic::CutFilament &cf, uint8_t cutSlot) {
ForceReinitAllAutomata();
EnsureActiveSlotIndex(0);
EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley);
REQUIRE(VerifyEnvironmentState(mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off));

View File

@ -39,9 +39,7 @@ void FailingIdler(hal::tmc2130::ErrorFlags ef, ErrorCode ec) {
ForceReinitAllAutomata();
// change the startup to what we need here
EnsureActiveSlotIndex(0);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
EnsureActiveSlotIndex(0, mg::FilamentLoadState::InNozzle);
// set FINDA ON + debounce
SetFINDAStateAndDebounce(true);

View File

@ -122,7 +122,7 @@ void InvalidSlot(SM &logicSM, uint8_t activeSlot, uint8_t invSlot){
REQUIRE(VerifyEnvironmentState(mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), ms::Selector::IdleSlotIndex(), false, false, ml::off, ml::off));
EnsureActiveSlotIndex(activeSlot);
EnsureActiveSlotIndex(activeSlot, mg::FilamentLoadState::AtPulley);
logicSM.Reset(invSlot);
REQUIRE(VerifyState(logicSM, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), activeSlot, false, false, ml::off, ml::off, ErrorCode::INVALID_TOOL, ProgressCode::OK));

View File

@ -25,7 +25,7 @@ void LoadFilamentCommonSetup(uint8_t slot, logic::LoadFilament &lf) {
ForceReinitAllAutomata();
// change the startup to what we need here
EnsureActiveSlotIndex(slot);
EnsureActiveSlotIndex(slot, mg::FilamentLoadState::AtPulley);
// verify startup conditions
REQUIRE(VerifyState(lf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));

View File

@ -65,8 +65,7 @@ void ForceReinitAllAutomata() {
mm::ReinitMotion();
// let's assume we have the filament NOT loaded and active slot 0
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::AtPulley);
mg::globals.SetActiveSlot(0);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley);
}
void HomeIdlerAndSelector() {
@ -86,7 +85,7 @@ void HomeIdlerAndSelector() {
main_loop();
}
void EnsureActiveSlotIndex(uint8_t slot) {
void EnsureActiveSlotIndex(uint8_t slot, mg::FilamentLoadState loadState) {
HomeIdlerAndSelector();
// move selector to the right spot
@ -94,7 +93,8 @@ void EnsureActiveSlotIndex(uint8_t slot) {
while (ms::selector.Slot() != slot)
main_loop();
mg::globals.SetActiveSlot(slot);
// mg::globals.SetActiveSlot(slot);
mg::globals.SetFilamentLoaded(slot, loadState);
}
void SetFINDAStateAndDebounce(bool press) {

View File

@ -1,5 +1,6 @@
#pragma once
#include "../../../../src/logic/command_base.h"
#include "../../../../src/modules/globals.h"
extern void main_loop();
extern void ForceReinitAllAutomata();
@ -21,7 +22,7 @@ bool WhileTopState(SM &sm, ProgressCode state, uint32_t maxLoops = 5000) {
sm, [&](int) { return sm.TopLevelState() == state; }, maxLoops);
}
extern void EnsureActiveSlotIndex(uint8_t slot);
extern void EnsureActiveSlotIndex(uint8_t slot, modules::globals::FilamentLoadState loadState);
extern void SetFINDAStateAndDebounce(bool press);

View File

@ -50,7 +50,7 @@ void FeedingToBondtech(logic::ToolChange &tc, uint8_t toSlot) {
void ToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
ForceReinitAllAutomata();
EnsureActiveSlotIndex(fromSlot);
EnsureActiveSlotIndex(fromSlot, mg::FilamentLoadState::InNozzle);
// restart the automaton
tc.Reset(toSlot);
@ -63,7 +63,9 @@ void ToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
}
return tc.TopLevelState() == ProgressCode::UnloadingFilament; },
200000UL));
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::AtPulley);
CHECKED_ELSE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::AtPulley) {
++toSlot;
}
FeedingToFinda(tc, toSlot);
@ -78,9 +80,7 @@ void NoToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
ForceReinitAllAutomata();
// the filament is LOADED
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
EnsureActiveSlotIndex(fromSlot);
EnsureActiveSlotIndex(fromSlot, mg::FilamentLoadState::InNozzle);
REQUIRE(VerifyEnvironmentState(mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), toSlot, false, false, ml::off, ml::off));
@ -95,7 +95,7 @@ void NoToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
void JustLoadFilament(logic::ToolChange tc, uint8_t slot) {
ForceReinitAllAutomata();
EnsureActiveSlotIndex(slot);
EnsureActiveSlotIndex(slot, mg::FilamentLoadState::AtPulley);
// verify filament NOT loaded
REQUIRE(VerifyEnvironmentState(mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off));

View File

@ -26,9 +26,7 @@ void RegularUnloadFromSlot04Init(uint8_t slot, logic::UnloadFilament &uf) {
ForceReinitAllAutomata();
// change the startup to what we need here
EnsureActiveSlotIndex(slot);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
EnsureActiveSlotIndex(slot, mg::FilamentLoadState::InNozzle);
// set FINDA ON + debounce
SetFINDAStateAndDebounce(true);
@ -102,12 +100,12 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) {
// change the startup to what we need here
// move selector to the right spot
EnsureActiveSlotIndex(slot);
EnsureActiveSlotIndex(slot, mg::FilamentLoadState::InNozzle);
// set FINDA ON + debounce
SetFINDAStateAndDebounce(true);
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
// mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
// verify startup conditions
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
@ -265,3 +263,23 @@ TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_fil
RegularUnloadFromSlot04(slot, uf);
}
}
TEST_CASE("unload_filament::not_loaded", "[unload_filament]") {
logic::UnloadFilament uf;
// prepare startup conditions
ForceReinitAllAutomata();
// change the startup to what we need here
// move selector to the right spot
EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley);
// verify startup conditions
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
// restart the automaton
uf.Reset(0);
// Stage 0 - unload filament should finish immediately as there is no filament loaded
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
}

View File

@ -28,7 +28,7 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
// we need finda ON
SetFINDAStateAndDebounce(true);
// and MMU "thinks" it has the filament loaded
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
logic::UnloadToFinda ff;
@ -82,7 +82,7 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
// we need finda ON
SetFINDAStateAndDebounce(true);
// and MMU "thinks" it has the filament loaded
mg::globals.SetFilamentLoaded(mg::FilamentLoadState::InNozzle);
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
logic::UnloadToFinda ff;