mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2026-03-09 04:24:48 -06:00
🐛 Fix FT Motion motion+dir for endstops (#28326)
Co-Authored-By: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
parent
5b71e64a77
commit
097fc30201
13 changed files with 276 additions and 186 deletions
|
|
@ -366,17 +366,17 @@
|
|||
#define STR_Z2 STR_C "2"
|
||||
#define STR_Z3 STR_C "3"
|
||||
#define STR_Z4 STR_C "4"
|
||||
#if CORE_IS_XY || CORE_IS_XZ
|
||||
#if ANY(HAS_REAL_X, IS_SCARA, DELTA)
|
||||
#define STEPPER_A_NAME 'A'
|
||||
#else
|
||||
#define STEPPER_A_NAME 'X'
|
||||
#endif
|
||||
#if CORE_IS_XY || CORE_IS_YZ
|
||||
#if ANY(HAS_REAL_Y, IS_SCARA, DELTA, POLAR)
|
||||
#define STEPPER_B_NAME 'B'
|
||||
#else
|
||||
#define STEPPER_B_NAME 'Y'
|
||||
#endif
|
||||
#if CORE_IS_XZ || CORE_IS_YZ
|
||||
#if ANY(HAS_REAL_Z, DELTA)
|
||||
#define STEPPER_C_NAME 'C'
|
||||
#else
|
||||
#define STEPPER_C_NAME 'Z'
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ typedef struct {
|
|||
//
|
||||
// - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
|
||||
// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
|
||||
// - X_HEAD, Y_HEAD, and Z_HEAD should be used for axes on Core kinematics
|
||||
// - X_REAL, Y_REAL, and Z_REAL should be used for axes on Core kinematics
|
||||
//
|
||||
enum AxisEnum : uint8_t {
|
||||
|
||||
|
|
@ -364,8 +364,14 @@ enum AxisEnum : uint8_t {
|
|||
#undef _EN_ITEM
|
||||
|
||||
// Core also keeps toolhead directions
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
X_HEAD, Y_HEAD, Z_HEAD,
|
||||
#if HAS_REAL_X
|
||||
X_REAL,
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
Y_REAL,
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
Z_REAL,
|
||||
#endif
|
||||
|
||||
// Distinct axes, including all E and Core
|
||||
|
|
@ -374,6 +380,10 @@ enum AxisEnum : uint8_t {
|
|||
// Most of the time we refer only to the single E_AXIS
|
||||
#if HAS_EXTRUDERS
|
||||
E_AXIS = E0_AXIS,
|
||||
E_REAL = E_AXIS,
|
||||
#define _EN_REAL(N) E##N##_REAL = E##N##_AXIS,
|
||||
REPEAT(EXTRUDERS, _EN_REAL)
|
||||
#undef _EN_REAL
|
||||
#endif
|
||||
|
||||
// A, B, and C are for DELTA, SCARA, etc.
|
||||
|
|
@ -387,6 +397,35 @@ enum AxisEnum : uint8_t {
|
|||
C_AXIS = Z_AXIS,
|
||||
#endif
|
||||
|
||||
// Aliases to distinguish tool axes from stepper indexes
|
||||
#if HAS_X_AXIS && !HAS_REAL_X
|
||||
X_REAL = X_AXIS,
|
||||
#endif
|
||||
#if HAS_Y_AXIS && !HAS_REAL_Y
|
||||
Y_REAL = Y_AXIS,
|
||||
#endif
|
||||
#if HAS_Z_AXIS && !HAS_REAL_Z
|
||||
Z_REAL = Z_AXIS,
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
I_REAL = I_AXIS,
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
J_REAL = J_AXIS,
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
K_REAL = K_AXIS,
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
U_REAL = U_AXIS,
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
V_REAL = V_AXIS,
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
W_REAL = W_AXIS,
|
||||
#endif
|
||||
|
||||
// To refer to all or none
|
||||
ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
|
||||
};
|
||||
|
|
@ -1153,8 +1192,14 @@ public:
|
|||
#define _EN_ITEM(N) bool e##N:1;
|
||||
REPEAT(EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool rx:1, ry:1, rz:1;
|
||||
#if HAS_REAL_X
|
||||
bool rx:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool ry:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool rz:1;
|
||||
#endif
|
||||
};
|
||||
// Axes X, Y, Z ... E0, E1, E2 ... RX, RY, RZ
|
||||
|
|
@ -1165,8 +1210,14 @@ public:
|
|||
#define _EN_ITEM(N) bool E##N:1;
|
||||
REPEAT(EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool RX:1, RY:1, RZ:1;
|
||||
#if HAS_REAL_X
|
||||
bool RX:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool RY:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool RZ:1;
|
||||
#endif
|
||||
};
|
||||
// a, b, c, e ... ra, rb, rc
|
||||
|
|
@ -1177,8 +1228,14 @@ public:
|
|||
REPEAT_S(1,EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#endif
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool ra:1, rb:1, rc:1;
|
||||
#if HAS_REAL_X
|
||||
bool ra:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool rb:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool rc:1;
|
||||
#endif
|
||||
};
|
||||
// A, B, C, E ... RA, RB, RC
|
||||
|
|
@ -1189,8 +1246,14 @@ public:
|
|||
REPEAT_S(1,EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#endif
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool RA:1, RB:1, RC:1;
|
||||
#if HAS_REAL_X
|
||||
bool RA:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool RB:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool RC:1;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -584,6 +584,15 @@
|
|||
#if ANY(COREYZ, COREZY)
|
||||
#define CORE_IS_YZ 1
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY)
|
||||
#define HAS_REAL_X 1
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_YX)
|
||||
#define HAS_REAL_Y 1
|
||||
#endif
|
||||
#if CORE_IS_XZ || CORE_IS_YZ
|
||||
#define HAS_REAL_Z 1
|
||||
#endif
|
||||
#if CORE_IS_XY || CORE_IS_XZ || CORE_IS_YZ
|
||||
#define IS_CORE 1
|
||||
#if CORE_IS_XY
|
||||
|
|
|
|||
|
|
@ -1943,7 +1943,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i
|
|||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
#if EXTRUDERS < 2
|
||||
#error "DUAL_X_CARRIAGE requires 2 (or more) extruders."
|
||||
#elif ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
#elif HAS_REAL_X
|
||||
#error "DUAL_X_CARRIAGE cannot be used with COREXY, COREYX, COREXZ, COREZX, MARKFORGED_YX, or MARKFORGED_XY."
|
||||
#elif !GOOD_AXIS_PINS(X2)
|
||||
#error "DUAL_X_CARRIAGE requires X2 stepper pins to be defined."
|
||||
|
|
|
|||
|
|
@ -462,30 +462,6 @@ void Endstops::update() {
|
|||
#define X_MIN_TEST() TERN1(DUAL_X_CARRIAGE, stepper.last_moved_extruder == 0) // Check min for the left carriage
|
||||
#define X_MAX_TEST() TERN1(DUAL_X_CARRIAGE, stepper.last_moved_extruder != 0) // Check max for the right carriage
|
||||
|
||||
// Use HEAD for core axes, AXIS for others
|
||||
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
#define X_AXIS_HEAD X_HEAD
|
||||
#else
|
||||
#define X_AXIS_HEAD X_AXIS
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
#define Y_AXIS_HEAD Y_HEAD
|
||||
#else
|
||||
#define Y_AXIS_HEAD Y_AXIS
|
||||
#endif
|
||||
#if CORE_IS_XZ || CORE_IS_YZ
|
||||
#define Z_AXIS_HEAD Z_HEAD
|
||||
#else
|
||||
#define Z_AXIS_HEAD Z_AXIS
|
||||
#endif
|
||||
|
||||
#define I_AXIS_HEAD I_AXIS
|
||||
#define J_AXIS_HEAD J_AXIS
|
||||
#define K_AXIS_HEAD K_AXIS
|
||||
#define U_AXIS_HEAD U_AXIS
|
||||
#define V_AXIS_HEAD V_AXIS
|
||||
#define W_AXIS_HEAD W_AXIS
|
||||
|
||||
/**
|
||||
* Check and update endstops
|
||||
*/
|
||||
|
|
@ -680,8 +656,8 @@ void Endstops::update() {
|
|||
#define PROCESS_ENDSTOP_Z(MINMAX) PROCESS_DUAL_ENDSTOP(Z, MINMAX)
|
||||
#endif
|
||||
|
||||
#define AXIS_IS_MOVING(A) TERN(FT_MOTION, ftMotion, stepper).axis_is_moving(_AXIS(A))
|
||||
#define AXIS_DIR_REV(A) !TERN(FT_MOTION, ftMotion, stepper).motor_direction(A)
|
||||
#define AXIS_IS_MOVING(A) TERN(FT_MOTION, ftMotion, stepper).axis_is_moving(A##_REAL)
|
||||
#define AXIS_DIR_REV(A) !TERN(FT_MOTION, ftMotion, stepper).axis_direction(A##_REAL)
|
||||
|
||||
#if ENABLED(G38_PROBE_TARGET)
|
||||
// For G38 moves check the probe's pin for ALL movement
|
||||
|
|
@ -704,8 +680,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_X_AXIS
|
||||
if (AXIS_IS_MOVING(X)) {
|
||||
const AxisEnum x_head = TERN0(FT_MOTION, ftMotion.cfg.active) ? X_AXIS : X_AXIS_HEAD;
|
||||
if (AXIS_DIR_REV(x_head)) {
|
||||
if (AXIS_DIR_REV(X)) {
|
||||
#if HAS_X_MIN_STATE
|
||||
PROCESS_ENDSTOP_X(MIN);
|
||||
#if CORE_DIAG(XY, Y, MIN)
|
||||
|
|
@ -738,8 +713,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_Y_AXIS
|
||||
if (AXIS_IS_MOVING(Y)) {
|
||||
const AxisEnum y_head = TERN0(FT_MOTION, ftMotion.cfg.active) ? Y_AXIS : Y_AXIS_HEAD;
|
||||
if (AXIS_DIR_REV(y_head)) {
|
||||
if (AXIS_DIR_REV(Y)) {
|
||||
#if HAS_Y_MIN_STATE
|
||||
PROCESS_ENDSTOP_Y(MIN);
|
||||
#if CORE_DIAG(XY, X, MIN)
|
||||
|
|
@ -772,8 +746,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_Z_AXIS
|
||||
if (AXIS_IS_MOVING(Z)) {
|
||||
const AxisEnum z_head = TERN0(FT_MOTION, ftMotion.cfg.active) ? Z_AXIS : Z_AXIS_HEAD;
|
||||
if (AXIS_DIR_REV(z_head)) {
|
||||
if (AXIS_DIR_REV(Z)) {
|
||||
// Z- : Gantry down, bed up
|
||||
#if HAS_Z_MIN_STATE
|
||||
// If the Z_MIN_PIN is being used for the probe there's no
|
||||
|
|
@ -820,7 +793,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_I_AXIS && HAS_I_STATE
|
||||
if (AXIS_IS_MOVING(I)) {
|
||||
if (AXIS_DIR_REV(I_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(I)) {
|
||||
#if HAS_I_MIN_STATE
|
||||
PROCESS_ENDSTOP(I, MIN);
|
||||
#endif
|
||||
|
|
@ -835,7 +808,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_J_AXIS && HAS_J_STATE
|
||||
if (AXIS_IS_MOVING(J)) {
|
||||
if (AXIS_DIR_REV(J_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(J)) {
|
||||
#if HAS_J_MIN_STATE
|
||||
PROCESS_ENDSTOP(J, MIN);
|
||||
#endif
|
||||
|
|
@ -850,7 +823,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_K_AXIS && HAS_K_STATE
|
||||
if (AXIS_IS_MOVING(K)) {
|
||||
if (AXIS_DIR_REV(K_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(K)) {
|
||||
#if HAS_K_MIN_STATE
|
||||
PROCESS_ENDSTOP(K, MIN);
|
||||
#endif
|
||||
|
|
@ -865,7 +838,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_U_AXIS && HAS_U_STATE
|
||||
if (AXIS_IS_MOVING(U)) {
|
||||
if (AXIS_DIR_REV(U_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(U)) {
|
||||
#if HAS_U_MIN_STATE
|
||||
PROCESS_ENDSTOP(U, MIN);
|
||||
#endif
|
||||
|
|
@ -880,7 +853,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_V_AXIS && HAS_V_STATE
|
||||
if (AXIS_IS_MOVING(V)) {
|
||||
if (AXIS_DIR_REV(V_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(V)) {
|
||||
#if HAS_V_MIN_STATE
|
||||
PROCESS_ENDSTOP(V, MIN);
|
||||
#endif
|
||||
|
|
@ -895,7 +868,7 @@ void Endstops::update() {
|
|||
|
||||
#if HAS_W_AXIS && HAS_W_STATE
|
||||
if (AXIS_IS_MOVING(W)) {
|
||||
if (AXIS_DIR_REV(W_AXIS_HEAD)) {
|
||||
if (AXIS_DIR_REV(W)) {
|
||||
#if HAS_W_MIN_STATE
|
||||
PROCESS_ENDSTOP(W, MIN);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -390,15 +390,9 @@ bool FTMotion::plan_next_block() {
|
|||
#endif
|
||||
|
||||
// Some kinematics track axis motion in RX, RY, RZ
|
||||
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
stepper.last_direction_bits.rx = current_block->direction_bits.rx;
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
stepper.last_direction_bits.ry = current_block->direction_bits.ry;
|
||||
#endif
|
||||
#if ANY(CORE_IS_XZ, CORE_IS_YZ)
|
||||
stepper.last_direction_bits.rz = current_block->direction_bits.rz;
|
||||
#endif
|
||||
TERN_(HAS_REAL_X, stepper.last_direction_bits.rx = current_block->direction_bits.rx);
|
||||
TERN_(HAS_REAL_Y, stepper.last_direction_bits.ry = current_block->direction_bits.ry);
|
||||
TERN_(HAS_REAL_Z, stepper.last_direction_bits.rz = current_block->direction_bits.rz);
|
||||
|
||||
// Cache the extruder index / axis for this block
|
||||
#if ANY(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER)
|
||||
|
|
@ -411,7 +405,7 @@ bool FTMotion::plan_next_block() {
|
|||
const float totalLength = current_block->millimeters;
|
||||
|
||||
startPos = endPos_prevBlock;
|
||||
const xyze_pos_t &moveDist = current_block->distance_mm;
|
||||
const ext_distance_t &moveDist = current_block->ext_distance_mm;
|
||||
ratio = moveDist / totalLength;
|
||||
|
||||
// Plan the trajectory using the trajectory generator
|
||||
|
|
@ -422,9 +416,15 @@ bool FTMotion::plan_next_block() {
|
|||
TERN_(FTM_HAS_LIN_ADVANCE, use_advance_lead = current_block->use_advance_lead);
|
||||
|
||||
axis_move_dir = current_block->direction_bits;
|
||||
#define _SET_MOVE_END(A) moving_axis_flags.A = bool(moveDist.A);
|
||||
|
||||
// Set moving flags for axes that have movement in this block
|
||||
// For CORE kinematics: moveDist.x/.y/.z contain motor distances (a/b/c)
|
||||
// HEAD movement flags need to be inferred: if either motor moves, the head moves
|
||||
#define _SET_MOVE_END(A) moving_axis_flags.A = bool(moveDist.A);
|
||||
LOGICAL_AXIS_MAP(_SET_MOVE_END);
|
||||
TERN_(HAS_REAL_X, moving_axis_flags.rx = bool(moveDist.real.x));
|
||||
TERN_(HAS_REAL_Y, moving_axis_flags.ry = bool(moveDist.real.y));
|
||||
TERN_(HAS_REAL_Z, moving_axis_flags.rz = bool(moveDist.real.z));
|
||||
|
||||
// If the endstop is already pressed, endstop interrupts won't invoke
|
||||
// endstop_triggered and the move will grind. So check here for a
|
||||
|
|
|
|||
|
|
@ -300,11 +300,11 @@ class FTMotion {
|
|||
static TrajectoryType getTrajectoryType() { return TERN(FTM_POLYS, trajectoryType, TrajectoryType::TRAPEZOIDAL); }
|
||||
static FSTR_P getTrajectoryName();
|
||||
|
||||
FORCE_INLINE static bool axis_is_moving(const AxisEnum axis) {
|
||||
return cfg.active ? moving_axis_flags[axis] : TERN0(HAS_STANDARD_MOTION, stepper.axis_is_moving(axis));
|
||||
FORCE_INLINE static bool axis_is_moving(const AxisEnum real) {
|
||||
return cfg.active ? moving_axis_flags[real] : TERN0(HAS_STANDARD_MOTION, stepper.axis_is_moving(real));
|
||||
}
|
||||
FORCE_INLINE static bool motor_direction(const AxisEnum axis) {
|
||||
return cfg.active ? axis_move_dir[axis] : stepper.last_direction_bits[axis];
|
||||
FORCE_INLINE static bool axis_direction(const AxisEnum real) {
|
||||
return cfg.active ? axis_move_dir[real] : stepper.last_direction_bits[real];
|
||||
}
|
||||
|
||||
// A frame of the stepping plan
|
||||
|
|
|
|||
|
|
@ -33,10 +33,16 @@ void AxisShaping::set_axis_shaping_A(
|
|||
OPTARG(HAS_FTM_EI_SHAPING, const float vtol)
|
||||
) {
|
||||
|
||||
const float K = exp(-zeta * M_PI / sqrt(1.f - sq(zeta))),
|
||||
K2 = sq(K),
|
||||
K3 = K2 * K,
|
||||
K4 = K3 * K;
|
||||
const float K = exp(-zeta * M_PI / sqrt(1.f - sq(zeta)));
|
||||
#if ANY(FTM_SHAPER_ZVD, FTM_SHAPER_ZVDD, FTM_SHAPER_ZVDDD, FTM_SHAPER_EI, FTM_SHAPER_2HEI, FTM_SHAPER_3HEI, FTM_SHAPER_MZV)
|
||||
const float K2 = sq(K);
|
||||
#endif
|
||||
#if ANY(FTM_SHAPER_ZVDD, FTM_SHAPER_ZVDDD, FTM_SHAPER_2HEI, FTM_SHAPER_3HEI)
|
||||
const float K3 = K2 * K;
|
||||
#endif
|
||||
#if ANY(FTM_SHAPER_ZVDDD, FTM_SHAPER_3HEI)
|
||||
const float K4 = K3 * K;
|
||||
#endif
|
||||
|
||||
switch (shaper) {
|
||||
|
||||
|
|
|
|||
|
|
@ -1854,42 +1854,36 @@ bool Planner::_populate_block(
|
|||
#endif // PREVENT_COLD_EXTRUSION || PREVENT_LENGTHY_EXTRUDE
|
||||
|
||||
// Compute direction bit-mask for this block
|
||||
// In this context Core kinematics "real" bits pertain to Cartesian
|
||||
// directions and others pertain directly to stepper directions.
|
||||
AxisBits dm;
|
||||
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
dm.rx = (steps_dist.a > 0); // True direction in X
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_XY, MARKFORGED_YX)
|
||||
dm.ry = (steps_dist.b > 0); // True direction in Y
|
||||
#endif
|
||||
#if ANY(CORE_IS_XZ, CORE_IS_YZ)
|
||||
dm.rz = (steps_dist.c > 0); // True direction in Z
|
||||
#endif
|
||||
TERN_(HAS_REAL_X, dm.rx = (steps_dist.x > 0)); // True direction in X
|
||||
TERN_(HAS_REAL_Y, dm.ry = (steps_dist.y > 0)); // True direction in Y
|
||||
TERN_(HAS_REAL_Z, dm.rz = (steps_dist.z > 0)); // True direction in Z
|
||||
#if CORE_IS_XY
|
||||
dm.a = (steps_dist.a + steps_dist.b > 0); // Motor A direction
|
||||
dm.b = (CORESIGN(steps_dist.a - steps_dist.b) > 0); // Motor B direction
|
||||
TERN_(HAS_Z_AXIS, dm.z = (steps_dist.c > 0)); // Axis Z direction
|
||||
#elif CORE_IS_XZ
|
||||
dm.a = (steps_dist.a + steps_dist.c > 0); // Motor A direction
|
||||
dm.y = (steps_dist.b > 0); // Axis Y direction
|
||||
dm.c = (CORESIGN(steps_dist.a - steps_dist.c) > 0); // Motor C direction
|
||||
#elif CORE_IS_YZ
|
||||
dm.x = (steps_dist.a > 0); // Axis X direction
|
||||
dm.b = (steps_dist.b + steps_dist.c > 0); // Motor B direction
|
||||
dm.c = (CORESIGN(steps_dist.b - steps_dist.c) > 0); // Motor C direction
|
||||
#elif ENABLED(MARKFORGED_XY)
|
||||
dm.a = (steps_dist.a TERN(MARKFORGED_INVERSE, -, +) steps_dist.b > 0); // Motor A direction
|
||||
dm.b = (steps_dist.b > 0); // Motor B direction
|
||||
TERN_(HAS_Z_AXIS, dm.z = (steps_dist.c > 0)); // Axis Z direction
|
||||
#elif ENABLED(MARKFORGED_YX)
|
||||
dm.a = (steps_dist.a > 0); // Motor A direction
|
||||
dm.b = (steps_dist.b TERN(MARKFORGED_INVERSE, -, +) steps_dist.a > 0); // Motor B direction
|
||||
TERN_(HAS_Z_AXIS, dm.z = (steps_dist.c > 0)); // Axis Z direction
|
||||
#else
|
||||
XYZ_CODE(
|
||||
dm.x = (steps_dist.a > 0),
|
||||
dm.y = (steps_dist.b > 0),
|
||||
dm.z = (steps_dist.c > 0)
|
||||
dm.a = (steps_dist.x + steps_dist.y) > 0, // Motor A direction
|
||||
dm.b = CORESIGN(steps_dist.x - steps_dist.y) > 0, // Motor B direction
|
||||
dm.z = (steps_dist.z > 0) // Axis Z direction
|
||||
);
|
||||
#elif CORE_IS_XZ
|
||||
dm.a = (steps_dist.x + steps_dist.z) > 0; // Motor A direction
|
||||
dm.y = (steps_dist.y > 0); // Axis Y direction
|
||||
dm.c = (CORESIGN(steps_dist.x - steps_dist.z) > 0); // Motor C direction
|
||||
#elif CORE_IS_YZ
|
||||
dm.x = (steps_dist.x > 0); // Axis X direction
|
||||
dm.b = (steps_dist.y + steps_dist.z > 0); // Motor B direction
|
||||
dm.c = (CORESIGN(steps_dist.y - steps_dist.z) > 0); // Motor C direction
|
||||
#elif ENABLED(MARKFORGED_XY)
|
||||
dm.a = (steps_dist.x TERN(MARKFORGED_INVERSE, -, +) steps_dist.y > 0); // Motor A direction
|
||||
dm.b = (steps_dist.y > 0); // Motor B direction
|
||||
TERN_(HAS_Z_AXIS, dm.z = (steps_dist.z > 0)); // Axis Z direction
|
||||
#elif ENABLED(MARKFORGED_YX)
|
||||
dm.a = (steps_dist.x > 0); // Motor A direction
|
||||
dm.b = (steps_dist.y TERN(MARKFORGED_INVERSE, -, +) steps_dist.x > 0); // Motor B direction
|
||||
TERN_(HAS_Z_AXIS, dm.z = (steps_dist.z > 0)); // Axis Z direction
|
||||
#else
|
||||
XYZ_CODE(dm.x = (steps_dist.x > 0), dm.y = (steps_dist.y > 0), dm.z = (steps_dist.z > 0));
|
||||
#endif
|
||||
|
||||
SECONDARY_AXIS_CODE(
|
||||
|
|
@ -1965,82 +1959,86 @@ bool Planner::_populate_block(
|
|||
/**
|
||||
* This part of the code calculates the total length of the movement.
|
||||
* For Cartesian bots, the distance in XY axes equals the X_AXIS/Y_AXIS joint displacement.
|
||||
* But for geometries like CORE_XY that is not true. For these machines we need to create 2 additional variables, named X_HEAD and Y_HEAD, to store the displacent of the head along the X and Y axes in a cartesian coordinate system.
|
||||
* The displacement of the head along the axes of the cartesian coordinate system has to be calculated from "X_AXIS" and "Y_AXIS" (should be renamed to A_JOINT and B_JOINT)
|
||||
* For Core/H-bot geometries we use X_REAL and Y_REAL to store the real XY displacement of the head in Cartesian coordinates.
|
||||
* The Cartesian head displacement is calculated from a combined ABC stepper positions.
|
||||
* For the joint displacements use forward kinematics (A=X+Y and B=X-Y in the case of CORE_XY).
|
||||
* Next we can calculate the total movement length and apply the desired speed.
|
||||
*/
|
||||
struct DistanceMM : abce_float_t {
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
struct { float x, y, z; } head;
|
||||
#endif
|
||||
} dist_mm;
|
||||
ext_distance_t dist_mm;
|
||||
|
||||
#if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX)
|
||||
dist_mm.head.x = steps_dist.a * mm_per_step[A_AXIS];
|
||||
dist_mm.head.y = steps_dist.b * mm_per_step[B_AXIS];
|
||||
TERN_(HAS_Z_AXIS, dist_mm.z = steps_dist.c * mm_per_step[Z_AXIS]);
|
||||
#if HAS_X_AXIS
|
||||
const float dx = steps_dist.x * mm_per_step[X_AXIS]; // Axis X or Tower A Steps
|
||||
#endif
|
||||
#if HAS_Y_AXIS
|
||||
const float dy = steps_dist.y * mm_per_step[Y_AXIS]; // Axis Y or Tower B Steps
|
||||
#endif
|
||||
#if HAS_Z_AXIS
|
||||
const float dz = steps_dist.z * mm_per_step[Z_AXIS]; // Axis Z or Tower C Steps
|
||||
#endif
|
||||
#if CORE_IS_XY
|
||||
dist_mm.a = (steps_dist.a + steps_dist.b) * mm_per_step[A_AXIS];
|
||||
dist_mm.b = CORESIGN(steps_dist.a - steps_dist.b) * mm_per_step[B_AXIS];
|
||||
#elif CORE_IS_XZ
|
||||
dist_mm.head.x = steps_dist.a * mm_per_step[A_AXIS];
|
||||
dist_mm.y = steps_dist.b * mm_per_step[Y_AXIS];
|
||||
dist_mm.head.z = steps_dist.c * mm_per_step[C_AXIS];
|
||||
dist_mm.a = (steps_dist.a + steps_dist.c) * mm_per_step[A_AXIS];
|
||||
dist_mm.c = CORESIGN(steps_dist.a - steps_dist.c) * mm_per_step[C_AXIS];
|
||||
#elif CORE_IS_YZ
|
||||
dist_mm.x = steps_dist.a * mm_per_step[X_AXIS];
|
||||
dist_mm.head.y = steps_dist.b * mm_per_step[B_AXIS];
|
||||
dist_mm.head.z = steps_dist.c * mm_per_step[C_AXIS];
|
||||
dist_mm.b = (steps_dist.b + steps_dist.c) * mm_per_step[B_AXIS];
|
||||
dist_mm.c = CORESIGN(steps_dist.b - steps_dist.c) * mm_per_step[C_AXIS];
|
||||
#elif ENABLED(MARKFORGED_XY)
|
||||
dist_mm.a = (steps_dist.a TERN(MARKFORGED_INVERSE, +, -) steps_dist.b) * mm_per_step[A_AXIS];
|
||||
dist_mm.b = steps_dist.b * mm_per_step[B_AXIS];
|
||||
#elif ENABLED(MARKFORGED_YX)
|
||||
dist_mm.a = steps_dist.a * mm_per_step[A_AXIS];
|
||||
dist_mm.b = (steps_dist.b TERN(MARKFORGED_INVERSE, +, -) steps_dist.a) * mm_per_step[B_AXIS];
|
||||
#else
|
||||
XYZ_CODE(
|
||||
dist_mm.a = steps_dist.a * mm_per_step[A_AXIS],
|
||||
dist_mm.b = steps_dist.b * mm_per_step[B_AXIS],
|
||||
dist_mm.c = steps_dist.c * mm_per_step[C_AXIS]
|
||||
dist_mm.a = dx + dy,
|
||||
dist_mm.b = CORESIGN(dx - dy),
|
||||
dist_mm.z = dz
|
||||
);
|
||||
#elif CORE_IS_XZ
|
||||
dist_mm.a = dx + dz,
|
||||
dist_mm.y = dy,
|
||||
dist_mm.c = CORESIGN(dx - dz)
|
||||
#elif CORE_IS_YZ
|
||||
dist_mm.x = dx;
|
||||
dist_mm.b = dy + dz;
|
||||
dist_mm.c = CORESIGN(dy - dz);
|
||||
#elif ENABLED(MARKFORGED_XY)
|
||||
XYZ_CODE(
|
||||
dist_mm.a = dx TERN(MARKFORGED_INVERSE, +, -) dy,
|
||||
dist_mm.b = dy,
|
||||
dist_mm.z = dz
|
||||
);
|
||||
#elif ENABLED(MARKFORGED_YX)
|
||||
XYZ_CODE(
|
||||
dist_mm.a = dx,
|
||||
dist_mm.b = dy TERN(MARKFORGED_INVERSE, +, -) dx,
|
||||
dist_mm.z = dz
|
||||
);
|
||||
#else
|
||||
// Cartesian, Delta, SCARA, etc.
|
||||
XYZ_CODE(dist_mm.a = dx, dist_mm.b = dy, dist_mm.c = dz);
|
||||
#endif
|
||||
|
||||
SECONDARY_AXIS_CODE(
|
||||
dist_mm.i = steps_dist.i * mm_per_step[I_AXIS], dist_mm.j = steps_dist.j * mm_per_step[J_AXIS], dist_mm.k = steps_dist.k * mm_per_step[K_AXIS],
|
||||
dist_mm.u = steps_dist.u * mm_per_step[U_AXIS], dist_mm.v = steps_dist.v * mm_per_step[V_AXIS], dist_mm.w = steps_dist.w * mm_per_step[W_AXIS]
|
||||
dist_mm.i = steps_dist.i * mm_per_step[I_AXIS], dist_mm.j = steps_dist.j * mm_per_step[J_AXIS],
|
||||
dist_mm.k = steps_dist.k * mm_per_step[K_AXIS], dist_mm.u = steps_dist.u * mm_per_step[U_AXIS],
|
||||
dist_mm.v = steps_dist.v * mm_per_step[V_AXIS], dist_mm.w = steps_dist.w * mm_per_step[W_AXIS]
|
||||
);
|
||||
|
||||
TERN_(HAS_EXTRUDERS, dist_mm.e = esteps_float * mm_per_step[E_AXIS_N(extruder)]);
|
||||
TERN_(HAS_REAL_X, dist_mm.real.x = dx);
|
||||
TERN_(HAS_REAL_Y, dist_mm.real.y = dy);
|
||||
TERN_(HAS_REAL_Z, dist_mm.real.z = dz);
|
||||
|
||||
TERN_(HAS_EXTRUDERS, dist_mm.e = esteps_float * mm_per_step[E_AXIS_N(extruder)]);
|
||||
TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator += dist_mm.e);
|
||||
|
||||
TERN_(FT_MOTION, block->ext_distance_mm = dist_mm); // Store the distance for all axes in mm for this block
|
||||
|
||||
#if HAS_ROTATIONAL_AXES
|
||||
bool cartesian_move = hints.cartesian_move;
|
||||
#endif
|
||||
|
||||
// Determine linear distance for block->millimeters
|
||||
|
||||
if (!XYZ_HAS_ENOUGH_STEPS(block)) {
|
||||
block->millimeters = TERN0(HAS_EXTRUDERS, ABS(dist_mm.e));
|
||||
}
|
||||
else {
|
||||
if (hints.millimeters)
|
||||
// Use a provided move length (e.g., always provided by Kinematic robots)
|
||||
if (/* ANY(DELTA, IS_SCARA, TPARA) || */ hints.millimeters)
|
||||
block->millimeters = hints.millimeters;
|
||||
else {
|
||||
// Calculate move length from axis positions
|
||||
const xyze_pos_t displacement = LOGICAL_AXIS_ARRAY(
|
||||
dist_mm.e,
|
||||
#if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX)
|
||||
dist_mm.head.x, dist_mm.head.y, dist_mm.z,
|
||||
#elif CORE_IS_XZ
|
||||
dist_mm.head.x, dist_mm.y, dist_mm.head.z,
|
||||
#elif CORE_IS_YZ
|
||||
dist_mm.x, dist_mm.head.y, dist_mm.head.z,
|
||||
#else
|
||||
dist_mm.x, dist_mm.y, dist_mm.z,
|
||||
#endif
|
||||
dx, dy, dz,
|
||||
dist_mm.i, dist_mm.j, dist_mm.k,
|
||||
dist_mm.u, dist_mm.v, dist_mm.w
|
||||
);
|
||||
|
|
@ -2051,19 +2049,19 @@ bool Planner::_populate_block(
|
|||
/**
|
||||
* At this point at least one of the axes has more steps than
|
||||
* MIN_STEPS_PER_SEGMENT, ensuring the segment won't get dropped as
|
||||
* zero-length. It's important to not apply corrections
|
||||
* to blocks that would get dropped!
|
||||
* zero-length. It's important to not apply corrections to blocks
|
||||
* that would get dropped!
|
||||
*
|
||||
* A correction function is permitted to add steps to an axis, it
|
||||
* should *never* remove steps!
|
||||
* A correction function is permitted to add steps to an axis, but
|
||||
* it should *never* remove steps!
|
||||
*/
|
||||
TERN_(BACKLASH_COMPENSATION, backlash.add_correction_steps(steps_dist, dm, block));
|
||||
}
|
||||
|
||||
TERN_(FT_MOTION, block->distance_mm = dist_mm); // Store the distance for all axes in mm for this block
|
||||
|
||||
TERN_(HAS_EXTRUDERS, block->steps.e = esteps);
|
||||
|
||||
// Set the block's Step Event Count based from the axis with the most steps
|
||||
|
||||
block->step_event_count = (
|
||||
#if NUM_AXES
|
||||
_MAX(LOGICAL_AXIS_LIST(esteps,
|
||||
|
|
@ -2076,9 +2074,11 @@ bool Planner::_populate_block(
|
|||
#endif
|
||||
);
|
||||
|
||||
// Bail if this is a zero-length block
|
||||
// Bail if this is a "zero-length" block
|
||||
if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false;
|
||||
|
||||
E_TERN_(block->extruder = extruder);
|
||||
|
||||
TERN_(MIXING_EXTRUDER, mixer.populate_block(block->b_color));
|
||||
|
||||
#if HAS_FAN
|
||||
|
|
@ -2090,8 +2090,6 @@ bool Planner::_populate_block(
|
|||
block->e_to_p_pressure = baricuda_e_to_p_pressure;
|
||||
#endif
|
||||
|
||||
E_TERN_(block->extruder = extruder);
|
||||
|
||||
#if ENABLED(AUTO_POWER_CONTROL)
|
||||
if (XYZ_HAS_STEPS(block)) powerManager.power_on();
|
||||
#endif
|
||||
|
|
@ -2983,6 +2981,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s
|
|||
// Cartesian XYZ to kinematic ABC, stored in global 'delta'
|
||||
inverse_kinematics(machine);
|
||||
|
||||
// Provide known Cartesian length in the hints structure
|
||||
PlannerHints ph = hints;
|
||||
if (!hints.millimeters)
|
||||
ph.millimeters = get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, ph.cartesian_move));
|
||||
|
|
|
|||
|
|
@ -190,6 +190,52 @@ typedef struct {
|
|||
|
||||
#endif
|
||||
|
||||
typedef struct DistanceMM : abce_float_t {
|
||||
#if ANY(HAS_REAL_X, HAS_REAL_Y, HAS_REAL_Z)
|
||||
struct {
|
||||
#if HAS_REAL_X
|
||||
float x;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
float y;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
float z;
|
||||
#endif
|
||||
} real;
|
||||
#endif
|
||||
const float& operator[](const int n) const {
|
||||
switch (n) {
|
||||
#if HAS_REAL_X
|
||||
case X_REAL: return real.x;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
case Y_REAL: return real.y;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
case Z_REAL: return real.z;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
return pos[n];
|
||||
}
|
||||
float& operator[](const int n) {
|
||||
switch (n) {
|
||||
#if HAS_REAL_X
|
||||
case X_REAL: return real.x;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
case Y_REAL: return real.y;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
case Z_REAL: return real.z;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
return pos[n];
|
||||
}
|
||||
} ext_distance_t;
|
||||
|
||||
/**
|
||||
* struct block_t
|
||||
*
|
||||
|
|
@ -262,7 +308,7 @@ typedef struct PlannerBlock {
|
|||
AxisBits direction_bits; // Direction bits set for this block, where 1 is negative motion
|
||||
|
||||
#if ENABLED(FT_MOTION)
|
||||
xyze_pos_t distance_mm; // The distance traveled in mm along each axis
|
||||
ext_distance_t ext_distance_mm; // The distance traveled in mm along each axis
|
||||
#endif
|
||||
|
||||
#if ANY(SMOOTH_LIN_ADVANCE, FTM_HAS_LIN_ADVANCE)
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ void Stepper::disable_all_steppers() {
|
|||
// Set a single axis direction based on the last set flags.
|
||||
// A direction bit of "1" indicates forward or positive motion.
|
||||
#define SET_STEP_DIR(A) do{ \
|
||||
const bool fwd = motor_direction(_AXIS(A)); \
|
||||
const bool fwd = axis_direction(_AXIS(A)); \
|
||||
A##_APPLY_DIR(fwd, false); \
|
||||
count_direction[_AXIS(A)] = fwd ? 1 : -1; \
|
||||
}while(0)
|
||||
|
|
@ -2389,19 +2389,12 @@ void Stepper::isr() {
|
|||
#endif
|
||||
|
||||
// Set flags for all axes that move in this block
|
||||
// These are set per-axis, not per-stepper
|
||||
AxisBits didmove;
|
||||
NUM_AXIS_CODE(
|
||||
if (X_MOVE_TEST) didmove.a = true, // Cartesian X or Kinematic A
|
||||
if (Y_MOVE_TEST) didmove.b = true, // Cartesian Y or Kinematic B
|
||||
if (Z_MOVE_TEST) didmove.c = true, // Cartesian Z or Kinematic C
|
||||
if (!!current_block->steps.i) didmove.i = true,
|
||||
if (!!current_block->steps.j) didmove.j = true,
|
||||
if (!!current_block->steps.k) didmove.k = true,
|
||||
if (!!current_block->steps.u) didmove.u = true,
|
||||
if (!!current_block->steps.v) didmove.v = true,
|
||||
if (!!current_block->steps.w) didmove.w = true
|
||||
);
|
||||
#define _DID_MOVE(A) didmove.A = bool(current_block->steps.A);
|
||||
MAIN_AXIS_MAP(_DID_MOVE);
|
||||
TERN_(HAS_REAL_X, didmove.rx = X_MOVE_TEST); // Cartesian X
|
||||
TERN_(HAS_REAL_Y, didmove.ry = Y_MOVE_TEST); // ... Y
|
||||
TERN_(HAS_REAL_Z, didmove.rz = Z_MOVE_TEST); // ... Z
|
||||
axis_did_move = didmove;
|
||||
}
|
||||
|
||||
|
|
@ -2563,7 +2556,7 @@ void Stepper::isr() {
|
|||
const bool forward_e = la_step_rate < step_rate;
|
||||
la_interval = calc_timer_interval((forward_e ? step_rate - la_step_rate : la_step_rate - step_rate) >> current_block->la_scaling);
|
||||
|
||||
if (forward_e != motor_direction(E_AXIS)) {
|
||||
if (forward_e != axis_direction(E_AXIS)) {
|
||||
last_direction_bits.toggle(E_AXIS);
|
||||
count_direction.e *= -1;
|
||||
|
||||
|
|
@ -3009,7 +3002,7 @@ void Stepper::isr() {
|
|||
#endif
|
||||
|
||||
la_interval = calc_timer_interval(uint32_t(ABS(step_rate)));
|
||||
if (forward_e != motor_direction(E_AXIS)) {
|
||||
if (forward_e != axis_direction(E_AXIS)) {
|
||||
last_direction_bits.toggle(E_AXIS);
|
||||
count_direction.e *= -1;
|
||||
DIR_WAIT_BEFORE();
|
||||
|
|
@ -3595,13 +3588,13 @@ int32_t Stepper::triggered_position(const AxisEnum axis) {
|
|||
* Reporting
|
||||
*/
|
||||
|
||||
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY, MARKFORGED_YX, IS_SCARA, DELTA)
|
||||
#if ANY(HAS_REAL_X, IS_SCARA, DELTA)
|
||||
#define SAYS_A 1
|
||||
#endif
|
||||
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_XY, MARKFORGED_YX, IS_SCARA, DELTA, POLAR)
|
||||
#if ANY(HAS_REAL_Y, IS_SCARA, DELTA, POLAR)
|
||||
#define SAYS_B 1
|
||||
#endif
|
||||
#if ANY(CORE_IS_XZ, CORE_IS_YZ, DELTA)
|
||||
#if ANY(HAS_REAL_Z, DELTA)
|
||||
#define SAYS_C 1
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -657,18 +657,18 @@ class Stepper {
|
|||
// Quickly stop all steppers
|
||||
FORCE_INLINE static void quick_stop() { abort_current_block = true; }
|
||||
|
||||
// The direction of a single motor. A true result indicates forward or positive motion.
|
||||
FORCE_INLINE static bool motor_direction(const AxisEnum axis) { return last_direction_bits[axis]; }
|
||||
// The direction of a single motor and/or real axis. A true result indicates forward or positive motion.
|
||||
FORCE_INLINE static bool axis_direction(const AxisEnum real) { return last_direction_bits[real]; }
|
||||
|
||||
#if HAS_STANDARD_MOTION
|
||||
// The last movement direction was not null on the specified axis. Note that motor direction is not necessarily the same.
|
||||
FORCE_INLINE static bool axis_is_moving(const AxisEnum axis) { return axis_did_move[axis]; }
|
||||
// The last segment moved on the specified motor and/or real axis.
|
||||
FORCE_INLINE static bool axis_is_moving(const AxisEnum real) { return axis_did_move[real]; }
|
||||
#endif
|
||||
|
||||
// Handle a triggered endstop
|
||||
static void endstop_triggered(const AxisEnum axis);
|
||||
|
||||
// Triggered position of an axis in steps
|
||||
// Triggered position of an axis in steps, converted as needed from Core kinematics
|
||||
static int32_t triggered_position(const AxisEnum axis);
|
||||
|
||||
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
|
||||
|
|
|
|||
|
|
@ -1938,7 +1938,8 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T
|
|||
#endif
|
||||
|
||||
temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_hotend_preheating(e))
|
||||
&& temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0;
|
||||
&& (temp_hotend[e].celsius < temp_range[e].maxtemp)
|
||||
? (int)get_pid_output_hotend(e) >> 1 : 0;
|
||||
|
||||
#if WATCH_HOTENDS
|
||||
// Make sure temperature is increasing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue