Better start gcode to mitigate first layer clogs (all-metal hotends)

I’ve not seen this discussed in detail elsewhere, but another improvement for the J1…

On the monster thread regarding intermittent skips/clogs, and the ultimate solution of all-metal hotends, I highlighted that whether homemade or Snapmaker official, I started sometimes getting first-layer hard clogs with all-metal hotends.

I suggested the solution might be the default start gcode (at least for Cura plugin) could be the problem: It heats both the hotend and bed at the same time, but the bed takes a few more minutes. Instead, preheating the bed before heating the hotend works better. I discovered this accidentally because I usually preheat while slicing, and in that case hadn’t noticed any clogs.

@Mechanikus says yes and suggests one better: Preheat the bed to 5 degrees less than target, then heat both to target. This wastes less time, since the nozzle takes about 5 degrees of bed temperature to fully heat itself.

Let’s take a look at the start gcode as specified in the Snapmaker Plugin for Cura. (Your slicer may vary!)

;--- Start G-code Begin ---
M104 S{material_print_temperature_layer_0} ;Set Hotend Temperature
M140 S{material_bed_temperature_layer_0} ;Set Bed Temperature
G28 ;Home
G1 Z0.8
M109 S{material_print_temperature_layer_0}
M190 S{material_bed_temperature_layer_0}
G1 Z0.8 F6000
M201 X10000 Y10000 Z500 E5000
M205 V5
G92 E0
G1 F200 E2
G92 E0
;--- Start G-code End ---

Line 2 (M104) starts the hotend heating. Line 3 (M140) starts the bed heating. Lines 5 and 6 then wait for the hotend and bed, respectively. The hotend heats in about a minute. The thick glass bed takes 4-5 minutes.

The following is an alternative solution that follows @Mechanikus improved suggestion. Unfortunately Cura does not permit math in start/stop gcode macros like Prusa Slicer. We find this solution instead on StackExchange.

1) Define the bed pre-heat temp:
First, in $CURA_PATH$\share\cura\resources\definitions (Windows), find the file fdmprinter.def.json. In this, find the block definition for the variable "material_bed_temperature_layer_0": and add the following variable definition in the block after:

                "material_bed_temperature_pre":
                    {
                        "label": "Build Plate Preheat Temperature",
                        "description": "The temperature used for preheating the heated build plate.",
                        "unit": "°C",
                        "type": "float",
                        "resolve": "material_bed_temperature_pre",
                        "default_value": "material_bed_temperature_layer_0 - 5",
                        "value": "material_bed_temperature_layer_0 - 5",
                        "minimum_value": "0",
                        "minimum_value_warning": "max(build_volume_temperature, max(extruderValues('material_bed_temperature')))",
                        "maximum_value_warning": "130",
                        "maximum_value": "200",
                        "enabled": "false",
                        "settable_per_mesh": false,
                        "settable_per_extruder": false,
                        "settable_per_meshgroup": false
                },

This creates a new variable material_bed_temperature_pre we can use in our start gcode that’s 5 degC lower than the first layer bed temp.

2) Modify start gcode for Snapmaker J1
Now in Cura, go to the Machine Settings for the Snapmaker J1 and modify the first few lines of the start gcode to be:

;--- Start G-code Begin ---
M140 S{material_bed_temperature_pre} ;Set Bed Preheat Temperature
G28 ;Home
G1 Z0.8
M190 S{material_bed_temperature_pre} ;Wait for bed preheat
M104 S{material_print_temperature_layer_0} ;Set hotend temp
M140 S{material_bed_temperature_layer_0} ;Set full bed temp
M109 S{material_print_temperature_layer_0} ;Wait for hotend temp
M190 S{material_bed_temperature_layer_0} ;And full bed temp
G1 Z0.8 F6000
M201 X10000 Y10000 Z500 E5000
M205 V5
G92 E0
G1 F200 E2
G92 E0
;--- Start G-code End ---

Note we still do M104 and M140 before doing M109 and M190. This is to make sure both start heating before getting to the first wait command, so one does not possibly block the other from starting because it hasn’t reached temp yet.

Save the new start gcode, and restart Cura if you haven’t already to pick up the changes. Also double check the start gcode sticks after restarting.

Starting from cold, this is now the result:

The bed (blue) preheats to 55 C in 3-4 minutes. The hotend (red) then turns on and heats to 210 C while the bed finishes heating from 55C to 60 C in about one additional minute.

And @Mechanikus is right! In this test for PLA-like settings, the hotend and bed were finished heating at almost the exact same time.

Snapmaker Luban
Luban is very Cura-like. The above should work, however I think the variable must be added in the file $LUBAN_PATH$\resources\app\resources\print-settings\printing\fdmprinter.def.json. Then the start gcode modified as it is above for Cura.

