Homing probe virtual endstop

I am trying to debug an issue with an extension that has to do with using the probe as a virtual endstop.

The relevant sections of the config are:

[stepper_z]
step_pin: PB3
dir_pin: PB2
enable_pin: PA5
endstop_pin: probe:z_virtual_endstop
microsteps: 32
full_steps_per_rotation: 200
rotation_distance: 8
#position_endstop: 0.0
position_max: 250
position_min: -2

[probe]
pin: PG15
x_offset: 0
y_offset: 0.0
z_offset: 10.0
speed: 5.0
lift_speed: 80.0
samples: 3
samples_result: median
sample_retract_dist: 1.2
samples_tolerance: 0.006
samples_tolerance_retries: 3

What I am seeing has to do with the bed position after the initial probe trigger. When homing X or Y, what I see is

printer probe:  (0.0, 0.0, 10.0)
toolhead set_position [450.0, 0.0, 0.0, 0.0] x
move: start [450.0, 0.0, 0.0, 0.0], end [0.0, 0.0, 0.0, 0.0]
toolhead set_position [0.0, 0.0, 0.0, 0.0] 

That makes sense. Klipper sets the forcepos to 1.5 times the length of the axis and then drip moves until the endstop triggers. At that point, it sets the toolhead position to 0.0.

However, when it is homing Z, I get:

_do_home_z_via_probe: homing_info(speed=5.0, position_endstop=10.0, retract_speed=5.0, retract_dist=5.0, positive_dir=False, second_homing_speed=2.5)
_do_home_z_via_probe: start position [None, None, 370.0, None]
toolhead set_position [0.0, 0.0, 370.0, 0.0] z
descend_until_trigger [0.0, 0.0, -2.0, 0.0]
move: start [0.0, 0.0, 370.0, 0.0], end [0.0, 0.0, -2.0, 0.0]
toolhead set_position [0.0, 0.0, 354.01875, 0.0] 
descend_until_trigger: probe_result(bed_x=0.0, bed_y=0.0, bed_z=344.02375, test_x=0.0, test_y=0.0, test_z=354.02375)
_probing_home: probe_result(bed_x=0.0, bed_y=0.0, bed_z=344.02375, test_x=0.0, test_y=0.0, test_z=354.02375)
_probing_home (result): [0.0, 0.0, 354.01875, 0.0]
_probing_home (toolhead): [0.0, 0.0, 9.995000000000005, 0.0]
toolhead set_position [0.0, 0.0, 9.995000000000005, 0.0] 
_do_home_z_via_probe (retract): [None, None, 370.0, None] [None, None, 10.0, None]
_retract_move: [0.0, 0.0, 15.0, 0.0]
move: start [0.0, 0.0, 9.995000000000005, 0.0], end [0.0, 0.0, 15.0, 0.0]

First, it sets the toolhead position to 1.5 times the length of the Z axis, then drip moves to -2 (position_min). But when the probe triggers, it sets the toolhead position to 370 - distance traveled. Why is that? Why doesn’t set the position to 0.0?

Also, after it retracts and probes again, why does it set the toolhead position to the probe offset instead of 0?

Weba @voidtrance !

I think this belongs more to the General Discussion sub-forum (I’ll move it).

Please attach the klippy.log to your next post.

Are you sure this is 10 mm? Or ist it 5 mm:

#homing_retract_dist: 5.0
#   Distance to backoff (in mm) before homing a second time during
#   homing. Set this to zero to disable the second home. The default
#   is 5mm.

Here is the Klippy log.

klippy.log (73.0 KB)

I am not sure what you mean. The retract is 5mm:

_retract_move: [0.0, 0.0, 15.0, 0.0]

which is 10 + 5. That is consistent with the toolhead position + 5mm:

toolhead set_position [0.0, 0.0, 9.995000000000005, 0.0] 
_retract_move: [0.0, 0.0, 15.0, 0.0]

What I was asking why is the toolhead position being set to ~10 (which matches the probe offset)?

