Can stepper moves be synchronized unevenly?

Before I started digging into code to do this, I wanted to sanity check it with people who are more familiar with Klipper’s architecture than I am …

I have a problem I’ve been trying to solve in various ways. Without getting into too much unnecessary detail, the issue I have is that the minimum possible extrusion length based on 256 microstepping for my particular extruder geometry (0.00001953125mm) is actually about 3x bigger than I really need it to be for some of the stuff I’m using it for. (Yes, its crazy small…) E moves smaller than that just get lost.

I’ve worked around it in a couple of less-than-ideal ways. The “easiest” was to parse the E length in G1 and if its set to something more than zero and less than that, to set it to that. It causes some overextrusion in smaller moves, but the extrusions don’t disappear. A slightly better model has been to apply a linear extrusion modifier such that the extruded amount is boosted to keep the minimum being requested to the physical minimum, and to ease that variance off in a linear fashion to the largest E length. That takes running a pre-processor, though, and still means over-extruding in the fine details.

What I’m thinking might be best is to use arcwelder to convert small moves into arcs, and have the arcs spread the E distance out over a larger number of X/Y moves. The current gcode_arc code calculates the arc and translates it to a bunch of G1 moves. My hope is to have it aggregate a few (or maybe all) of the arc segments into a single extruder move, since (by definition) you know you’re following a smooth path without any corners. That’d get the actual amount being stepped to be much higher. (And, as a side-effect, improve surface finish on arcs.)

I can tell from looking at the MCU documentation that the underlying protocol being sent to the MCU should support that – its not synchronized with any other moves, other than via the timestamp and interval. So it seems like it should be possible to tell the MCU to start the extruder move at the same time as the kinematic moves and have it run through multiple segments of the kinematic moves while a single extruder move is running.

What I can’t figure out is where, in the code, that translation actually happens. It looks like gcode_move.py is just updating its internal state, and something else is introspecting it later to actually do the moves?

My first pass of looking at this makes it look like it might be a very deep set of changes to make this work, as there’s no clear path from a module like gcode_arcs.py to the motion queues for the toolhead and steppers? It’s just passing XYZE down to the toolhead?

Basically, I’m curious what people’s first impression is of the feasibility, based on what everyone knows of the guts of Klipper.

And, yes, I’ve considered using a finer stepper (there aren’t any applicable sized ones less than .9 degrees) and/or gears (far too much slop in afforable gears).

There is information on how Klipper processes move requests at Code overview - Klipper documentation . The extruder motion is primarily controlled in klippy/kinematics/extruder.py and klippy/chelper/kin_extruder.c.

FWIW, I think you may have misunderstood how Klipper translates extrusion movement. Klipper does not arrange for a discreet number of motor steps per g-code move - Klipper instead times extruder steps to match the requested g-code moves and that timing is done across multiple g-code moves. Said another way, the accuracy of the motor movement is not only based on the step distance, it is also based on the motor timing, and the motor timing is very precise.

-Kevin

What are you doing to have the need for such small extrusion lengths/movements??
Did you already include the possible gearing of your feeder? Maybe you can built a feeder with higher gear ratio or geared stepper motors for X and Y.
Best for the axes motors would be belt geared ones due to the absence of/reduced backlash.

Klipper supports arcs but most slicers aren’t yet. So best would be to have a slicer that natively supports arcs rather than using ArcWelder. The latter is really nice but sometimes produces corruptions and it rounds the values during conversion or approximates the paths! :wink:
If you are already in the nanometer scale even small roundings of such a tool might unhinge your world.

I think you may have misunderstood how Klipper translates extrusion movement. Klipper does not arrange for a discreet number of motor steps per g-code move

No, I understand that. Its actually precisely what I asked about the access to it. Because the arc code translates calls into a sequence of G1s, not a single request for the extruder to move and a coordinated set of requests for the kinematics to move, you end up with a long sequence of the toolhead code scheduling kinematic stepper movement and similarly-timed scheduled extruder moves.

