Bed Tramming from the LCD

I wanted to be able to use my Z probe to tram the bed and tell me how to adjust the leveling screws all from the LCD without having to use the computer. I finally got it working, and here’s a video of it in action.

As of 2/3/2023 (commit fa78e6b), this solution works on mainline Klipper without the need for any code patches. To get started, create a new screws_display.cfg containing the following:

#############################################
### DISPLAY GROUP FOR "MEASURING" MESSAGE ###
#############################################

[display_data screws_running line1]
position: 1, 0
text: { " Measuring Bed." }

[display_data screws_running line2]
position: 2, 0
text: { " Please wait..." }

#########################################
### DISPLAY GROUP FOR "ERROR" MESSAGE ###
#########################################

[display_data screws_error line1]
position: 0, 0
text: Tilt exceeds

[display_data screws_error line2]
position: 1, 0
text: max deviation.

[display_data screws_error line3]
position: 2, 0
text: Adjust screws

[display_data screws_error line4]
position: 3, 0
text: and try again.

########################################
### DISPLAY GROUP FOR RESULTS SCREEN ###
########################################

[display_template _results_template_text]
param_adjust: None
param_base: None
text:
    {% if param_base %}
        Base
    {% else %}
        { '{} '.format(param_adjust) }
    {% endif %}

[display_template _results_template_sign]
param_sign: None
text:
    {% if param_sign == 'CW' %}
        ~clockwise_1~~clockwise_2~
    {% elif param_sign == 'CCW' %}
        ~counter_clockwise_1~~counter_clockwise_2~
    {% endif %}


# Back left screw
[display_data screws_results back_left_text]
position: 1, 0
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_back = coords[1] >= bed_depth_fifth * 3 %}
        {% set x_left = coords[0] <= bed_width_fifth * 2 %}
        {% if y_back and x_left %}
            {% if results.get('is_base') %}
                { render("_results_template_text", param_base=True) }
            {% else %}
                { render("_results_template_text", param_adjust=results.get('adjust')) }
            {% endif %}
        {% endif %}
    {% endfor %}

[display_data screws_results back_left_sign]
position: 0, 1
text: 
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_back = coords[1] >= bed_depth_fifth * 3 %}
        {% set x_left = coords[0] <= bed_width_fifth * 2 %}
        {% if y_back and x_left %}
            {% if not results.get('is_base') %}
                { render("_results_template_sign", param_sign=results.get('sign')) }
            {% endif %}
        {% endif %}
    {% endfor %}

# Front left screw
[display_data screws_results front_left_text]
position: 3, 0
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_front = coords[1] <= bed_depth_fifth * 2 %}
        {% set x_left = coords[0] <= bed_width_fifth * 2 %}
        {% if y_front and x_left %}
            {% if results.get('is_base') %}
                { render("_results_template_text", param_base=True) }
            {% else %}
                { render("_results_template_text", param_adjust=results.get('adjust')) }
            {% endif %}
        {% endif %}
    {% endfor %}

[display_data screws_results front_left_sign]
position: 2, 1
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_front = coords[1] <= bed_depth_fifth * 2 %}
        {% set x_left = coords[0] <= bed_width_fifth * 2 %}
        {% if y_front and x_left %}
            {% if not results.get('is_base') %}
                { render("_results_template_sign", param_sign=results.get('sign')) }
            {% endif %}
        {% endif %}
    {% endfor %}

# Back right screw
[display_data screws_results back_right_text]
position: 0, 11
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_back = coords[1] >= bed_depth_fifth * 3 %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_back and x_right %}
            {% if results.get('is_base') %}
                { render("_results_template_text", param_base=True) }
            {% else %}
                { render("_results_template_text", param_adjust=results.get('adjust')) }
            {% endif %}
        {% endif %}
    {% endfor %}

[display_data screws_results back_right_sign]
position: 1, 12
text: 
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_back = coords[1] >= bed_depth_fifth * 3 %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_back and x_right %}
            {% if not results.get('is_base') %}
                { render("_results_template_sign", param_sign=results.get('sign')) }
            {% endif %}
        {% endif %}
    {% endfor %}

