Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ script:
- opt_enable LCM1602
- build_marlin
#
# Enable FILAMENTCHANGEENABLE
# Enable FILAMENT_CHANGE_ENABLE
#
- restore_configs
- opt_enable FILAMENTCHANGEENABLE ULTIMAKERCONTROLLER
- opt_enable FILAMENT_CHANGE_ENABLE ULTIMAKERCONTROLLER
- build_marlin
#
# Enable filament sensor
Expand Down
34 changes: 24 additions & 10 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,16 +506,30 @@ const unsigned int dropsegments = 5; //everything with less than this number of

// Add support for experimental filament exchange support M600; requires display
#if ENABLED(ULTIPANEL)
//#define FILAMENTCHANGEENABLE
#if ENABLED(FILAMENTCHANGEENABLE)
#define FILAMENTCHANGE_XPOS 3
#define FILAMENTCHANGE_YPOS 3
#define FILAMENTCHANGE_ZADD 10
#define FILAMENTCHANGE_FIRSTRETRACT -2
#define FILAMENTCHANGE_FINALRETRACT -100
#define AUTO_FILAMENT_CHANGE //This extrude filament until you press the button on LCD
#define AUTO_FILAMENT_CHANGE_LENGTH 0.04 //Extrusion length on automatic extrusion loop
#define AUTO_FILAMENT_CHANGE_FEEDRATE 300 //Extrusion feedrate (mm/min) on automatic extrusion loop
// #define FILAMENT_CHANGE_ENABLE // Enable filament exchange menu and M600 g-code (used for runout sensor too)
#if ENABLED(FILAMENT_CHANGE_ENABLE)
#define FILAMENT_CHANGE_X_POS 3 // X position of hotend
#define FILAMENT_CHANGE_Y_POS 3 // Y position of hotend
#define FILAMENT_CHANGE_Z_ADD 10 // Z addition of hotend (lift)
#define FILAMENT_CHANGE_XY_FEEDRATE 100 // X and Y axes feedrate in mm/s (also used for delta printers Z axis)
#define FILAMENT_CHANGE_Z_FEEDRATE 5 // Z axis feedrate in mm/s (not used for delta printers)
#define FILAMENT_CHANGE_RETRACT_LENGTH 2 // Initial retract in mm
// It is a short retract used immediately after print interrupt before move to filament exchange position
#define FILAMENT_CHANGE_RETRACT_FEEDRATE 60 // Initial retract feedrate in mm/s
#define FILAMENT_CHANGE_UNLOAD_LENGTH 100 // Unload filament length from hotend in mm
// Longer length for bowden printers to unload filament from whole bowden tube,
// shorter lenght for printers without bowden to unload filament from extruder only,
// 0 to disable unloading for manual unloading
#define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10 // Unload filament feedrate in mm/s - filament unloading can be fast
#define FILAMENT_CHANGE_LOAD_LENGTH 0 // Load filament length over hotend in mm
// Longer length for bowden printers to fast load filament into whole bowden tube over the hotend,
// Short or zero length for printers without bowden where loading is not used
#define FILAMENT_CHANGE_LOAD_FEEDRATE 10 // Load filament feedrate in mm/s - filament loading into the bowden tube can be fast
#define FILAMENT_CHANGE_EXTRUDE_LENGTH 50 // Extrude filament length in mm after filament is load over the hotend,
// 0 to disable for manual extrusion
// Filament can be extruded repeatedly from the filament exchange menu to fill the hotend,
// or until outcoming filament color is not clear for filament color change
#define FILAMENT_CHANGE_EXTRUDE_FEEDRATE 3 // Extrude filament feedrate in mm/s - must be slower than load feedrate
#endif
#endif

Expand Down
13 changes: 11 additions & 2 deletions Marlin/Marlin.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ FORCE_INLINE void serialprintPGM(const char* str) {
}

void idle(
#if ENABLED(FILAMENTCHANGEENABLE)
bool no_stepper_sleep=false // pass true to keep steppers from disabling on timeout
#if ENABLED(FILAMENT_CHANGE_ENABLE)
bool no_stepper_sleep = false // pass true to keep steppers from disabling on timeout
#endif
);

