MachineKit Delta configuration + calibration

tl;dr: Instructions to run (and calibrate!) a linear delta 3D printer on MachineKit. I use a CRAMPS board but much of this applies to other boards too.

The first post in this series showed how to get a CRAMPS board up and running with MachineKit, along with how to verify that each board feature works as expected.

This second post shows how to get a Linear Delta 3D printer (a la Rostock, Kossel, 3DR, Wolfstock, etc.) running and calibrated with this same CRAMPS/MachineKit combination. Most of the instructions will apply equally to other boards like the BeBoPr.

Get the code

The first step is to get MachineKit code that supports this combination. I have a small fork of MachineKit that does just this, and your first step is to check out this code. First, log in to the BeagleBone however you prefer: direct keyboard, VNC, or SSH w/X (my preference).

Then, I strongly recommend updating the clock to avoid issues with broken builds due to unexpected timestamps. With an internet connection (in my case, provided by Mac Internet Connection Sharing via Thunderbolt-to-Ethernet):

sudo ntpdate

Verify the date:


Alternately, you can set this manually with the ‘date -s’ command.

Add a remote repository and check out the code with my config:

cd ~/machinekit-dev
git remote add brandon
git fetch brandon
git checkout -b delta brandon/delta

Update LinuxCNC:

cd ~/machinekit-dev/src
sudo make setuid

Only those two steps are necessary if you started from Charles’ SD image for BeagleBone:

make clean + + ./configure --with-platform=beaglebone --with-xenomai --with-posix

… may be needed if you’re coming from a more experimental branch.

Customize the config

MachineKit/LinuxCNC configs mostly live in two files, .ini (Initialization) and .hal (Hardware Abstraction Layer). The .ini files mostly set specific machine parameters, like rod lengths, max speeds and accelerations, and even stepper motor timings. The .hal mostly configures the board, the visuals you see in LinuxCNC, and things like pin names and assignments. If someone has already made a .hal file for your board (CRAMPS) and your machine type (linear delta), most of the work is already done for you, and you can just focus on the machine-specific customizations.

The curious should take a look at the .hal file, which derives from one I did last year plus for a BeBoPr, combined with one that’s currently in the MachineKit config dir for the BeBoPr-Bridge board, written by Bas be Brujin. Again, you shouldn’t need to change anything here, but it’s nice to see the flexibility LinuxCNC provides; all this HAL stuff can be changed without having to recompile the software.

Open up CRAMPS.lineardelta.ini, at You can do this with any text editor (vim, nano, etc) or what I prefer: use Eclipse with Remote Systems Extensions. This way I get full syntax highlighting for any code style, mouse usage, and one single pane for all machines I’m connected to. Eclipse has nice built-in visual diffs.

CRAMPS.lineardelta.hal is currently configured for my larger Kossel Mini with 300mm triangles and about 600mm of wire-length-limited verticals. This is not a standard size, so you’ll certainly need to change plenty of config params. However, some good news is that you can “port” the calibration over from any other kind of firmware like Marlin or Repetier.

Machine Dimensions

Don’t load LinuxCNC just yet! To make config changes, you need to reload all of LinuxCNC. Yes, it sucks, because it takes ~30 seconds to reload and doesn’t always close properly when you click the close button using X forwarding. In the rest of this post, I’ll walk through some common things you’ll want to change. Change the stuff, then start it up. The next sections will cover stuff you’ll want to verify and possibly change.

Configure DELTA_R

Here’s a sample Marlin configuration.h file with delta support. It has these lines:

// Effective horizontal distance bridged by diagonal push rods.

It would be nice if you could just copy these lines into the .ini, but LinuxCNC does not support expressions in .ini files. You’ll want to compute the DELTA_RADIUS value and replace the DELTA_R value here. If you don’t have the value, measure from one of the ball joints on the effector to where the other ball joint on that rod would hit the XY plane with the effector in the center.

Make this change in the .ini file.

Configure CF_ROD

Marlin configuration.h has these lines:

