How to improve responsiveness of Speed Factor/Pause commands? (for manual jogging, etc.)

I’d like to improve responsiveness for manual jogging, as well as for other robotics-related purposes. The easiest solution would be if the system could respond to M220 and PAUSE commands much faster, or if there was a way to somehow control the speed of the clock.

For manual jogging, I could just send a command to go to X_AXIS_MAX (or whatever) at X_AXIS_MAX_SPEED, then I could control the actual speed of it by controlling system speed, like M220 would. But, from what I’ve seen, neither M220 or PAUSE take effect until after some number of previously-queued move commands execute. Also, this would require being able to cancel a motion, once started, and I don’t know that there’s a way to do that.

I’d like to be able to have these things respond at least as fast as 20ms, or whatever would be imperceptible from instant to a human. I wouldn’t mind if I had to give up 10x the possible speed, or maybe even 100x - I can use a faster PC and a STM32F4, if I need to.

Is there a smart way to do this? I’m presently looking at, more or less, just porting over a stepper library as a Klipper host program, and using it to create stepper commands. I’ve already found that these libraries (ie: AccelStepper, FastAccelStepper) are good for manual control, but I’ve been experimenting with Klipper because I was having difficulty with synchronized motion, reliable communication between PC and microcontrollers, etc. But, doing this would only give me part of what I want - manual control of individual motors - and I really also want the ability to run G-code commands, but to have more or less instant access to controlling their speed or pausing them entirely.

I found this post, which seems like it’s pretty much confronting the same problem for different reasons Fast closed-loop controllers on the MCU? - so I don’t guess the outlook is too good, as far as a simple solution goes, unless the idea of controlling the clock’s speed or the willingness to lose a lot of speed make things easier.

I’m not sure I understand what you want to tune. Currently, Klipper tries to buffer 2 seconds worth of movement in the micro-controller. If you are a developer looking to tune this, you can try altering the settings in klippy/toolhead.py . Look for the various settings near the definition of buffer_time_high. Note that if one of the variables is changed then it may be necessary to tweak the settings of other variables in toolhead.py to get a stable system.

Cheers,
-Kevin

Hi Kevin,

Thank you for your input! I’ll try to explain my problem more clearly.

The first thing I want to do is have manual jogging individual axies using joysticks, where pushing the joystick further makes it travel faster, and to have it be responsive enough to manually do delicate/precise/fairly rapid operations (but, human-controlled, so nowhere near as fast as some klipper-driven 3d printers I’ve seen). The only reason I separate this from the next is because it seems like an easier problem to solve (given that I’ve solved it with simple Arduino libraries, like AccelStepper), but they’re really both the same problem.

My second goal is to be able to jog along a pre-defined line or arc (ie: jog along the segment connecting [0, 0, 0] to [1, 10, 5]), or jog along any given arbitrary set of gcode commands - backward, and forward, ideally, though forward-only would still be worthwhile. Also, I’d like to be able to abandon the current line/arc/gcode, and start along a new one ad-hoc.

I realize that this isn’t really Klipper’s focus. I was just hoping that it would be possible and preferably easy and effective, because I’m already using Klipper for my printer, and I’d rather get better with Klipper instead of spreading my time and my knowledge thinner by picking up more tools. It may just be the wrong tool for the job, though. I just don’t know what the right tool would be. I tried writing my own, but it’s been a struggle.

It sounds like you are looking for low-latency motion control using the Klipper motion planner. I suspect that will be a very challenging task because the Klipper code is not designed that way.

Klipper is designed so that the host software plans motions with precise timing, that movement is then buffered well in advance on the micro-controllers, and then the micro-controllers execute the requested movements using the requested timing.

I’d guess that if you want low-latency arbitrary movement you could accept some amount of latency and try to rework the host code to do less buffering, or alternatively rework the mcu code to directly read the joystick inputs, perform the motion planning, and directly execute the resulting movements. In either case, I expect it would be a bit of work.

Cheers,
-Kevin

Most of the audience here will cough up a hairball at this suggestion because it compromises the Klipper model so badly, but it is possible to improve responsiveness by modifying logic around the step queue on the mcu. On a STM32H7 I was able to get on the order of one microsecond between an input event and the start of motion. I used Klipper as a toolbox for prototyping a motion control application, the host remains largely unaware of what’s going on behind the scenes on the mcu.

2 Likes

Can you share your solution, or part of the code? I’m trying to do something similar to jog a microscope stage, would love to know where to start

1 Like

Welcome Maalus,

i hope you get a response from @m32825.

For my application I knew the entire move I wanted to execute before the trigger showed up, your case sounds different. The approach I took assumes that the motion coordination is the most important thing on the planet. All the action goes on behind the scenes on the MCU and the host remains mostly unaware. This was a one-off proof of concept, so I don’t have code that’s in shape to share but I will gladly describe the approach for those who are interested.

First, find the stepper loop and become very familiar with it. Once you understand how it works add flags and logic to gate whether a queued step executes or not. Let’s call the flag CMD_INPUT_HIGH. If the queued step does not have a command flag it executes normally. If the flag is present then the stepper checks to see if an input pin is high to decide whether to execute the step or not. You can extend this with flags for additional inputs (i.e. left, right, up, down) . You can also add flags to toggle an output pin for timing information (like my scope screenshot) or to send a signal to coordinate with some other component.

If one were interested in more generalized support for this type of experimentation, one might consider adding support to the printer config file to make it easy to specify and configure input and output pins for use by the MCU to control the stepper loop.

– Carl