3D Printing And Robotics

Project 2: Semi-Automatic Bed Leveling

I am lucky enough to have two roommates that have 3D printers, giving me access to an Ender 3 and a MakerBot. However, this also means that I there is a never-ending stream of complaining about leveling the print beds, as both printers use manual bed-leveling.

Although add-on solutions such as the BLTouch Z-Probe exist to automate the process of bed leveling, I was curious if it was possible to make a mesh-leveling (that is, 'automatic' leveling) that used a manual user-driven process, simplifying bed leveling without any added cost.

Background

The manual bed-leveling process typically uses a sheet of paper placed tightly between the extruder nozzle and the bed of the printer, with the tension of the paper being checked at each corner of the bed. If the paper will not move freely while still being snug with the extruder, the corner's tension screw is loosened. If it slides freely, the tension screw is tightened.

The difficulty of this process comes after the first cycle of this process. After rechecking the tension at each corner, each of the other screws' positioning seems to affect the others. Therefore, this cycle of rechecking the tension must be repeated several times.

Design Considerations

Early in the design process, I realized that I would have to implement this "bed-level routine" in pure handwritten G-Code. Many people seem to treat this process as a laughably difficult process akin to writing machine code by hand, but I pushed through this for two reasons:

*For two other classes, EE443 (Advanced Digital Systems Analysis And Design) and a project in CS 301 (Assembly Language Programming), I wrote MIPS and x86_64 machine code by hand, so I have already done this dreaded process.

*As a frequent Assembly Language programmer, I am brave.

I elected to design this bed-leveling routine first for the Ender-3, which runs the Marlin firmware. Reviewing the Marlin G-Code reference, I found several instructions that would be useful for this process:

G-TYPE INSTRUCTIONS:

*G29 - This is the main instruction that handles mesh (automatically-generated) bed leveling. This instruction handles automatic bed leveling for Z-Probes like the BLTouch, but different subcommands and parameterizations can initiate manual point-leveling modes for refining points that the probe cannot reach.

G28.2 and G28.3 - Initiates a single Z-Probe at a given X/Y coordinate.

G26 - Print a single-layer, full-bed pattern that highlights any errors in the bed-leveling mesh. Parameters can adjust size, heat, and other interesting parameters.

M-TYPE INSTRUCTIONS:

M117 - Write a message to the LCD screen. Potentially helpful for prompting the user.

M119 - See status of the end stop sensors on each axis

M420 - After loading a mesh pattern from memory, set this as the active mesh to use for future prints.

EEPROM INSTRUCTIONS: To prevent Bed-Leveling from needed to be repeated on every reboot, I wanted to use the following:

M501 - Load EEPROM values into RAM, where they are usable to printer subroutines

M502 - Set the EEPROM values in RAM to the factory defaults

M500 - Write EEPROM values from RAM to EEPROM (CAREFUL!!!)

In addition to these instructions, the general instructions such as G0 (movement), G28 (Home axes), etc. would be used extensively. By writing the routine in pure G-Code, my goal was to write the routine to an SD Card and be able to level the bed by simply selecting the routine to "Print" from the SD Card, eliminating the need to write a custom firmware release with my bed-leveling routine.

Early Testing

Initially, I wrote a GCode file that followed the following simple procedure:

*Read EEPROM into RAM, reset it, and write defaults back to EEPROM (odd, but Marlin insisted on it)

*Heat bed, extruder, and home axes

*Clean Nozzle

*Run a single bed-probe, being sure to specify that no Z-Probe was installed
GCODE INSTRUCTIONS FOR THIS PROCESS:
 G29 P0 ;LOAD DEFAULT MESH, START BED-LEVEL PROCESS
 G1 X110 Y110 ;GO TO CENTER OF BED
 G29 P2 B T ;PROBE THIS POINT, TREATING A USER BUTTON CLICK AS AN INDICATION TO CONTINUE

However, the printer would abort the process just after heating and homing. To make debugging easier, I decided to use a USB Serial monitor to send each command line-by-line, also adding the ability to check the printer status after each GCode instruction.

My discovery was disappointing: the Ender-3 would report many of the instructions, such as nozzle cleaning, mesh validation, and all probing commands, as illegal instructions.