# Middle right screw
[display_data screws_results middle_right_text]
position: 1, 11
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_middle = (bed_depth_fifth * 2) < coords[1] < (bed_depth_fifth * 3) %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_middle and x_right %}
           {% if results.get('is_base') %}
                { render("_results_template_text", param_base=True) }
            {% else %}
                { render("_results_template_text", param_adjust=results.get('adjust')) }
            {% endif %}
        {% endif %}
    {% endfor %}

[display_data screws_results middle_right_sign]
position: 2, 12
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_middle = (bed_depth_fifth * 2) < coords[1] < (bed_depth_fifth * 3) %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_middle and x_right %}
            {% if not results.get('is_base') %}
                { render("_results_template_sign", param_sign=results.get('sign')) }
            {% endif %}
        {% endif %}
    {% endfor %}

# Front right screw
[display_data screws_results front_right_text]
position: 3, 11
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_front = coords[1] <= bed_depth_fifth * 2 %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_front and x_right %}
           {% if results.get('is_base') %}
                { render("_results_template_text", param_base=True) }
            {% else %}
                { render("_results_template_text", param_adjust=results.get('adjust')) }
            {% endif %}
        {% endif %}
    {% endfor %}

[display_data screws_results front_right_sign]
position: 2, 12
text:
    {% set bed_width_fifth = printer.configfile.settings.stepper_x.position_max / 5 %}
    {% set bed_depth_fifth = printer.configfile.settings.stepper_y.position_max / 5 %}
    {% for screw in printer.screws_tilt_adjust.results %}
        {% set coords = printer.configfile.settings.screws_tilt_adjust.get(screw) %}
        {% set results = printer.screws_tilt_adjust.results.get(screw) %}
        {% set y_front = coords[1] <= bed_depth_fifth * 2 %}
        {% set x_right = coords[0] >= bed_width_fifth * 3 %}
        {% if y_front and x_right %}
            {% if not results.get('is_base') %}
                { render("_results_template_sign", param_sign=results.get('sign')) }
            {% endif %}
        {% endif %}
    {% endfor %}

#########################################
### EXTRA GLYPHS FOR SCREW DIRECTIONS ###
#########################################

[display_glyph clockwise_1]
data:
  ................
  .........******.
  ........***..***
  .......**......*
  ......**........
  ......*........*
  ......*.......**
  ................
  ................
  ....******......
  ....*****.......
  ....****........
  ....*****......*
  ....**..***..***
  ....*....******.
  ................

[display_glyph clockwise_2]
data:
  ................
  ...*............
  ..**............
  ****............
  ****............
  ****............
  ****............
  ................
  ................
  .*..............
  .*..............
  **..............
  *...............
  ................
  ................
  ................

[display_glyph counter_clockwise_1]
data:
  ................
  ....*....******.
  ....**..***..***
  ....*****......*
  ....****........
  ....*****.......
  ....******......
  ................
  ................
  ......*.......**
  ......*........*
  ......**........
  .......**......*
  ........***..***
  .........******.
  ................

[display_glyph counter_clockwise_2]
data:
  ................
  ................
  ................
  *...............
  **..............
  .*..............
  .*..............
  ................
  ................
  ****............
  ****............
  ****............
  ****............
  ..**............
  ...*............
  ................

This also requires a custom menu.cfg to override defaults. I was already using a custom menu from this thread. Here’s my new menu.cfg with the bed-tramming additions:

[menu __main]
type: list
name: Main

### TOP-LEVEL MENUS ###
[menu __main __tune]
type: list
enable: 
    {% set printing = printer.idle_timeout.state == "Printing" %}
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {printing and mainmenu}
name: Tune
index: 1

[menu __main __octoprint]
type: list
name: OctoPrint
enable: false

[menu __main __settings]
type: list
name: Settings
enable:
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {mainmenu}
index: 2

[menu __main __calibrate]
type: list
enable:
    {% set printing = printer.idle_timeout.state == "Printing" %}
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {not printing and mainmenu}
name: Calibrate
index: 3

[menu __main __control]
type: list
enable:
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {mainmenu}
name: Control

[menu __main __temp]
type: list
enable:
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {mainmenu}
name: Temperature

[menu __main __filament]
type: list
enable:
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {mainmenu}
name: Filament

[menu __main __sdcard]
type: vsdlist
enable: false
name: SD Card