Expand Down Expand Up @@ -352,6 +352,15 @@ extern bool axis_homed[3]; // axis[n].is_homed
extern int meas_delay_cm; //delay distance
#endif

#if ENABLED(FILAMENT_CHANGE_ENABLE)
enum FilamentChangeMenuResponse {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to remove the attributions:

enum FilamentChangeMenuResponse {
  FILAMENT_CHANGE_RESPONSE_WAIT_FOR,
  FILAMENT_CHANGE_RESPONSE_EXTRUDE_MORE,
  FILAMENT_CHANGE_RESPONSE_RESUME_PRINT
};

FILAMENT_CHANGE_RESPONSE_WAIT_FOR,
FILAMENT_CHANGE_RESPONSE_EXTRUDE_MORE,
FILAMENT_CHANGE_RESPONSE_RESUME_PRINT
};
extern FilamentChangeMenuResponse filament_change_menu_response;
#endif

#if ENABLED(PID_ADD_EXTRUSION_RATE)
extern int lpq_len;
#endif
Expand Down
215 changes: 126 additions & 89 deletions Marlin/Marlin_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,10 @@ static uint8_t target_extruder;
static bool filament_ran_out = false;
#endif

#if ENABLED(FILAMENT_CHANGE_ENABLE)
FilamentChangeMenuResponse filament_change_menu_response;
#endif

static bool send_ok[BUFSIZE];

