# Bed Tramming from the LCD

**URL:** <https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809>\
**Category:** Macros\
**Created:** [September 2, 2021, 1:09am UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809 "2021-09-02T01:09:12Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [September 2, 2021, 1:09am UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/1 "2021-09-02T01:09:12Z")

</div>

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](https://photos.google.com/share/AF1QipNoS6i6Wz1GwuVHsH28CQQvyiyO7nIutSMQPJdSrlQ0lWaoG2Qw1S1w8Xwb1q_n-Q/photo/AF1QipPSKxPdqiJ6OivZUyQ0sxC_eB909t0NErepVJtu?key=blZpNEtIWVFaeDdUQWZFVVNxMWxIS09OWVRhUXp3).

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:

```auto
#############################################
### 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](https://klipper.discourse.group/t/aboms-kipper-menu/199). Here’s my new `menu.cfg` with the bed-tramming additions:

```auto
[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.

```auto
[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.

```auto
[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.

```auto
[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.

---

<div class="post-metadata">

**Author:** ![rick88Mustang](https://avatars.discourse-cdn.com/v4/letter/r/4491bb/32.png) [@rick88Mustang](https://klipper.discourse.group/u/rick88Mustang)\
**Post date:** [September 13, 2022, 3:58pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/2 "2022-09-13T15:58:41Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![rick88Mustang](https://avatars.discourse-cdn.com/v4/letter/r/4491bb/32.png) [@rick88Mustang](https://klipper.discourse.group/u/rick88Mustang)\
**Post date:** [September 17, 2022, 11:41pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/3 "2022-09-17T23:41:00Z")

</div>

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

```auto
#############################################
### 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:
  ................
  ................
  ................
  *...............
  **..............
  .*..............
  .*..............
  ................
  ................
  ****............
  ****............
  ****............
  ****............
  ..**............
  ...*............
  ................

```

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [September 18, 2022, 2:48pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/4 "2022-09-18T14:48:57Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![rick88Mustang](https://avatars.discourse-cdn.com/v4/letter/r/4491bb/32.png) [@rick88Mustang](https://klipper.discourse.group/u/rick88Mustang)\
**Post date:** [September 18, 2022, 4:02pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/5 "2022-09-18T16:02:19Z")

</div>

Base is back left. Its showing nothing right now.

 ![IMG_2129](https://global.discourse-cdn.com/free1/uploads/klipper/original/2X/a/a99947aba77d58e6c2474e04aa245a7416192353.jpeg)

Thanks for the help

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [September 18, 2022, 4:55pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/6 "2022-09-18T16:55:10Z")

</div>

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

#[display\_data screws\_results back\_left\_sign]

---

<div class="post-metadata">

**Author:** ![rick88Mustang](https://avatars.discourse-cdn.com/v4/letter/r/4491bb/32.png) [@rick88Mustang](https://klipper.discourse.group/u/rick88Mustang)\
**Post date:** [September 18, 2022, 7:57pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/7 "2022-09-18T19:57:56Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Kaan](https://avatars.discourse-cdn.com/v4/letter/k/b9bd4f/32.png) [@Kaan](https://klipper.discourse.group/u/Kaan)\
**Post date:** [February 8, 2023, 3:50pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/8 "2023-02-08T15:50:22Z")

</div>

This commit breaks the results screen, [screws\_tilt\_adjust: status result as dictionary · Klipper3d/klipper@fa78e6b (github.com)](https://github.com/Klipper3d/klipper/commit/fa78e6b8fb392baf0a8fdcdda9fad7c0383bd1ff)

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

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [February 8, 2023, 4:19pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/9 "2023-02-08T16:19:41Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Kaan](https://avatars.discourse-cdn.com/v4/letter/k/b9bd4f/32.png) [@Kaan](https://klipper.discourse.group/u/Kaan)\
**Post date:** [February 8, 2023, 5:31pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/10 "2023-02-08T17:31:10Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [February 8, 2023, 6:03pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/11 "2023-02-08T18:03:57Z")

</div>

Does your machine have 3 or 4 leveling screws?

---

<div class="post-metadata">

**Author:** ![Kaan](https://avatars.discourse-cdn.com/v4/letter/k/b9bd4f/32.png) [@Kaan](https://klipper.discourse.group/u/Kaan)\
**Post date:** [February 8, 2023, 6:16pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/12 "2023-02-08T18:16:31Z")

</div>

4, I used rick88Mustang’s modification above.

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [February 15, 2023, 12:58am UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/13 "2023-02-15T00:58:47Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![coitusmysterioso](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@coitusmysterioso](https://klipper.discourse.group/u/coitusmysterioso)\
**Post date:** [November 8, 2023, 8:00pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/14 "2023-11-08T20:00:10Z")

</div>

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](https://global.discourse-cdn.com/free1/uploads/klipper/original/2X/f/fd7aae98995d4df53e9c00457e750a1b24816c7d.png)

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [November 8, 2023, 10:17pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/15 "2023-11-08T22:17:16Z")

</div>

What happens if you issue a simple `SCREWS_TILT_CALCULATE` gcode command?

---

<div class="post-metadata">

**Author:** ![coitusmysterioso](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@coitusmysterioso](https://klipper.discourse.group/u/coitusmysterioso)\
**Post date:** [November 9, 2023, 12:20am UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/16 "2023-11-09T00:20:24Z")

</div>

> [@theophile](#):
>
> SCREWS\_TILT\_CALCULATE

I get "Unknown command:“SCREWS\_TILT\_CALCULATE”  
[menu.cfg](https://klipper.discourse.group/uploads/short-url/dDDjFJwkowlRFfPauKHL1zd7AhY.cfg) (4.7 KB)  
[screws\_display.cfg](https://klipper.discourse.group/uploads/short-url/q2u6Kw9KS2UOOH6tLJZF8jLkFXN.cfg) (11.2 KB)

---

<div class="post-metadata">

**Author:** ![theophile](https://yyz2.discourse-cdn.com/free1/user_avatar/klipper.discourse.group/theophile/32/31_2.png) [@theophile](https://klipper.discourse.group/u/theophile)\
**Post date:** [November 9, 2023, 1:11am UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/17 "2023-11-09T01:11:50Z")

</div>

> [@coitusmysterioso](#):
>
> I get "Unknown command:“SCREWS\_TILT\_CALCULATE”

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](https://www.klipper3d.org/Config_Reference.html#screws_tilt_adjust)

---

<div class="post-metadata">

**Author:** ![coitusmysterioso](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@coitusmysterioso](https://klipper.discourse.group/u/coitusmysterioso)\
**Post date:** [November 9, 2023, 1:20pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/18 "2023-11-09T13:20:38Z")

</div>

Ahhh got it thanks!

---

<div class="post-metadata">

**Author:** ![coitusmysterioso](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@coitusmysterioso](https://klipper.discourse.group/u/coitusmysterioso)\
**Post date:** [November 10, 2023, 1:11pm UTC](https://klipper.discourse.group/t/bed-tramming-from-the-lcd/809/19 "2023-11-10T13:11:58Z")

</div>

Added the required Screws\_tilt\_adjust code in the cfg and this now works perfectly.

thank you very much!
