KlipperLab
Flat isometric illustration of a purple 3D printer flanked by two pink speaker cabinets and a control box, cables running to pink pucks on a navy slab.
Tuning

Klipper Input Shaper Setup: Wiring and Tuning an ADXL345

Wiring, configuration, and calibration commands for measuring resonance with an ADXL345 in Klipper, plus fixes for the errors that stop a run.

By KlipperLab Editorial · · 7 min read

Input shaping is the one Klipper feature that turns a measurement into a configuration value with no guesswork in between. An accelerometer on the toolhead produces a resonance profile per axis, and Klipper’s calibration script reads that profile and recommends a shaper type, a frequency, and an acceleration ceiling. The setup is short. The failures are specific, and almost all of them happen before any useful data is collected.

This walks the procedure documented by the Klipper project, in the order the machine will actually make you do it, with the errors that interrupt each step.

Before You Wire Anything

Resonance compensation reduces the visible effect of vibration. It does not compensate for a loose belt, a flexing gantry, or a toolhead that rocks on its carriage. Measuring a machine that is mechanically unsound produces a clean graph of a problem you should have fixed instead.

Three things should be true first:

  • Belts tensioned and consistent, frame square, gantry not flexing under hand pressure.
  • Kinematics and motor directions confirmed. On CoreXY both motors contribute to both axes, so a mirrored motor shows up as skew rather than as an obvious single-axis fault.
  • Extruder rotation distance and flow calibrated, and pressure advance tuned. Otherwise every later artefact gets blamed on the wrong subsystem.

The reasoning behind that ordering is covered in Klipper firmware architecture and input shaper tuning. If you have not chosen an accelerometer or a place to plug it in yet, Klipper hardware requirements covers the options.

Step 1: Host Prerequisites

The calibration scripts run on the host and depend on numpy and matplotlib. Install them before wiring, because the usual sequence is that the sensor answers queries perfectly and then the analysis script exits on an import error twenty minutes later.

sudo apt update
sudo apt install python3-numpy python3-matplotlib

If the sensor is going to hang off the host’s own SPI pins rather than the printer’s control board, SPI has to be enabled on the host and Klipper needs a second microcontroller target built for the host itself. Klipper calls this the Linux process microcontroller, and it exists precisely so the host can own SPI devices like an accelerometer without spending pins on the printer board.

Step 2: Wiring

The ADXL345 is an SPI device. Four signal lines plus power and ground: chip select, clock, and the two data lines. Two details cause most of the trouble:

Voltage. Most breakout boards are 3.3V parts. Feeding one 5V, or driving its inputs from 5V logic, is the fastest way to a sensor that reads garbage or nothing at all.

Mounting. The sensor measures whatever it is bolted to. A rigid mount directly on the toolhead is the goal; a sensor taped to a cable or dangling from a zip tie measures the tape and the zip tie. On machines whose bed moves in Y, the bed needs its own measurement, so plan for a second mounting position rather than a single permanent one.

Keep the cable routed so it is not being whipped by the toolhead during the test. Cable noise shows up in the data and is easy to mistake for a resonance.

Step 3: Configuration

With the sensor on the host’s SPI bus, the configuration is three stanzas. The Klipper documentation gives this shape:

[mcu rpi]
serial: /tmp/klipper_host_mcu

[adxl345]
cs_pin: rpi:None

[resonance_tester]
accel_chip: adxl345
probe_points:
    100, 100, 20

probe_points is a coordinate near the middle of the bed at a safe height. The toolhead moves there and shakes in place, so give it room and make sure nothing on the bed is in the way.

If the sensor is wired to the printer’s control board instead of the host, the [mcu rpi] section is unnecessary and cs_pin names a pin on that board. If the machine has an accelerometer at both the toolhead and the bed, Klipper supports naming each chip and pointing the tester at the right one per axis.

Restart the firmware after saving, and confirm Klipper starts cleanly before going further.

Step 4: Verify the Sensor Answers

Two commands, in this order, from the console in your web front end:

ACCELEROMETER_QUERY
MEASURE_AXES_NOISE

ACCELEROMETER_QUERY returns a single reading. On a stationary printer it should be roughly one g on the vertical axis and near zero on the other two. If the numbers are wildly wrong or the command errors, stop here; nothing downstream will be meaningful.

