Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ See the [Kalico Additions document](https://docs.kalico.gg/Kalico_Additions.html

- [extruder: cold_extrude](https://github.com/KalicoCrew/kalico/pull/750)

- [core: automatic mesh bounds and home position](https://github.com/KalicoCrew/kalico/pull/879)

If you're feeling adventurous, take a peek at the extra features in the bleeding-edge-v2 branch [feature documentation](docs/Bleeding_Edge.md)
and [feature configuration reference](docs/Config_Reference_Bleeding_Edge.md):

Expand Down
4 changes: 4 additions & 0 deletions docs/Axis_Twist_Compensation.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ This command will calibrate the X-axis by default.
SAMPLE_COUNT=<value>
``

If `bed_size` and `bed_corner_position` are defined in the `[printer]`
section, the calibration points will be automatically calculated to cover
the largest reachable area of the bed.

2. **Adjust Your Z Offset:**
After completing the calibration, be sure to
[adjust your Z offset](Probe_Calibrate.md#calibrating-probe-z-offset).
Expand Down
18 changes: 18 additions & 0 deletions docs/Bed_Mesh.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ probe_count: 5, 3
as a single integer value that is used for both axes, ie `probe_count: 3`.
Note that a mesh requires a minimum probe_count of 3 along each axis.

### Automatic mesh bounds

If `bed_size` and `bed_corner_position` are defined in the `[printer]`
section, then `mesh_min` and `mesh_max` can be automatically calculated.
The calculated mesh will be the largest reachable rectangular area on the
bed, respecting the probe's offsets and any configured edge distance.
The `bed_corner_position` (as a nozzle coordinate) can be set to the true
physical location of the bed, even if that point is unreachable by the
nozzle or probe (i.e. outside the axis limits). Kalico will automatically
adjust the mesh to stay within the printer's reachable area.

Note that if `mesh_min` or `mesh_max` are explicitly defined in the
`[bed_mesh]` section, those values will take precedence over the
automatically calculated ones.

Automatic calculation is currently only supported for rectangular
kinematics systems.

The illustration below demonstrates how the `mesh_min`, `mesh_max`, and
`probe_count` options are used to generate probe points. The arrows indicate
the direction of the probing procedure, beginning at `mesh_min`. For reference,
Expand Down
25 changes: 22 additions & 3 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ kinematics:
# The type of printer in use. This option may be one of: cartesian,
# corexy, corexz, hybrid_corexy, hybrid_corexz, rotary_delta, delta,
# deltesian, polar, winch, or none. This parameter must be specified.
#bed_size:
# The physical size of the bed (width, height) in mm. This is used
# for automatic mesh bounds and home position calculation. This
# parameter is currently only supported for rectangular kinematics
# (cartesian, corexy, corexz, limited_*, and deltesian).
#bed_corner_position:
# The XY coordinate (as a nozzle coordinate) of the front-left corner
# of the bed. This is used for automatic mesh bounds and home
# position calculation. This parameter is currently only supported
# for rectangular kinematics (cartesian, corexy, corexz, limited_*,
# and deltesian). Note that this value can be outside of the axis
# limits defined for the steppers; Kalico will automatically find
# the nearest reachable point within the bed's boundaries.
max_velocity:
# Maximum velocity (in mm/s) of the toolhead (relative to the
# print). This value may be changed at runtime using the
Expand Down Expand Up @@ -1669,8 +1682,11 @@ Where x is the 0, 0 point on the bed
# A newline separated list of four X, Y points that should be probed
# during a QUAD_GANTRY_LEVEL command. Order of the locations is
# important, and should correspond to Z, Z1, Z2, and Z3 location in
# order. This parameter must be provided. For maximum accuracy,
# ensure your probe offsets are configured.
# order. If `bed_size` and `bed_corner_position` are defined in the
# `[printer]` section, this parameter is optional and defaults to
# the largest reachable area of the bed, while maintaining the
# aspect ratio of the gantry corners. For maximum accuracy, ensure
# your probe offsets are configured.
#speed: 50
# The speed (in mm/s) of non-probing moves during the calibration.
# The default is 50.
Expand Down Expand Up @@ -1775,7 +1791,10 @@ has to move to the center of the bed before Z can be homed.
[safe_z_home]
home_xy_position:
# A X, Y coordinate (e.g. 100, 100) where the Z homing should be
# performed. This parameter must be provided.
# performed. If `bed_size` and `bed_corner_position` are defined
# in the `[printer]` section, this parameter is optional and
# defaults to the center of the bed (adjusted by the probe's
# offsets if a probe is present).
#speed: 50.0
# Speed at which the toolhead is moved to the safe Z home
# coordinate. The default is 50 mm/s
Expand Down
4 changes: 3 additions & 1 deletion docs/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ Kalico supports many standard 3d printer features:
multiple Z steppers then Kalico can also level by independently
manipulating the Z steppers. Most Z height probes are supported,
including BL-Touch probes and servo activated probes. Probes may be
calibrated for axis twist compensation.
calibrated for axis twist compensation. Kalico can also
automatically calculate the mesh boundaries and safe Z home
position based on the physical bed size and corner position.

* Automatic delta calibration support. The calibration tool can
perform basic height calibration as well as an enhanced X and Y
Expand Down
1 change: 1 addition & 0 deletions docs/Kalico_Additions.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- Input shaper calibration now warns about active fans that may affect measurement accuracy.
- [`BED_MESH_CHECK`](./G-Codes.md#bed_mesh_check) validates the current bed mesh against specified criteria, allowing you to check maximum deviation and slope between adjacent points before printing.
- [`[resonance_tester]`](./Config_Reference.md#resonance_tester) now supports multiple accelerometer chips via the new `accel_chips` parameter, allowing data from multiple accelerometers to be combined for more accurate input shaper calibration.
- [`[printer] bed_size` and `bed_corner_position`](./Config_Reference.md#printer) can be used to automatically calculate mesh bounds for `[bed_mesh]`, `[quad_gantry_level]`, `[axis_twist_compensation]`, and the home position for `[safe_z_home]`.

## New Kalico Modules

Expand Down
136 changes: 102 additions & 34 deletions klippy/extras/axis_twist_compensation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
# Copyright (C) 2022 Jeremy Tan <[email protected]>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
from __future__ import annotations

import math

from ..mathutil import Point
from ..printer_info import PrinterInfo
from . import bed_mesh, manual_probe

DEFAULT_SAMPLE_COUNT = 3
Expand All @@ -24,9 +27,11 @@ def __init__(self, config):
"horizontal_move_z", DEFAULT_HORIZONTAL_MOVE_Z
)
self.speed = config.getfloat("speed", DEFAULT_SPEED)
self.calibrate_start_x = config.getfloat("calibrate_start_x")
self.calibrate_end_x = config.getfloat("calibrate_end_x")
self.calibrate_y = config.getfloat("calibrate_y")
self.calibrate_start_x = config.getfloat(
"calibrate_start_x", default=None
)
self.calibrate_end_x = config.getfloat("calibrate_end_x", default=None)
self.calibrate_y = config.getfloat("calibrate_y", default=None)
self.z_compensations = config.getlists(
"z_compensations", default=[], parser=float
)
Expand Down Expand Up @@ -145,6 +150,16 @@ def __init__(self, compensation, config):
)
self.speed = compensation.speed
self.horizontal_move_z = compensation.horizontal_move_z
self._update_points_with(compensation)
self.results = None
self.current_point_index = None
self.gcmd = None
self.configname = config.get_name()

# register gcode handlers
self._register_gcode_handlers()

def _update_points_with(self, compensation: AxisTwistCompensation) -> None:
self.x_start_point = (
compensation.calibrate_start_x,
compensation.calibrate_y,
Expand All @@ -161,13 +176,6 @@ def __init__(self, compensation, config):
compensation.calibrate_x,
compensation.calibrate_end_y,
)
self.results = None
self.current_point_index = None
self.gcmd = None
self.configname = config.get_name()

# register gcode handlers
self._register_gcode_handlers()

def _handle_connect(self):
self.probe = self.printer.lookup_object("probe", None)
Expand All @@ -178,6 +186,90 @@ def _handle_connect(self):
self.lift_speed = self.probe.get_lift_speed()
self.probe_x_offset, self.probe_y_offset, _ = self.probe.get_offsets()

# If all are defined, then no need to update the points:
if None not in [
*self.x_start_point,
*self.x_end_point,
*self.y_start_point,
*self.y_end_point,
]:
return

printer_info: PrinterInfo = self.printer.lookup_object("printer_info")

required_fields = [
"calibrate_start_x",
"calibrate_end_x",
"calibrate_y",
]
if not printer_info.is_rectangular or None in [
printer_info.bed_size,
printer_info.bed_corner_position,
printer_info.min_position,
printer_info.max_position,
]:
missing_fields = [
field
for field in required_fields
if getattr(self.compensation, field) is None
]
if len(missing_fields) > 0:
if not printer_info.is_rectangular:
raise self.printer.config_error(
f"AXIS_TWIST_COMPENSATION automatic field calculation"
f" is not supported for {printer_info.kinematics_name}"
f" kinematics, please specify {missing_fields} manually"
)
raise self.printer.config_error(
f"AXIS_TWIST_COMPENSATION requires the fields"
f" {missing_fields} to be set, or printer properties"
f" bed_size, and bed_corner_position to be defined for"
f" automatic field calculation"
)
# If the required fields are set, and the optional ones can not be calculated, then return
return

mesh_min, mesh_max = printer_info.get_mesh_bounds(
mesh_min=None,
mesh_max=None,
use_offsets=True,
error=self.printer.config_error,
probe_offset=(self.probe_x_offset, self.probe_y_offset),
)

center = Point(*mesh_min) + (Point(*mesh_max) - Point(*mesh_min)) / 2.0

# First update the points in self.compensation, ensuring that other tools which access
# these points have the updated values instead of None:
(
(
calibrate_start_x,
calibrate_start_y,
),
(calibrate_x, calibrate_y),
(
calibrate_end_x,
calibrate_end_y,
),
) = [mesh_min, (center[0], center[1]), mesh_max]

for name, value in {
"calibrate_start_x": calibrate_start_x,
"calibrate_start_y": calibrate_start_y,
"calibrate_x": calibrate_x,
"calibrate_y": calibrate_y,
"calibrate_end_x": calibrate_end_x,
"calibrate_end_y": calibrate_end_y,
}.items():
if getattr(self.compensation, name) is not None:
continue

setattr(self.compensation, name, value)

# The same points are stored in a different representation in self,
# which have to be updated as well:
self._update_points_with(self.compensation)

def _register_gcode_handlers(self):
# register gcode handlers
self.gcode = self.printer.lookup_object("gcode")
Expand Down Expand Up @@ -209,18 +301,6 @@ def cmd_AXIS_TWIST_COMPENSATION_CALIBRATE(self, gcmd):
if axis == "X":
self.compensation.clear_compensations("X")

if (
self.x_start_point[0] is None
or self.x_end_point[0] is None
or self.x_start_point[1] is None
):
raise gcmd.error(
"""AXIS_TWIST_COMPENSATION for X axis requires
calibrate_start_x, calibrate_end_x and calibrate_y
to be defined
"""
)

start_point = self.x_start_point
end_point = self.x_end_point

Expand All @@ -235,18 +315,6 @@ def cmd_AXIS_TWIST_COMPENSATION_CALIBRATE(self, gcmd):
elif axis == "Y":
self.compensation.clear_compensations("Y")

if (
self.y_start_point[0] is None
or self.y_end_point[0] is None
or self.y_start_point[1] is None
):
raise gcmd.error(
"""AXIS_TWIST_COMPENSATION for Y axis requires
calibrate_start_y, calibrate_end_y and calibrate_x
to be defined
"""
)

start_point = self.y_start_point
end_point = self.y_end_point

Expand Down
Loading
Loading