🚸 Improve MMU2 unload (like original MMU2S) (#20147)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
Thomas Niccolo Reyes 2023-05-05 07:09:36 +08:00 committed by GitHub
parent 6bf789d93f
commit 001d1fd7cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 125 additions and 114 deletions

View file

@ -4250,30 +4250,29 @@
// Add an LCD menu for MMU2
//#define MMU2_MENUS
#if EITHER(MMU2_MENUS, HAS_PRUSA_MMU2S)
// Settings for filament load / unload from the LCD menu.
// This is for Průša MK3-style extruders. Customize for your hardware.
#define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0
#define MMU2_LOAD_TO_NOZZLE_SEQUENCE \
{ 7.2, 1145 }, \
{ 14.4, 871 }, \
{ 36.0, 1393 }, \
{ 14.4, 871 }, \
{ 50.0, 198 }
#define MMU2_RAMMING_SEQUENCE \
{ 1.0, 1000 }, \
{ 1.0, 1500 }, \
{ 2.0, 2000 }, \
{ 1.5, 3000 }, \
{ 2.5, 4000 }, \
{ -15.0, 5000 }, \
{ -14.0, 1200 }, \
{ -6.0, 600 }, \
{ 10.0, 700 }, \
{ -10.0, 400 }, \
{ -50.0, 2000 }
#endif
// Settings for filament load / unload from the LCD menu.
// This is for Průša MK3-style extruders. Customize for your hardware.
#define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0
#define MMU2_LOAD_TO_NOZZLE_SEQUENCE \
{ 7.2, 1145 }, \
{ 14.4, 871 }, \
{ 36.0, 1393 }, \
{ 14.4, 871 }, \
{ 50.0, 198 }
#define MMU2_RAMMING_SEQUENCE \
{ 1.0, 1000 }, \
{ 1.0, 1500 }, \
{ 2.0, 2000 }, \
{ 1.5, 3000 }, \
{ 2.5, 4000 }, \
{ -15.0, 5000 }, \
{ -14.0, 1200 }, \
{ -6.0, 600 }, \
{ 10.0, 700 }, \
{ -10.0, 400 }, \
{ -50.0, 2000 }
/**
* Using a sensor like the MMU2S
@ -4296,6 +4295,8 @@
#define MMU2_CAN_LOAD_INCREMENT_SEQUENCE \
{ -MMU2_CAN_LOAD_INCREMENT, MMU2_CAN_LOAD_FEEDRATE }
// Continue unloading if sensor detects filament after the initial unload move
//#define MMU_IR_UNLOAD_MOVE
#else
/**

View file

@ -84,7 +84,7 @@ uint8_t MMU2::cmd, MMU2::cmd_arg, MMU2::last_cmd, MMU2::extruder;
int8_t MMU2::state = 0;
volatile int8_t MMU2::finda = 1;
volatile bool MMU2::finda_runout_valid;
int16_t MMU2::version = -1, MMU2::buildnr = -1;
uint16_t MMU2::version = 0, MMU2::buildnr = 0;
millis_t MMU2::prev_request, MMU2::prev_P0_request;
char MMU2::rx_buffer[MMU_RX_SIZE], MMU2::tx_buffer[MMU_TX_SIZE];
@ -93,14 +93,11 @@ struct E_Step {
feedRate_t feedRate; //!< feed rate in mm/s
};
static constexpr E_Step
ramming_sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE }
, load_to_nozzle_sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }
#if HAS_PRUSA_MMU2S
, can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }
, can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }
#endif
;
inline void unscaled_mmu2_e_move(const float &dist, const feedRate_t fr_mm_s, const bool sync=true) {
current_position.e += dist / planner.e_factor[active_extruder];
line_to_current_position(fr_mm_s);
if (sync) planner.synchronize();
}
MMU2::MMU2() {
rx_buffer[0] = '\0';
@ -136,12 +133,12 @@ void MMU2::reset() {
#endif
}
uint8_t MMU2::get_current_tool() {
return extruder == MMU2_NO_TOOL ? -1 : extruder;
}
int8_t MMU2::get_current_tool() { return extruder == MMU2_NO_TOOL ? -1 : extruder; }
#if EITHER(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR)
#define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE)
#else
#define FILAMENT_PRESENT() true
#endif
void mmu2_attn_buzz(const bool two=false) {
@ -200,15 +197,15 @@ void MMU2::mmu_loop() {
break;
#if ENABLED(MMU2_MODE_12V)
case -5:
// response to M1
if (rx_ok()) {
DEBUG_ECHOLNPGM("MMU => ok");
DEBUG_ECHOLNPGM("MMU <= 'P0'");
MMU2_SEND("P0"); // Read FINDA
state = -4;
}
break;
case -5:
// response to M1
if (rx_ok()) {
DEBUG_ECHOLNPGM("MMU => ok");
DEBUG_ECHOLNPGM("MMU <= 'P0'");
MMU2_SEND("P0"); // Read FINDA
state = -4;
}
break;
#endif
case -4:
@ -458,8 +455,15 @@ static void mmu2_not_responding() {
BUZZ(100, 659);
}
inline void beep_bad_cmd() { BUZZ(400, 40); }
#if HAS_PRUSA_MMU2S
/**
* Load filament until the sensor at the gears is triggered
* and give up after a number of attempts set with MMU2_C0_RETRY.
* Each try has a timeout before returning a fail state.
*/
bool MMU2::load_to_gears() {
command(MMU_CMD_C0);
manage_response(true, true);
@ -484,6 +488,11 @@ static void mmu2_not_responding() {
set_runout_valid(false);
if (index != extruder) {
if (ENABLED(MMU_IR_UNLOAD_MOVE) && FILAMENT_PRESENT()) {
DEBUG_ECHOLNPGM("Unloading\n");
while (FILAMENT_PRESENT()) // Filament present? Keep unloading.
unscaled_mmu2_e_move(-0.25, MMM_TO_MMS(120)); // 0.25mm is a guessed value. Adjust to preference.
}
stepper.disable_extruder();
ui.status_printf(0, GET_TEXT_F(MSG_MMU2_LOADING_FILAMENT), int(index + 1));
@ -520,9 +529,9 @@ static void mmu2_not_responding() {
#if ENABLED(MMU2_MENUS)
const uint8_t index = mmu2_choose_filament();
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
load_filament_to_nozzle(index);
load_to_nozzle(index);
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
@ -541,13 +550,13 @@ static void mmu2_not_responding() {
active_extruder = 0;
}
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
case 'c': {
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
load_to_nozzle();
load_to_nozzle_sequence();
} break;
}
@ -608,9 +617,9 @@ static void mmu2_not_responding() {
#if ENABLED(MMU2_MENUS)
uint8_t index = mmu2_choose_filament();
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
load_filament_to_nozzle(index);
load_to_nozzle(index);
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
@ -630,14 +639,14 @@ static void mmu2_not_responding() {
extruder = index;
active_extruder = 0;
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
case 'c': {
DEBUG_ECHOLNPGM("case c\n");
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
load_to_nozzle_sequence();
} break;
}
@ -723,9 +732,9 @@ static void mmu2_not_responding() {
#if ENABLED(MMU2_MENUS)
uint8_t index = mmu2_choose_filament();
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
load_filament_to_nozzle(index);
load_to_nozzle(index);
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
@ -744,14 +753,14 @@ static void mmu2_not_responding() {
extruder = index;
active_extruder = 0;
#else
ERR_BUZZ();
beep_bad_cmd();
#endif
} break;
case 'c': {
DEBUG_ECHOLNPGM("case c\n");
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
load_to_nozzle_sequence();
} break;
}
@ -823,13 +832,12 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
}
}
else if (mmu_print_saved) {
SERIAL_ECHOLNPGM("MMU starts responding\n");
SERIAL_ECHOLNPGM("\nMMU starts responding");
if (turn_off_nozzle && resume_hotend_temp) {
thermalManager.setTargetHotend(resume_hotend_temp, active_extruder);
LCD_MESSAGE(MSG_HEATING);
ERR_BUZZ();
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(1000);
}
@ -842,7 +850,6 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
if (move_axes && all_axes_homed()) {
// Move XY to starting position, then Z
do_blocking_move_to_xy(resume_position, feedRate_t(NOZZLE_PARK_XY_FEEDRATE));
// Move Z_AXIS to saved position
do_blocking_move_to_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
}
@ -877,23 +884,24 @@ void MMU2::filament_runout() {
}
// Slowly spin the extruder during C0
else {
while (planner.movesplanned() < 3) {
current_position.e += 0.25;
line_to_current_position(MMM_TO_MMS(120));
}
while (planner.movesplanned() < 3)
unscaled_mmu2_e_move(0.25, MMM_TO_MMS(120), false);
}
}
mmu2s_triggered = present;
}
bool MMU2::can_load() {
execute_extruder_sequence((const E_Step *)can_load_sequence, COUNT(can_load_sequence));
static const E_Step can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE },
can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE };
execute_extruder_sequence(can_load_sequence, COUNT(can_load_sequence));
int filament_detected_count = 0;
const int steps = (MMU2_CAN_LOAD_RETRACT) / (MMU2_CAN_LOAD_INCREMENT);
DEBUG_ECHOLNPGM("MMU can_load:");
LOOP_L_N(i, steps) {
execute_extruder_sequence((const E_Step *)can_load_increment_sequence, COUNT(can_load_increment_sequence));
execute_extruder_sequence(can_load_increment_sequence, COUNT(can_load_increment_sequence));
check_filament(); // Don't trust the idle function
DEBUG_CHAR(mmu2s_triggered ? 'O' : 'o');
if (mmu2s_triggered) ++filament_detected_count;
@ -911,7 +919,7 @@ void MMU2::filament_runout() {
#endif
// Load filament into MMU2
void MMU2::load_filament(const uint8_t index) {
void MMU2::load_to_feeder(const uint8_t index) {
if (!_enabled) return;
command(MMU_CMD_L0 + index);
@ -922,8 +930,7 @@ void MMU2::load_filament(const uint8_t index) {
/**
* Switch material and load to nozzle
*/
bool MMU2::load_filament_to_nozzle(const uint8_t index) {
bool MMU2::load_to_nozzle(const uint8_t index) {
if (!_enabled) return false;
if (thermalManager.tooColdToExtrude(active_extruder)) {
@ -932,6 +939,13 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) {
return false;
}
if (TERN0(MMU_IR_UNLOAD_MOVE, index != extruder) && FILAMENT_PRESENT()) {
DEBUG_ECHOLNPGM("Unloading\n");
ramming_sequence(); // Unloading instructions from printer side when operating LCD
while (FILAMENT_PRESENT()) // Filament present? Keep unloading.
unscaled_mmu2_e_move(-0.25, MMM_TO_MMS(120)); // 0.25mm is a guessed value. Adjust to preference.
}
stepper.disable_extruder();
command(MMU_CMD_T0 + index);
manage_response(true, true);
@ -941,23 +955,12 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) {
mmu_loop();
extruder = index;
active_extruder = 0;
load_to_nozzle();
load_to_nozzle_sequence();
mmu2_attn_buzz();
}
return success;
}
/**
* Load filament to nozzle of multimaterial printer
*
* This function is used only after T? (user select filament) and M600 (change filament).
* It is not used after T0 .. T4 command (select filament), in such case, G-code is responsible for loading
* filament to nozzle.
*/
void MMU2::load_to_nozzle() {
execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
}
bool MMU2::eject_filament(const uint8_t index, const bool recover) {
if (!_enabled) return false;
@ -970,10 +973,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) {
LCD_MESSAGE(MSG_MMU2_EJECTING_FILAMENT);
stepper.enable_extruder();
current_position.e -= MMU2_FILAMENTCHANGE_EJECT_FEED;
line_to_current_position(MMM_TO_MMS(2500));
planner.synchronize();
unscaled_mmu2_e_move(-(MMU2_FILAMENTCHANGE_EJECT_FEED), MMM_TO_MMS(2500));
command(MMU_CMD_E0 + index);
manage_response(false, false);
@ -983,7 +983,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) {
TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER)));
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER)));
TERN_(HAS_RESUME_CONTINUE, wait_for_user_response());
mmu2_attn_buzz(true);
mmu2_attn_buzz();
command(MMU_CMD_R0);
manage_response(false, false);
@ -1017,7 +1017,7 @@ bool MMU2::unload() {
}
// Unload sequence to optimize shape of the tip of the unloaded filament
execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
ramming_sequence();
command(MMU_CMD_U0);
manage_response(false, true);
@ -1032,23 +1032,26 @@ bool MMU2::unload() {
return true;
}
void MMU2::ramming_sequence() {
static const E_Step sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE };
execute_extruder_sequence(sequence, COUNT(sequence));
}
void MMU2::load_to_nozzle_sequence() {
static const E_Step sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE };
execute_extruder_sequence(sequence, COUNT(sequence));
}
void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) {
planner.synchronize();
stepper.enable_extruder();
const E_Step* step = sequence;
const E_Step *step = sequence;
LOOP_L_N(i, steps) {
const float es = pgm_read_float(&(step->extrude));
const feedRate_t fr_mm_m = pgm_read_float(&(step->feedRate));
DEBUG_ECHO_MSG("E step ", es, "/", fr_mm_m);
current_position.e += es;
line_to_current_position(MMM_TO_MMS(fr_mm_m));
planner.synchronize();
unscaled_mmu2_e_move(es, MMM_TO_MMS(fr_mm_m));
step++;
}

View file

@ -47,13 +47,12 @@ public:
static void mmu_loop();
static void tool_change(const uint8_t index);
static void tool_change(const char *special);
static uint8_t get_current_tool();
static int8_t get_current_tool();
static void set_filament_type(const uint8_t index, const uint8_t type);
static bool unload();
static void load_filament(uint8_t);
static void load_all();
static bool load_filament_to_nozzle(const uint8_t index);
static void load_to_feeder(const uint8_t index);
static bool load_to_nozzle(const uint8_t index);
static bool eject_filament(const uint8_t index, const bool recover);
private:
@ -71,8 +70,9 @@ private:
static bool get_response();
static void manage_response(const bool move_axes, const bool turn_off_nozzle);
static void load_to_nozzle();
static void execute_extruder_sequence(const E_Step * sequence, int steps);
static void ramming_sequence();
static void load_to_nozzle_sequence();
static void filament_runout();
@ -96,7 +96,7 @@ private:
static int8_t state;
static volatile int8_t finda;
static volatile bool finda_runout_valid;
static int16_t version, buildnr;
static uint16_t version, buildnr;
static millis_t prev_request, prev_P0_request;
static char rx_buffer[MMU_RX_SIZE], tx_buffer[MMU_TX_SIZE];

View file

@ -102,7 +102,7 @@ void GcodeSuite::M701() {
// Load filament
#if HAS_PRUSA_MMU2
mmu2.load_filament_to_nozzle(target_extruder);
mmu2.load_to_nozzle(target_extruder);
#else
constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH,
slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;

View file

@ -33,20 +33,19 @@
// Load Filament
//
inline void action_mmu2_load_filament_to_nozzle(const uint8_t tool) {
ui.reset_status();
inline void action_mmu2_load_to_nozzle(const uint8_t tool) {
ui.return_to_status();
ui.status_printf(0, GET_TEXT_F(MSG_MMU2_LOADING_FILAMENT), int(tool + 1));
if (mmu2.load_filament_to_nozzle(tool)) ui.reset_status();
ui.return_to_status();
if (mmu2.load_to_nozzle(tool)) ui.reset_status();
}
void _mmu2_load_filament(uint8_t index) {
void _mmu2_load_to_feeder(const uint8_t index) {
ui.return_to_status();
ui.status_printf(0, GET_TEXT_F(MSG_MMU2_LOADING_FILAMENT), int(index + 1));
mmu2.load_filament(index);
mmu2.load_to_feeder(index);
ui.reset_status();
}
void action_mmu2_load_all() {
EXTRUDER_LOOP() _mmu2_load_filament(e);
ui.return_to_status();
@ -56,14 +55,14 @@ void menu_mmu2_load_filament() {
START_MENU();
BACK_ITEM(MSG_MMU2_MENU);
ACTION_ITEM(MSG_MMU2_ALL, action_mmu2_load_all);
EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_filament(MenuItemBase::itemIndex); });
EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_to_feeder(MenuItemBase::itemIndex); });
END_MENU();
}
void menu_mmu2_load_to_nozzle() {
START_MENU();
BACK_ITEM(MSG_MMU2_MENU);
EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_filament_to_nozzle(MenuItemBase::itemIndex); });
EXTRUDER_LOOP() ACTION_ITEM_N(e, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_to_nozzle(MenuItemBase::itemIndex); });
END_MENU();
}
@ -117,7 +116,7 @@ void menu_mmu2() {
// T* Choose Filament
//
uint8_t feeder_index;
int8_t feeder_index;
bool wait_for_mmu_menu;
inline void action_mmu2_chosen(const uint8_t index) {
@ -144,10 +143,10 @@ void menu_mmu2_pause() {
#if LCD_HEIGHT > 2
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, SS_DEFAULT|SS_INVERT);
#endif
ACTION_ITEM(MSG_MMU2_RESUME, []{ wait_for_mmu_menu = false; });
ACTION_ITEM(MSG_MMU2_RESUME, []{ wait_for_mmu_menu = false; });
ACTION_ITEM(MSG_MMU2_UNLOAD_FILAMENT, []{ mmu2.unload(); });
ACTION_ITEM(MSG_MMU2_LOAD_FILAMENT, []{ mmu2.load_filament(feeder_index); });
ACTION_ITEM(MSG_MMU2_LOAD_TO_NOZZLE, []{ mmu2.load_filament_to_nozzle(feeder_index); });
ACTION_ITEM(MSG_MMU2_LOAD_FILAMENT, []{ mmu2.load_to_feeder(feeder_index); });
ACTION_ITEM(MSG_MMU2_LOAD_TO_NOZZLE, []{ mmu2.load_to_nozzle(feeder_index); });
END_MENU();
}

View file

@ -73,6 +73,14 @@ opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 TEMP_SENSOR_PROBE
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER FIX_MOUNTED_PROBE Z_SAFE_HOMING
exec_test $1 $2 "Rambo heated bed only" "$3"
#
# Rambo with MMU2
#
restore_configs
opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 5 MMU_MODEL PRUSA_MMU2
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE EMERGENCY_PARSER MMU2_DEBUG
exec_test $1 $2 "Rambo with PRUSA_MMU2 " "$3"
#
# Build with the default configurations
#