Cut filament prototype state machine

pull/21/head
D.R.racer 2021-06-09 12:42:33 +02:00 committed by DRracer
parent 4a79b4b865
commit 7bfc1bad97
12 changed files with 153 additions and 28 deletions

View File

@ -193,11 +193,14 @@ target_sources(
src/modules/buttons.cpp src/modules/buttons.cpp
src/modules/debouncer.cpp src/modules/debouncer.cpp
src/modules/finda.cpp src/modules/finda.cpp
src/modules/idler.cpp
src/modules/leds.cpp src/modules/leds.cpp
src/modules/motion.cpp src/modules/motion.cpp
src/modules/selector.cpp
src/logic/command_base.cpp src/logic/command_base.cpp
src/logic/cut_filament.cpp src/logic/cut_filament.cpp
src/logic/eject_filament.cpp src/logic/eject_filament.cpp
src/logic/feed_to_finda.cpp
src/logic/load_filament.cpp src/logic/load_filament.cpp
src/logic/no_command.cpp src/logic/no_command.cpp
src/logic/tool_change.cpp src/logic/tool_change.cpp

View File

@ -1,23 +1,106 @@
#include "cut_filament.h" #include "cut_filament.h"
#include "../modules/buttons.h" #include "../modules/buttons.h"
#include "../modules/finda.h" #include "../modules/finda.h"
#include "../modules/idler.h"
#include "../modules/leds.h" #include "../modules/leds.h"
#include "../modules/motion.h" #include "../modules/motion.h"
#include "../modules/permanent_storage.h" #include "../modules/permanent_storage.h"
#include "../modules/selector.h"
namespace logic { namespace logic {
CutFilament cutFilament; CutFilament cutFilament;
namespace mm = modules::motion;
namespace mi = modules::idler;
namespace ms = modules::selector;
void CutFilament::Reset() { void CutFilament::Reset() {
namespace mm = modules::motion;
state = ProgressCode::EngagingIdler;
error = ErrorCode::OK; error = ErrorCode::OK;
bool isFilamentLoaded = true; //@@TODO
if (isFilamentLoaded) {
state = ProgressCode::CutUnloadingFilament;
unl.Reset();
} else {
SelectFilamentSlot();
}
}
void CutFilament::SelectFilamentSlot() {
state = ProgressCode::SelectingFilamentSlot;
uint8_t newFilamentSlot = 0; //@@TODO
mi::idler.Engage(newFilamentSlot);
ms::selector.MoveToSlot(newFilamentSlot);
} }
bool CutFilament::Step() { bool CutFilament::Step() {
namespace mm = modules::motion; const int cut_steps_pre = 700;
const int cut_steps_post = 150;
switch (state) { switch (state) {
case ProgressCode::CutUnloadingFilament:
if (unl.Step()) {
// unloading sequence finished
switch (unl.Error()) {
case ErrorCode::OK: // finished successfully
case ErrorCode::UNLOAD_ERROR2: // @@TODO what shall we do in case of this error?
case ErrorCode::UNLOAD_FINDA_DIDNT_TRIGGER:
break;
}
}
break;
case ProgressCode::SelectingFilamentSlot:
if (mm::motion.QueueEmpty()) { // idler and selector finished their moves
feed.Reset(true);
state = ProgressCode::FeedingToFINDA;
}
break;
case ProgressCode::FeedingToFINDA: // @@TODO this state will be reused for repeated cutting of filament ... probably there will be multiple attempts, not sure
if (feed.Step()) {
if (feed.State() == FeedToFinda::Failed) {
// @@TODO
} else {
// move selector aside - prepare the blade into active position
state = ProgressCode::PreparingBlade;
uint8_t newFilamentSlot = 1; //@@TODO
ms::selector.MoveToSlot(newFilamentSlot + 1);
}
}
break;
case ProgressCode::PreparingBlade:
if (mm::motion.QueueEmpty()) {
state = ProgressCode::EngagingIdler;
uint8_t newFilamentSlot = 0; //@@TODO
mi::idler.Engage(newFilamentSlot);
}
break;
case ProgressCode::EngagingIdler:
if (mi::idler.Engaged()) {
state = ProgressCode::PushingFilament;
mm::motion.PlanMove(cut_steps_pre, 0, 0, 1500, 0, 0); //@@TODO
}
break;
case ProgressCode::PushingFilament:
if (mm::motion.QueueEmpty()) {
state = ProgressCode::PerformingCut;
ms::selector.MoveToSlot(0);
}
break;
case ProgressCode::PerformingCut:
if (mm::motion.QueueEmpty()) { // this may not be necessary if we want the selector and pulley move at once
state = ProgressCode::ReturningSelector;
uint8_t newFilamentSlot = 0; //@@TODO
ms::selector.MoveToSlot(newFilamentSlot); // return selector back
}
break;
case ProgressCode::ReturningSelector:
if (mm::motion.QueueEmpty()) { // selector returned to position, feed the filament back to FINDA
state = ProgressCode::FeedingToFINDA;
feed.Reset(true);
}
break;
} }
return false; return false;
} }

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "command_base.h" #include "command_base.h"
#include "unload_to_finda.h" #include "unload_filament.h"
#include "feed_to_finda.h"
namespace logic { namespace logic {
@ -19,6 +20,10 @@ public:
bool Step() override; bool Step() override;
private: private:
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
FeedToFinda feed;
void SelectFilamentSlot();
}; };
extern CutFilament cutFilament; extern CutFilament cutFilament;

View File

@ -15,5 +15,13 @@ enum class ProgressCode : uint_fast8_t {
AvoidingGrind, AvoidingGrind,
FinishingMoves, FinishingMoves,
ERR1DisengagingIdler, ERR1DisengagingIdler,
ERR1WaitingForUser ERR1WaitingForUser,
CutUnloadingFilament,
SelectingFilamentSlot,
FeedingToFINDA,
PreparingBlade,
PushingFilament,
PerformingCut,
ReturningSelector,
}; };

View File

@ -10,8 +10,10 @@ namespace logic {
UnloadFilament unloadFilament; UnloadFilament unloadFilament;
namespace mm = modules::motion;
namespace mi = modules::idler;
void UnloadFilament::Reset() { void UnloadFilament::Reset() {
namespace mm = modules::motion;
// unloads filament from extruder - filament is above Bondtech gears // unloads filament from extruder - filament is above Bondtech gears
mm::motion.InitAxis(mm::Pulley); mm::motion.InitAxis(mm::Pulley);
state = ProgressCode::EngagingIdler; state = ProgressCode::EngagingIdler;
@ -20,8 +22,6 @@ void UnloadFilament::Reset() {
} }
bool UnloadFilament::Step() { bool UnloadFilament::Step() {
namespace mm = modules::motion;
namespace mi = modules::idler;
switch (state) { switch (state) {
case ProgressCode::EngagingIdler: // state 1 engage idler case ProgressCode::EngagingIdler: // state 1 engage idler
if (mi::idler.Engaged()) { // if idler is in parked position un-park it get in contact with filament if (mi::idler.Engaged()) { // if idler is in parked position un-park it get in contact with filament

View File

@ -11,7 +11,7 @@ class UnloadFilament : public CommandBase {
public: public:
inline UnloadFilament() inline UnloadFilament()
: CommandBase() : CommandBase()
, unl(3) { Reset(); } , unl(3) {}
/// Restart the automaton /// Restart the automaton
void Reset() override; void Reset() override;

View File

@ -1,15 +1,16 @@
#include "unload_to_finda.h" #include "unload_to_finda.h"
#include "../modules/motion.h"
#include "../modules/leds.h"
#include "../modules/buttons.h" #include "../modules/buttons.h"
#include "../modules/finda.h" #include "../modules/finda.h"
#include "../modules/leds.h"
#include "../modules/motion.h"
#include "../modules/permanent_storage.h" #include "../modules/permanent_storage.h"
namespace logic { namespace logic {
namespace mm = modules::motion;
namespace mf = modules::finda;
void UnloadToFinda::Reset() { void UnloadToFinda::Reset() {
namespace mm = modules::motion;
namespace mf = modules::finda;
// check the inital state of FINDA and plan the moves // check the inital state of FINDA and plan the moves
if (mf::finda.Pressed()) { if (mf::finda.Pressed()) {
state = OK; // FINDA is already off, we assume the fillament is not there, i.e. already unloaded state = OK; // FINDA is already off, we assume the fillament is not there, i.e. already unloaded
@ -25,8 +26,6 @@ void UnloadToFinda::Reset() {
} }
bool UnloadToFinda::Step() { bool UnloadToFinda::Step() {
namespace mm = modules::motion;
namespace mf = modules::finda;
switch (state) { switch (state) {
case WaitingForFINDA: case WaitingForFINDA:
if (modules::finda::finda.Pressed()) { if (modules::finda::finda.Pressed()) {

View File

@ -7,12 +7,19 @@
namespace modules { namespace modules {
namespace idler { namespace idler {
Idler idler;
namespace mm = modules::motion; namespace mm = modules::motion;
bool Idler::Disengage() { bool Idler::Disengage() {
if (state == Moving) if (state == Moving)
return false; return false;
if (!Engaged())
return true;
plannedEngage = false; plannedEngage = false;
mm::motion.InitAxis(mm::Idler);
// plan move to idle position // plan move to idle position
// mm::motion.PlanMove(0, idle_position, 0, 1000, 0, 0); // @@TODO // mm::motion.PlanMove(0, idle_position, 0, 1000, 0, 0); // @@TODO
state = Moving; state = Moving;
@ -22,8 +29,13 @@ bool Idler::Disengage() {
bool Idler::Engage(uint8_t slot) { bool Idler::Engage(uint8_t slot) {
if (state == Moving) if (state == Moving)
return false; return false;
if (Engaged())
return true;
plannedSlot = slot; plannedSlot = slot;
plannedEngage = true; plannedEngage = true;
mm::motion.InitAxis(mm::Idler);
// mm::motion.PlanMove(0, slotPositions[slot], 0, 1000, 0, 0); // @@TODO // mm::motion.PlanMove(0, slotPositions[slot], 0, 1000, 0, 0); // @@TODO
state = Moving; state = Moving;
return true; return true;
@ -33,6 +45,7 @@ bool Idler::Home() {
if (state == Moving) if (state == Moving)
return false; return false;
plannedEngage = false; plannedEngage = false;
mm::motion.InitAxis(mm::Idler);
mm::motion.Home(mm::Idler, false); mm::motion.Home(mm::Idler, false);
return true; return true;
} }
@ -48,6 +61,10 @@ bool Idler::Step() {
case Ready: case Ready:
currentlyEngaged = plannedEngage; currentlyEngaged = plannedEngage;
currentSlot = plannedSlot; currentSlot = plannedSlot;
if (!Engaged()) // turn off power into the Idler motor when disengaged (no force necessary)
mm::motion.DisableAxis(mm::Idler);
return true; return true;
case Failed: case Failed:
default: default:

View File

@ -16,6 +16,13 @@ public:
Failed Failed
}; };
inline Idler()
: plannedEngage(false)
, plannedSlot(0)
, state(Ready)
, currentSlot(0)
, currentlyEngaged(false) {}
// public operations on the idler // public operations on the idler
/// @retuns false in case an operation is already underway /// @retuns false in case an operation is already underway
@ -47,13 +54,6 @@ private:
/// current state /// current state
uint8_t currentSlot; uint8_t currentSlot;
bool currentlyEngaged; bool currentlyEngaged;
inline Idler()
: plannedEngage(false)
, plannedSlot(0)
, state(Ready)
, currentSlot(0)
, currentlyEngaged(false) {}
}; };
extern Idler idler; extern Idler idler;

View File

@ -61,7 +61,8 @@ public:
/// @@TODO this is subject of discussion and change in the future /// @@TODO this is subject of discussion and change in the future
class Motion { class Motion {
public: public:
/// Init axis driver /// Init axis driver - @@TODO this should be probably hidden somewhere deeper ... something should manage the axes and their state
/// especially when the TMC may get randomly reset (deinited)
void InitAxis(Axis axis) {} void InitAxis(Axis axis) {}
/// Disable axis motor /// Disable axis motor

View File

@ -7,12 +7,19 @@
namespace modules { namespace modules {
namespace selector { namespace selector {
Selector selector;
namespace mm = modules::motion; namespace mm = modules::motion;
bool Selector::MoveToSlot(uint8_t slot) { bool Selector::MoveToSlot(uint8_t slot) {
if (state == Moving) if (state == Moving)
return false; return false;
if (currentSlot == slot)
return true;
plannedSlot = slot; plannedSlot = slot;
mm::motion.InitAxis(mm::Selector);
// mm::motion.PlanMove(1, slotPositions[slot], 0, 1000, 0, 0); // @@TODO // mm::motion.PlanMove(1, slotPositions[slot], 0, 1000, 0, 0); // @@TODO
state = Moving; state = Moving;
return true; return true;
@ -21,6 +28,7 @@ bool Selector::MoveToSlot(uint8_t slot) {
bool Selector::Home() { bool Selector::Home() {
if (state == Moving) if (state == Moving)
return false; return false;
mm::motion.InitAxis(mm::Selector);
mm::motion.Home(mm::Selector, false); mm::motion.Home(mm::Selector, false);
return true; return true;
} }
@ -35,6 +43,7 @@ bool Selector::Step() {
return false; return false;
case Ready: case Ready:
currentSlot = plannedSlot; currentSlot = plannedSlot;
mm::motion.DisableAxis(mm::Selector); // turn off selector motor's power every time
return true; return true;
case Failed: case Failed:
default: default:

View File

@ -16,6 +16,11 @@ public:
Failed Failed
}; };
inline Selector()
: state(Ready)
, currentSlot(0)
, plannedSlot(0) {}
// public operations on the selector // public operations on the selector
/// @retuns false in case an operation is already underway /// @retuns false in case an operation is already underway
@ -40,11 +45,6 @@ private:
/// current state /// current state
uint8_t currentSlot; uint8_t currentSlot;
inline Selector()
: state(Ready)
, currentSlot(0)
, plannedSlot(0) {}
}; };
extern Selector selector; extern Selector selector;