Git version: 'd8659974-dirty'
Untracked files: klippy/extras/.#pid_calibrate.py, klippy/extras/gcode_shell_command.py, klippy/extras/led_interpolate.py, klippy/extras/loop_macro.py, klippy/extras/pizza_oven.py, klippy/extras/settling_probe.py, klippy/extras/state_notify.py, klippy/extras/temp_tracker.py, klippy/extras/temperature_smoothing.py
Modified files: klippy/extras/homing.py, klippy/extras/probe.py, klippy/toolhead.py

This appears not to be a regular Klipper version.
Also, have you tried without the addons? The "dirty" Flag and the Team's Position

Maybe the author of Tracked URL: git@github.com:voidtrance/klipper.git can help.

I am the owner of that repository. That is just a straight fork of Klipper without any changes.

I can try without the extensions. The changes to the actual Klipper files are purely debug prints, no other code changes.

The exact same thing happens when remove all extensions:

Git version: 'd8659974-dirty'
Modified files: klippy/extras/homing.py, klippy/extras/probe.py, klippy/toolhead.py
_do_home_z_via_probe: homing_info(speed=5.0, position_endstop=10.0, retract_speed=5.0, retract_dist=5.0, positive_dir=False, second_homing_speed=2.5)
_do_home_z_via_probe: start position [None, None, 370.0, None]
toolhead set_position [0.0, 0.0, 370.0, 0.0] z
descend_until_trigger [0.0, 0.0, -2.0, 0.0]
move: start [0.0, 0.0, 370.0, 0.0], end [0.0, 0.0, -2.0, 0.0]
toolhead set_position [0.0, 0.0, 356.55625, 0.0] 
descend_until_trigger: probe_result(bed_x=0.0, bed_y=0.0, bed_z=346.5575, test_x=0.0, test_y=0.0, test_z=356.5575)
_probing_home: probe_result(bed_x=0.0, bed_y=0.0, bed_z=346.5575, test_x=0.0, test_y=0.0, test_z=356.5575)
_probing_home (result): [0.0, 0.0, 356.55625, 0.0]
_probing_home (toolhead): [0.0, 0.0, 9.998749999999973, 0.0]
toolhead set_position [0.0, 0.0, 9.998749999999973, 0.0] 
_do_home_z_via_probe (retract): [None, None, 370.0, None] [None, None, 10.0, None]
_retract_move: [0.0, 0.0, 15.0, 0.0]
move: start [0.0, 0.0, 9.998749999999973, 0.0], end [0.0, 0.0, 15.0, 0.0]
toolhead set_position [0.0, 0.0, 20.0, 0.0] 
descend_until_trigger [0.0, 0.0, -2.0, 0.0]
move: start [0.0, 0.0, 20.0, 0.0], end [0.0, 0.0, -2.0, 0.0]
toolhead set_position [0.0, 0.0, 15.0025, 0.0] 

Then why bother? Point Kiauh to offical repo and reinstall.

Again, I am lost. What do you mean?

I am not trying to fix a “broken” Klipper. I am trying to understand how Klipper works because I need to debug an extension.

Reinstalling Klipper won’t help with that at all.

I’m not sure if it helps:

diff --git a/klippy/extras/homing.py b/klippy/extras/homing.py
index 5b484529b..ce4f020f7 100644
--- a/klippy/extras/homing.py
+++ b/klippy/extras/homing.py
@@ -259,7 +259,9 @@ class Homing:
         probe_session.run_probe(gcmd)
         ppos = probe_session.pull_probed_results()[0]
         # Update toolhead position
+        logging.info("ppos: %s" % (repr(ppos)))
         curpos = self.toolhead.get_position()
+        logging.info("curpos: %s" % (repr(curpos)))
         curpos[2] -= ppos.bed_z
         self.toolhead.set_position(curpos)
     def _do_home_z_via_probe(self, rails, forcepos, movepos):

This is my output:

ppos: probe_result(bed_x=200.0, bed_y=214.6, bed_z=588.542784, test_x=200.0, test_y=200.0, test_z=589.489375)
curpos: [200.0, 200.0, 589.489375, 0.0]
ppos: probe_result(bed_x=200.0, bed_y=214.6, bed_z=2.9993315, test_x=200.0, test_y=200.0, test_z=3.9803124999999997)
curpos: [200.0, 200.0, 3.9803124999999997, 0.0]

