Firmware retraction including zhop and auto-retract

Hi Folks. I’m working on the zhop firmware retraction issue and already implemented it via reassigning handlers as Kevin and Arksine discussed a while back. I also implemented different zhop move styles including standard-vertical, diagonal (as proposes by teaching tech) and helix (as implemented by Bambu labs, still beta, see comment further below).

Now I am figuring out how to solve the canceled/finished-print-with-active-retraction issue. Further, I want to implement auto-firmware retraction like in Marlin, to replace slicer retraction on the go.

To implement the helix zhop move style in a way that enables the smoothest possible movements, I need to know the coordinates of the next move after retraction. For a good auto-firmware retraction, the issue is even more complex, as I’d need to know all moves between slicer retract and unretract, to then exchange those with the firmware retract moves including zhops. I’d very much appreciate if you guys could point me in the right direction how this could work in a stable way.

Finally, to tackle the cancel-finished print issue, I was thinking of using the reset-file-event from the virtual SD card module. Alternatively, I thought of polling the print-stats state to figure out if a print finished or was canceled. Both solutions need virtual SD card enabled. Implementing firmware zhop for steamed gcodes is almost impossible from how I see it. Any indications on how this can be done better are most welcome. Maybe I have overlooked a cancel-finished print related event.

I hope to have this ready within may and will do a PR then. Cheers Florian

This is exciting. Thanks for your work on this! I have an idea for a z-hop method that I’ve long wished I could implement. I’m interested in your thoughts on it.

The diagonal z-hop that TeachingTech proposes is similar to what I have in mind, except that instead of a caret-shaped motion (^) it would be a continuous arc with the z-hop height at the apex. If I’m understanding the kinematics correctly, I believe this would have two slight advantages over diagonal z-hop:

  1. The arc shape means that over the same linear distance across the XY plane, the average nozzle high above layer height would be greater, making it slightly better for avoidance of surface marring and object collision; and
  2. A continuous arc move would avoid the time wasted by the decel/accel associated with commanding the nozzle to the peak of the diagonal z-hop and then again to the end of the travel move.

I briefly looked into testing this as a proof of concept using gcode post-processing and/or macros but quickly discovered that the existing G2/G3 gcode commands only support arcs on three planes (XY, XZ, or YZ).

Now, I’m not familiar with this Bambu helix z-hop you mentioned. I did a couple searches and so far haven’t been able to figure out exactly what it is or what the path looks like. But I wonder if it’s intended to be something similar to this? One variation I briefly considered was splitting up the arc move into two arcs, one on each of the permitted Z planes, but this would seem likely to introduce more problems than it solves.

My idea can’t work consistently without the ability to draw an arc on an arbitrary plane, which (I think) means that some custom kinematics would be needed to make it work. I’m curious whether you think there’s any merit to the concept, and perhaps more importantly, whether you think it would be feasible to implement.

Hi Theophile. Regarding a zhop arc, there would probably be quite some math involved to figure out the coordinates of the line segments needed for a random plane arc. It would probably be doable and interesting for e.g. CNC milling. For a zhop arc, just like diagonal zhop, I don’t see the benefits that justify the effort. The diagonal zhop I implemented is the second type teaching tech discusses. This diaonal zhop was very easy to implement and yielded the best results. The helix style from Bambu Labs basically replaces the vertical up movement by a vertical helix movement. It is meant to shake any strings off.
I am thinking ot implementing several line segments at the end of the zhop movement to have a smoother unretract zhop. This goes in the direction you were thinking. Cheers Florian

Wouldn’t be a diagonal Z hop more precise than a arc shaped one or a hyperbola?
There might be much more rounding errors for the arc than for a straight line/vector or am I wrong here?

I think, from a motion system perspective, this is feasible for almost all printers today. Regarding the arc resolution, this can be set in the config. With the standard 1mm setting, the actual movement may or may not look like a hyperbola depending on the travel move length. For short travel moves, we may end up with a diagonal zhop move trajectory. This can be fixed by increasing arc resolution though. All in all, I don’t see the benefit compared to alternate diagonal zhop or helix zhop. Cheers Florian