// Center-to-center distance of the holes in the diagonal push rods.
#define DELTA_DIAGONAL_ROD 175.89 // mm

No change needed here, just a new name, CF_ROD, in the .ini file. This is another one that can be measured fairly accurately.

Also make this change in the .ini file, and all the ones the follow.


HOME and HOME_OFFSET must be configured for each axis in the .ini. These refer to joint position, so these should be pretty large. Pretty different than Marlin… Marlin configuration.h has this line:

#define MANUAL_Z_HOME_POS 176 // For delta: Distance between nozzle and print surface after homing.

This is easy enough to understand, but the way this height is defined for the lineardeltakins Kinematics module we’re using is a bit different. Plus, if you have a printer with software endstop adjustment (like a Mini Kossel) rather than hardware endstop adjustment (like a Rostock), the offsets will need to be configured.

The kinematics module calculates the effector position from the HOME/HOME_OFFSET vals and the two delta params above. That is, it does the trig to compute the Z height from the ball joints on the effector (near the XY plane) to the Z height of the ball joints on the carriages. So your HOME/HOME_OFFSET values must be at least as a large as this Z-height, which you can easily measure. Add to that the MANUAL_Z_HOME_POS – the distance from the bottom of the hotend to the top of the build plate. If this doesn’t make sense, then just set all the HOME/HOME_OFFSET values the same and see what the readout in LinuxCNC shows for the Z-height after homing; this is described in more detail below.

To make it a bit easier to change the HOME and HOME_OFFSET values, my fork has a little script,, which will replace all 6 of these values to the value you provide. For example:

cd ~/machinekit-dev
./ 400

… will set all to 400.

Also make sure to mix in the individual joint offsets if using software endstops. If you use M666 with Marlin, you can reuse the joint offsets for calibrating each tower. Add these for each axis. However, don’t expect the params to exactly match. Marlin homes endstops twice – the second time with a slower speed, which means the switch when homed will be slightly pressed in. LinuxCNC reverses until the endstop flips polarity. I’m pretty sure that this explains a small offset between my Marlin params and the LinuxCNC ones.

Machine Motion params

For each axis section in the .ini, set the following parameters. They should all the same for each axis, so I’d suggest setting them once, then copy/pasting twice.

  • MAX_VELOCITY: I set mine to 350 mm/s to have a bit of margin.
  • MAX_ACCELERATION: Don’t drop this too low or you may see error reported.
  • MIN_LIMIT: I set this to -10 to get a little space to go downward below the XY limit for calibration.
  • MAX_LIMIT: Make sure this is large enough to cover your HOME/HOME_LIMIT vals!
  • HOME_SEARCH_VEL: This is the axis speed during homing. I would drop this (to, say, 10mm/s) until you’re sure homing is working; it’ll give you time to shut off power if the steppers are plugged in the opposite way, too.
  • SCALE: This is the steps/mm for the axis. For 16-tooth GT2 belts with 16x micro stepping, the value is 100. Nice round 0.01mm max resolution.

Stepper Params

The bottom of each axis section has stepper params, including DIRSETUP, DIRHOLD, STEPLEN, and STEPSPACE. The .ini has sample values for two typical drivers, the DRV8825 and A4988. Comment/uncomment each one as necessary.

This covers the params. You’ll certainly need to make some changes later, but this should be enough to get going.

Run the configuration

Go into LinuxCNC:

linuxcnc &

Verify Endstops

The .hal file connects the endstops to max limit pins.

Verify that Endstops are connected NC.

Why? Trust me, verify this. Make sure that the endstops report TRUE when not pressed and FALSE when pressed, which will happen with NC (normally-connected) switches. Yes, the config already inverts the axes, so this is not what you would expect. In the terminal, run:

halcmd show signal limit-x-max

Run this for each axis and make sure the value changes when pressed.

Verify Motor Direction

Hopefully you dropped HOME_VEL for each axis in the .ini to something slow, like 10mm/s, so that if anything is wired wrong, you have time to catch it and shut off power or hit the e-stop.

