Skip to main content

Site Navigation

Your Account

Choose Language

Bed levelling using multiple independent Z motors

On a printer which uses two or more Z motors to raise/lower the bed or gantry, you can have the firmware probe the bed and adjust the motors individually to eliminate tilt. This feature is implemented in firmware version 1.19 and later.


  • You must have a bed or gantry that is raised/lowered by two, three or four leadscrews or similar, where each one is driven by its own Z motor
  • Each Z motor must be driven from a separate stepper motor output on the Duet + optional DueX expansion board
  • As usual with this arrangement, you must use M584 to assign the 2, 3 or 4 drivers to the Z axis
  • You must use the M671 command to define the X and Y coordinates of the leadscrews. The M671 command must come after the M584 command and must specify the same number of X and Y coordinates as the number of motors assigned to the Z axis in the M584 command; and these coordinates must be in the same order as the driver numbers of the associated motors in the M584 command. The M671 command must also come after any M667 or M669 command.
  • You can optionally specify a maximum correction per leadscrew in the M671 command (S parameter). If you don't, it defaults to 1mm.
  • You must set up a bed.g file in the usual way with at least as many probe points as Z motors. You can have more if you wish.
  • The value of the S parameter on the final G30 command in bed.g must equal the number of Z motors.

How it works

A valid M671 command enables auto calibration of the Z motors. When you run G32 to perform bed probing, the final G30 command (the one with the S parameter) in bed.g will then cause auto calibration to be performed. The auto calibration uses a least squares algorithm that minimises the sum of the height errors. The deviation before and expected deviation after calibration is reported.

If you have two Z motors, the calibration process adjusts the bed tilt along a line between the two leadscrew positions, on the assumption that the tilt at right angles to this will not change. With three motors, it adjusts the tilt in both directions. With four motors, it adjusts the tilt in both directions and also the twist. You should not use 4 leadscrews with a bed that is rigid enough to resist twisting strongly.

You can run G32 again to repeat the process if you wish.

If your bed is not perfectly flat or the gantry sags a little when the head is over the middle of the bed, the process will cause a small shift in the Z=0 position. To correct this, if you are using the Z probe to do Z homing, you can just re-home Z at the end of your bed.g file.


  • If you have 3 or 4 Z motors, in bed.g use at least one probe point close to each leadscrew.
  • If you have just 2 Z motors, one at each end of the X axis, then set the Y coordinates of the leadscrews in the M671 command to be equal (the value doesn't matter, so you can use zero). Use at least two probe points, one at each end of the X axis. All your probe points should have the same Y coordinate, which should be at or near the middle of the printable range.

Example for 3 motors

File config.g:

M584 X0 Y1 Z2:5:6 ; three Z motors connected to driver outputs 2, 5 and 6
M671 X-15:100:215 Y190:-10:190 S0.5 ; leadscrews at rear left, front middle and rear right

File bed.g:

G28 ; home
M401 ; deploy Z probe (omit if using bltouch)
G30 P0 X20 Y190 Z-99999 ; probe near a leadscrew
G30 P1 X180 Y190 Z-99999 ; probe near a leadscrew
G30 P2 X100 Y10 Z-99999 S3 ; probe near a leadscrew and calibrate 3 motors
M402 ; retract probe (omit if using bltouch)

Example for 2 motors

File config.g:

M584 X0 Y1 Z2:4 ; two Z motors connected to driver outputs Z and E1
M671 X-20:220 Y0:0 S0.5 ; leadscrews at left and right of X axis
M208 X-5:205 Y0:200 ; X carriage moves from -5 to 205, Y bed goes from 0 to 200

File bed.g:

G28 ; home
M401 ; deploy Z probe (omit if using bltouch)
G30 P0 X20 Y100 Z-99999 ; probe near a leadscrew, half way along Y axis
G30 P1 X180 Y100 Z-99999 S2 ; probe near a leadscrew and calibrate 2 motors
M402 ; retract probe (omit if using bltouch)


Can M584 be used to assign the extra Z motor to the driver normally used for E1? Forgive me if this has been answered somewhere else.

Jeremy Watkins - Reply

Yes it can, Please use the Duet3D forum for support :

Tony -

I would like to upgrade a UM2 clone with Duet electronics.

Would it be possible to program it to adjust the normal single Z axis for a overall Z adjust and then add two small Z adjustment systems (smaller steppers with gears) to the two front corners of the heatbed to adjust the level of the bed?


Casper Mønsted - Reply

please discuss this on the forum.

Tony -

Whats the point of having a comment section if you direct to the forum?

Chad Hurd - Reply

The forum allows for a much better way of giving advice to specific problems. Comments here much more cumbersome to handle.

Tony -

I’m wondering if I could use the StallGuard2 feature of the TMC2660 stepper drivers with four Z servos, to level the bed?

3dPrintClean Filtration - Reply


I jist saw, it is for a z bed . What is the setting, when you have a cartesian setup with y bed, where the nozzle sits on X an Z ?

Ziraxas - Reply

Hi Ziraxes,

Yes for the Z, I’m designing a new printer. so exploring ideas. I’m thinking of using a fixed bed, with four Zs, driving a coreXY gantry. like this, but with 4 Z servos and lead screws -,76...


3dPrintClean Filtration - Reply

I am about to rebuilt my printer, too. I had a cr10s and rebuilt it to an prusa style printer with the crearibo mod on thingiverse. I have rewritten the homing file, that it would sync the two z screws. Was looking for advises

Ziraxas -

Hello, the configuration would be more complete if it were added to verify in "config-override.g" that the ports eventually assigned to another Z engine are not occupied by the extrusion service and that if they were, it would be sufficient to add ";" to the beginning of the command string of the door concerned

Massimo - Reply

Add Comment

View Statistics:

Past 24 Hours: 39

Past 7 Days: 160

Past 30 Days: 1,086

All Time: 12,811