Thinking more about the arc proposal, I envision the shape as being more of a semi-ellipse rather than a hyperbola, so that the nozzle moves further away from the print surface sooner (and returns closer to it later) than would be the case with straight-line diagonal moves, while taking the same amount of time as a single straight-line move with no z-hop at all. I imagine the benefit would be a movement that takes the least amount of time, while at the same time providing most of the collision-avoidance benefit of the traditional square-shaped z-hop move, while at the same time reducing the tendency for stringing that results from surface tension of the filament when doing a straight vertical lift.

Regarding the pragmatics of implementation, in thinking more about it, I realized that the typical method of producing an arc (by approximating it with short line segments) probably introduces a lot of computational overhead and potential for error, as @LifeOfBrian noted. But I wonder if there’s a better, easier way to accomplish the same result.

The curvature always happens entirely on the Z axis. The X and Y motion is otherwise a straight line from the beginning of the travel move to the end, as it would be with no z-hop at all. So rather than calculating the approximate shape of the arc using multiple line segments, I wonder if it’s possible to command the X and Y steppers to execute the straight-line move like normal, while simultaneously commanding the Z stepper to increase the Z height by the z-hop distance and then lower it again over the same time period, in such a way as to produce the arc shape. This way, the only additional math required would be the rate at which the Z stepper moves, which is what would determine the precise shape of the arc.

The other thought I had is that the implementation could be modular in nature, so that a variety of other “hop” shapes could be experimented with. Perhaps there could be a kinematics module specifically for firmware z-hop that could function as something like a Z stepper “overlay” on top of what is otherwise a normal linear travel move on the XY plane.

So for example, to implement a relatively simple “diagonal” z-hop, the firmware would execute the regular G1 command to move the toolhead in a straight line from the beginning point of the travel move to the end point, and then while that is happening, the z-hop overlay module would increase the z height to the z-hop distance at a linear rate during the first half of the G1 move, and then decrease the z height back to the layer height at a linear rate during the second half of the G1 move.

Producing an arc shape would work exactly the same way, except that the z-hop module would increase and then decrease the z height at (say) an exponential rate rather than a linear rate.

Such a system could allow for a wide variety of z-hop shapes without ever needing to interpolate the overall shape and render it as a series of line segments.

I like the idea. Any idea how this could be implemented using gcode? As the current Firmware retraction code, I am using the gcode macro execution method. Hence, if there is a gcode command sequence for this movement, we can implement it.

Unfortunately not. Two gcode commands can’t be executed simultaneously. I think to do this it would be necessary to control the Z stepper directly at a lower level than the gcode interpreter. I think it would be be similar to the way extrusion is handled, where the extruder stepper executes an extrusion move that is timed according to the tool head movements.

Hi Folks.

Quick Update: After being busy with work for the past 3 weeks, I finally got back to coding. As things stand, the zhop functionality will only be implemented for virtual sd card prints as the cancel/finish print failure case is almost impossible to prevent if printing via gcode streaming.

To figure out the move right before and the move(s) after a retract until the following unretract, I am thinking of intercepting Gcodes lines read via the work_handler method in the module. Once having those, they could be checked for G10, G11 and only-extrusion G1 commands to detect retractions and un-retractions.

With the G10 and G11 commands being localized, the moves before the retract and until the un-retract commands can be used e.g. for the calculation of helix center point to optimize the movement path, adding wiping capability to the firmware retraction, etc. The same applies to being able to localize only-extrusion G1 commands (e.g. from slicers which don’t support firmware retraction like Cura). This would basically allow to configure in the firmware not only retraction parameters (e.g. length, speed) and zhop parameters (style, height, speed) but also wiping parameters (length, retract length before wipe).

If this can be implemented reliably (I hope so…), it would basically take a large chunk of calibration parameters away from the slicer and put it into the firmware of the printer. This should make sharing gcode files between printers much easier and should also allow using “old” gcode files without re-slicing for changes in retraction settings. Besides, all setting could be changed while printing, thus allowing for on-the-fly adjustments of e.g. retraction length for e.g. wet filament…

