Updates:
- 2025/06/05: published with a few more references
- 2025/05/31: adding MAF reference to support multi-axis functionality better
- 2025/05/14: starting write-up
Table of Contents
Introduction

Klipper is a host software running usually on a dedicated Single Board Computer (SBC) like Raspberry Pi or alike, and sends compact binary to MCUs for low-level to control stepper motors, and various sensors.
The kinematics and the resulting motion (acceleration, speed, deceleration) is planned on the host, therefore it’s very good to prototype experimental setups such as my Ashtar Q with multiple gantries and multiple extruders on each gantry.
In the past I was skeptic about introducing another part like an SBC for operating a 3D printer, as one introduces another point-of-failure, yet, the Klipper developers in particular Kevin O’Connor, managed to find the right balance to separate the planning from the realtime sensitive aspects from the “host” vs the “microcontroller” (aka MCU).
I still like RepRapFirmware running on a more powerful MCU without the need of a separate SBC – but I wanted to experiment with Klipper and so far I really liked its capabilities.
Hardware Declaration
What I really like is that Klipper allows to describe the MCUs at the low-level:
- pins are named which control the stepper motor
- simply add “
!
” in front, and the logic is inverted (e.g. change direction of the motor) - multiple MCUs can control different aspect of the printer, each MCU is named, and the pins are referenced
<mcu_name>:<pin_name>
and so (re)use older MCUs to build quite capable kinematic systems (not just 3D printers)
So a multitude of MCUs are available, from cheap ~10 EUR board up to Duet3D boards at 200+ EUR price – all capable running Klipper MCU firmware.
Extended G-code
Klipper provides vast features, and therefore requires more powerful way to distinct settings from the limited way G-code does it, so it introduces a powerful macro system based on Jinja2, and an additional set of new G-code commands, such as:
RESTART
starts host softwareFIRMWARE_RESTART
restarts the MCU software/firmware
and SOMETHING A=100 BC=100,200
can be processed like this:
[gcode_macro SOMETHING]
gcode:
{% set A = params['A'] %}
{% set B,C = params['BC'].split(',') %}
MANUAL_STEPPER STEPPER=my_stepper MOVE={A}
MANUAL_STEPPER STEPPER=my_stepper_2 MOVE={B}
{% set C2 = (A|int + B|int)/2 %}
MANUAL_STEPPER STEPPER=my_stepper_3 MOVE={C}
and a bare/subset of Python is available within the macro coding – one has to refrain (like me) to code complex code there as one will reach its limits quickly.
Software & Hardware Modularity
By having multiple microcontrollers (MCUs) attached via USB and addressable within Klipper printer configuration, and declaring so called multiple “manual steppers“ outside of the common kinematics system, together with its macro-system one can do more than just move an extruder in XYZ, but create a robotic system with a lot of functionality, but it misses multiple motions queues limiting some applications.
Multi-Axis Capability
As of May 2025, Klipper is able to handle multi-axis G-code:
- declare
MANUAL_STEPPER
with connection with a driver, such as TMC2209 (move driver declaration beforeMANUAL_STEPPER
in case you usevirtual_endstop
) - home that axis with Extended G-code of Klipper (or use the “MAF” macro collection I wrote using
G28
) - register
MANUAL_STEPPER
into “G-gcode space” by assigning an axis, e.g. A, B, C, D, U, V, W, or I, J, K, P, Q, R (be awareI
andJ
is used for G2/G3 arc motions); MAF does handle this as well
Example of 2nd X carriage, in my case I have a dedicated MCU for the 2nd extruder named mcu2
, this is for a BTT SKR MINI E3 V2.0 board:
[tmc2209 manual_stepper stepper_x1] # -- must come before [manual_stepper] https://github.com/Klipper3d/klipper/issues/2563
uart_pin: mcu2:PC11
diag_pin: ^mcu2:PC0
uart_address: 0
run_current: 0.580
stealthchop_threshold: 999999
driver_SGTHRS: 100 # 255 is most sensitive value, 0 is least sensitive
[manual_stepper stepper_x1]
step_pin: mcu2:PB13
dir_pin: mcu2:PB12
enable_pin: !mcu2:PB14
microsteps: 16
rotation_distance: 40
#endstop_pin: ^PC0
endstop_pin: tmc2209_stepper_x1:virtual_endstop
at point writing this, homing a “manual stepper” with G28
wasn’t yet supported – so I wrote a “Multi-Axis For Klipper” aka “MAF” macros which implements some of the missing functionalities:
G28 X U
G0 X200 Y200 U300 F3000
moving two X-carriages independently but together or atomic, whereas using something like:
T0
G0 X200 Y200 F3000
T1
G0 X300 F3000
would not guarantee the exact atomicity, given both carriages mounted on the same Y gantry, but introduce slight drift as introduced from the motion planner and stepper motor control – having it done as a new “axis”, we have it guaranteed at the same time.
Note: T<number>
(tool selection) notion requires macros to define the behavior, like changing extruder and such – regardless, G-code line-wise only guarantees atomicity at line-level, not beyond.
So, treating the 2nd (or 3rd) X carriage as separate axis allows to implement True IDEX, independent motion of multiple extruders, but fully coordinated. Usually firmware handles mirror or copy of IDEX systems at low-level, now one controls the carriages at G-code level fully giving great freedom for multiple extruders printing at the same time.
Limitations
No Multiple Motion Queues (Yet)
As of writing (2025/06) Klipper does not yet support multiple motion queues like RepRapFirmware (RRF) provides. In essence it means, one cannot issue two concurrent running G0
or G1
commands but they run in sequence always, even if those G0/G1
commands might address different axes or gantries altogether.
References
- Github Klipper: the source
- Klipper documentation: comprehensive resource
- Klipper forum/discourse: excellent resource to study
- Multi-Axis for Klipper
- Klipper for CNC: interesting fork
- Kalico: Risky Klipper: more features, riskier to use