Fix ToolChange operation + unit tests

pull/126/head
D.R.racer 2021-09-27 09:49:14 +02:00 committed by DRracer
parent 505930c576
commit bbd14ed217
5 changed files with 121 additions and 44 deletions

View File

@ -81,11 +81,8 @@ bool LoadFilament::StepInner() {
break;
case ProgressCode::OK:
return true;
case ProgressCode::ERRDisengagingIdler: // couldn't unload to FINDA
if (!mi::idler.Engaged()) {
state = ProgressCode::ERRWaitingForUser;
mui::userInput.Clear(); // remove all buffered events if any just before we wait for some input
}
case ProgressCode::ERRDisengagingIdler: // couldn't load to FINDA
ErrDisengagingIdler();
return false;
case ProgressCode::ERRWaitingForUser: {
// waiting for user buttons and/or a command from the printer

View File

@ -7,6 +7,7 @@
#include "../modules/motion.h"
#include "../modules/permanent_storage.h"
#include "../modules/selector.h"
#include "../modules/user_input.h"
#ifdef DEBUG_LOGIC
#include "../hal/usart.h"
#include <string.h>
@ -41,11 +42,13 @@ void ToolChange::Reset(uint8_t param) {
state = ProgressCode::UnloadingFilament;
unl.Reset(mg::globals.ActiveSlot());
} else {
state = ProgressCode::LoadingFilament;
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
#ifdef DEBUG_LOGIC
hu::usart1.puts("Filament is not loaded --> load\n");
#endif //DEBUG_LOGIC
load.Reset(plannedSlot);
mg::globals.SetActiveSlot(plannedSlot);
feed.Reset(true);
}
}
@ -56,21 +59,85 @@ bool ToolChange::StepInner() {
// unloading sequence finished - basically, no errors can occurr here
// as UnloadFilament should handle all the possible error states on its own
// There is no way the UnloadFilament to finish in an error state
state = ProgressCode::LoadingFilament;
load.Reset(plannedSlot);
state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING;
feed.Reset(true);
}
break;
case ProgressCode::LoadingFilament:
if (load.StepInner()) {
// loading sequence finished - basically, no errors can occurr here
// as LoadFilament should handle all the possible error states on its own
// There is no way the LoadFilament to finish in an error state
case ProgressCode::FeedingToFinda:
if (feed.Step()) {
if (feed.State() == FeedToFinda::Failed) {
state = ProgressCode::ERRDisengagingIdler;
error = ErrorCode::FINDA_DIDNT_SWITCH_ON;
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::FeedingToBondtech;
james.Reset(3);
}
}
break;
case ProgressCode::FeedingToBondtech:
if (james.Step()) {
if (james.State() == FeedToBondtech::Failed) {
state = ProgressCode::ERRDisengagingIdler;
error = ErrorCode::FSENSOR_DIDNT_SWITCH_ON;
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 {
mg::globals.SetFilamentLoaded(true);
state = ProgressCode::OK;
error = ErrorCode::OK;
}
}
break;
case ProgressCode::OK:
return true;
// @@TODO error handling definitely needs unifying with the LoadFilament state machine
case ProgressCode::ERRDisengagingIdler:
ErrDisengagingIdler();
return false;
case ProgressCode::ERRWaitingForUser: {
// waiting for user buttons and/or a command from the printer
mui::Event ev = mui::userInput.ConsumeEvent();
switch (ev) {
case mui::Event::Left: // try to manually load just a tiny bit - help the filament with the pulley
state = ProgressCode::ERREngagingIdler;
mi::idler.Engage(mg::globals.ActiveSlot());
break;
case mui::Event::Middle: // try again the whole sequence
Reset(mg::globals.ActiveSlot());
break;
case mui::Event::Right: // problem resolved - the user pushed the fillament by hand?
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
// mm::motion.PlanMove(mm::Pulley, 450, 5000); // @@TODO constants
state = ProgressCode::AvoidingGrind;
break;
default: // no event, continue waiting for user input
break;
}
return false;
}
case ProgressCode::ERREngagingIdler:
if (mi::idler.Engaged()) {
state = ProgressCode::ERRHelpingFilament;
mm::motion.PlanMove(mm::Pulley, 450, 5000); //@@TODO constants
}
return false;
case ProgressCode::ERRHelpingFilament:
if (mf::finda.Pressed()) {
// the help was enough to press the FINDA, we are ok, continue normally
state = ProgressCode::FeedingToBondtech;
error = ErrorCode::RUNNING;
} else if (mm::motion.QueueEmpty()) {
// helped a bit, but FINDA didn't trigger, return to the main error state
state = ProgressCode::ERRDisengagingIdler;
}
return false;
default: // we got into an unhandled state, better report it
state = ProgressCode::ERRInternal;
error = ErrorCode::INTERNAL;
@ -83,8 +150,6 @@ ProgressCode ToolChange::State() const {
switch (state) {
case ProgressCode::UnloadingFilament:
return unl.State(); // report sub-automaton states properly
case ProgressCode::LoadingFilament:
return load.State(); // report sub-automaton states properly
default:
return state;
}
@ -92,10 +157,10 @@ ProgressCode ToolChange::State() const {
ErrorCode ToolChange::Error() const {
switch (state) {
case ProgressCode::UnloadingFilament:
return unl.Error(); // report sub-automaton errors properly
case ProgressCode::LoadingFilament:
return load.Error(); // report sub-automaton errors properly
case ProgressCode::UnloadingFilament: {
ErrorCode ec = unl.Error(); // report sub-automaton errors properly, only filter out OK and replace them with RUNNING
return ec == ErrorCode::OK ? ErrorCode::RUNNING : ec;
}
default:
return error;
}

View File

@ -2,7 +2,8 @@
#include <stdint.h>
#include "command_base.h"
#include "unload_filament.h"
#include "load_filament.h"
#include "feed_to_finda.h"
#include "feed_to_bondtech.h"
namespace logic {
@ -25,7 +26,8 @@ public:
private:
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
LoadFilament load;
FeedToFinda feed;
FeedToBondtech james; // bond ;)
uint8_t plannedSlot;
};

View File

@ -69,10 +69,7 @@ bool UnloadFilament::StepInner() {
}
return false;
case ProgressCode::ERRDisengagingIdler: // couldn't unload to FINDA
if (!mi::idler.Engaged()) {
state = ProgressCode::ERRWaitingForUser;
mui::userInput.Clear(); // remove all buffered events if any just before we wait for some input
}
ErrDisengagingIdler();
return false;
case ProgressCode::ERRWaitingForUser: {
// waiting for user buttons and/or a command from the printer

View File

@ -21,6 +21,32 @@ using Catch::Matchers::Equals;
#include "../helpers/helpers.ipp"
void FeedingToFinda(logic::ToolChange &tc, uint8_t toSlot) {
// feeding to finda
REQUIRE(WhileCondition(
tc,
[&](int step) -> bool {
if(step == 1000){ // on 1000th step make FINDA trigger
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::high);
}
return tc.TopLevelState() == ProgressCode::FeedingToFinda; },
200000UL));
REQUIRE(VerifyState(tc, false, toSlot, toSlot, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToBondtech));
}
void FeedingToBondtech(logic::ToolChange &tc, uint8_t toSlot) {
// james is feeding
REQUIRE(WhileCondition(
tc,
[&](int step) -> bool {
if(step == 5000){ // on 5000th step make filament sensor trigger
mfs::fsensor.ProcessMessage(true);
}
return tc.TopLevelState() == ProgressCode::FeedingToBondtech; },
200000UL));
REQUIRE(VerifyState(tc, true, mi::Idler::IdleSlotIndex(), toSlot, true, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK));
}
void ToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
ForceReinitAllAutomata();
@ -39,14 +65,9 @@ void ToolChange(logic::ToolChange tc, uint8_t fromSlot, uint8_t toSlot) {
200000UL));
REQUIRE(mg::globals.FilamentLoaded() == false);
REQUIRE(WhileCondition(
tc,
[&](int step) -> bool {
if(step == 1000){ // on 1000th step make FINDA trigger
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::high);
}
return tc.TopLevelState() == ProgressCode::LoadingFilament; },
200000UL));
FeedingToFinda(tc, toSlot);
FeedingToBondtech(tc, toSlot);
REQUIRE(tc.TopLevelState() == ProgressCode::OK);
REQUIRE(mg::globals.FilamentLoaded() == true);
@ -82,14 +103,9 @@ void JustLoadFilament(logic::ToolChange tc, uint8_t slot) {
// restart the automaton
tc.Reset(slot);
REQUIRE(WhileCondition(
tc,
[&](int step) -> bool {
if(step == 1000){ // on 1000th step make FINDA trigger
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::high);
}
return tc.TopLevelState() == ProgressCode::LoadingFilament; },
200000UL));
FeedingToFinda(tc, slot);
FeedingToBondtech(tc, slot);
REQUIRE(tc.TopLevelState() == ProgressCode::OK);
REQUIRE(mg::globals.FilamentLoaded() == true);