#if HAS_SERVOS
Expand Down Expand Up @@ -5997,7 +6001,7 @@ inline void gcode_M503() {

#endif // CUSTOM_M_CODE_SET_Z_PROBE_OFFSET

#if ENABLED(FILAMENTCHANGEENABLE)
#if ENABLED(FILAMENT_CHANGE_ENABLE)

/**
* M600: Pause for filament change
Expand All @@ -6018,130 +6022,163 @@ inline void gcode_M503() {
SERIAL_ERRORLNPGM(MSG_TOO_COLD_FOR_M600);
return;
}


// Show initial message and wait for synchronize steppers
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_INIT);
st_synchronize();

float lastpos[NUM_AXIS];
#if ENABLED(DELTA)
float fr60 = feedrate / 60;
#endif


// Save current position of all axes
for (int i = 0; i < NUM_AXIS; i++)
lastpos[i] = destination[i] = current_position[i];


// Define runplan for move axes
#if ENABLED(DELTA)
#define RUNPLAN calculate_delta(destination); \
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], fr60, active_extruder);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], FILAMENT_CHANGE_XY_FEEDRATE * 60, active_extruder);
#else
#define RUNPLAN line_to_destination();
#define RUNPLAN line_to_destination(FILAMENT_CHANGE_XY_FEEDRATE * 60);
#endif

//retract by E

KEEPALIVE_STATE(IN_HANDLER);

// Initial retract before move to filament change position
if (code_seen('E')) destination[E_AXIS] += code_value();
#ifdef FILAMENTCHANGE_FIRSTRETRACT
else destination[E_AXIS] += FILAMENTCHANGE_FIRSTRETRACT;
#endif

RUNPLAN;

//lift Z
#ifdef FILAMENT_CHANGE_RETRACT_LENGTH
else destination[E_AXIS] -= FILAMENT_CHANGE_RETRACT_LENGTH;
#endif
line_to_destination(FILAMENT_CHANGE_RETRACT_FEEDRATE * 60);

// Lift Z axis
if (code_seen('Z')) destination[Z_AXIS] += code_value();
#ifdef FILAMENTCHANGE_ZADD
else destination[Z_AXIS] += FILAMENTCHANGE_ZADD;
#ifdef FILAMENT_CHANGE_Z_ADD
else {
if (destination[Z_AXIS] + FILAMENT_CHANGE_Z_ADD > Z_MAX_POS)
destination[Z_AXIS] = Z_MAX_POS;
else
destination[Z_AXIS] += FILAMENT_CHANGE_Z_ADD;
}
#endif
#if ENABLED(DELTA)
RUNPLAN;
#else
line_to_destination(FILAMENT_CHANGE_Z_FEEDRATE * 60);
#endif

RUNPLAN;

//move xy

// Move XY axes to filament exchange position
if (code_seen('X')) destination[X_AXIS] = code_value();
#ifdef FILAMENTCHANGE_XPOS
else destination[X_AXIS] = FILAMENTCHANGE_XPOS;
#endif

#ifdef FILAMENT_CHANGE_X_POS
else destination[X_AXIS] = FILAMENT_CHANGE_X_POS;
#endif
if (code_seen('Y')) destination[Y_AXIS] = code_value();
#ifdef FILAMENTCHANGE_YPOS
else destination[Y_AXIS] = FILAMENTCHANGE_YPOS;
#endif

#ifdef FILAMENT_CHANGE_Y_POS
else destination[Y_AXIS] = FILAMENT_CHANGE_Y_POS;
#endif
RUNPLAN;


// Synchronize steppers and show unload message
st_synchronize();
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_UNLOAD);

// Unload filament
if (code_seen('L')) destination[E_AXIS] += code_value();
#ifdef FILAMENTCHANGE_FINALRETRACT
else destination[E_AXIS] += FILAMENTCHANGE_FINALRETRACT;
#endif

RUNPLAN;

//finish moves
#ifdef FILAMENT_CHANGE_UNLOAD_LENGTH
else destination[E_AXIS] -= FILAMENT_CHANGE_UNLOAD_LENGTH;
#endif
line_to_destination(FILAMENT_CHANGE_UNLOAD_FEEDRATE * 60);

// Synchronize steppers and then disable extruders steppers for manual filament changing
st_synchronize();
//disable extruder steppers so filament can be removed
disable_e0();
disable_e1();
disable_e2();
disable_e3();
delay(100);
LCD_ALERTMESSAGEPGM(MSG_FILAMENTCHANGE);
#if DISABLED(AUTO_FILAMENT_CHANGE)
millis_t next_tick = 0;
#endif
KEEPALIVE_STATE(PAUSED_FOR_USER);

millis_t next_tick = 0;

// Wait for filament insert by user and press button
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_INSERT);

while (!lcd_clicked()) {
#if DISABLED(AUTO_FILAMENT_CHANGE)
#if HAS_BUZZER
millis_t ms = millis();
if (ELAPSED(ms, next_tick)) {
lcd_quick_feedback();
next_tick = ms + 2500UL; // feedback every 2.5s while waiting
if (ms >= next_tick) {
buzz(300, 2000);
next_tick = ms + 2500; // Beep every 2.5s while waiting
}
idle(true);
#else
current_position[E_AXIS] += AUTO_FILAMENT_CHANGE_LENGTH;
destination[E_AXIS] = current_position[E_AXIS];
line_to_destination(AUTO_FILAMENT_CHANGE_FEEDRATE);
st_synchronize();
#endif
} // while(!lcd_clicked)
KEEPALIVE_STATE(IN_HANDLER);
lcd_quick_feedback(); // click sound feedback

#if ENABLED(AUTO_FILAMENT_CHANGE)
current_position[E_AXIS] = 0;
st_synchronize();
#endif

//return to normal
idle(true);
}
delay(100);
while (lcd_clicked()) {
idle(true);
}
delay(100);

// Show load message
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_LOAD);

// Load filament
if (code_seen('L')) destination[E_AXIS] -= code_value();
#ifdef FILAMENTCHANGE_FINALRETRACT
else destination[E_AXIS] -= FILAMENTCHANGE_FINALRETRACT;
#ifdef FILAMENT_CHANGE_LOAD_LENGTH
else destination[E_AXIS] += FILAMENT_CHANGE_LOAD_LENGTH;
#endif
line_to_destination(FILAMENT_CHANGE_LOAD_FEEDRATE * 60);
st_synchronize();

#ifdef FILAMENT_CHANGE_EXTRUDE_LENGTH
do {
// Extrude filament to get into hotend
KEEPALIVE_STATE(IN_HANDLER);
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_EXTRUDE);
destination[E_AXIS] += FILAMENT_CHANGE_EXTRUDE_LENGTH;
line_to_destination(FILAMENT_CHANGE_EXTRUDE_FEEDRATE * 60);
st_synchronize();
// Ask user if more filament should be extruded
KEEPALIVE_STATE(PAUSED_FOR_USER);
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_OPTION);
while (filament_change_menu_response == FILAMENT_CHANGE_RESPONSE_WAIT_FOR) {
idle(true);
}
} while (filament_change_menu_response != FILAMENT_CHANGE_RESPONSE_RESUME_PRINT);
#endif

current_position[E_AXIS] = destination[E_AXIS]; //the long retract of L is compensated by manual filament feeding
sync_plan_position_e();

RUNPLAN; //should do nothing

lcd_reset_alert_level();


lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_RESUME);

KEEPALIVE_STATE(IN_HANDLER);

// Set extruder to saved position
current_position[E_AXIS] = lastpos[E_AXIS];
destination[E_AXIS] = lastpos[E_AXIS];
plan_set_e_position(current_position[E_AXIS]);

#if ENABLED(DELTA)
// Move XYZ to starting position, then E
calculate_delta(lastpos);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], fr60, active_extruder);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], lastpos[E_AXIS], fr60, active_extruder);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], FILAMENT_CHANGE_XY_FEEDRATE * 60, active_extruder);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], lastpos[E_AXIS], FILAMENT_CHANGE_XY_FEEDRATE * 60, active_extruder);
#else
// Move XY to starting position, then Z, then E
destination[X_AXIS] = lastpos[X_AXIS];
destination[Y_AXIS] = lastpos[Y_AXIS];
line_to_destination();
line_to_destination(FILAMENT_CHANGE_XY_FEEDRATE * 60);
destination[Z_AXIS] = lastpos[Z_AXIS];
line_to_destination();
destination[E_AXIS] = lastpos[E_AXIS];
line_to_destination();
line_to_destination(FILAMENT_CHANGE_Z_FEEDRATE * 60);
#endif

st_synchronize();

#if ENABLED(FILAMENT_RUNOUT_SENSOR)
filament_ran_out = false;
#endif


// Show status screen
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_STATUS);
KEEPALIVE_STATE(NOT_BUSY);
}

#endif // FILAMENTCHANGEENABLE
#endif // FILAMENT_CHANGE_ENABLE

#if ENABLED(DUAL_X_CARRIAGE)

Expand Down Expand Up @@ -6994,11 +7031,11 @@ void process_next_command() {
break;
#endif // CUSTOM_M_CODE_SET_Z_PROBE_OFFSET

#if ENABLED(FILAMENTCHANGEENABLE)
#if ENABLED(FILAMENT_CHANGE_ENABLE)
case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
gcode_M600();
break;
#endif // FILAMENTCHANGEENABLE
#endif // FILAMENT_CHANGE_ENABLE

#if ENABLED(DUAL_X_CARRIAGE)
case 605:
Expand Down Expand Up @@ -7738,13 +7775,13 @@ void disable_all_steppers() {
* Standard idle routine keeps the machine alive
*/
void idle(
#if ENABLED(FILAMENTCHANGEENABLE)
#if ENABLED(FILAMENT_CHANGE_ENABLE)
bool no_stepper_sleep/*=false*/
#endif
) {
manage_heater();
manage_inactivity(
#if ENABLED(FILAMENTCHANGEENABLE)
#if ENABLED(FILAMENT_CHANGE_ENABLE)
no_stepper_sleep
#endif
);
Expand Down
6 changes: 4 additions & 2 deletions Marlin/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@
/**
* Filament Change with Extruder Runout Prevention
*/
#if ENABLED(FILAMENTCHANGEENABLE) && ENABLED(EXTRUDER_RUNOUT_PREVENT)
#error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE.
#if ENABLED(FILAMENT_CHANGE_ENABLE) && ENABLED(EXTRUDER_RUNOUT_PREVENT)
#error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENT_CHANGE.
#endif

/**
Expand Down Expand Up @@ -506,6 +506,8 @@
#error DISABLE_MAX_ENDSTOPS and DISABLE_MIN_ENDSTOPS deprecated. Use individual USE_*_PLUG options instead.
#elif ENABLED(Z_DUAL_ENDSTOPS) && !defined(Z2_USE_ENDSTOP)
#error Z_DUAL_ENDSTOPS settings are simplified. Just set Z2_USE_ENDSTOP to the endstop you want to repurpose for Z2
#elif ENABLED(FILAMENTCHANGEENABLE)
#error FILAMENTCHANGEENABLE was renamed to FILAMENT_CHANGE_ENABLE
#endif

#endif //SANITYCHECK_H
Loading