Add bowden length runtime detection and tuning
Still, unit tests must check this thoroughly as this code is extremely hard to test on the real HW.pull/141/head
parent
860b91e42b
commit
ecd63b6138
|
|
@ -18,7 +18,10 @@
|
||||||
/// Wrangler for assorted compile-time configuration and constants.
|
/// Wrangler for assorted compile-time configuration and constants.
|
||||||
namespace config {
|
namespace config {
|
||||||
|
|
||||||
static constexpr const uint8_t toolCount = 5U; ///< Max number of extruders/tools/slots
|
/// Max number of extruders/tools/slots
|
||||||
|
/// Beware - if you change this, the EEPROM structure will become invalid and no migration procedures have been implemented.
|
||||||
|
/// So if you really have to change this, erase your EEPROM content then.
|
||||||
|
static constexpr const uint8_t toolCount = 5U;
|
||||||
static_assert(toolCount < 15, "Up to 14 valid slots (+1 parking) is supported in EEPROM storage");
|
static_assert(toolCount < 15, "Up to 14 valid slots (+1 parking) is supported in EEPROM storage");
|
||||||
|
|
||||||
// Printer's filament sensor setup
|
// Printer's filament sensor setup
|
||||||
|
|
@ -84,9 +87,9 @@ static constexpr U_mm couplerToBowden = 3.5_mm; /// 3.5_mm /// FINDA Coupler scr
|
||||||
// just another piece of PLA (probably having more resistance in the tubes)
|
// just another piece of PLA (probably having more resistance in the tubes)
|
||||||
// and we are at least 40mm off! It looks like this really depends on the exact position
|
// and we are at least 40mm off! It looks like this really depends on the exact position
|
||||||
// We'll probably need to check for stallguard while pushing the filament to avoid ginding the filament
|
// We'll probably need to check for stallguard while pushing the filament to avoid ginding the filament
|
||||||
static constexpr U_mm defaultBowdenLength = 427.0_mm; ///< ~427.0_mm - Default Bowden length. @TODO Should be stored in EEPROM. 392 a 784
|
static constexpr U_mm defaultBowdenLength = 427.0_mm; /// ~427.0_mm /// Default Bowden length.
|
||||||
static constexpr U_mm minimumBowdenLength = 341.0_mm; ///< ~341.0_mm - Minimum bowden length. @TODO Should be stored in EEPROM.
|
static constexpr U_mm minimumBowdenLength = 341.0_mm; /// ~341.0_mm /// Minimum bowden length.
|
||||||
static constexpr U_mm maximumBowdenLength = 792.0_mm; ///< ~792.0_mm - Maximum bowden length. @TODO Should be stored in EEPROM.
|
static constexpr U_mm maximumBowdenLength = 792.0_mm; /// ~792.0_mm /// Maximum bowden length.
|
||||||
static constexpr U_mm feedToFinda = cuttingEdgeToFindaMidpoint + filamentMinLoadedToMMU;
|
static constexpr U_mm feedToFinda = cuttingEdgeToFindaMidpoint + filamentMinLoadedToMMU;
|
||||||
static constexpr U_mm maximumFeedToFinda = feedToFinda + 20.0_mm; ///< allow for some safety margin to load to FINDA
|
static constexpr U_mm maximumFeedToFinda = feedToFinda + 20.0_mm; ///< allow for some safety margin to load to FINDA
|
||||||
static constexpr U_mm pulleyHelperMove = 10.0_mm; ///< Helper move for Load/Unload error states - when the MMU should slowly move the filament a bit
|
static constexpr U_mm pulleyHelperMove = 10.0_mm; ///< Helper move for Load/Unload error states - when the MMU should slowly move the filament a bit
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,13 @@ void EEPROM::UpdateByte(EEPROM::addr_t addr, uint8_t value) {
|
||||||
eeprom_update_byte((uint8_t *)addr, value);
|
eeprom_update_byte((uint8_t *)addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t EEPROM::ReadWord(EEPROM::addr_t addr) {
|
||||||
|
return eeprom_read_word((const uint16_t *)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EEPROM::UpdateWord(EEPROM::addr_t addr, uint16_t value) {
|
||||||
|
eeprom_update_word((uint16_t *)addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace eeprom
|
} // namespace eeprom
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,31 @@ void logic::FeedToBondtech::GoToPushToNozzle() {
|
||||||
state = PushingFilamentIntoNozzle;
|
state = PushingFilamentIntoNozzle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FeedToBondtech::UpdateBowdenLength(int32_t feedEnd_mm) {
|
||||||
|
int32_t measuredBowdenLength = abs(feedEnd_mm - feedStart_mm);
|
||||||
|
if (measuredBowdenLength < config::maximumBowdenLength.v) { // is the measured length any valid/acceptable?
|
||||||
|
static_assert(config::maximumBowdenLength.v <= 65535, "Max bowden length too long");
|
||||||
|
int16_t mbl = (int16_t)measuredBowdenLength;
|
||||||
|
int16_t difference = abs(mbl - mps::BowdenLength::Get(mg::globals.ActiveSlot()));
|
||||||
|
if (difference > 5) { // @@TODO 5_mm is it good enough?
|
||||||
|
mps::BowdenLength::Set(mg::globals.ActiveSlot(), mbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FeedToBondtech::PushingFilament() {
|
||||||
|
if (mfs::fsensor.Pressed()) {
|
||||||
|
mm::motion.AbortPlannedMoves(); // stop pushing filament
|
||||||
|
GoToPushToNozzle();
|
||||||
|
} else if (mm::motion.StallGuard(mm::Pulley)) {
|
||||||
|
// stall guard occurred during movement - the filament got stuck
|
||||||
|
state = Failed; // @@TODO may be even report why it failed
|
||||||
|
} else if (mm::motion.QueueEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FeedToBondtech::Step() {
|
bool FeedToBondtech::Step() {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case EngagingIdler:
|
case EngagingIdler:
|
||||||
|
|
@ -67,6 +92,30 @@ bool FeedToBondtech::Step() {
|
||||||
// // stall guard occurred during movement - the filament got stuck
|
// // stall guard occurred during movement - the filament got stuck
|
||||||
// state = PulleyStalled;
|
// 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
|
||||||
|
/*=======
|
||||||
|
dbg_logic_fP(PSTR("Pulley start steps %u"), mm::motion.CurPosition(mm::Pulley));
|
||||||
|
state = PushingFilamentToFSensorFast;
|
||||||
|
mm::motion.InitAxis(mm::Pulley);
|
||||||
|
feedStart_mm = mm::stepsToUnit<mm::P_pos_t>(mm::P_pos_t({ mm::motion.CurPosition(mm::Pulley) }));
|
||||||
|
// fast feed in millimeters - if the EEPROM value is incorrect, we'll get the default length
|
||||||
|
mm::motion.PlanMove<mm::Pulley>(
|
||||||
|
{ (long double)mps::BowdenLength::Get(mg::globals.ActiveSlot()) },
|
||||||
|
config::pulleyFeedrate, config::pulleySlowFeedrate);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case PushingFilamentToFSensorFast:
|
||||||
|
if (!PushingFilament()) { // ran out of stored bowden length, continue slowly
|
||||||
|
state = PushingFilamentToFSensorSlow;
|
||||||
|
// do the remaining move up to maximum bowden length slowly
|
||||||
|
mm::motion.PlanMove<mm::Pulley>(
|
||||||
|
{ (long double)abs(config::maximumBowdenLength.v - mps::BowdenLength::Get(mg::globals.ActiveSlot())) }, // fast feed in millimeters - if the EEPROM value is incorrect, we'll
|
||||||
|
config::pulleySlowFeedrate, config::pulleySlowFeedrate);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case PushingFilamentToFSensorSlow:
|
||||||
|
if (!PushingFilament()) { // all moves have been finished and the fsensor didn't switch on
|
||||||
|
>>>>>>> Add bowden length runtime detection and tuning
|
||||||
|
*/
|
||||||
state = Failed;
|
state = Failed;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -92,6 +141,9 @@ bool FeedToBondtech::Step() {
|
||||||
dbg_logic_P(PSTR("Feed to Bondtech --> Idler disengaged"));
|
dbg_logic_P(PSTR("Feed to Bondtech --> Idler disengaged"));
|
||||||
dbg_logic_fP(PSTR("Pulley end steps %u"), mpu::pulley.CurrentPosition_mm());
|
dbg_logic_fP(PSTR("Pulley end steps %u"), mpu::pulley.CurrentPosition_mm());
|
||||||
state = OK;
|
state = OK;
|
||||||
|
mpu::pulley.Disable();
|
||||||
|
UpdateBowdenLength(mm::stepsToUnit<mm::P_pos_t>(mm::P_pos_t({ mm::motion.CurPosition(mm::Pulley) })));
|
||||||
|
mm::motion.Disable(mm::Pulley);
|
||||||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
|
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/// @file feed_to_bondtech.h
|
/// @file feed_to_bondtech.h
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "../modules/axisunit.h"
|
||||||
|
|
||||||
namespace logic {
|
namespace logic {
|
||||||
|
|
||||||
|
|
@ -10,6 +11,10 @@ namespace logic {
|
||||||
/// Then it feeds a bit more very gently to push the filament into the nozzle
|
/// Then it feeds a bit more very gently to push the filament into the nozzle
|
||||||
/// Disengages the Idler after finishing the feed.
|
/// Disengages the Idler after finishing the feed.
|
||||||
/// Disables the Pulley axis after disengaging the idler.
|
/// Disables the Pulley axis after disengaging the idler.
|
||||||
|
///
|
||||||
|
/// If filament has been successfully fed into the fsensor,
|
||||||
|
/// records/updates PTFE length for the active slot.
|
||||||
|
/// To prevent constant EEPROM updates only significant changes are recorded.
|
||||||
struct FeedToBondtech {
|
struct FeedToBondtech {
|
||||||
/// internal states of the state machine
|
/// internal states of the state machine
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -46,8 +51,15 @@ struct FeedToBondtech {
|
||||||
void GoToPushToNozzle();
|
void GoToPushToNozzle();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Update bowden length if changed significantly
|
||||||
|
void UpdateBowdenLength(int32_t feedEnd_mm);
|
||||||
|
|
||||||
|
/// Common processing of pushing filament into fsensor (reused by multiple states)
|
||||||
|
bool PushingFilament();
|
||||||
|
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint8_t maxRetries;
|
uint8_t maxRetries;
|
||||||
|
int32_t feedStart_mm; // intentionally trying to avoid using U_mm because it is a float (reps. long double)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace logic
|
} // namespace logic
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,13 @@ static constexpr typename AU::type_t unitToSteps(U v) {
|
||||||
return unitToAxisUnit<AU>(v).v;
|
return unitToAxisUnit<AU>(v).v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a steps type (pos_t or steps_t) to a unit::Unit.
|
||||||
|
/// Extract the raw step count from an AxisUnit with type checking.
|
||||||
|
template <typename U, typename AU>
|
||||||
|
static constexpr typename U::type_t stepsToUnit(AU pos) {
|
||||||
|
return axisUnitToUnit<U, AU>(pos);
|
||||||
|
}
|
||||||
|
|
||||||
// Pulley
|
// Pulley
|
||||||
typedef AxisUnit<pos_t, Pulley, Lenght> P_pos_t; ///< Pulley position type (steps)
|
typedef AxisUnit<pos_t, Pulley, Lenght> P_pos_t; ///< Pulley position type (steps)
|
||||||
typedef AxisUnit<steps_t, Pulley, Speed> P_speed_t; ///< Pulley speed type (steps/s)
|
typedef AxisUnit<steps_t, Pulley, Speed> P_speed_t; ///< Pulley speed type (steps/s)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../hal/eeprom.h"
|
#include "../hal/eeprom.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "../config/config.h"
|
#include "../config/config.h"
|
||||||
|
#include "axisunit.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
@ -43,10 +44,14 @@ static const uint8_t layoutVersion = 0xff;
|
||||||
// ideally, this would have been a nice constexpr (since it is a compile time constant), but the C++ standard prohibits reinterpret_casts in constexpr
|
// ideally, this would have been a nice constexpr (since it is a compile time constant), but the C++ standard prohibits reinterpret_casts in constexpr
|
||||||
static eeprom_t *const eepromBase = reinterpret_cast<eeprom_t *>(0); ///< First EEPROM address
|
static eeprom_t *const eepromBase = reinterpret_cast<eeprom_t *>(0); ///< First EEPROM address
|
||||||
constexpr const uint16_t eepromEmpty = 0xffffU; ///< EEPROM content when erased
|
constexpr const uint16_t eepromEmpty = 0xffffU; ///< EEPROM content when erased
|
||||||
constexpr const uint16_t eepromLengthCorrectionBase = 7900U; ///< legacy bowden length correction base (~391mm)
|
|
||||||
constexpr const uint16_t eepromBowdenLenDefault = 8900U; ///< Default bowden length (~427 mm)
|
namespace mm = modules::motion;
|
||||||
constexpr const uint16_t eepromBowdenLenMinimum = 6900U; ///< Minimum bowden length (~341 mm)
|
constexpr const uint16_t eepromLengthCorrectionBase = config::defaultBowdenLength.v;
|
||||||
constexpr const uint16_t eepromBowdenLenMaximum = 16000U; ///< Maximum bowden length (~792 mm)
|
constexpr const uint16_t eepromBowdenLenDefault = config::defaultBowdenLength.v; ///< Default bowden length (~427 mm)
|
||||||
|
constexpr const uint16_t eepromBowdenLenMinimum = config::minimumBowdenLength.v; ///< Minimum bowden length (~341 mm)
|
||||||
|
constexpr const uint16_t eepromBowdenLenMaximum = config::maximumBowdenLength.v; ///< Maximum bowden length (~792 mm)
|
||||||
|
|
||||||
|
// static_assert (mm::unitToSteps<mm::P_pos_t>(config::maximumBowdenLength) < 65535U, "");
|
||||||
|
|
||||||
namespace ee = hal::eeprom;
|
namespace ee = hal::eeprom;
|
||||||
|
|
||||||
|
|
@ -88,11 +93,10 @@ static bool validBowdenLen(const uint16_t BowdenLength) {
|
||||||
///
|
///
|
||||||
/// Returns stored value, doesn't return actual value when it is edited by increase() / decrease() unless it is stored.
|
/// Returns stored value, doesn't return actual value when it is edited by increase() / decrease() unless it is stored.
|
||||||
/// @return stored bowden length
|
/// @return stored bowden length
|
||||||
uint16_t BowdenLength::get() {
|
uint16_t BowdenLength::Get(uint8_t slot) {
|
||||||
uint8_t filament = mg::globals.ActiveSlot();
|
if (validFilament(slot)) {
|
||||||
if (validFilament(filament)) {
|
|
||||||
// @@TODO these reinterpret_cast expressions look horrible but I'm keeping them almost intact to respect the original code from MM_control_01
|
// @@TODO these reinterpret_cast expressions look horrible but I'm keeping them almost intact to respect the original code from MM_control_01
|
||||||
uint16_t bowdenLength = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromBowdenLen[filament])));
|
uint16_t bowdenLength = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromBowdenLen[slot])));
|
||||||
|
|
||||||
if (eepromEmpty == bowdenLength) {
|
if (eepromEmpty == bowdenLength) {
|
||||||
const uint8_t LengthCorrectionLegacy = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromLengthCorrection)));
|
const uint8_t LengthCorrectionLegacy = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromLengthCorrection)));
|
||||||
|
|
@ -107,46 +111,10 @@ uint16_t BowdenLength::get() {
|
||||||
return eepromBowdenLenDefault;
|
return eepromBowdenLenDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Construct BowdenLength object which allows bowden length manipulation
|
void BowdenLength::Set(uint8_t slot, uint16_t steps) {
|
||||||
///
|
if (validFilament(slot)) {
|
||||||
/// To be created on stack, new value is permanently stored when object goes out of scope.
|
ee::EEPROM::UpdateWord(EEOFFSET(eepromBase->eepromBowdenLen[slot]), steps);
|
||||||
/// Active filament and associated bowden length is stored in member variables.
|
|
||||||
BowdenLength::BowdenLength()
|
|
||||||
: filament(mg::globals.ActiveSlot()) // @@TODO - verify correct initialization order
|
|
||||||
, length(BowdenLength::get()) // @@TODO
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Increase bowden length
|
|
||||||
///
|
|
||||||
/// New value is not stored immediately. See ~BowdenLength() for storing permanently.
|
|
||||||
/// @retval true passed
|
|
||||||
/// @retval false failed, it is not possible to increase, new bowden length would be out of range
|
|
||||||
bool BowdenLength::increase() {
|
|
||||||
if (validBowdenLen(length + stepSize)) {
|
|
||||||
length += stepSize;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Decrease bowden length
|
|
||||||
///
|
|
||||||
/// New value is not stored immediately. See ~BowdenLength() for storing permanently.
|
|
||||||
/// @retval true passed
|
|
||||||
/// @retval false failed, it is not possible to decrease, new bowden length would be out of range
|
|
||||||
bool BowdenLength::decrease() {
|
|
||||||
if (validBowdenLen(length - stepSize)) {
|
|
||||||
length -= stepSize;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Store bowden length permanently.
|
|
||||||
BowdenLength::~BowdenLength() {
|
|
||||||
if (validFilament(filament))
|
|
||||||
ee::EEPROM::UpdateWord(EEOFFSET(eepromBase->eepromBowdenLen[filament]), length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get filament storage status
|
/// @brief Get filament storage status
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,17 @@ void Init();
|
||||||
/// Erase the whole EEPROM
|
/// Erase the whole EEPROM
|
||||||
void EraseAll();
|
void EraseAll();
|
||||||
|
|
||||||
/// @brief Read manipulate and store bowden length
|
/// @brief Read and store bowden length
|
||||||
///
|
///
|
||||||
/// Value is stored independently for each filament.
|
/// Value is stored independently for each filament.
|
||||||
/// Active filament is deduced from active_extruder global variable.
|
/// Active filament is deduced from active_extruder global variable.
|
||||||
class BowdenLength {
|
class BowdenLength {
|
||||||
public:
|
public:
|
||||||
static uint16_t get();
|
/// @returns bowden length for selected slot
|
||||||
static const uint8_t stepSize = 10u; ///< increase()/decrease() bowden length step size
|
static uint16_t Get(uint8_t slot);
|
||||||
BowdenLength();
|
|
||||||
bool increase();
|
|
||||||
bool decrease();
|
|
||||||
~BowdenLength();
|
|
||||||
|
|
||||||
private:
|
/// Sets
|
||||||
uint8_t filament; ///< Selected filament
|
static void Set(uint8_t slot, uint16_t steps);
|
||||||
uint16_t length; ///< Selected filament bowden length
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Read and store last filament loaded to nozzle
|
/// @brief Read and store last filament loaded to nozzle
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ TEST_CASE("feed_to_bondtech::feed_phase_unlimited", "[feed_to_bondtech]") {
|
||||||
if( step == 100 ){
|
if( step == 100 ){
|
||||||
mfs::fsensor.ProcessMessage(true);
|
mfs::fsensor.ProcessMessage(true);
|
||||||
}
|
}
|
||||||
return fb.State() == FeedToBondtech::PushingFilamentToFSensor; },
|
return fb.State() == FeedToBondtech::PushingFilamentToFSensorFast; },
|
||||||
1500));
|
1500));
|
||||||
|
|
||||||
REQUIRE(mfs::fsensor.Pressed());
|
REQUIRE(mfs::fsensor.Pressed());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue