Moonraker websocket to klipper, changing the size of the buffer

Basic Information:

Printer Model: Ender 3 V1
MCU / Printerboard: Creality V1.4.1, running on RPI3 model B

Hi all, thanks in advance for your help! I have a problem, I am designing an on-the-fly 3D printing system, where external inputs are directly executed by the 3D printer. I am running klipper and moonraker connected to my computer.

My Gcode is calculated on-the-fly, so it works by sending G-code to the moonraker websocket untill the buffer is full (arround 30mm of gcode in my examples), after that everytime a gcode command is finished my Code receives an OK from moonraker websocket and recalculates and sends a new Gcode command.

This all works fine and as expected, the main problem is however with this buffer, you can imagine that if I have calculated new code based on some inputs (I have external sensors etc. connected to a slave arduino), the time it takes before this is executed is the length of the buffer.

I’ve tried to make my own buffer with websocket implementations like the “motion_report” this however takes 250ms on average to get a response from klipper, which is waaaaay to slow. I am working in the 20ms/Gcode streaming speed.

I’ve found some config commands like:
[printer]
#buffer_time_high: 10
To increase the buffer however these were removed in a recent patch.

So then finally my question is, does anyone know how I can configure the size of the buffer that klipper uses.
Or knows a websocket command/implementation on getting the printhead location which takes arround 10ms (as fast as the regular OK response from klipper as it receives Gcode).

(Yes I know this can lead to stuttering if the buffer is empty, I am not looking for reasons not to do this, I just want to tune the buffer size myself for optimal response)

Thanks again for your help! If I have to I’ll dive in the source files myself but any pointers would be greatly appreciated.

For future reference;

Was able to solve by going into the klipper firmware directly; Through ssh on the py, ~nano ~/klippy-env/bin/python ~/klipper/klippy/toolhead.py did the trick.

In the file klipper/klippy/toolhead.py

There are two main settings; BUFFER_TIME (high low and start) → this determines how much seconds of future g-code is allowed to enter the buffer.

And the LOOKAHEAD_FLUSH_TIME
G-code is loaded in small batches, the batch size determined by time (0.25s of gcode by default) can be changes with this variable.

I got it down to 5ms average per gcode command, with a latency of 300 ms. This seems to not stutter and be adequately responsive for my needs.

BUFFER_TIME_HIGH = 0.25
BUFFER_TIME_LOW = 0.2

LOOKAHEAD_FLUSH_TIME = 0.005

There are some other BGF_FLUSH variables, I am not sure what they do, I’ve lowered them (but I do not see a direct result), and everything seems to run fine!

Again I do not know what it all does, I just report what worked for me! So take it with a grain of salt.

Most probably you are aware of this but still i will add some details.

Please don’t forget that klipper have asynchronous engine.

Main Klipper code (Python) is working in “future” and calculating where toolhead should be and in what exact moment - from that it derives a future commands for MCU to execute on hardware level, then it sends this data to MCU for future execution, MCU will process them and execute them by referencing internal clock which is synced with klipper (Python)

That all means you will always experience some dynamic delays (up to 1-2s) between real world and klipper G-Code execution, and as a result you can experience delays on some external sensing device.

As Gaolist said, Everything in Klipper is done via look ahead. So before an action even happens the command has usually been send to the mcu(s) and is queued up to run. You might get this to work through some creativity but i feel like you’re going to run into some huge barriers as Klipper wasn’t really designed for this as far as I can see from my messing with the code.

When you say “Real time” do you mean you’re just executing gcode commands? As in, Mid print?

Can you provide more details?

I may totally be misunderstanding your goal, I don’t want to be a naysayer, I’ve learned some of my most valuable things by just purely messing around to see if it would work.

Yes! So I know the general flow, the commands are sent from my python on my pc through the websocket, are stored in klipper, calculated to specific stepper movements which are sent to the MCU.

What I am doing is calculating the code as I go, so I am making a cilinder, where I want to print different patterns by manipulating the Extrusion, by the use of a “drumpad” type interface.

So what I do is I send a gcode command through the websocket, asynchronously I am checking my buttons, and some other peripherals. As I get the ok back through the websocket I calculate the next command with either changed or unchanged parameters. And send it again

So I am re-calculating every command as I need a new one.

Performance wise I now have it down to 0.2seconds latency! Which is much lower than the 1-2 sec suggested. I calculate and send gcode every 0.05 seconds, and as such have around 5 commands ready in the buffer! But beware I’m calculating an F speed in correlation with the distance, such that the machine always takes 0.05 seconds to actually execute the command → so that I do not have to deal with the sharp radius corned gcode density.

I will have to say that occasionally when computation takes longer (for some random reason) it can happen that the buffer runs out and there is a small stutter, which is acceptable every 5 minutes or so. I am happy to make a video of what it can do later on!

My concern is that, when you’re using the websocket and sending commands it may be giving you confirmation that it received the command but that doesn’t mean klipper has processed it yet. Klipper “queues up” the commands and processes them as it can based on where it’s at with a movement/previous commands/etc.

That’s typically why when you change a setting in Mainsail you won’t see it actually take place until the end of the current line/perimeter/whatever.

Unless you mean you’re sending the gcode to make the moves and extrusions by hand? In case yeah, that would probably work. As in… You have a cylinder and you know the radius and so you’re tapping on the drumpad and it takes those inputs as variations in extrusion and chains them together with the gcode arc movement and makes it’s own gcode command list to make that movement?

In other words, If you’re trying to dynamically update during a print, I’m not sure your idea will work. Or it will but not in real time, it will be delayed until probably the next perimeter line. But if you’re feeding your own commands, which is complex but doable, then yeah. That’s probably possible.

Yeah, I am feeding it complete commands (what you call “by hand” with Jupiter on my PC), so indeed I am sending and adding it to the buffer, and I do need a small buffer otherwise it will stutter constantly. But the buffer should be as small as possible.

the system works like normal thought the websocket, just make a for loop in Python where you feed it new coordinates, the buffer fills up very quickly, after which it “tops off” the buffer as gcodes get executed.

I am also using a polar printbed and I am doing some other cool stuff happy to share a project description later if interested :).

Sounds interesting, Maybe later when you work out any bugs post a video to youtube and share the link. I’m sure others would like to see what creative things are being done with Klipper.

There are many different buffers involved, my statement “up to 1-2sec” is about possible time delays which you can experience - depends from many things.

Judging by your statements - seems you did put your klipper in constant buffer starvation mode to get minimal predictable delays, and any “hiccup” in system can skew printer behavior.

I still didn’t fully understand what your code is doing with G-Code, but if main objective was just changing Extrusion amount - then it’s possible to get “Real time control” without klipper tweaks by integrating hardware control right before Extruder stepper driver, by intercepting Step/Dir pulses, then your hardware (like Arduino) can analyze requested Step/Dir pulses and external environment (other inputs) and can transform it to desired Output.

Yeah I understand, and in a way I am indeed putting it in a “buffer starvation”, at least the buffer is just as big as I need it, to have minimal delay without “empty buffer hickups”.

So the G-code is calculated on the fly; I have the following code-structure

#Calculate Gcode differentiations on XYZE;
→ spits out delta values for all the axis based on parameters determined by button interface/ potmeters/ etc.

#Calculate Gcode
Xcoor = Xcoor + deltaX
Ycoor = Ycoor + deltaY

#Send Gcode;
→ the newly calculated gcodes are sent through the websocket

#Wait for OK from the WebSocket,

#Repeat the process.

I am doing manipulations on all axis and as such the klipper implementation is way faster as I can send gcode with a speed of up to 10ms/command/ where effectively I am printing at 50ms/command.