Thoughts on homing support in Klipper

This is an interesting direction! I see that you, Kevin, want to do a major revamp of homing in Klipper. I want to share my thoughts on this matter.

Generally, I think the idea of adding more primitive, low-level commands for homing makes a lot of sense. Unlike fiddling with various ways to override G28, these will provide a way to get the expected behavior in a predictable and guaranteed way. It will also be much easier to add new homing functionality.

That said, I have some questions about the current proposal. For example

  • It is not immediately clear to me how homing of a delta printer can be represented using the suggested primitives? Specifically, for a delta printer all 3 rails must be homed simultaneously, but they must be moved until their respective endstops trigger, and the proposed low-level commands do not support that behavior AFAICT. I think deltesian will have similar issues, not sure about other kinematics.
  • It is a little bit difficult for me to picture how features like endstop_phase, multi-mcu homing and such would fit this new architecture - such as to not introduce code deduplication and having to reimplement their support in each of the homing module (though it is probably possible, just would require some thinking).

Also, if we are doing complete revamp of the homing, I think the following features would be really nice to have (not a must, just nice to have):

  • An ability to home any stepper (or combination of steppers); for example a common request from various filament changing projects is to be able to move several steppers, including extruder, until a certain endstop triggers, something Klipper does not support today.
  • An ability to define a homing sequence using default homing primitives for obscure kinematics like deltesian and linear axis tripteron.
  • An ability to home several axes in parallel, of course when it is meaningful to do so, something that the user could configure using default homing primitives.
  • endstop_phase support on Cartesian-style kinematics other than plain Cartesian (FWIW, this would only work if all ‘entangled’ axes are homed together in the same homing sequence).

And my thoughts on ‘homing’ decomposition into building blocks:

  • The most basic low-level homing primitive is moving groups of steppers with a certain ‘overall’ speed and ramp-up acceleration, but with each stepper having its own linear coefficient, until a certain event occurs for each stepper group, or until main Klipper issues a stop even (e.g. if the max distance is traveled). In case of a simple endstop or probe homing these events would be that a certain pin is triggered, and in case of a multi-mcu, loadcell, etc. homing, it would just be the main Klipper event. FWIW, this primitive may or may not be exposed to the user.
  • Interpretation of such ‘homing move’, given the time of the event(s), stepper positions at the event(s) and their final positions, kinematics-aware.
  • Implementation of the ‘homing’ of an ‘axis’ (or groups of axes): depends on the hardware used (endstop, sensorless homing, loadcell) and must use the other two blocks above in order to organize the motion of the axis of interest as appropriate. This may or may not be exposed to the user.
  • Kinematics-aware homing of the printer axes: defines which axes/carriages can be homed and defines and implements commands to do so.
  • High-level homing routine (which axes to home and in which order), defined by the user.

So, we can still have

[home_endstop stepper_x]
endstop_pin: PB3
position_endstop: -5
homing_speed: 20

[home_sensorless stepper_y]
position_endstop: -5
homing_speed: 20

[home_loadcell stepper_z]
position_endstop: 0
homing_speed: 5
...

However the user would not typically call HOME_ENDSTOP CARRIAGE=stepper_x. Instead, the kinematic would define a command like HOME_TOOLHEAD with the arguments that would depend on the kinematics. For example, for Cartesian-style kinematics that would be HOME_TOOLHEAD CARRIAGE=<carriage_id>. For a delta, it could be HOME_TOOLHEAD [AXIS=Z], and for deltesian, it could be HOME_TOOLHEAD [AXIS=[Y|Z]]. It would also be appropriate to restrict that all carriages participating in the single homing action from kinematic perspective (e.g. all delta carriages) must use the same endstop mechanism, so that the kinematic class could just forward the execution to the appropriate class.

And we could also have a class [extruder_endstop] and extruder would define a command similar to manual_stepper like MOVE_EXTRUDER EXTRUDER=<extruder_id> [STOP_ON_ENDSTOP=[1|2|-1|-2]] ....

Alternatively, we’d have to support HOME_ENDSTOP CARRIAGE=stepper_a,stepper_b,stepper_c and alike, but I feel like here the kinematic abstraction would be leaking into the underlying endstop classes, and also a simple typo could easily ruin the day and damage the printer (e.g. if a user of a delta printer enters something like HOME_ENDSTOP CARRIAGE=stepper_a,stepper_b ,stepper_c or say prematurely accidentally hits ‘Enter’ after typing HOME_ENDSTOP CARRIAGE=stepper_a,stepper_b).

Let me know what your thoughts are.