[toolchanger] [Prusa XL] M104.1 is useless (for now)
OrcaSlicer Version
2.2.0 nightly
Operating System (OS)
Linux
OS Version
Ubuntu 24.04 LTS
Printer
Original Prusa XL 5T
Expected results
M104.1 is NOT yet implemented by Prusa Buddy Firmware, it is processed as it was standard M104, it should not be used on the current tool.
Anything else?
M104.1 GCode was introduced to Prusa-Firmware-Buddy by this commit: https://github.com/prusa3d/Prusa-Firmware-Buddy/commit/652a65f8c176db7069917d13bb51dab6b40769ae
and PrusaSlicer started to use M104.1 in place of M104 with this commit: https://github.com/prusa3d/PrusaSlicer/commit/c916249f2b0e2d9b50077cf3c2402115426ef4f4
Its current implementation is to simply process this command as if it was standard M104 :
void PrusaGcodeSuite::M104_1() {
const bool is_stealth_mode = marlin_vars()->stealth_mode.get();
// We will be applying a thermal model in the future to better evaluate when the tool should start being heated.
// For now, we start heating as soon as we see the gcode and ignore the time data.
const bool should_start_preheating = //
(parser.seen('P') && !is_stealth_mode)
|| (parser.seen('Q') && is_stealth_mode);
// If we should start preheating, simply process this command as if it was standard M104 (otherwise do nothing)
if (should_start_preheating) {
GcodeSuite::M104();
}
}
So for now issuing this command modifies the temperature of the nozzle too early, so it should not be used on the current tool !
How to reproduce
compile a multicolor print for prusa XL
related to #6285
In my example, I have two tools ( T0 and T1). T1 is purged first, T0 second. A very strange effect (probably by fw planner) I found out (watching the display of my Prusa XL) that issuing a M104.1 on current tool has the effect of immediately setting the tool to the temperature that will be set in the future (but not the one given as its S parameter). In the picture bellow (also video below), M104.1 at line 489 (sets a temp of 225) has the effect of immediately setting T1 temperature to 199, as set by M104 at line 500:
video: https://youtu.be/8H7SEEuuDPg?feature=shared .
I requested prusa:
- to ignore m104.1 for current tool https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4115
- investigate why m104.1 sets the temp of future M104 https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4116
- to fully implement M104.1 https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4117
seems like M104.1 will be implemented one way or another: https://github.com/prusa3d/Prusa-Firmware-Buddy/pull/4143/commits/df63454018c5b9e47b3fff93275a88e53cbb26b1
Seems like M104.1 will not be implemented soon. @bkerler : https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4115#issuecomment-2318925584
M104.1 should be removed, for now, from OrcaSlicer
Orca bot: this issue is stale because it has been open for 90 days with no activity.
M104.1 îs still not implemented in fw
Orca bot: this issue is stale because it has been open for 90 days with no activity.
M104.1 is still not implemented in prusa buddy fw
M104.1 will be fixed în Prusa FW: https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4117#issuecomment-2709994590 Internal Prusa ticket: BFW-6887: https://github.com/prusa3d/Prusa-Firmware-Buddy/issues/4115#issuecomment-2709821658
Just want to make sure that completely removing the M104.1 command solves this issue?
If fully implemented in Prusa FW, the M104.1 command is usefull because M104.1 is an early set hotend temperature, this GCode is used to tell the XL printer the time estimate when a tool will be used next, so that the printer can start preheating the tool in advance.
I would remove M104.1 until Prusa FW bugs 4115 and 4116 are fixed. and replace it with a M104 called 2 minutes before the temperature is needed for that tool (almost 2 minutes is the time my prusa XL takes to heat up a nozzle from 27 degrees to 230 degrees)
If fully implemented in Prusa FW, the M104.1 command is usefull because M104.1 is an early set hotend temperature, this GCode is used to tell the XL printer the time estimate when a tool will be used next, so that the printer can start preheating the tool in advance.
I would remove M104.1 until Prusa FW bugs 4115 and 4116 are fixed. and replace it with a M104 called 2 minutes before the temperature is needed for that tool (almost 2 minutes is the time my prusa XL takes to heat up a nozzle from 27 degrees to 230 degrees)
Would you be able to provide me with an updated start G-Code to include in #8833? As I don't own this printer and I'm not sure where the optimal spot for the M104 command is.
M104.1 was added to orcaslicer by commit 7d0fb4f42a3f6a1f43503a601491071b8e29052c, at line https://github.com/SoftFever/OrcaSlicer/commit/7d0fb4f42a3f6a1f43503a601491071b8e29052c#diff-1f5d18f06c84f1f68257febe446ee00eee453682fb6b116dd8bdb6796ef0f319R4951 in GCodeProcessor.cpp (now at line https://github.com/SoftFever/OrcaSlicer/blob/79a5a9b5f85895ae24fad8b5070c64b495e1f522/src/libslic3r/GCode/GCodeProcessor.cpp#L4608 )
// Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from
// Prusa-Firmware-Buddy here
/**
* M104.1: Early Set Hotend Temperature (preheat, and with stealth mode support)
*
* This GCode is used to tell the XL printer the time estimate when a tool will be used next,
* so that the printer can start preheating the tool in advance.
*
* ## Parameters
* - `P` - <number> - time in seconds till the temperature S is required (in standard mode)
* - `Q` - <number> - time in seconds till the temperature S is required (in stealth mode)
* The rest is same as M104
*/
if (this->m_is_XL_printer) {
std::string out = "M104.1 T" + std::to_string(tool_number);
if (time_diffs.size() > 0)
out += " P" + std::to_string(int(std::round(time_diffs[0])));
if (time_diffs.size() > 1)
out += " Q" + std::to_string(int(std::round(time_diffs[1])));
out += " S" + std::to_string(temperature) + "\n";
return out;
} else {
std::string comment = "preheat tool " + std::to_string(tool_number) +
"time: " + std::to_string(std::round(time_diffs[0])) + "s";
return GCodeWriter::set_temperature(temperature, this->m_flavor, false, tool_number, comment);
}
M104.1 is not in the default start G-Code , but added later in processing.
The current PrusaSlicer start G-code for prusa XL is ( https://github.com/prusa3d/PrusaSlicer-settings-prusa-fff/blob/6dfc7ff5d851f6f7d059936cf28c534b2849c2c3/PrusaResearch/2.2.4.ini#L34394 ):
M17 ; enable steppers
M862.3 P "XL" ; printer model check
M862.5 P2 ; g-code level check
M862.6 P"Input shaper" ; FW feature check
M115 U6.2.2+8853
G90 ; use absolute coordinates
M83 ; extruder relative mode
; set print area
M555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}
; inform about nozzle diameter
{if (is_extruder_used[0])}M862.1 T0 P{nozzle_diameter[0]} A{(filament_abrasive[0] ? 1 : 0)} F{(nozzle_high_flow[0] ? 1 : 0)}{endif}
{if (is_extruder_used[1])}M862.1 T1 P{nozzle_diameter[1]} A{(filament_abrasive[1] ? 1 : 0)} F{(nozzle_high_flow[1] ? 1 : 0)}{endif}
{if (is_extruder_used[2])}M862.1 T2 P{nozzle_diameter[2]} A{(filament_abrasive[2] ? 1 : 0)} F{(nozzle_high_flow[2] ? 1 : 0)}{endif}
{if (is_extruder_used[3])}M862.1 T3 P{nozzle_diameter[3]} A{(filament_abrasive[3] ? 1 : 0)} F{(nozzle_high_flow[3] ? 1 : 0)}{endif}
{if (is_extruder_used[4])}M862.1 T4 P{nozzle_diameter[4]} A{(filament_abrasive[4] ? 1 : 0)} F{(nozzle_high_flow[4] ? 1 : 0)}{endif}
; turn off unused heaters
{if ! is_extruder_used[0]}M104 T0 S0{endif}
{if ! is_extruder_used[1]}M104 T1 S0{endif}
{if num_extruders > 2 and ! is_extruder_used[2]}M104 T2 S0{endif}
{if num_extruders > 3 and ! is_extruder_used[3]}M104 T3 S0{endif}
{if num_extruders > 4 and ! is_extruder_used[4]}M104 T4 S0{endif}
M217 Z{max(zhop, 2.0)} ; set toolchange z hop to 2mm, or zhop variable from slicer if higher
; set bed and extruder temp for MBL
M140 S[first_layer_bed_temperature] ; set bed temp
G0 Z5 ; add Z clearance
M109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == "PC" or filament_type[initial_tool] == "PA") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == "FLEX") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp
; Home XY
G28 XY
; try picking tools used in print
G1 F{travel_speed * 60}
{if (is_extruder_used[0]) and (initial_tool != 0)}T0 S1 L0 D0{endif}
{if (is_extruder_used[1]) and (initial_tool != 1)}T1 S1 L0 D0{endif}
{if (is_extruder_used[2]) and (initial_tool != 2)}T2 S1 L0 D0{endif}
{if (is_extruder_used[3]) and (initial_tool != 3)}T3 S1 L0 D0{endif}
{if (is_extruder_used[4]) and (initial_tool != 4)}T4 S1 L0 D0{endif}
; select tool that will be used to home & MBL
T{initial_tool} S1 L0 D0
; home Z with MBL tool
M84 E ; turn off E motor
G28 Z
G0 Z5 ; add Z clearance
M104 T{initial_tool} S{if is_nil(idle_temperature[initial_tool])}70{else}{idle_temperature[initial_tool]}{endif} ; set idle temp
M190 S[first_layer_bed_temperature] ; wait for bed temp
G29 G ; absorb heat
M109 T{initial_tool} S{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == "PC" or filament_type[initial_tool] == "PA") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == "FLEX") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp
; move to the nozzle cleanup area
G1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F{(travel_speed * 60)}
M302 S160 ; lower cold extrusion limit to 160C
G1 E{-(filament_type[0] == "FLEX" ? 4 : 2)} F2400 ; retraction for nozzle cleanup
; nozzle cleanup
M84 E ; turn off E motor
G29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}
G0 Z5 F480 ; move away in Z
M107 ; turn off the fan
; MBL
M84 E ; turn off E motor
G29 P1 ; invalidate mbl & probe print area
G29 P1 X30 Y0 W{(((is_extruder_used[4]) or ((is_extruder_used[3]) or (is_extruder_used[2]))) ? "300" : ((is_extruder_used[1]) ? "130" : "50"))} H20 C ; probe near purge place
G29 P3.2 ; interpolate mbl probes
G29 P3.13 ; extrapolate mbl outside probe area
G29 A ; activate mbl
G1 Z10 F720 ; move away in Z
G1 F{travel_speed * 60}
P0 S1 L1 D0; park the tool
; set extruder temp
{if first_layer_temperature[0] > 0 and (is_extruder_used[0])}M104 T0 S{first_layer_temperature[0]}{endif}
{if first_layer_temperature[1] > 0 and (is_extruder_used[1])}M104 T1 S{first_layer_temperature[1]}{endif}
{if first_layer_temperature[2] > 0 and (is_extruder_used[2])}M104 T2 S{first_layer_temperature[2]}{endif}
{if first_layer_temperature[3] > 0 and (is_extruder_used[3])}M104 T3 S{first_layer_temperature[3]}{endif}
{if first_layer_temperature[4] > 0 and (is_extruder_used[4])}M104 T4 S{first_layer_temperature[4]}{endif}
{if (is_extruder_used[0]) and initial_tool != 0}
;
; purge first tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T0 S{first_layer_temperature[0]}
T0 S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X30 Y-7 Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[0])}10{else}30{endif} X40 Z0.2 F{if is_nil(filament_multitool_ramming[0])}500{else}170{endif} ; purge while moving towards the sheet
G0 X70 E9 F800 ; continue purging and wipe the nozzle
G0 X73 Z0.05 F8000 ; wipe, move close to the bed
G0 X76 Z0.2 F8000 ; wipe, move quickly away from the bed
G1 E{-retract_length_toolchange[0]} F2400 ; retract
{e_retracted[0] = retract_length_toolchange[0]}
G92 E0 ; reset extruder position
M104 S{(is_nil(idle_temperature[0]) ? (first_layer_temperature[0] + standby_temperature_delta) : (idle_temperature[0]))} T0
{endif}
{if (is_extruder_used[1]) and initial_tool != 1}
;
; purge second tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T1 S{first_layer_temperature[1]}
T1 S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X150 Y-7 Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[1])}10{else}30{endif} X140 Z0.2 F{if is_nil(filament_multitool_ramming[1])}500{else}170{endif} ; purge while moving towards the sheet
G0 X110 E9 F800 ; continue purging and wipe the nozzle
G0 X107 Z0.05 F8000 ; wipe, move close to the bed
G0 X104 Z0.2 F8000 ; wipe, move quickly away from the bed
G1 E{-retract_length_toolchange[1]} F2400 ; retract
{e_retracted[1] = retract_length_toolchange[1]}
G92 E0 ; reset extruder position
M104 S{(is_nil(idle_temperature[1]) ? (first_layer_temperature[1] + standby_temperature_delta) : (idle_temperature[1]))} T1
{endif}
{if (is_extruder_used[2]) and initial_tool != 2}
;
; purge third tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T2 S{first_layer_temperature[2]}
T2 S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X210 Y-7 Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[2])}10{else}30{endif} X220 Z0.2 F{if is_nil(filament_multitool_ramming[2])}500{else}170{endif} ; purge while moving towards the sheet
G0 X250 E9 F800 ; continue purging and wipe the nozzle
G0 X253 Z0.05 F8000 ; wipe, move close to the bed
G0 X256 Z0.2 F8000 ; wipe, move quickly away from the bed
G1 E{-retract_length_toolchange[2]} F2400 ; retract
{e_retracted[2] = retract_length_toolchange[2]}
G92 E0 ; reset extruder position
M104 S{(is_nil(idle_temperature[2]) ? (first_layer_temperature[2] + standby_temperature_delta) : (idle_temperature[2]))} T2
{endif}
{if (is_extruder_used[3]) and initial_tool != 3}
;
; purge fourth tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T3 S{first_layer_temperature[3]}
T3 S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X330 Y-7 Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[3])}10{else}30{endif} X320 Z0.2 F{if is_nil(filament_multitool_ramming[3])}500{else}170{endif} ; purge while moving towards the sheet
G0 X290 E9 F800 ; continue purging and wipe the nozzle
G0 X287 Z0.05 F8000 ; wipe, move close to the bed
G0 X284 Z0.2 F8000 ; wipe, move quickly away from the bed
G1 E{-retract_length_toolchange[3]} F2400 ; retract
{e_retracted[3] = retract_length_toolchange[3]}
G92 E0 ; reset extruder position
M104 S{(is_nil(idle_temperature[3]) ? (first_layer_temperature[3] + standby_temperature_delta) : (idle_temperature[3]))} T3
{endif}
{if (is_extruder_used[4]) and initial_tool != 4}
;
; purge fifth tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T4 S{first_layer_temperature[4]}
T4 S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X330 Y-4.5 Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[4])}10{else}30{endif} X320 Z0.2 F{if is_nil(filament_multitool_ramming[4])}500{else}170{endif} ; purge while moving towards the sheet
G0 X290 E9 F800 ; continue purging and wipe the nozzle
G0 X287 Z0.05 F8000 ; wipe, move close to the bed
G0 X284 Z0.2 F8000 ; wipe, move quickly away from the bed
G1 E{-retract_length_toolchange[4]} F2400 ; retract
{e_retracted[4] = retract_length_toolchange[4]}
G92 E0 ; reset extruder position
M104 S{(is_nil(idle_temperature[4]) ? (first_layer_temperature[4] + standby_temperature_delta) : (idle_temperature[4]))} T4
{endif}
;
; purge initial tool
;
G1 F{travel_speed * 60}
P0 S1 L2 D0; park the tool
M109 T{initial_tool} S{first_layer_temperature[initial_tool]}
T{initial_tool} S1 L0 D0; pick the tool
G92 E0 ; reset extruder position
G0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330)))} Y{(initial_tool < 4 ? -7 : -4.5)} Z10 F{(travel_speed * 60)} ; move close to the sheet's edge
G0 E{if is_nil(filament_multitool_ramming[initial_tool])}10{else}30{endif} X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 10)} Z0.2 F{if is_nil(filament_multitool_ramming[initial_tool])}500{else}170{endif} ; purge while moving towards the sheet
G0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40)} E9 F800 ; continue purging and wipe the nozzle
G0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3)} Z{0.05} F{8000} ; wipe, move close to the bed
G0 X{(initial_tool == 0 ? 30 : (initial_tool == 1 ? 150 : (initial_tool == 2 ? 210 : 330))) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 40) + ((initial_tool == 0 or initial_tool == 2 ? 1 : -1) * 3 * 2)} Z0.2 F{8000} ; wipe, move quickly away from the bed
G1 E-{retract_length[initial_tool]} F2400 ; retract
{e_retracted[initial_tool] = retract_length[initial_tool]}
G92 E0 ; reset extruder position
Seeing as this seems to be a issue from the code that you pointed out. I commented the relative code out and this issue should hopefully be fixed. The build with this change can be found here.
Thanks for finding out about that code change!
Orca bot: this issue is stale because it has been open for 90 days with no activity.
Orca bot: this issue is stale because it has been open for 90 days with no activity.