[menu __main __setup]
type: list
enable:
    {% set printing = printer.idle_timeout.state == "Printing" %}
    {% set mainmenu = printer['gcode_macro GLOBALS'].display_group == printer.configfile.settings.display.display_group %}
    {not printing and mainmenu}
name: Setup

### SETTINGS SUB-MENU ###
[menu __main __settings __pause]
type: command
enable: {printer.idle_timeout.state == "Printing"}
name: Pause printing
gcode: PAUSE

[menu __main __settings __resume]
type: command
enable: {not printer.idle_timeout.state == "Printing"}
name: Resume printing
gcode: RESUME

[menu __main __settings __abort]
type: command
enable: {printer.idle_timeout.state == "Printing"}
name: Abort printing
gcode: CANCEL_PRINT

### CONTROL SUB-MENU ###
[menu __main __control __home]
type: command
enable: false
name: Home All

[menu __main __control __smart_home]
type: command
name: Smart Home All
index: 1
gcode: SMART_HOME

### CALIBRATE SUB-MENU ###
[menu __main __calibrate __calibration_mesh_calibrate]
type: command
name: Measure Bed Mesh
gcode: MEASURE_BED_MESH

[menu __main __calibrate __calibration_bed_tram]
type: command
name: Tram Bed
gcode:
    {(menu.exit(true))}
    TRAM_BED

[menu __main __calibrate __calibration_probe_calibrate]
type: list
name: Probe Calibrate

[menu __main __calibrate __calibration_probe_calibrate __calibrate]
type: command
name: Probe Calib.
gcode:
    SMART_HOME
    PROBE_CALIBRATE

[menu __main __calibrate __calibration_probe_calibrate __adjust_Z+1]
type: command
name: Z+1: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=+1

[menu __main __calibrate __calibration_probe_calibrate __adjust_Z-1]
type: command
name: Z-1: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=-1

[menu __main __calibrate __calibration_probe_calibrate __adjust_Z+.1]
type: command
name: Z+.1: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=+.1

[menu __main __calibrate __calibration_probe_calibrate __adjust_Z-.1]
type: command
name: Z-.1: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=-.1

[menu __main __calibrate __calibration_probe_calibrate __adjust_Zpp]
type: command
name: Z+: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=+

[menu __main __calibrate __calibration_probe_calibrate __adjust_Zmm]
type: command
name: Z-: {'%05.1f' % printer.gcode_move.position.z}
gcode: TESTZ Z=-

[menu __main __calibrate __calibration_probe_calibrate __calibration_accept]
type: command
name: Accept Adj.
gcode:
    ACCEPT
    SAVE_CONFIG
    {(menu.back.True)}

[menu __main __calibrate __calibration_probe_calibrate __calibration_abort]
type: command
name: Abort
gcode:
    ABORT
    {(menu.back.True)}

### SECONDARY MENU FOR BED TRAMMING RESULTS SCREEN ###
[menu __main __redo_tramming]
type: command
enable:
    {printer['gcode_macro GLOBALS'].display_group == 'screws_results'}
name: Measure Again
gcode:
    {(menu.exit(true))}
    TRAM_BED    
index: 0

[menu __main __finished]
type: command
enable:
    {printer['gcode_macro GLOBALS'].display_group == 'screws_results'}
name: Done
gcode:
    SET_DISPLAY_GROUP GROUP={printer.configfile.settings.display.display_group}
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=display_group VALUE="'_default_16x4'"
    {(menu.exit(true))}
index: 1

Finally, some macros need to be added to printer.cfg:

This one is a hack to store a variable that is used to keep track of what menu structure to display.

[gcode_macro GLOBALS]
variable_display_group:"_default_16x4"
gcode:
    M115 ; must provide something

This one will home all axes that aren’t already homed. This isn’t strictly necessary but it saves time when repeating the measurements.

[gcode_macro SMART_HOME]
gcode:
    {% set toHome = [] %}
    {% if 'x' not in printer.toolhead.homed_axes %}
        { toHome.append('x') or "" }
    {% endif %}
    {% if 'y' not in printer.toolhead.homed_axes %}
        { toHome.append('y') or "" }
    {% endif %}
    {% if 'z' not in printer.toolhead.homed_axes %}
        { toHome.append('z') or "" }
    {% endif %}
    {% if toHome|length == 0 %}
        { action_respond_info('All axes homed!') }
    {% else %}
        G28 { toHome|join(' ') }
    {% endif %}

