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.
|
||||
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");
|
||||
|
||||
// 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)
|
||||
// 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
|
||||
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 minimumBowdenLength = 341.0_mm; ///< ~341.0_mm - Minimum bowden length. @TODO Should be stored in EEPROM.
|
||||
static constexpr U_mm maximumBowdenLength = 792.0_mm; ///< ~792.0_mm - Maximum bowden length. @TODO Should be stored in EEPROM.
|
||||
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.
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -15,5 +15,13 @@ void EEPROM::UpdateByte(EEPROM::addr_t addr, uint8_t 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 hal
|
||||
|
|
|
|||
|
|
@ -28,6 +28,31 @@ void logic::FeedToBondtech::GoToPushToNozzle() {
|
|||
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() {
|
||||
switch (state) {
|
||||
case EngagingIdler:
|
||||
|
|
@ -67,6 +92,30 @@ bool FeedToBondtech::Step() {
|
|||
// // stall guard occurred during movement - the filament got stuck
|
||||
// state = PulleyStalled;
|
||||
} 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;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -92,6 +141,9 @@ 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;
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/// @file feed_to_bondtech.h
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../modules/axisunit.h"
|
||||
|
||||
namespace logic {
|
||||
|
||||
|
|
@ -10,6 +11,10 @@ namespace logic {
|
|||
/// Then it feeds a bit more very gently to push the filament into the nozzle
|
||||
/// Disengages the Idler after finishing the feed.
|
||||
/// 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 {
|
||||
/// internal states of the state machine
|
||||
enum {
|
||||
|
|
@ -46,8 +51,15 @@ struct FeedToBondtech {
|
|||
void GoToPushToNozzle();
|
||||
|
||||
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 maxRetries;
|
||||
int32_t feedStart_mm; // intentionally trying to avoid using U_mm because it is a float (reps. long double)
|
||||
};
|
||||
|
||||
} // namespace logic
|
||||
|
|
|
|||
|
|
@ -145,6 +145,13 @@ static constexpr typename AU::type_t unitToSteps(U 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
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "../hal/eeprom.h"
|
||||
#include "globals.h"
|
||||
#include "../config/config.h"
|
||||
#include "axisunit.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
|
||||
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 eepromLengthCorrectionBase = 7900U; ///< legacy bowden length correction base (~391mm)
|
||||
constexpr const uint16_t eepromBowdenLenDefault = 8900U; ///< Default bowden length (~427 mm)
|
||||
constexpr const uint16_t eepromBowdenLenMinimum = 6900U; ///< Minimum bowden length (~341 mm)
|
||||
constexpr const uint16_t eepromBowdenLenMaximum = 16000U; ///< Maximum bowden length (~792 mm)
|
||||
|
||||
namespace mm = modules::motion;
|
||||
constexpr const uint16_t eepromLengthCorrectionBase = config::defaultBowdenLength.v;
|
||||
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;
|
||||
|
||||
|
|
@ -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.
|
||||
/// @return stored bowden length
|
||||
uint16_t BowdenLength::get() {
|
||||
uint8_t filament = mg::globals.ActiveSlot();
|
||||
if (validFilament(filament)) {
|
||||
uint16_t BowdenLength::Get(uint8_t slot) {
|
||||
if (validFilament(slot)) {
|
||||
// @@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) {
|
||||
const uint8_t LengthCorrectionLegacy = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromLengthCorrection)));
|
||||
|
|
@ -107,46 +111,10 @@ uint16_t BowdenLength::get() {
|
|||
return eepromBowdenLenDefault;
|
||||
}
|
||||
|
||||
/// @brief Construct BowdenLength object which allows bowden length manipulation
|
||||
///
|
||||
/// To be created on stack, new value is permanently stored when object goes out of scope.
|
||||
/// 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
|
||||
{
|
||||
void BowdenLength::Set(uint8_t slot, uint16_t steps) {
|
||||
if (validFilament(slot)) {
|
||||
ee::EEPROM::UpdateWord(EEOFFSET(eepromBase->eepromBowdenLen[slot]), steps);
|
||||
}
|
||||
|
||||
/// @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
|
||||
|
|
|
|||
|
|
@ -16,22 +16,17 @@ void Init();
|
|||
/// Erase the whole EEPROM
|
||||
void EraseAll();
|
||||
|
||||
/// @brief Read manipulate and store bowden length
|
||||
/// @brief Read and store bowden length
|
||||
///
|
||||
/// Value is stored independently for each filament.
|
||||
/// Active filament is deduced from active_extruder global variable.
|
||||
class BowdenLength {
|
||||
public:
|
||||
static uint16_t get();
|
||||
static const uint8_t stepSize = 10u; ///< increase()/decrease() bowden length step size
|
||||
BowdenLength();
|
||||
bool increase();
|
||||
bool decrease();
|
||||
~BowdenLength();
|
||||
/// @returns bowden length for selected slot
|
||||
static uint16_t Get(uint8_t slot);
|
||||
|
||||
private:
|
||||
uint8_t filament; ///< Selected filament
|
||||
uint16_t length; ///< Selected filament bowden length
|
||||
/// Sets
|
||||
static void Set(uint8_t slot, uint16_t steps);
|
||||
};
|
||||
|
||||
/// @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 ){
|
||||
mfs::fsensor.ProcessMessage(true);
|
||||
}
|
||||
return fb.State() == FeedToBondtech::PushingFilamentToFSensor; },
|
||||
return fb.State() == FeedToBondtech::PushingFilamentToFSensorFast; },
|
||||
1500));
|
||||
|
||||
REQUIRE(mfs::fsensor.Pressed());
|
||||
|
|
|
|||
Loading…
Reference in New Issue