Put your effector in the middle and be ready to press the software e-stop or shut off motor power. Disable e-stop, enable the machine, and click Home. The effector should move up. If not, make sure to shut off motor power, flip the connections, and try again.

Delta Calibration

Delta Calibration is a subject of many more comprehensive blog posts and videos; look at the end of this post for some more detailed references to follow up.

At a high level, the typical procedure is to adjust the tower offsets so that the effector moves to the exact same height for a triangle of 3 points, then to get the middle of the triangle to the same height by adjusting the delta radius. Optionally, you can then get dimensionally accurate parts by tweaking the rod length.

Most people use a strip of paper or feeler gauges to calibrate the effector height. You can make it work, but you’ll waste time, because you have to manually move the effector until it “catches” the paper, and you’ll have to guess on the amounts to adjust each iteration. Plus, the paper can deform.

I do things a little differently by employing a precision gauge (a dial indicator) to do probing and having pre-made G-codes to move the effector to do the measuring. For me, this yields extremely high precision and repeatability, and more importantly, you can measure exactly how accurate you are. A dial indicator is a cheap purchase from eBay and can be used for other stuff. Here’s what it looks like:

In the video, I’m executing the home command within LinuxCNC, then doing G70-G72 commands and G79 in sequence. The indicator face has been turned to 0 to highlight the deviation. The calibration is within 0.001″ and it’s easy enough to get sub-0.0005″.

Those delta-specific G-codes come from a script in my fork. I have the tip start out above the XY plane, then go down 7mm at each triangle location. You can customize the positions in this script for your machine – for example, you can change the probing radius:

cd ~/machinekit-dev
python ./ --radius [probe radius]

Mine probes at a radius of 80 mm. There are other params to change as well. To see them, run with the help flag:

cd ~/machinekit-dev
python ./ -h

Also note that my enlarged Mini Kossel in the video has my dial indicator mount on it. You can download this part from my dti_holder Kossel GitHub repo branch. Generate the STL from the OpenSCAD and print without supports in PLA, at some reasonable infill like 20-25%. To mount it to Mini Kossel effector, just use 2 or 3 m3 screws and add one more m3 screw to lock down on the dial indicator. I formed the threads in plastic with an electric drill with an allen tip pushing in a screw. Looks like this:


Using this setup, here’s the technique:

Step 1: Tower heights

Use the script to set some reasonable starting place. If you click on the MDI tab in LinuxCNC after homing, the preview window will show the perceived XYZ position of the effector, as something near X=0 and Y=0 but with a higher Z. See that the Z value matches the distance between the bottom of the effector and the top of the build plate. If there’s a difference between these, change all the tower heights by that difference in the .ini for each tower, then restart LinuxCNC, re-home, and measure again.

Once Z = 0 is close to the build plate, you can tune the tower offsets. Start by getting G70 (X tower) and G71 (Y tower) to match. Adjust the towers a bit more than the indicator difference; note that the indicator can’t go all the way to the tower end, so it’s showing you a fraction of the real amount. In fact, just multiply by the delta radius over the tower probe distance and adjust by that amount. Usually I can get to 0.001″ accuracy in a few iterations, so fortunately, it’s not too much waiting time for LinuxCNC to load. Run G70, G71, and G72 each time and adjust the Y and Z towers each time. You want to be within 0.001″ on the indicator and ideally at the resolution of the indicator.

Step 2: Tower center

G79 does the center probe. This one’s a bit different; you can adjust the relevant parameters in real-time, which is pretty cool!

halcmd setp lineardeltakins.R [new dimension]

Write down each delta radius value, then each indicator value, make a change, and then see if the value goes in the right direction. Pretty quickly you’ll see which direction to go and the right amount to tweak.

Make sure to set the value in your .ini once you’ve found the right combinations, or else it’ll be cleared.

(later) Step 3: Part-Size Calibration