MEASURE_AXES_NOISE reports the background noise on each axis with the machine idle. The Klipper documentation describes good values as being on the order of 1 to 100. Values far above that mean the sensor is picking up something other than the machine’s structure, and the usual culprits are power supply noise, a long unshielded cable, or a fan running near the sensor.

Step 5: Measure and Calibrate

TEST_RESONANCES AXIS=X
TEST_RESONANCES AXIS=Y

Each command sweeps the toolhead through a frequency range and writes a CSV to /tmp on the host. That data can be plotted with the project’s calibrate_shaper.py script, which produces a graph of response against frequency and prints a recommended shaper and frequency.

For the shorter path, Klipper can do the measurement and the recommendation in one step and write the result straight into the configuration:

SHAPER_CALIBRATE
SAVE_CONFIG

SAVE_CONFIG appends the chosen values to an autosave block at the end of printer.cfg and restarts the firmware. Know that this block exists and that it overrides what you wrote by hand higher up in the file, because a value you edited manually and cannot make take effect is usually being overridden down there.

SHAPER_CALIBRATE accepts a MAX_SMOOTHING argument. Constraining smoothing biases the recommendation toward shapers that cost less detail, at the price of leaving more vibration unsuppressed. It is the right knob when the default recommendation produces visibly softened corners.

Step 6: Read the Result Like a Trade, Not a Score

The output names a shaper type and a frequency per axis, which end up as an [input_shaper] section. The values below are placeholders to show the shape of the block, not numbers to copy:

[input_shaper]
shaper_freq_x: 52.4
shaper_type_x: mzv
shaper_freq_y: 38.1
shaper_type_y: ei

Shapers differ in how much vibration they cancel and how much smoothing they impose to do it. More aggressive suppression tolerates a wider error in the frequency estimate but costs more smoothing, and smoothing costs effective acceleration and fine detail. A lower resonant frequency makes every option worse, which is why a heavy toolhead or a flexible gantry is a mechanical problem that no shaper choice repairs.

Acceleration is where that trade becomes a number you have to set. Use the input shaper and acceleration sizer to see how a measured frequency and a shaper choice constrain usable acceleration before committing a max_accel, then verify against what the calibration script itself recommended for your machine. The script’s recommendation is the authority; the sizer is for understanding the shape of the trade-off quickly.

Print a ringing test after saving. The graph says the resonance was suppressed; the print says whether the result is what you wanted.

Troubleshooting

SymptomLikely causeWhat to do
An invalid chip id error on ACCELEROMETER_QUERYWrong CS pin, SPI not enabled on the host, miswired data lines, or a board that is not actually an ADXL345Re-check the CS pin name, confirm SPI is enabled, verify the two data lines are not swapped
Klipper will not start after adding the configMissing host microcontroller target, or a typo in a section nameConfirm the host process microcontroller is built and running before adding [adxl345]
calibrate_shaper.py exits immediatelynumpy or matplotlib missing on the hostInstall both, then re-run against the CSV already in /tmp
Noise values far above the documented rangeCable routing, an unshielded run, or a fan near the sensorShorten and route the cable away from motors, re-measure with fans off to isolate
Both axes return near-identical peaksSensor is measuring the frame rather than the toolheadRe-mount rigidly to the moving mass
Recommendation changes every runSensor mount is not rigid, or belts moved between runsFix the mount first; an unrepeatable measurement is not a measurement
Values edited by hand have no effectAn autosave block at the end of printer.cfg is overriding themEdit or remove the autosave entry, then restart

When to Measure Again

The resonance profile belongs to a specific machine in a specific state. Remeasure after anything that changes moving mass or frame stiffness: a new hotend or toolhead, a different carriage, retensioned belts, a rebuilt gantry, or moving the printer to a different surface. Copying shaper values from another machine of the same model is the one shortcut that reliably wastes the whole exercise, because the values encode that machine’s mass and stiffness rather than the model’s.

If you are still weighing whether this workflow justifies running Klipper at all, the measurement pipeline described here is the clearest difference between the two options in Klipper vs Marlin.

Sources

  1. Klipper: Measuring Resonances
  2. Klipper: Resonance Compensation
  3. Klipper: Raspberry Pi as a Secondary MCU
  4. Klipper: G-Codes

Related