What I’d like is to write a version of the gcode_arc that does the latter – schedules a single extruder move for the arc, and given the underlying kinematics don’t understand non-linear moves, continue sending those out as discrete moves. Basically, if the arc is 20mm long and the arc resolution is sent to 1mm, I want to send 21 move messages not 40 – 20 for the toolhead and 1 for the extruder. The resulting movements are the same, except that the extrusion would be smoother and, in my specific usecase, aggregated over the longer arc. Ten moves of .000002 would add up to a compatible extrusion of .00002 and I’d get the correct output, vs ten moves that are below the minimum step and I end up with none.

I’m not really asking how to do it, I can figure that out. I’m just curious if there’s any reason it definitely can’t be done, in which case its a waste of time to start going through the code.

If you are already in the nanometer scale even small roundings of such a tool might unhinge your world.

Yeah, that’s the kind of range I’m in. I’ve got a ~4200:1 ratio of extruder movement to extruded material. There’s too much slop in belts or gears for that kind of resolution. Surprisingly, the output is remarkably consistent even at a 1/256th microstep. That’s why I consistently get gaps in the output if the E value drops below 0.00001953125mm, and its visually obvious in the output if I’m rounding up.

I also fiddled with collapsing small extrusions – basically taking the start coordinates of a sequence of too-small extrusions, and collapsing them into a single movement/extrusion that goes over the limit. It also helped, and that may be my final fallback if I can’t get smooth arc extrusions working. (The problem is sort of like sampling audio at too low of a bitrate – the difference between 1 or 2 steps is visible in the output at small distances, so aggregating moves like that tends to create visible patterns in the output.)

For what it is worth, this is not how Klipper works.

If you have a step size of 0.001 and Klipper receives 20 moves each of a distance of 0.0003 then Klipper will take take a total of 6 steps during those moves. If one were to look within the timing of those 6 steps they would see that it is not tied to the timing of the start/end of each g-code move. Instead, the requested position is tracked to a very fine precision (far more precise than the step size) and Klipper times the stepper motor steps according to the requested position.

-Kevin

Well, now that is interesting. I’m definitely seeing extrusion stopping entirely as soon as it crosses that threshold. An E0.000019 doesn’t produce any output, an E0.00002 does. Rounding my E values up to that minimum causes none of the extrusions to disappear.

If its supposed to be aggregating extrusion steps across G1 commands, it doesn’t appear to be because of how binary that is.

Is there a way to enable more detailed logging of the specific commands being sent to the MCU, so I can check if I’m seeing that?

Edit: using your example, what if the smallest possible step in your example was 0.002?

Because what I’m talking about is the opposite – one move that is smaller than a step. Those seem to disappear.

Both the “motan tool” and “batch mode” described at Debugging - Klipper documentation can be used to inspect Klipper’s timing.

See also other developer documentation at Overview - Klipper documentation .

The precision of the “requested position” is determined by the precision of a double precision floating point value as described at Double-precision floating-point format - Wikipedia

-Kevin

Thanks, I’ll take a look at those.

But, that still didn’t answer the question – will Klipper aggregate extrusion steps when the requested step size for a given move is smaller than the minimum possible step size for the extruder? Because, objectively the tests are showing it does not. A move – no matter how big or small (and, thus no matter how many steps the kinematics are taking) – where the extruder’s requested step amount is less than a single microstep just doesn’t happen. Setting the E distance to an amount that is at least the size of a single microstep, it does happen.

That appears, with admittedly less testing, too be true with both relative and absolute E values, although the absolute case seems to fail the same way as relative, which is a little weird.

Re: double precision, that’s good to know, but these numbers have, at best, seven or so significant digits given they’re less than 1 and the first six digits are zero. Although, interestingly, if I modify G1 such that E has 0.00001953125 as the minimum non-zero value, the system doesn’t miss any extrusions, but the fuzziness of a double means that its actually 0.000019531249, which is less than a microstep. So there’s some rounding happening somewhere that is making that work even though it shouldn’t.