This one requires printing parts, so it’s a little out of scope for this blog post. Anyway, you make a part that’s long in one direction and skinny in the other, like a 175mm x 2mm x 0.5mm strip. After printing a part, you modify the CF_ROD length, to zero in on 100% accurate parts. I did this for some Simpson parts and go to within 0.2mm or so over 175mm, which is not perfect but good enough.

Once the machine is calibrated, you’re pretty close. In an upcoming post, I’ll show the final steps to get this thing printing! Post in the comments if you have any questions.


Minow’s calibration guide.

Jay Couture’s video on M665/666 homing

Bas de Brujin’s MachineKit linear delta post (some overlap)


18 thoughts on “MachineKit Delta configuration + calibration

  1. Thanks for the writeup. I am familiar with LinuxCNC, but am new to deltabots, so this was useful reading, especially the use of dial indicator.

  2. This is incredibly helpful! Your write ups have got me up and running in a matter of days after months of messing with Arduino. Thank you so much for taking the time to simplify this process for those less versed in LInux.

  3. Brandon, during ./configure i run into:

    checking for CZMQ… no
    configure: error: Package requirements (libczmq > 2.0) were not met:

    No package ‘libczmq’ found

    This after it also cannot find uuid-runtime, which I successfully installed. Any ideas? Thx in advance…

  4. Pingback: Together for a test run | linearcreations

  5. updates to updates for Python2+ requires casts to int or float.

    line 60: g_code = int(g_code_base) + int(g_code_index)
    line 74: z2 = z1 – int(opts.z_depth)
    line 81: x = sin(theta_r) * float(opts.radius)
    line 82: y = cos(theta_r) * float(opts.radius)

  6. we can now adjust HOME, HOME_OFFSET and DELTA_R using halcmd so no need to go in/out of Machinekit and lots of editing of the INI file. Examples below:

    halcmd setp axis.0.home
    halcmd setp axis.1.home_offset
    halcmd setp lineardeltakins.R

  7. Thanks for these clear instruction. After lot’s of readings of other stuff around I finaly found your post; thanks a lot.
    A give away from my site: Try an induction cook-plate to replace the traditional hotplate; a little more expensive but so fast and soo temp precise. (And yes you need a flat steel plate too)

  8. Thank you for the write up. I am trying to get my large custom delta working with machinekit but when I try to calibrate the tower heights as you have described above it keeps telling me that the Z height is at ~750mm when it should be around ~475mm. When I then move to Z=0 it’s still about 100mm up off the build plate. Any ideas why this might be so? I have HOME and HOME_OFFSET set to 1141 right now for all axes.

    • IF it’s off by 100mm, maybe you need to account for the length of the hotend? Not sure about your particular numbers, as I don’t know the arm lengths. Good luck!

      • It turns out I needed to remove some of the microstepping jumpers that came on my cramps board. I have it dialed in now. Now I just need to figure out why I can’t extrude (the hotend keeps getting jammed up) and how to turn on the fan without having to use halcmd from another terminal.

  9. I am printing on my Trestle delta with Machinekit and the CRAMPS board! Thanks for all the info you have put up here and the code you have contributed. I am not sure I could have done it without you having blazed the trail. Here’s a bit of video from my first test print for all who are interested:

    • Very cool! Thanks for letting me know, and congrats on your printer working!!! I just got my “production” Printrboard-based delta back up and running a week ago, and once I get part cooling and extrusion to 100% reliable, it’s time to switch back to MachineKit for me.

  10. @Brandon, having issues incorporating your GIT into the machinekit 2015-08-31 release BBB/CRAMPS. The generic CRAMPS (Cartesian) startup will power into Machinekit, but your CRAMPS and CRAMPS.lineardelta INI and HAL files all error out at the EMCMOT line of the HAL file. Any ideas? What am I missing? Error is -1 returned for insmod and rtapi_app_main(motmod):

    • My git commits are probably hopelessly out of date at this point, and since MachineKit has not focused on a stable API, it’s expected. I don’t have a board handy to look at, but I’d strongly suggest going to the MachineKit google group and posing your question there, and request a sample delta config. Good luck! People there have been really helpful to me in the past.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s