Printer Model: CoreXY
MCU / Printerboard: Not relevant
`klippy.log not relevant
Describe your issue:
Hi, new to the klipper here. I haven’t found how to go around this:
To make it short, in gcode macro, how to get out of print area for tool change.(defined in config.cfg stepper_x or _y : position_max: )
So far I have had to extend the position_max out of the actual print area. But in long run, I don’t wan’t to be possible to accidentally command, or try to print to the tool parking area. Crashing to the tools can do damages.
Is there command to bypass the position_max value temporarily? (I know, this should not be the way to go)
OR
Can I manipulate the positon_max in macro temporarily and then restore after tool chg?
OR
Is there a config setting for actual printable area?
OR
Is there setting for “no go” area, but accessible with permission?
If there is no solution, this could be a feature request. Could be helpful for other features too, like nozzle cleaning. In my opinion, tool parking area should be somehow protected in normal operation.
I’m pretty sure that the firmware also prevents the gcode from actually causing the tool head to go outside the defined “physical limits”, right? So I think what OP is asking is how to use different “physical limits” definitions while printing and while changing tools.
Yes, that is what I’m looking for and would be good feature.
Unbreakable limits for the machine (as they are now, position_min / _max)
And
Additional llimits that could be defined but bypass when needed. Should be <positon_max OR >Position_min.
If there is a user that don’t care to define slicer print area, one could easily and accidentally try to print to tool park area = mayhem
Manual move does not care about slicer.
The buttons/menus in (whatever) UI, its easy to confuse and run Y100 when he meant to go Y10 because failed to select 10mm movement instead of 100mm and rams 300mm/s to the tools parked = Mayhem.
As @jakep_82 already indicated: Presently this is not foreseen. Klipper’s architecture requires:
Physical machine limits (that should stay immutable, since well, they are the physical limits) are defined in Klipper
All movements and actions within these limits are defined in the slicer. This is exactly the reason why slicers already offer machine dependent profiles to care for such
My personal opinion is that it belongs into the realm of slicers and has no real benefit in a firmware. Each puzzle piece in the 3D printing process chain shall care for their core competency and not start duplicating stuff. There is already enough “grey area” out of history.
If you like then you can consider this a feature request and hope to find a developer willing to dig into it.
@mattiras have you try to make the print area in variable ? so you can add in your tool changing scripts/macros (I come to klipper from RRF) there are 3 files tfree tpre tpost and you can change in tfree in first line your tool_move_area and in tpost you can after picking your tool is done change back to print_save area. Maybe this help you I can show you e3d tool changer scripts for duet3d to get more inspired.
Yes, I have custom print area variables, and the tool change macros are working.
But they don’t prevent accidental G1/G0 moves to tool park area, which in my consept = trouble.
I can live with the idea that the slicer is always configured correctly (in perfect world)
But still, Slicer has NOTHING to do with moves made other ways (say, by the user) in printer.
I don’t understand that the slicer is to be held responsible of moves in printer when it comes to implementing tools. Specially I should have means to prevent accidental manual moves (which WILL happen to everyone, not one time, not twice but many times) to tool park area.
I totally understand that the Min/Max are there to protect the machine.
But not the tools. Aren’t the tools part of the machine?
English is not my native language, I hope my input here does not seem too harsh.
Klipper is great and flexible firmware but I just disagree here. Could this thread be changed to be FR?
EDIT BTW. I’m converting my machine from Marlin, there the tool change is executed outside of defined min/max by default. And the machine prevented G1/G0 commands to go to tool park area.
This is simply not true. E.g., when I move the gantry using the buttons in mainsail it has absolutely nothing to do with the slicer.
I’m with @mattiras on this one; there are cases where you would want to have two (or more) sets of “physical limits”, and ability to switch between them somehow (if not automatically/procedurally then at least manually using some macro). Maybe you have some toolchanger, or maybe you have asymmetric idex heads (i.e., the left head can’t go fully to the right, and/or vice versa), or perhaps you have a delta printer where the print area is smaller high up, or you have some cleaning brush or poop-chute or heating system at some height range, or whatever. The fact is, this can very well be a feature that is immensely useful for many people in multiple different situations.
Either change this post to the “Features” Category or create a new one.
But let me consult my magic crystal ball: …The mists of the distant future are clearing up…I see…I see…<scared gasp (for the drama)>…very limited developer resources…tons of features with a higher impact still undeveloped…then…nothing
I can totally get behind the idea that certain functionality belongs in a certain place and not try to duplicate functionality “just in case” someone might think of a reason.
But for this request I’m on the side of allowing the firmware to move outside the defined limits. There are many real life, non-hypothetical reasons to allow this. I’ll add my own to the list @marcus-in-3d already made:
I have dual piggyback z steppers on my gantry. I’ve placed carefully measured hard stops at the upper extreme of the vertical limit. To level the gantry I drive the z axis up and into the hard stops, the steppers skip as many steps as they need to until it’s perfectly level, and then I re-home the z. In regular printing the z axis has no business going that high, in fact I want the firmware to throw an error if it tries to go out of bounds. But to level the gantry I need some way to forcibly drive into the hard stops.
In marlin there are codes to turn off/on “soft end stops” (M211). It’s up to the user to not be stupid when the end stops are turned off. This would be my preferred implementation, but I’m sure it’s not the only way to address it.
While this post has nothing to do with ignoring the limits and crashing the printer but rather defining different “keep in” / “keep out” areas within the physical limits and while I think this is a highly debatable way of leveling (please don’t! It’s your printer, do what you want with it) you can probably achieve this with set_kinematic_position
move the printhead to a designated position inside the current max/min limits
run an M208 to see the new limits (print head has to already be inside this)
move around within the new limits, and do what you need to do.
move back to the original position used in step #1
run an M208 to set the limits to the original values.
continue on with a print
this works for purge buckets tool changes, dockable probes etc, and ensures no matter what you are doing you can never crash the print head (assuming you defined the limits properly).
Imo, it is disappointing that klipper doesn’t already support this.
I should add, SET_KINEMATIC_POSITION doesn’t give me warm fuzzy feelings.
from the documentation
Setting an incorrect or invalid position may lead to internal software errors. This command may invalidate future boundary checks; issue a G28 afterwards to reset the kinematics.
Since @Sineos mentioned set_kinematic_position, I decided to play around with it to see what was possible.
The following is a mostly working purge routine. I say mostly because it seems like maybe 1 time out of 5 Klipper goes stupid, and swaps the x and y axis around. what’s odd about it, is that the swap happens before SET_KINEMATIC_POSITION comes into play. it almost seems like a race condition or something be run non sequentially.
The sequence of commands I’m using are.
G28
Z_TILT_ADJUST
G28 Z
PURGE TEMP=220
# Macro Parameters
# amount - How much filament to extrude. The default is 10 mm.
# rate - How fast the filament should be extruded. The default is 5 mm/s.
# wipes - the number of wipe iterations to perform The default is 2.
# temp - the temp the extruder needs to be brought to if it needs to change
# ret - should the toolhead return to the point it was before a purge was
# commanded. The default is false.
[gcode_macro PURGE]
description: Runs a purge routine
gcode:
{% set ammount = params.AMOUNT|default(10)|float %}
{% set rate = params.RATE|default(5)|float %}
{% set wipes = params.WIPES|default(2)|int %}
{% set temp = params.TEMP|default(-1)|float %}
{% set ret = params.RET|default("false")|string %}
{% set moveVelocity = printer.toolhead.max_velocity * 60 %}
{% set extrudeVelocity = rate * 60 %}
{% set minTemp = printer.configfile.config['extruder'].min_extrude_temp|int %}
# the point at the limit of the bed where the kinematic position change will take place
{% set refPointA = {
'x': 0.25,
'y': 135}
%}
# when the print head reaches refPointA SET_KINEMATIC_POSITION will swap to this value
# this is so when the purge and wipe tasks don't accidentally move out of range
{% set refPointB = {
'x': 150,
'y': 150}
%}
# the point where a purge will take place, the values are relative to refPointA/refPointB
{% set purgePoint = {
'x': -25.25,
'y': -30}
%}
# the length of a wipe pass
{% set wipeDistance = 60 %}
# input validation
{% if temp > 0.0 and temp < minTemp %}
{action_raise_error("temp must be greater than or equal to the minimum extruder temp")}
{% endif %}
{% if ret != "true" and ret != "false" %}
{action_raise_error("ret must be 'true' or 'false'")}
{% endif %}
{% if ret == "true" %}
{% set ret = True %}
{% else %}
{% set ret = False %}
{% endif %}
# start processing and generating gcode
{% set StartPoint = printer.toolhead.position %}
# move the toolhead into position
G0 X{refPointA.x} Y{refPointA.y} F{moveVelocity}
M400
SET_KINEMATIC_POSITION X={refPointB.x} Y={refPointB.y} Z={StartPoint.z}
G0 X{refPointB.x + purgePoint.x} Y{refPointB.y + purgePoint.y}
# change the temp if needed
{% if temp > 0.0 %}
M109 S{temp}
{% endif %}
# conditionally purge
{% if ammount > 0 %}
M83
G1 E{ammount} F{extrudeVelocity}
M82
{% endif %}
# wipe
{% for wipe in range(wipes) %}
G0 Y{refPointB.y + purgePoint.y + wipeDistance} F{moveVelocity}
G0 Y{refPointB.y + purgePoint.y}
{% endfor %}
# return to refPointA/refPointB
G0 X{refPointB.x} Y{refPointB.y}
M400
SET_KINEMATIC_POSITION X={refPointA.x} Y={refPointA.y} Z={StartPoint.z}
{% if ret %}
G0 X{StartPoint.x} Y{StartPoint.y}
{% endif %}
G92 E{StartPoint.e}
The issue seems to be related to some kind of race condition when calling G28. adding an m400 between the G28 and calling the macros fixed the axis swapping issue.