Please give me some feedback on this. Is all of this something that you also consider valuable? Any thoughts on intercepting and analyzing the gcode before processing in the gcode module? Could this cause issues? Any thoughts on securely detecting starting, canceled and finished prints?

Cheers Florian

I think this is a great approach for firmware retraction, but i don’t think it’s a good idea to have the firmware intercept and modify sliced gcode.

Yeah, I am not 100% sure if gcode manipulation can be done reliably…For now I focus on getting the standard FW retraction going. There are quite a few edge cases to consider but I am confident that I got pretty much all of them. Debugging and testing is key. Better spending that time now and be safe than sorry.

Btw, I figured out a way to enable FW retraction while gcode streaming. Octoprint by default disables motors if a print is canceled and pretty much all slicer end_print gcodes do the same. Hence, I’ll use the corresponding event to clear retraction in case a G10 was issued at the end of the print without following G11. That addresses Kevin’s second failure case. For VSD card prints, print status is accessible and hence an “easy” implementation. I think, I’ll have a PR ready soon.

After that, I’ll see if further developments like gcode manipulation via FW to add wiping capability and auro-retract (recognition of retract/unretract via pure extrusion moves with pursuant replacement by G10 and G11 commands) finds enough interest. After having studied the code flow in depth, I think it is doable but certainly not easy. In my humble opinion, it would be worth it for such great features but then again getting it right involves a ton of work (which I am happy to put in if the community has interest).

Cheers and thanks for posting =)

1 Like

Hi Folks

Quick update: Finished the coding and testing now. So far, no flaws. Retraction state is reliably reset once a print finished or is canceled. Bonus: it also works with gcode streaming =) Cero Nozzle crashed identified, even when using custom G0, G1, G2 and G3 commands. Backwards compatibility is ensured by having zhop disabled as standard. I’m updating the accompanying documents now and prepare the PR for submission once I completed testing. Failure case test macro is executed without errors. Now, I’m doing real world print tests including benchys and proper retraction torture test models.

What retraction torture yes model would you recommend? Lattice cube by Maker’s Muse or E3D overhang egg or any other?

Cheers Florian

1 Like

Thanks for taking this on, I can’t wait for klipper firmware zhop - as a torture test, did you consider “the unprintable thing” , also mentioned in this video?

Thanks for the tip. BTW, I agree that standard zhop introduces fluffy mini strings. Helix, similar to bambu labs, and diagonal, as proposed by teaching tech, don’t or do much less. All three options are implemented. Let’s see if this print is doable… Cheers

@gandy92 : The impossible print is not that impossible :stuck_out_tongue: I did print rather fast and knocked over the circular pattern right at the end. The linear patter printed without issue using firmware zhop with ramp style. I also printed with standard slicer retraction…print failed. I am bout to submitt PR…

Hi Folks. It is done…I submitted a PR for native firmware retraction support including zhop:
firmware_retraction: Support nozzle lifting on G10 by flopana77 · Pull Request #6239 · Klipper3d/klipper (

The PR enables nozzle lifting (zhop) when retracting using G10 command; fully configurable at runtime; in absolute or relative mode. In addition, it introduces three different zhop movement styles (standard, ramp and helix) suitable for different use cases. It clears retraction reliably to prevent nozzle crashes and other unwanted behavior after changes of the printing state (start, cancel or finish prints from virtual SD Card as well as via GCode streaming).

If you could review, this would be very much appreciated :slight_smile:

Cheers Florian

@Florian great work, hopefully the PR will be merged soon!

1 Like

HI Florian, the reduced PR #6311 for this feature is being merged into the DangerKlipper fork. Based on recent conversation this feature is unlikely to be brought into the mainline klipper fork. If you had time and drive for this feature it would be great if you could add the additional features from #6239 which are not in #6311 into a PR on the dangerklipper fork.

I think you did great work and it would be unfortunate for this to die on the vine when there is a viable place for the feature to live and be used.