This one is the magic.

[gcode_macro TRAM_BED]
gcode:
    SET_DISPLAY_GROUP GROUP=screws_running
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=display_group VALUE="'screws_running'"
    SMART_HOME
    screws_tilt_calculate
    {% if printer.screws_tilt_adjust.error %}
        SET_DISPLAY_GROUP GROUP=screws_error
    {% else %}
        SET_DISPLAY_GROUP GROUP=screws_results
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=display_group VALUE="'screws_results'"
    {% endif %}

This should work with any bed that has 4 leveling screws. It should also work with 3 screws as long as the third screw (the “middle” one) is on the side of the bed opposite the X endstop and has a Y location roughly half way between the other two screws. In other words, on an otherwise stock Ender 3 that’s been converted to three bed screws, if there are two screws on the left and one on the right, this should work.

6 Likes

I know this is an old post but I love this! How do I get this to properly work on a 4 screw bed? I tried adding some screws in the screw_display.cfg but it seems to only want me to adjust 1 screw. Thanks in advance

Got it working for the most part. Only thing left to figure out is why Base is not showing.

#############################################
### DISPLAY GROUP FOR "MEASURING" MESSAGE ###
#############################################

[display_data screws_running line1]
position: 0, 0
text: { " Measuring Bed." }

[display_data screws_running line2]
position: 1, 0
text: { " Please wait..." }

#########################################
### DISPLAY GROUP FOR "ERROR" MESSAGE ###
#########################################

[display_data screws_error line1]
position: 0, 0
text: Tilt exceeds

[display_data screws_error line2]
position: 1, 0
text: max deviation.

[display_data screws_error line3]
position: 2, 0
text: Adjust screws

[display_data screws_error line4]
position: 3, 0
text: and try again.

########################################
### DISPLAY GROUP FOR RESULTS SCREEN ###
########################################

[display_template _results_template_text]
param_adjust: None
text:
    {% if not param_adjust %}
        Base
    {% else %}
        { '{} '.format(param_adjust) }
    {% endif %}

[display_template _results_template_sign]
param_sign: None
text:
    {% if param_sign == 'CW' %}
        ~clockwise_1~~clockwise_2~
    {% elif param_sign == 'CCW' %}
        ~counter_clockwise_1~~counter_clockwise_2~
    {% endif %}

########################################
###            BACK SCREWS           ###
########################################

############# BACK LEFT ################
# Back Left Screw Text
[display_data screws_results back_left_text]
position: 1, 0
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_back = result['y'] >= bed_depth_half %}
        {% set x_left = result['x'] <= bed_width_half %}
        {% if y_back and x_left %}
            { render("_results_template_text", param_adjust=result.get('adjust')) }
        {% endif %}
    {% endfor %}

#[display_data screws_results back_left_sign]
position: 0, 1
text: 
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_back = result['y'] >= bed_depth_half %}
        {% set x_left = result['x'] <= bed_width_half %}
        {% if y_back and x_left %}
            { render("_results_template_sign", param_sign=result.get('sign')) }
        {% endif %}
    {% endfor %}

############# BACK RIGHT ################
# Back Right Screw Text
[display_data screws_results back_right_text]
position: 0, 11
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_back = result['y'] >= bed_depth_half %}
        {% set x_right = result['x'] >= bed_width_half %}
        {% if y_back and x_right %}
            { render("_results_template_text", param_adjust=result.get('adjust')) }
        {% endif %}
    {% endfor %}

# Back Right Screw Sign
[display_data screws_results back_right_sign]
position: 1, 12
text: 
   {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_back = result['y'] >= bed_depth_half %}
        {% set x_right = result['x'] >= bed_width_half %}
        {% if y_back and x_right %}
            { render("_results_template_sign", param_sign=result.get('sign')) }
        {% endif %}
    {% endfor %}


########################################
###           FRONT SCREWS           ###
########################################

############# Front Left ################
# Front Left Screw Text
[display_data screws_results front_left_text]
position: 3, 0
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_front = result['y'] <= bed_depth_half %}
        {% set x_left = result['x'] <= bed_width_half %}
        {% if y_front and x_left %}
            { render("_results_template_text", param_adjust=result.get('adjust')) }
        {% endif %}
    {% endfor %}

