From 3376973477a2446a4e1cc8dbec01daaa390cbe3b Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Sat, 11 Feb 2023 16:52:12 -0800 Subject: [PATCH] initial limited-corexz --- config/example-limited-corexz.conf | 78 +++++++++++++++++ docs/Config_Reference.md | 59 +++++++++++++ klippy/kinematics/limited_corexz.py | 130 ++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 config/example-limited-corexz.conf create mode 100644 klippy/kinematics/limited_corexz.py diff --git a/config/example-limited-corexz.conf b/config/example-limited-corexz.conf new file mode 100644 index 000000000000..7e90d3ba5543 --- /dev/null +++ b/config/example-limited-corexz.conf @@ -0,0 +1,78 @@ +# This file is an example config file for corexz style printers. One +# may copy and edit this file to configure a new corexz printer. + +# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT +# FIRST. Incorrectly configured parameters may cause damage. + +# See docs/Config_Reference.md for a description of parameters. + +[stepper_x] +step_pin: PF0 +dir_pin: PF1 +enable_pin: !PD7 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PE5 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_y] +step_pin: PF6 +dir_pin: PF7 +enable_pin: !PF2 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PJ1 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_z] +step_pin: PL3 +dir_pin: PL1 +enable_pin: !PK0 +microsteps: 16 +rotation_distance: 8 +endstop_pin: ^PD3 +position_endstop: 0.5 +position_max: 200 + +[extruder] +step_pin: PA4 +dir_pin: PA6 +enable_pin: !PA2 +microsteps: 16 +rotation_distance: 33.500 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PB4 +sensor_type: ATC Semitec 104GT-2 +sensor_pin: PK5 +control: pid +pid_Kp: 22.2 +pid_Ki: 1.08 +pid_Kd: 114 +min_temp: 0 +max_temp: 250 + +[heater_bed] +heater_pin: PH5 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PK6 +control: watermark +min_temp: 0 +max_temp: 130 + +[fan] +pin: PH6 + +[mcu] +serial: /dev/ttyACM0 + +[printer] +kinematics: limited_corexz +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 50 +max_z_accel: 30 diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index e69b7346d794..f6ce5dff66c2 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -565,6 +565,65 @@ max_z_accel: [stepper_z] ``` +### CoreXZ Kinematics with limits for X and Y axes + +Behaves exactly the as corexz kinematics, but allows to set a velocity and +acceleration limit for X and Y axis. + +If you set accelerations per feature type in the slicer, and have tuned your +acceleration to get similar resonance amplitudes and level of smoothing on X and +Y, you may want to enable `scale_xy_accel: true`. This will scale the X and Y +accelerations by the ratio `M204 acceleration / config.max_accel`. For example, +if you have `max_accel: 10000` in your config and set in the slicer an +acceleration of 5000 mm/s² (`M204 S5000`), effective `max_x_accel` and +`max_y_accel` values will be halved compared to their original values set in the +`[printer]` config. Otherwise, with `scale_xy_accel: false` (the default) they +behave as machine limits, like `max_z_accel` and `max_z_velocity` always do. +Gcode velocities under the limits are never scaled per axis and stay isotropic. + +``` +[printer] +kinematics: limited_corexz +max_x_velocity: +# This sets the maximum velocity (in mm/s) of movement along the x +# axis. This setting can be used to restrict the maximum speed of +# the x stepper motor. The default is to use max_velocity for +# max_x_velocity. +max_y_velocity: +# This sets the maximum velocity (in mm/s) of movement along the y +# axis. This setting can be used to restrict the maximum speed of +# the y stepper motor. The default is to use max_velocity for +# max_x_velocity. +max_z_velocity: +# See cartesian above. +max_velocity: +# In order to get maximum velocity gains on diagonals, this should be equal or +# greater than the hypotenuse (sqrt(x*x + y*y)) of max_x_velocity and +# max_y_velocity. +max_x_accel: +# This sets the maximum acceleration (in mm/s^2) of movement along +# the x axis. It limits the acceleration of the x stepper motor. The +# default is to use max_accel for max_x_accel. +max_y_accel: +# This sets the maximum acceleration (in mm/s^2) of movement along +# the y axis. It limits the acceleration of the y stepper motor. The +# default is to use max_accel for max_y_accel. +max_z_accel: +# See cartesian above. +max_accel: +# In order to get maximum acceleration gains on diagonals, this should be +# equal or greater than the hypotenuse (sqrt(x*x + y*y)) of max_x_accel and +# max_y_accel. +scale_xy_accel: +# If scale_xy_accel is False, `max_accel`, set by M204 or SET_VELOCITY_LIMIT, +# acts as a third limit. This means that moves with an acceleration lower +# than max_x_accel and max_y_accel, have no per-axis limits applied. When set +# to True, max_x_accel and max_y_accel are scaled by the ratio of the +# acceleration set at runtime and the max_accel value from the config. Then +# the actual acceleration will always depend on the orientation. +``` + + ### Hybrid-CoreXY Kinematics See [example-hybrid-corexy.cfg](../config/example-hybrid-corexy.cfg) diff --git a/klippy/kinematics/limited_corexz.py b/klippy/kinematics/limited_corexz.py new file mode 100644 index 000000000000..ac83df0b0537 --- /dev/null +++ b/klippy/kinematics/limited_corexz.py @@ -0,0 +1,130 @@ +# Code for handling the kinematics of corexz robots +# with per-axis limits for velocity and acceleration +# +# Copyright (C) 2020-2021 Mael Kerbiriou +# Copyright (C) 2023 Kyle Brown +# +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Usage: +# Copying this file under `klipper/klippy/kinematics/` should be enough (click +# the `raw` button on github, then save as) +# Then your config's [printer] should look like: +# [printer] +# kinematics: limited_corexz +# max_velocity: 500 # Hypotenuse of the two values bellow +# max_x_velocity: 400 +# max_y_velocity: 300 +# max_z_velocity: 5 +# max_accel: 1500 # Default acceleration of your choice +# max_x_accel: 12000 +# max_y_accel: 9000 +# max_z_accel: 100 +# scale_xy_accel: [True/False, default False] +# +# max_velocity is usually the hypotenuses of X and Y velocity, For example: +# with max_x_velocity = 300 and max_y_velocity = 400, the recommended value +# is max_velocity = 500. +# +# If scale_xy_accel is False, `max_accel`, set by M204 or +# SET_VELOCITY_LIMIT, acts as a third limit. In that case, this module +# doesn't apply limitations to moves with an acceleration lower than +# max_x_accel and max_y_accel. +# When scale_xy_accel is True, max_x_accel and max_y_accel are scaled by +# the ratio of the dynamically set acceleration and the hypotenuse of +# max_x_accel and max_y_accel, as reported from `SET_KINEMATICS_LIMIT`. +# This means that the actual acceleration will always depend on the +# direction. +# For example with these settings: +# [printer] +# max_x_accel: 12000 +# max_y_accel: 9000 +# scale_xy_accel: true +# SET_KINEMATICS_LIMIT will report a maximum acceleration of 15000 mm/s^2 +# on 37 degrees diagonals. Thus, setting an acceleration of 3000 mm/s^2 in +# the slicer will make the toolhead accelerate at 3000 mm/s^2 on these 37 +# and 143 degrees diagonals, but only 12000 * 3000 / 15000 = 2400 mm/s^2 +# for moves aligned with the X axis and 18000 mm/s^2 for pure Y moves. + + +from sys import float_info +from math import hypot, atan2, pi + +from . import corexz + +EPSILON = float_info.epsilon + + +class LimitedCoreXZKinematics(corexz.CoreXZKinematics): + def __init__(self, toolhead, config): + corexz.CoreXZKinematics.__init__(self, toolhead, config) + # Setup y axis limits + max_velocity, max_accel = toolhead.get_max_velocity() + self.max_velocities = [ + config.getfloat("max_%s_velocity" % ax, max_velocity, above=0.0) + for ax in "xyz" + ] + self.max_accels = [ + config.getfloat("max_%s_accel" % ax, max_accel, above=0.0) for ax in "xyz" + ] + self.xy_hypot_accel = hypot(*self.max_accels[:2]) + self.scale_per_axis = config.getboolean("scale_xy_accel", False) + config.get_printer().lookup_object("gcode").register_command( + "SET_KINEMATICS_LIMIT", self.cmd_SET_KINEMATICS_LIMIT + ) + + def cmd_SET_KINEMATICS_LIMIT(self, gcmd): + self.max_velocities = [ + gcmd.get_float("%s_VELOCITY" % ax, max_v, above=0.0) + for max_v, ax in zip(self.max_velocities, "XYZ") + ] + self.max_accels = [ + gcmd.get_float("%s_ACCEL" % ax, max_a, above=0.0) + for max_a, ax in zip(self.max_accels, "XYZ") + ] + self.xy_hypot_accel = hypot(*self.max_accels[:2]) + self.scale_per_axis = bool( + gcmd.get_int("SCALE", self.scale_per_axis, minval=0, maxval=1) + ) + msg = ("x,y,z max_velocities: %r\n" "x,y,z max_accels: %r\n") % ( + self.max_velocities, + self.max_accels, + ) + if self.scale_per_axis: + msg += "Per axis accelerations limits scale with current acceleration.\n" + else: + msg += "Per axis accelerations limits are independent of current acceleration.\n" + msg += ( + "Maximum XY velocity of %.1f mm/s reached on %.0f degrees diagonals.\n" + "Maximum XY acceleration of %.0f mm/s^2 reached on %.0f degrees diagonals." + ) % ( + hypot(*self.max_velocities[:2]), + 180 * atan2(self.max_velocities[1], self.max_velocities[0]) / pi, + self.xy_hypot_accel, + 180 * atan2(self.max_accels[1], self.max_accels[0]) / pi, + ) + gcmd.respond_info(msg) + + def check_move(self, move): + if not move.is_kinematic_move: + return + self._check_endstops(move) + x_r, y_r, z_r = move.axes_r[:3] + x_max_v, y_max_v, z_max_v = self.max_velocities + x_max_a, y_max_a, z_max_a = self.max_accels + x_r = max(abs(x_r), EPSILON) + y_r = max(abs(y_r), EPSILON) + max_v = min(x_max_v / x_r, y_max_v / y_r) + max_a = min(x_max_a / x_r, y_max_a / y_r) + if self.scale_per_axis: + _, toolhead_max_a = move.toolhead.get_max_velocity() + max_a *= toolhead_max_a / self.xy_hypot_accel + if z_r: + z_r = abs(z_r) + max_v = min(max_v, z_max_v / z_r) + max_a = min(max_a, z_max_a / z_r) + move.limit_speed(max_v, max_a) + + +def load_kinematics(toolhead, config): + return LimitedCoreXZKinematics(toolhead, config)