There is not a UI interface to editing the start gcode in Luban. I seem to recall you need to directly edit the machine json file for the Snapmaker J1 to change start gcode? It is contained in $LUBAN_PATH$\resources\app\resources\print-settings\printing\snapmaker_j1\machine.def.json in the variable machine_start_gcode.

One would need to test and confirm details.

Prusa/Orca Slicers
The modified start gcode above would be similar. However, these slicers support variable arithmetic. So you can skip defining material_bed_temperature_pre and replace it in the start gcode above with the arithmetic for “whatever bed temp variable - 5”. I’m not so familiar with those slicers, but maybe someone can post their tested solution.

1 Like

@Wombley Nicely done - and you reminded me of one of the reasons why I believe Marlin is dumb like sh*t - no standby temp support, and especially no M116 support which is why you to have to tell a Marlin printer everything temp related not once but twice :slight_smile:

My Prusaslicer start gcode varies from what a standard J1 requires since Reprapfirmware is not Marlin, so please doublecheck the following since I backported it without being able to test:

{if is_extruder_used[0] && is_extruder_used[1]}
  M190 S{(first_layer_bed_temperature[0] > first_layer_bed_temperature[1] ? first_layer_bed_temperature[1] - 5 : first_layer_bed_temperature[0] - 5 )} ; preheat bed and wait
  M104 S{first_layer_temperature[0]} T0          ; set final temp for hotend 1
  M104 S{first_layer_temperature[1]} T1          ; set final temp for hotend 2
  M140 S{(first_layer_bed_temperature[0] > first_layer_bed_temperature[1] ? first_layer_bed_temperature[1] : first_layer_bed_temperature[0] )} ; set final bed temp, choose the lower one if both vary
  ; add whatever code the original J1 needs to move both hotends away from the silicone pads by 8mm here...
  M109 S{first_layer_temperature[0]} T0          ; wait for final temp for hotend 1
  M109 S{first_layer_temperature[1]} T1          ; wait for final temp for hotend 2 
  M190 S{(first_layer_bed_temperature[0] > first_layer_bed_temperature[1] ? first_layer_bed_temperature[1] : first_layer_bed_temperature[0] )} ; wait final bed temp, choose the lower one if both vary
{else}
  M190 S{first_layer_bed_temperature[initial_extruder] - 5}                   ; preheat bed and wait
  M104 S{first_layer_temperature[initial_extruder]} T{initial_extruder}       ; set final temp for hotend to be used, whichever one that is
  M140 S{first_layer_bed_temperature[initial_extruder]}                       ; set final bed temp
  ; add whatever code the original J1 needs to move the active hotend away from the silicone pad by 8mm here...
  M109 S{first_layer_temperature[initial_extruder]} T{initial_extruder}       ; wait for final temp for hotend to be used, whichever one that is
  M190 S{first_layer_bed_temperature[initial_extruder]}                       ; wait for final bed temp
{endif}

In this setup, the lower bed temperature is chosen if both hotends are used and have varying bed temperatures. If you want the higher temperature to be used, just flip the “>” signs to “<”.

1 Like

Nah, you can do one set and wait command (109/190) and it will start going up immediately. Unless you need it to wait for two or wanna do something else, then you need the non blocking sets (104/140) to get them going so you can wait for both or do whatever else (like homing).

That’s exactly what I meant - apart from the simplest of all use cases, Marlin is dumb :stuck_out_tongue:

In RRF, I can choose between M109/M190 and M104 (or rather M568 if I want to set hotend standby temps as well)/M140 - followed by a single M116 which tells the system to wait until all set temperatures are reached - and can even define the target temp tolerance on the fly there if I want.

1 Like

Ohhhhh! M116! :sweat_smile: Reading comprehension failure on my part. Is this not available in Marlin or newer Marlin? Wonder if it could be compiled in. Although I’m not too bothered now that it works.

If the list at Gcode | Marlin Firmware is complete, then no :wink:

1 Like

(slightly OT, hence separate post)

That should be possible, but you need to know how and you need to write it first in… whatever programming language Marlin is written in. And you need to compile it in every time you want an upgrade of the base firmware.

In Reprapfirmware on the other hand, I recreated everything custom including all the calibration routines of the J1 as a plain conditional gcode macro. This was easier (I am an absolutely lousy programmer, but gcode is something I believe I can create at least rather decent results in), and the firmware itself remains completely clean like that - if I want to upgrade, I download any latest revision from the Duet team, upload it to the printer via the webinterface - and that’s it, at least unless the rare case of a significant change within a gcode command happens.

Now try the same using Marlin… :joy: :innocent:

1 Like