So, start Z position was some large value (~600).
It triggered at bed_z=588.542784, toolhead (nozzle) is at test_z=589.489375.
We compute where the toolhead is above the sensor trigger position (z_offset):
curpos[2] -= ppos.bed_z
Which should be 589.489375 - 588.542784 = 0.946mm
So, trigger happened at zero, and toolhead is at 0.946 above zero.

Then we repeat from a different height, but otherwise the math looks the same.

Hope that helps:
-Timofey

So, in my example, why would the toolhead be at 10mm (which coincidentally is the probe offset)?

If I change the probe offset to 20, I get

_probing_home (result): [0.0, 0.0, 350.0575, 0.0]
_probing_home (toolhead): [0.0, 0.0, 20.0, 0.0]
toolhead set_position [0.0, 0.0, 20.0, 0.0] 

The toolhead posistion follows the probe offset.

I’m not sure I understand the reason for your confusion, but when the probe triggers, it is zero (the coordinate where the nozzle will probably touch the bed).

The probe trigger point is always below the nozzle (otherwise the nozzle will collide with the bed).

So, if the probe is triggered, we expect that the bed is at the trigger point and the nozzle at z_offset above that level.

-Timofey

Let me post some code and matching output to illustrate my confusion:

With the following change:

        ppos = probe_session.pull_probed_results()[0]
        # Update toolhead position
        print("_probing_home:", ppos)
        curpos = self.toolhead.get_position()
        print("_probing_home (result):", curpos)
        curpos[2] -= ppos.bed_z
        print("_probing_home (toolhead):", curpos)
        self.toolhead.set_position(curpos)

and matching output:

_probing_home: probe_result(bed_x=0.0, bed_y=0.0, bed_z=336.8525, test_x=0.0, test_y=0.0, test_z=346.8525)
_probing_home (result): [0.0, 0.0, 346.85125, 0.0]
_probing_home (toolhead): [0.0, 0.0, 9.998749999999973, 0.0]

In the above example, the toolhead start position is z=23.1537 and the probe is at z=33.1538 (probe offset is 10mm).

By my understanding of your example:

  1. Probing starts at toolhead set_position [0.0, 0.0, 370.0, 0.0] (~(250 z-height * 1.5).
  2. Probe triggers, toolhead is at 336.8525. It travel distance of 23.1537 + 10mm offset.
  3. Current toolhead position is returned as 346.85125.
  4. ppos.bed_z is subtracted and the toolhead position is set to 9.9987.

The only thing that makes sense given the above number is that with a setting of z_offset: 10, the probe is 10mm below the toolhead. The documentation does not specify what positive and negative values mean so my assumption is that positive means that the probe trigger point is above the nozzle.

Why would you assume that? The documentation is very clear about what the parameter value means:

z_offset:
#   The distance (in mm) between the bed and the nozzle when the probe
#   triggers.

To me that is ambiguous. Can it be a negative value? What does it mean when it’s a negative vs. positive value?

How can you tell if the probe is below or above the nozzle (in absolute Z height)? In other words, if the probe z offset is 10, how does Klipper know whether the toolhead is at 0 or 20?

That’s the root of my confusion. I am sorry if I am getting people frustrated. I am not trying to be difficult. I simple don’t understand.

As mentioned above, normally, the trigger point is below the nozzle because the nozzle is an impenetrable object and will break the bed (or the bed will break the nozzle) if the trigger point is above the nozzle.

So, normally it is a positive distance.

The only exception to this is nozzle tap with Eddy or LoadCell, where the nozzle actually collides with the bed, tilts, and things get complicated.

So, a negative offset is allowed. (But we normally talk about -0.1 mm, for example).


z_offset is the definition how far the nozzle/toolhead from the trigger point.

What about a Klicky-style probe that is docked and could be well below the nozzle tip?

They can’t, that is it. When klicky is attached, it will contact with the surface before nozzle.
So, it is below nozzle.

I will find a picture of Klicky and attach it here :smiley:

Yeah, it just klicked (no pun intended). I feel a bit stupid now. Of course, the probe can’t be triggering above the nozzle!

Sorry for the wasted time!