Too my chagrin, I discovered that, since the printer does not come with any sort of hardware to support automatic bed leveling, the Ender-3 optimized release of Marlin had almost all of these very useful GCode instructions omitted during compilation, meaning that these instructions were completely missing from the printer.

I took a deep breath, because I knew the solution to this problem: I would have to configure a custom release of Marlin from source, compile it for the Ender-3's microcontroller (a Sanguino 1284P 16MHz compatible), and flash it to the Ender-3. Thankfully, because of his dislike for the bed-leveling process, my roommate kindly consented to this.

Writing A Custom Marlin Release

Now that I had committed to writing a custom firmware, I considered different ways to prepare. Initial thoughts included yoga, illicit drugs, therapy, or even interpretive dance. In the end, I decided that the best preparation was actually to checkout the Marlin 1.1.9 source tree from its official repository.

To not bore the reader, I will just give a quick summary of firmware design process:

*After setting up the Arduino IDE and installing the CPU definitions for the Ender-3's microcontroller, I compiled the standard firmware unmodified to verify the development environment's operation.

*I found that enabling/disabling printer features was controlled by a series of preprocessor macros. "Well, that seems easy enough," I thought. I enabled all of the macros that were relevant to my routine and compiled.
I was met with a semi-expected error: the binary was now much too large to fit into the microcontroller's limited flash memory

*What followed next was a long process of trial-and-error. Eventually, I was able to fit all of the desired features by disabling the following features:

*The custom boot screen and Ender-3 logo

*Speaker support (which I wanted anyway, since the speaker is quite annoying)

*Shortening or removing version and identification strings

*Removing some on-screen menus, since I could control the printer via the Serial Console

*SD Card support (quite a big deal, but I fixed this later; see the last section for details)

Finally, after flashing the firmware to the microcontroller, I was ready to write and debug my G-Code.

Bed Leveler (Version 1)

The complete G-Code for this routine is available at the bottom of this page in the Files section. The downloadable code contains comments on every line, which explain the function of every instruction. To further organize the code, it is divided into titled sections.

The High-Level layout of this bed-leveler is as follows:

Initialize the printer
    Heat bed/extruder
    Reset EEPROM
    Home Axes
    Clean extruder nozzle and wait for user to clean bed

Level Bed
    Center Extruder in X/Y Plane
    Load the "Zero" bed mesh
    Probe the bed, allowing user to microstep extruder to adjust for bed height
    Repeat this process for four additional points
    Construct a mesh of the bed
    Feather and interpolate the entire bed mesh

Save
    Write mesh to EEPROM
    Enable mesh bed leveling using the constructed mesh

Print Test Pattern
    Use 60C bed, 210C extruder, print two closely-packed single layer passes

Clean Up
    Turn off heaters
    Retract filament
    Home X/Y
    Turn off steppers

Bed Leveler (Version 2)

For the second version of the bed-leveler, I made the following adjustments:

*Waiting for the user to clean the bed now waits for a button press, rather than the fixed-length pause in the previous version.

*The mesh pattern was changed from four corners plus the center to a nine-point grid.

Bed Leveler (Version 3)

This version of the bed leveler changed the probing instruction to G29 J3, which specifically focuses on the tilt of the bed as a plane, rather than trying to get an entire mesh of the bed from a limited probe sequence.

However, the fact that the G29 P3 is run after the probing sequence still means that the printer will correct for slight mountains or valleys toward the center of the bed.

Outcome

My bed-leveling system is not as accurate as an automatic probe such as the BLTouch, which I am not surprised about in the least. The BLTouch uses the automatic probe instructions of G29 (that is, G29 P2), which probes the bed in dozens of locations to build a very accurate mesh model of the entire bed.

For what it is, a no-cost-added system to compensate for slight errors in physical bed leveling, my bed leveler worked well. The results of the calibration print were noticeably improved after running the bed-level routine, as seen in the photo gallery. Overall, the system works as intended.

Restoring SD Card Support
I was able to restore SD Card support by removing the implementation code for G26. This prevents the ability to validate the mesh after creating it, but I found that this was not a major issue with practice using the system.



Mesh Validation Pattern (Post-Level)








Files

Bed Leveler Version 1

Bed Leveler Version 2

Bed Leveler Version 3