[display_data screws_results front_left_sign]
position: 2, 1
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_front = result['y'] <= bed_depth_half %}
        {% set x_left = result['x'] <= bed_width_half %}
        {% if y_front and x_left %}
            { render("_results_template_sign", param_sign=result.get('sign')) }
        {% endif %}
    {% endfor %}

############# Front RIGHT ################
# Front Right Screw Text
[display_data screws_results front_right_text]
position: 3, 11
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_front = result['y'] <= bed_depth_half %}
        {% set x_right = result['x'] >= bed_width_half %}
        {% if y_front and x_right %}
            { render("_results_template_text", param_adjust=result.get('adjust')) }
        {% endif %}
    {% endfor %}

# Front Right Screw Sign
[display_data screws_results front_right_sign]
position: 2, 12
text:
    {% set bed_width_half = printer.configfile.settings.stepper_x.position_max / 2 %}
    {% set bed_depth_half = printer.configfile.settings.stepper_y.position_max / 2 %}
    {% for result in printer.screws_tilt_adjust.results %}
        {% set y_front = result['y'] <= bed_depth_half %}
        {% set x_right = result['x'] >= bed_width_half %}
        {% if y_front and x_right %}
            { render("_results_template_sign", param_sign=result.get('sign')) }
        {% endif %}
    {% endfor %}

#########################################
### EXTRA GLYPHS FOR SCREW DIRECTIONS ###
#########################################

[display_glyph clockwise_1]
data:
  ................
  .........******.
  ........***..***
  .......**......*
  ......**........
  ......*........*
  ......*.......**
  ................
  ................
  ....******......
  ....*****.......
  ....****........
  ....*****......*
  ....**..***..***
  ....*....******.
  ................

[display_glyph clockwise_2]
data:
  ................
  ...*............
  ..**............
  ****............
  ****............
  ****............
  ****............
  ................
  ................
  .*..............
  .*..............
  **..............
  *...............
  ................
  ................
  ................

[display_glyph counter_clockwise_1]
data:
  ................
  ....*....******.
  ....**..***..***
  ....*****......*
  ....****........
  ....*****.......
  ....******......
  ................
  ................
  ......*.......**
  ......*........*
  ......**........
  .......**......*
  ........***..***
  .........******.
  ................

[display_glyph counter_clockwise_2]
data:
  ................
  ................
  ................
  *...............
  **..............
  .*..............
  .*..............
  ................
  ................
  ****............
  ****............
  ****............
  ****............
  ..**............
  ...*............
  ................

Which screw is your base screw and what is the display showing instead?

Base is back left. Its showing nothing right now.

Thanks for the help

In your “BACK LEFT” block, this line shouldn’t be commented out:

#[display_data screws_results back_left_sign]

So it was! Thank you! An extra set of eyes is great to have! Works perfectly now.

This commit breaks the results screen, screws_tilt_adjust: status result as dictionary · Klipper3d/klipper@fa78e6b (github.com)

I loved doing this via the LCD but I don’t understand what’s changed in this commit to make necessary adjustments.

I knew this was coming. I’ll plan to update the macros to be compatible with mainline Klipper, but I’ll need a tester as I’ve since migrated to KlipperScreen.

1 Like

If you do it, I’ll be up for testing.

Does your machine have 3 or 4 leveling screws?

4, I used rick88Mustang’s modification above.

All right, I’ve updated the original post to reflect the updated code and instructions. @Kaan tested this and it’s working with 4 bed screws. Ironically, I’m not using the stock LCD on my own printer anymore so I haven’t been able to test with my original 3-screw setup, but it should work just the same.

I created the new cfg files and put the new macros in printer.cfg and the menu shows on my 12864 screen but nothing happens when i select tram bed and i get this error.
image

What happens if you issue a simple SCREWS_TILT_CALCULATE gcode command?

I get "Unknown command:“SCREWS_TILT_CALCULATE”
menu.cfg (4.7 KB)
screws_display.cfg (11.2 KB)

This guide assumes your printer is already properly set up for probe-based tilt adjustment.

https://www.klipper3d.org/Config_Reference.html#screws_tilt_adjust

Ahhh got it thanks!

Added the required Screws_tilt_adjust code in the cfg and this now works perfectly.

thank you very much!

1 Like