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 pool.ntp.org
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:
git remote add brandon http://github.com/brandonheller/machinekit
git fetch brandon
git checkout -b delta brandon/delta
sudo make setuid
Only those two steps are necessary if you started from Charles’ SD image for BeagleBone:
make clean + autogen.sh + ./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 https://github.com/brandonheller/machinekit/blob/delta/configs/ARM/BeagleBone/CRAMPS/CRAMPS.lineardelta.hal. 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.
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.
Here’s a sample Marlin configuration.h file with delta support. It has these lines:
// Effective horizontal distance bridged by diagonal push rods.
#define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET)
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.
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, update_home.sh, which will replace all 6 of these values to the value you provide. For example:
… 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.
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:
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 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:
python ./create_delta_calibration_gcodes.py --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:
python ./create_delta_calibration_gcodes.py -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 update_home.sh 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.