From a programmers perspective, applying transforms to Z when Z state is unknown doesn’t make a lot of sense either, which is why it’s throwing an error. I think what we’re debating is whether or not it should be an error, or it should just ignore transforms to unhomed axes. If there was try/catch in gcode i would prefer the error, but there isn’t.
Come to think of it, the very same problem exists for skew correction. Home X, go to X150 and it might transform Y although Y isn’t homed. Though thankfully skew behaves like bed_mesh and requires explicit loading before it’s enabled.
What if there was a gcode command to toggle gcode transforms? GCODE_TRANSFORMS ENABLE=0|1 [AXIS=x|y|z]? At least that would allow for explicit control during a [homing_override] or similar where transforms are unwanted, and you wouldn’t have to know ahead of time exactly which modules potentially could cause unwanted transforms and whether or not they’re configured, and disable all of them one by one.
I’m open to suggestions on how to improve the handling. There are a couple of big issues here:
G-code is terrible. It’s cryptic to start, and just gets worse from there. It’s behavior is not well defined at all. Alas, because there are so many tools that emit it (and so many embedded expectations on its behavior) it is difficult to make real progress here.
I think this conversation may be missing the “elephant in the room”. In my experience one really wants a “start print macro” that takes the printer from a “power up state” to a “printing state”. Ideally most end-users would get this “self calibration macro” from the printer manufacturer or an experienced user. In my experience, performing “homing” outside of the main “self calibration process” is not a good idea. In particular, it’s not a good idea to individually home axes as doing so wont get the same repeatable results as an automated process that homes all axes. So, it may not make sense to spend lots of time making it “easy to get bad results”.
I’m all for improving the clarity of error messages. Alas, I don’t think we’ll ever get to the place where an error message will “tell the user how to fix the problem”. The point of an error message is to let the user know “that something went wrong”. Neither the software (nor the developers) know “the why”.
I don’t ever want my printer to assume I meant something else because what was actually requested can’t be done. It leads to tons of lost developer time (“oh, what would a user probably want in this case”) and tons of lost user time (“oh, what did the developer think I wanted in this case”) and lost work (“oh, how can I setup the printer state in just the right way so that it matches the expectations of some developer and will ultimately do what I really want”). It’s terrible. If the software can’t do what it has been configured to do, then it should report “I can’t do that”; it should not “do something else instead”.
Have you considered that we may just have different strategies for similar goals?
I also agree with this, the problem is this error is occurring within that self calibration macro from the printer manufacturer (me), specifically the homing override. The homing override does not have full control over the homing process (which is difficult to achieve because of #1, gcode sucks). GCODE_TRANSFORMS ENABLE=0|1 [AXIS=x|y|z] would help, but i’m not sure if it’s the right approach? Another option is to write the homing routine entirely in a klippy extra, i guess. It wouldn’t solve the single G28 X; G0 X10 → error scenario, but that would be improved significantly if transforms required explicit enabling in runtime, and i think z_thermal_adjust is the only one that is currently “on by default”.
I also agree with this. I think a simple way to improve the “Must home axis first” error is to explicitly communicate which axes needs to be homed.
If the software can’t do what it has been configured to do, then it should report “I can’t do that”; it should not “do something else instead”.
I agree with this too in principle. As i mentioned earlier, i now think the “fix” here, is to require transforms to be explicitly turned on, and have some way of disabling and re-enabling transforms in macro’s. What do you think about that?
Have you considered that we may just have different strategies for similar goals?
I apologize for assuming. It’s just the general impression you get from the klipper ecosystem currently (that it’s targeted mainly at people who has some level of developer experience), but i realize that isn’t necessarily intentional or the long term goal. I’m sorry, that’s my bad.
Would be super interesting to hear your thoughts on how to get there (“there” being the average 3d printing user) some day
Having used Klipper for 5+ years I can definitively say Klipper has made tremendous progress toward being user friendly. When I started using it we didn’t have Moonraker or any of the frontends that rely on the API. It didn’t even support simple 12864 screens. It could only be installed from the command line, and it could only be used with Octoprint. The barrier to entry is dramatically lower now, and in some ways I think it’s easier than Marlin.
I can’t comment on this without it sounding like i’m diminishing the value of moonraker and mainsail, which is incredibly important to the ecosystem, and the people behind both projects deserves all the praise. So please don’t misunderstand me when i say, it is so far off what i’m shooting for, that i think we’re gonna have a hard time debating here. Moonraker is an API, for crying out loud, it does nothing for ease of access, but it enables things to be built on top of it to add new capabilities, so you can say it indirectly helps. You’re listing features, not actual ease of use. I’ve been here through all of that, i’m not saying nothing has happened, but klipper is still very intimidating for non software people. They see linux and they run. It’s primarily the setup part, from zero to running printer. Operating the printer is pretty great, there’s not much to do there, but that is the only area where significant improvement has been made. People actually considered RRF easier, which is just wild to me, i couldn’t have that of course
It could only be installed from the command line
This is still the case (compiling firmware, connecting to the mcu, etc etc). RatOS solves that too.
I can agree that gcode is NOT the place to handle this issue. I do understand the concept of the macros and I can put BED_MESH_CLEAR and SET_Z_THERMAL_ADJUST ENABLE=0 in the end print macro and BED_MESH_PROFILE LOAD= and SET_Z_THERMAL_ADJUST ENABLE=1 in my start macro to get around the problem if i want to use a homing override, but for me to G28 my printer I have to do one of these things. Additionally I could SET_KINEMATIC_POSITION for XYZ and the printer will home properly with a bed mesh loaded or z thermal enabled, but this seems like a setup for crashing the printer.
What I think should be done is if a bed mesh is loaded or z_thermal_adjust is enabled, they should be ignored until Z is in a homed state.
I guess my line of thinking here is that why should I have to BED_MESH_CLEAR and SET_Z_THERMAL_ADJUST ENABLE=0 before I can G28 to home my printer if I use a homing override.
With z_thermal_adjust working like the rest of the transforms (has to be turned on to apply) and a way to explicitly disable or enable all transforms, you wouldn’t have to.
If you get this error while using a homing_override or safe_z_home then please attach a klipper log file showing the event. (Please be sure you are using the pristine Klipper code and issue an M112 immediately after receiving the error. Attach the full log here.)
I agree that the Klipper error messages could be improved.
I’m not sure about a GCODE_TRANSFORMS command. A more scalable solution may be to add a new MOVE_WITHOUT_TRANSFORM type of command. Not sure. I don’t think either command is a “show stopper” though. If you’re having problems getting this to work reliably from a “start print” type macro, I’d like to see the log of what you attempted, as it’s not clear to me what you are trying so it’s hard to understand the requirements.
I’m fine with making changes so that z_thermal_adjust no longer defaults enabled. I’m not the best person to make such a change though (as I don’t use the module and don’t have a good test setup for it).
I’m not sure about a GCODE_TRANSFORMS command. A more scalable solution may be to add a new MOVE_WITHOUT_TRANSFORM type of command.
I thought about that too, the latter is easy to write as an extra, so i might just do that.
I’d like to see the log of what you attempted,
Just a klippy.log where the error is reproduced?
This is the homing override:
[homing_override]
axes: xyz
gcode:
{% set x_homed = 'x' in printer.toolhead.homed_axes %}
{% set y_homed = 'y' in printer.toolhead.homed_axes %}
{% set safe_home_x = printer["gcode_macro RatOS"].safe_home_x %}
{% set safe_home_y = printer["gcode_macro RatOS"].safe_home_y %}
{% if safe_home_x is not defined or safe_home_x|lower == 'middle' %}
{% set safe_home_x = printer.toolhead.axis_maximum.x / 2 %}
{% endif %}
{% if safe_home_y is not defined or safe_home_y|lower == 'middle' %}
{% set safe_home_y = printer.toolhead.axis_maximum.y / 2 %}
{% endif %}
{% set z_probe = printer["gcode_macro RatOS"].z_probe|lower %}
{% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %}
{% set z_speed = printer["gcode_macro RatOS"].macro_z_speed|float * 60 %}
{% set z_hop = printer.configfile.config.ratos_homing.z_hop|float %}
{% set z_hop_speed = printer.configfile.config.ratos_homing.z_hop_speed|float * 60 %}
{% set homing_x = printer["gcode_macro RatOS"].homing_x|lower %}
{% set homing_y = printer["gcode_macro RatOS"].homing_y|lower %}
{% set homing = printer["gcode_macro RatOS"].homing|lower %}
{% set prev_stop_on_error = printer["gcode_macro RatOS"].stowable_probe_stop_on_error %}
# Make stowable probe assertion failures cause an emergency stop
SET_GCODE_VARIABLE MACRO=RatOS VARIABLE=stowable_probe_stop_on_error VALUE=True
M400 # Wait for moves to finish
G90 # Absolute positioning
{% if params.X is defined or params.Y is not defined and params.Z is not defined %}
{% if homing_x == 'endstop' or homing == 'endstops' %}
G28 X
{% elif homing_x == 'sensorless' or homing == 'sensorless' %}
HOME_X_SENSORLESS
{% else %}
{ action_emergency_stop("expected RatOS variable_homing_x to be 'sensorless' 'endstop' or variable_homing to be 'sensorless' or 'endstops' but found {} and {}".format(homing_x, homing)) }
{% endif %}
{% set x_homed = True %}
G0 X{safe_home_x} F{speed}
{% endif %}
{% if params.Y is defined or params.X is not defined and params.Z is not defined %}
{% if homing_y == 'endstop' or homing == 'endstops' %}
G28 Y
{% elif homing_y == 'sensorless' or homing == 'sensorless' %}
HOME_Y_SENSORLESS
{% else %}
{ action_emergency_stop("expected RatOS variable_homing_y to be 'sensorless' 'endstop' or variable_homing to be 'sensorless' or 'endstops' but found {} and {}".format(homing_y, homing)) }
{% endif %}
{% set y_homed = True %}
G0 Y{safe_home_y} F{speed}
{% endif %}
{% if params.Z is defined or params.Y is not defined and params.X is not defined %}
RESPOND MSG="Homing Z"
{% if x_homed == False or y_homed == False %}
M118 X and Y must be homed before homing Z
{ action_emergency_stop("X and Y must be homed before homing Z") }
{% else %}
{% if z_probe == "stowable" %}
DEPLOY_PROBE
G0 X{safe_home_x} Y{safe_home_y} F{speed}
G28 Z
G0 Z{z_hop} F{z_hop_speed}
STOW_PROBE
{% else %}
G0 X{safe_home_x} Y{safe_home_y} F{speed}
G28 Z
G0 Z{z_hop} F{z_hop_speed}
{% endif %}
{% endif %}
{% endif %}
# Reset stowable probe stop on error state
SET_GCODE_VARIABLE MACRO=RatOS VARIABLE=stowable_probe_stop_on_error VALUE={prev_stop_on_error}
[gcode_macro HOME_X_SENSORLESS]
gcode:
{% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %}
{% set safe_home_x = printer["gcode_macro RatOS"].safe_home_x %}
{% if safe_home_x is not defined or safe_home_x|lower == 'middle' %}
{% set safe_home_x = printer.toolhead.axis_maximum.x / 2 %}
{% endif %}
M204 S1000 # Set homing acceleration (important!)
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer["gcode_macro RatOS"].sensorless_x_current}
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer["gcode_macro RatOS"].sensorless_x_current}
G4 P300 # Wait for currents to settle
G28 X
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.config["tmc2209 stepper_x"].run_current}
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.config["tmc2209 stepper_y"].run_current}
G4 P300 # Wait for currents to settle
# Restore acceleration
M204 S{printer.configfile.config.printer.max_accel}
[gcode_macro HOME_Y_SENSORLESS]
gcode:
{% set safe_home_y = printer["gcode_macro RatOS"].safe_home_y %}
{% if safe_home_y is not defined or safe_home_y|lower == 'middle' %}
{% set safe_home_y = printer.toolhead.axis_maximum.y / 2 %}
{% endif %}
{% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %}
M204 S1000 # Set homing acceleration (important!)
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer["gcode_macro RatOS"].sensorless_y_current}
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer["gcode_macro RatOS"].sensorless_y_current}
G4 P300 # Wait for currents to settle
G28 Y
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.config["tmc2209 stepper_x"].run_current}
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.config["tmc2209 stepper_y"].run_current}
G4 P300 # Wait for currents to settle
# Restore acceleration
M204 S{printer.configfile.config.printer.max_accel}
z transforms causes the recentering of x and/or y to fail. MOVE_WITHOUT_TRANSFORM would work fine for this. I’m not happy about the idea of disabling single axis homing though (to prevent people from doing G28 X → G0 X150 or whatever). That seems like something that should work, and i’ve personally done it more than once during calibrations and debugging. With the fix to z_thermal_adjust i can however write documentation explaining how enabling transforms outside of a print might be a bad idea. It gets a bit more convoluted when things aren’t consistent in behavior.
I’m fine with making changes so that z_thermal_adjust no longer defaults enabled. I’m not the best person to make such a change though (as I don’t use the module and don’t have a good test setup for it).
Sounds good, i don’t use it either though. I’ll see if i can reach out to the author to get their input.
This is a combination of homing_override and safe_z_home, to get initial z-hop (via toolhead.manual_move) without setting z position because that has other bad side effects, like invalid state after a failed home - z state will be homed even though it never was). Behavior is the same with homing_override without set_position_z and initial z_hop. Source is here if you’re curious: RatOS-configuration/ratos_homing.py at v2.x · Rat-OS/RatOS-configuration · GitHub