Support for up to 9 axes (#23112, #24036, #24231)

This commit is contained in:
Scott Lahteine
2022-04-29 15:21:15 -05:00
parent 369542db3b
commit fd13a928c1
103 changed files with 4553 additions and 799 deletions

View File

@ -453,6 +453,42 @@ G29_TYPE GcodeSuite::G29() {
#endif
}
// Position bed horizontally and Z probe vertically.
#if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \
|| defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \
|| defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W)
xyze_pos_t safe_position = current_position;
#ifdef SAFE_BED_LEVELING_START_X
safe_position.x = SAFE_BED_LEVELING_START_X;
#endif
#ifdef SAFE_BED_LEVELING_START_Y
safe_position.y = SAFE_BED_LEVELING_START_Y;
#endif
#ifdef SAFE_BED_LEVELING_START_Z
safe_position.z = SAFE_BED_LEVELING_START_Z;
#endif
#ifdef SAFE_BED_LEVELING_START_I
safe_position.i = SAFE_BED_LEVELING_START_I;
#endif
#ifdef SAFE_BED_LEVELING_START_J
safe_position.j = SAFE_BED_LEVELING_START_J;
#endif
#ifdef SAFE_BED_LEVELING_START_K
safe_position.k = SAFE_BED_LEVELING_START_K;
#endif
#ifdef SAFE_BED_LEVELING_START_U
safe_position.u = SAFE_BED_LEVELING_START_U;
#endif
#ifdef SAFE_BED_LEVELING_START_V
safe_position.v = SAFE_BED_LEVELING_START_V;
#endif
#ifdef SAFE_BED_LEVELING_START_W
safe_position.w = SAFE_BED_LEVELING_START_W;
#endif
do_blocking_move_to(safe_position);
#endif
// Disable auto bed leveling during G29.
// Be formal so G29 can be done successively without G28.
if (!no_action) set_bed_leveling_enabled(false);

View File

@ -106,6 +106,43 @@ void GcodeSuite::G29() {
queue.inject(parser.seen_test('N') ? F("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : F("G29S2"));
TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart());
TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart());
// Position bed horizontally and Z probe vertically.
#if defined(SAFE_BED_LEVELING_START_X) || defined(SAFE_BED_LEVELING_START_Y) || defined(SAFE_BED_LEVELING_START_Z) \
|| defined(SAFE_BED_LEVELING_START_I) || defined(SAFE_BED_LEVELING_START_J) || defined(SAFE_BED_LEVELING_START_K) \
|| defined(SAFE_BED_LEVELING_START_U) || defined(SAFE_BED_LEVELING_START_V) || defined(SAFE_BED_LEVELING_START_W)
xyze_pos_t safe_position = current_position;
#ifdef SAFE_BED_LEVELING_START_X
safe_position.x = SAFE_BED_LEVELING_START_X;
#endif
#ifdef SAFE_BED_LEVELING_START_Y
safe_position.y = SAFE_BED_LEVELING_START_Y;
#endif
#ifdef SAFE_BED_LEVELING_START_Z
safe_position.z = SAFE_BED_LEVELING_START_Z;
#endif
#ifdef SAFE_BED_LEVELING_START_I
safe_position.i = SAFE_BED_LEVELING_START_I;
#endif
#ifdef SAFE_BED_LEVELING_START_J
safe_position.j = SAFE_BED_LEVELING_START_J;
#endif
#ifdef SAFE_BED_LEVELING_START_K
safe_position.k = SAFE_BED_LEVELING_START_K;
#endif
#ifdef SAFE_BED_LEVELING_START_U
safe_position.u = SAFE_BED_LEVELING_START_U;
#endif
#ifdef SAFE_BED_LEVELING_START_V
safe_position.v = SAFE_BED_LEVELING_START_V;
#endif
#ifdef SAFE_BED_LEVELING_START_W
safe_position.w = SAFE_BED_LEVELING_START_W;
#endif
do_blocking_move_to(safe_position);
#endif
return;
}
state = MeshNext;

View File

@ -82,7 +82,7 @@
#if ENABLED(SENSORLESS_HOMING)
sensorless_t stealth_states {
LINEAR_AXIS_LIST(
NUM_AXIS_LIST(
TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)),
TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)),
false, false, false, false
@ -214,7 +214,7 @@ void GcodeSuite::G28() {
#if ENABLED(MARLIN_DEV_MODE)
if (parser.seen_test('S')) {
LOOP_LINEAR_AXES(a) set_axis_is_at_home((AxisEnum)a);
LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a);
sync_plan_position();
SERIAL_ECHOLNPGM("Simulated Homing");
report_current_position();
@ -258,7 +258,7 @@ void GcodeSuite::G28() {
reset_stepper_timeout();
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K)
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W)
#define HAS_HOMING_CURRENT 1
#endif
@ -286,21 +286,6 @@ void GcodeSuite::G28() {
stepperY2.rms_current(Y2_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(I)
const int16_t tmc_save_current_I = stepperI.getMilliamps();
stepperI.rms_current(I_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(J)
const int16_t tmc_save_current_J = stepperJ.getMilliamps();
stepperJ.rms_current(J_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(K)
const int16_t tmc_save_current_K = stepperK.getMilliamps();
stepperK.rms_current(K_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
const int16_t tmc_save_current_Z = stepperZ.getMilliamps();
stepperZ.rms_current(Z_CURRENT_HOME);
@ -321,6 +306,21 @@ void GcodeSuite::G28() {
stepperK.rms_current(K_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(U)
const int16_t tmc_save_current_U = stepperU.getMilliamps();
stepperU.rms_current(U_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(V)
const int16_t tmc_save_current_V = stepperV.getMilliamps();
stepperV.rms_current(V_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(W)
const int16_t tmc_save_current_W = stepperW.getMilliamps();
stepperW.rms_current(W_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
@ -367,23 +367,28 @@ void GcodeSuite::G28() {
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')),
LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing
NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K)
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K),
needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W)
),
LINEAR_AXIS_LIST( // Home each axis if needed or flagged
NUM_AXIS_LIST( // Home each axis if needed or flagged
homeX = needX || parser.seen_test('X'),
homeY = needY || parser.seen_test('Y'),
homeZZ = homeZ,
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME)
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME),
homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME),
homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME)
),
home_all = LINEAR_AXIS_GANG( // Home-all if all or none are flagged
home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged
homeX == homeX, && homeY == homeX, && homeZ == homeX,
&& homeI == homeX, && homeJ == homeX, && homeK == homeX
&& homeI == homeX, && homeJ == homeX, && homeK == homeX,
&& homeU == homeX, && homeV == homeX, && homeW == homeX
),
LINEAR_AXIS_LIST(
NUM_AXIS_LIST(
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ,
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK,
doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW
);
#if HAS_Z_AXIS
@ -397,7 +402,7 @@ void GcodeSuite::G28() {
const bool seenR = parser.seenval('R');
const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT;
if (z_homing_height && (seenR || LINEAR_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) {
if (z_homing_height && (seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW))) {
// Raise Z before homing any other axes and z is not already high enough (never lower z)
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height);
do_z_clearance(z_homing_height);
@ -437,32 +442,52 @@ void GcodeSuite::G28() {
#endif
}
#if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS)
// Home I (after X)
if (doI) homeaxis(I_AXIS);
#endif
// Home Y (after X)
if (DISABLED(HOME_Y_BEFORE_X) && doY)
homeaxis(Y_AXIS);
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
// Home Z last if homing towards the bed
#if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST)
if (doZ) {
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
stepper.set_all_z_lock(false);
stepper.set_separate_multi_axis(false);
#endif
#if ENABLED(Z_SAFE_HOMING)
if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS);
#else
homeaxis(Z_AXIS);
#endif
probe.move_z_after_homing();
}
#if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS)
// Home J (after Y)
if (doJ) homeaxis(J_AXIS);
#endif
TERN_(HAS_I_AXIS, if (doI) homeaxis(I_AXIS));
TERN_(HAS_J_AXIS, if (doJ) homeaxis(J_AXIS));
TERN_(HAS_K_AXIS, if (doK) homeaxis(K_AXIS));
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
#if ENABLED(FOAMCUTTER_XYUV)
// skip homing of unused Z axis for foamcutters
if (doZ) set_axis_is_at_home(Z_AXIS);
#else
// Home Z last if homing towards the bed
#if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST)
if (doZ) {
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
stepper.set_all_z_lock(false);
stepper.set_separate_multi_axis(false);
#endif
#if ENABLED(Z_SAFE_HOMING)
if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS);
#else
homeaxis(Z_AXIS);
#endif
probe.move_z_after_homing();
}
#endif
SECONDARY_AXIS_CODE(
if (doI) homeaxis(I_AXIS),
if (doJ) homeaxis(J_AXIS),
if (doK) homeaxis(K_AXIS),
if (doU) homeaxis(U_AXIS),
if (doV) homeaxis(V_AXIS),
if (doW) homeaxis(W_AXIS)
);
#endif
sync_plan_position();
@ -545,6 +570,15 @@ void GcodeSuite::G28() {
#if HAS_CURRENT_HOME(K)
stepperK.rms_current(tmc_save_current_K);
#endif
#if HAS_CURRENT_HOME(U)
stepperU.rms_current(tmc_save_current_U);
#endif
#if HAS_CURRENT_HOME(V)
stepperV.rms_current(tmc_save_current_V);
#endif
#if HAS_CURRENT_HOME(W)
stepperW.rms_current(tmc_save_current_W);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
@ -568,7 +602,7 @@ void GcodeSuite::G28() {
// If not, this will need a PROGMEM directive and an accessor.
#define _EN_ITEM(N) , E_AXIS
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS),
NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS),
X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS
REPEAT(E_STEPPERS, _EN_ITEM)
};

View File

@ -343,7 +343,7 @@ static float auto_tune_a(const float dcr) {
abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f };
delta_t.reset();
LOOP_LINEAR_AXES(axis) {
LOOP_NUM_AXES(axis) {
delta_t[axis] = diff;
calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t);
delta_t[axis] = 0;
@ -557,7 +557,7 @@ void GcodeSuite::G33() {
case 1:
test_precision = 0.0f; // forced end
LOOP_LINEAR_AXES(axis) e_delta[axis] = +Z4(CEN);
LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN);
break;
case 2:
@ -605,14 +605,14 @@ void GcodeSuite::G33() {
// Normalize angles to least-squares
if (_angle_results) {
float a_sum = 0.0f;
LOOP_LINEAR_AXES(axis) a_sum += delta_tower_angle_trim[axis];
LOOP_LINEAR_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f;
LOOP_NUM_AXES(axis) a_sum += delta_tower_angle_trim[axis];
LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f;
}
// adjust delta_height and endstops by the max amount
const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c);
delta_height -= z_temp;
LOOP_LINEAR_AXES(axis) delta_endstop_adj[axis] -= z_temp;
LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp;
}
recalc_delta_settings();
NOMORE(zero_std_dev_min, zero_std_dev);

View File

@ -85,10 +85,19 @@
#if ALL(HAS_K_AXIS, CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX)
#define HAS_K_CENTER 1
#endif
#if ALL(HAS_U_AXIS, CALIBRATION_MEASURE_UMIN, CALIBRATION_MEASURE_UMAX)
#define HAS_U_CENTER 1
#endif
#if ALL(HAS_V_AXIS, CALIBRATION_MEASURE_VMIN, CALIBRATION_MEASURE_VMAX)
#define HAS_V_CENTER 1
#endif
#if ALL(HAS_W_AXIS, CALIBRATION_MEASURE_WMIN, CALIBRATION_MEASURE_WMAX)
#define HAS_W_CENTER 1
#endif
enum side_t : uint8_t {
TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES,
LIST_N(DOUBLE(SUB3(LINEAR_AXES)), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM)
LIST_N(DOUBLE(SECONDARY_AXES), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM, UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM)
};
static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER;
@ -282,6 +291,15 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t
#if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K)
_PCASE(K);
#endif
#if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U)
_PCASE(U);
#endif
#if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V)
_PCASE(V);
#endif
#if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W)
_PCASE(W);
#endif
default: return;
}
@ -335,6 +353,12 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
TERN_(CALIBRATION_MEASURE_JMAX, probe_side(m, uncertainty, JMAXIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_KMIN, probe_side(m, uncertainty, KMINIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_KMAX, probe_side(m, uncertainty, KMAXIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_UMIN, probe_side(m, uncertainty, UMINIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_UMAX, probe_side(m, uncertainty, UMAXIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_VMIN, probe_side(m, uncertainty, VMINIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_VMAX, probe_side(m, uncertainty, VMAXIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_WMIN, probe_side(m, uncertainty, WMINIMUM, probe_top_at_edge));
TERN_(CALIBRATION_MEASURE_WMAX, probe_side(m, uncertainty, WMAXIMUM, probe_top_at_edge));
// Compute the measured center of the calibration object.
TERN_(HAS_X_CENTER, m.obj_center.x = (m.obj_side[LEFT] + m.obj_side[RIGHT]) / 2);
@ -342,6 +366,9 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
TERN_(HAS_I_CENTER, m.obj_center.i = (m.obj_side[IMINIMUM] + m.obj_side[IMAXIMUM]) / 2);
TERN_(HAS_J_CENTER, m.obj_center.j = (m.obj_side[JMINIMUM] + m.obj_side[JMAXIMUM]) / 2);
TERN_(HAS_K_CENTER, m.obj_center.k = (m.obj_side[KMINIMUM] + m.obj_side[KMAXIMUM]) / 2);
TERN_(HAS_U_CENTER, m.obj_center.u = (m.obj_side[UMINIMUM] + m.obj_side[UMAXIMUM]) / 2);
TERN_(HAS_V_CENTER, m.obj_center.v = (m.obj_side[VMINIMUM] + m.obj_side[VMAXIMUM]) / 2);
TERN_(HAS_W_CENTER, m.obj_center.w = (m.obj_side[WMINIMUM] + m.obj_side[WMAXIMUM]) / 2);
// Compute the outside diameter of the nozzle at the height
// at which it makes contact with the calibration object
@ -352,13 +379,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
// The difference between the known and the measured location
// of the calibration object is the positional error
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x),
m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y),
m.pos_error.z = true_center.z - m.obj_center.z,
m.pos_error.i = TERN0(HAS_I_CENTER, true_center.i - m.obj_center.i),
m.pos_error.j = TERN0(HAS_J_CENTER, true_center.j - m.obj_center.j),
m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k)
m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k),
m.pos_error.u = TERN0(HAS_U_CENTER, true_center.u - m.obj_center.u),
m.pos_error.v = TERN0(HAS_V_CENTER, true_center.v - m.obj_center.v),
m.pos_error.w = TERN0(HAS_W_CENTER, true_center.w - m.obj_center.w)
);
}
@ -406,6 +436,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.obj_side[KMAXIMUM]);
#endif
#endif
#if HAS_U_AXIS
#if ENABLED(CALIBRATION_MEASURE_UMIN)
SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.obj_side[UMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_UMAX)
SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.obj_side[UMAXIMUM]);
#endif
#endif
#if HAS_V_AXIS
#if ENABLED(CALIBRATION_MEASURE_VMIN)
SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.obj_side[VMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_VMAX)
SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.obj_side[VMAXIMUM]);
#endif
#endif
#if HAS_W_AXIS
#if ENABLED(CALIBRATION_MEASURE_WMIN)
SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.obj_side[WMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_WMAX)
SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.obj_side[WMAXIMUM]);
#endif
#endif
SERIAL_EOL();
}
@ -427,6 +481,15 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
#if HAS_K_CENTER
SERIAL_ECHOLNPGM_P(SP_K_STR, m.obj_center.k);
#endif
#if HAS_U_CENTER
SERIAL_ECHOLNPGM_P(SP_U_STR, m.obj_center.u);
#endif
#if HAS_V_CENTER
SERIAL_ECHOLNPGM_P(SP_V_STR, m.obj_center.v);
#endif
#if HAS_W_CENTER
SERIAL_ECHOLNPGM_P(SP_W_STR, m.obj_center.w);
#endif
SERIAL_EOL();
}
@ -475,6 +538,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]);
#endif
#endif
#if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U)
#if ENABLED(CALIBRATION_MEASURE_UMIN)
SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_UMAX)
SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]);
#endif
#endif
#if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V)
#if ENABLED(CALIBRATION_MEASURE_VMIN)
SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_VMAX)
SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]);
#endif
#endif
#if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W)
#if ENABLED(CALIBRATION_MEASURE_WMIN)
SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]);
#endif
#if ENABLED(CALIBRATION_MEASURE_WMAX)
SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]);
#endif
#endif
SERIAL_EOL();
}
@ -498,7 +585,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
SERIAL_ECHOLNPGM_P(SP_J_STR, m.pos_error.j);
#endif
#if HAS_K_CENTER && AXIS_CAN_CALIBRATE(K)
SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z);
SERIAL_ECHOLNPGM_P(SP_K_STR, m.pos_error.k);
#endif
#if HAS_U_CENTER && AXIS_CAN_CALIBRATE(U)
SERIAL_ECHOLNPGM_P(SP_U_STR, m.pos_error.u);
#endif
#if HAS_V_CENTER && AXIS_CAN_CALIBRATE(V)
SERIAL_ECHOLNPGM_P(SP_V_STR, m.pos_error.v);
#endif
#if HAS_W_CENTER && AXIS_CAN_CALIBRATE(W)
SERIAL_ECHOLNPGM_P(SP_W_STR, m.pos_error.w);
#endif
SERIAL_EOL();
}
@ -587,6 +683,30 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
backlash.set_distance_mm(K_AXIS, m.backlash[KMAXIMUM]);
#endif
#if HAS_U_CENTER
backlash.distance_mm.u = (m.backlash[UMINIMUM] + m.backlash[UMAXIMUM]) / 2;
#elif ENABLED(CALIBRATION_MEASURE_UMIN)
backlash.distance_mm.u = m.backlash[UMINIMUM];
#elif ENABLED(CALIBRATION_MEASURE_UMAX)
backlash.distance_mm.u = m.backlash[UMAXIMUM];
#endif
#if HAS_V_CENTER
backlash.distance_mm.v = (m.backlash[VMINIMUM] + m.backlash[VMAXIMUM]) / 2;
#elif ENABLED(CALIBRATION_MEASURE_VMIN)
backlash.distance_mm.v = m.backlash[VMINIMUM];
#elif ENABLED(CALIBRATION_MEASURE_UMAX)
backlash.distance_mm.v = m.backlash[VMAXIMUM];
#endif
#if HAS_W_CENTER
backlash.distance_mm.w = (m.backlash[WMINIMUM] + m.backlash[WMAXIMUM]) / 2;
#elif ENABLED(CALIBRATION_MEASURE_WMIN)
backlash.distance_mm.w = m.backlash[WMINIMUM];
#elif ENABLED(CALIBRATION_MEASURE_WMAX)
backlash.distance_mm.w = m.backlash[WMAXIMUM];
#endif
#endif // BACKLASH_GCODE
}
@ -597,9 +717,10 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
// New scope for TEMPORARY_BACKLASH_CORRECTION
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
const xyz_float_t move = LINEAR_AXIS_ARRAY(
const xyz_float_t move = NUM_AXIS_ARRAY(
AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3,
AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3
AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3,
AXIS_CAN_CALIBRATE(U) * 3, AXIS_CAN_CALIBRATE(V) * 3, AXIS_CAN_CALIBRATE(W) * 3
);
current_position += move; calibration_move();
current_position -= move; calibration_move();
@ -650,6 +771,9 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const
TERN_(HAS_I_CENTER, update_measurements(m, I_AXIS));
TERN_(HAS_J_CENTER, update_measurements(m, J_AXIS));
TERN_(HAS_K_CENTER, update_measurements(m, K_AXIS));
TERN_(HAS_U_CENTER, update_measurements(m, U_AXIS));
TERN_(HAS_V_CENTER, update_measurements(m, V_AXIS));
TERN_(HAS_W_CENTER, update_measurements(m, W_AXIS));
sync_plan_position();
}

View File

@ -49,21 +49,24 @@ void GcodeSuite::M425() {
auto axis_can_calibrate = [](const uint8_t a) {
switch (a) {
default: return false;
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
case X_AXIS: return AXIS_CAN_CALIBRATE(X),
case Y_AXIS: return AXIS_CAN_CALIBRATE(Y),
case Z_AXIS: return AXIS_CAN_CALIBRATE(Z),
case I_AXIS: return AXIS_CAN_CALIBRATE(I),
case J_AXIS: return AXIS_CAN_CALIBRATE(J),
case K_AXIS: return AXIS_CAN_CALIBRATE(K)
case K_AXIS: return AXIS_CAN_CALIBRATE(K),
case U_AXIS: return AXIS_CAN_CALIBRATE(U),
case V_AXIS: return AXIS_CAN_CALIBRATE(V),
case W_AXIS: return AXIS_CAN_CALIBRATE(W)
);
}
};
LOOP_LINEAR_AXES(a) {
LOOP_NUM_AXES(a) {
if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) {
planner.synchronize();
backlash.set_distance_mm(AxisEnum(a), parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(AxisEnum(a)));
backlash.set_distance_mm((AxisEnum)a, parser.has_value() ? parser.value_axis_units((AxisEnum)a) : backlash.get_measurement((AxisEnum)a));
noArgs = false;
}
}
@ -88,7 +91,7 @@ void GcodeSuite::M425() {
SERIAL_ECHOLNPGM("active:");
SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
SERIAL_ECHOPGM(" Backlash Distance (mm): ");
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a)) {
LOOP_NUM_AXES(a) if (axis_can_calibrate(a)) {
SERIAL_CHAR(' ', AXIS_CHAR(a));
SERIAL_ECHO(backlash.get_distance_mm(AxisEnum(a)));
SERIAL_EOL();
@ -101,7 +104,7 @@ void GcodeSuite::M425() {
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
SERIAL_ECHOPGM(" Average measured backlash (mm):");
if (backlash.has_any_measurement()) {
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
SERIAL_CHAR(' ', AXIS_CHAR(a));
SERIAL_ECHO(backlash.get_measurement(AxisEnum(a)));
}
@ -120,13 +123,16 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) {
#ifdef BACKLASH_SMOOTHING_MM
, PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm())
#endif
, LIST_N(DOUBLE(LINEAR_AXES),
, LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)),
SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)),
SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)),
SP_I_STR, LINEAR_UNIT(backlash.get_distance_mm(I_AXIS)),
SP_J_STR, LINEAR_UNIT(backlash.get_distance_mm(J_AXIS)),
SP_K_STR, LINEAR_UNIT(backlash.get_distance_mm(K_AXIS))
SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)),
SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)),
SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)),
SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)),
SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)),
SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS))
)
);
}

View File

@ -44,7 +44,7 @@
void GcodeSuite::M666() {
DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING));
bool is_err = false, is_set = false;
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
if (parser.seen(AXIS_CHAR(i))) {
is_set = true;
const float v = parser.value_linear_units();

View File

@ -144,13 +144,16 @@ void GcodeSuite::M201() {
void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_ACCELERATION));
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES),
LIST_N(DOUBLE(NUM_AXES),
PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]),
SP_I_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
SP_J_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
SP_K_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS])
SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS])
)
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
@ -189,13 +192,16 @@ void GcodeSuite::M203() {
void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_FEEDRATES));
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES),
LIST_N(DOUBLE(NUM_AXES),
PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]),
SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS])
SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]),
SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]),
SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]),
SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS])
)
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
@ -282,9 +288,12 @@ void GcodeSuite::M205() {
if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()),
if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()),
if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()),
if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()),
if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.value_linear_units()),
if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.value_linear_units())
if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()),
if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()),
if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()),
if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()),
if (parser.seenval(AXIS8_NAME)) planner.set_max_jerk(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()),
if (parser.seenval(AXIS9_NAME)) planner.set_max_jerk(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)())
);
#if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
if (seenZ && planner.max_jerk.z <= 0.1f)
@ -298,9 +307,10 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
"Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>"
TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>")
#if HAS_CLASSIC_JERK
LINEAR_AXIS_GANG(
NUM_AXIS_GANG(
" X<max_jerk>", " Y<max_jerk>", " Z<max_jerk>",
" " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>"
" " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>",
" " STR_U "<max_jerk>", " " STR_V "<max_jerk>", " " STR_W "<max_jerk>"
)
#endif
TERN_(HAS_CLASSIC_E_JERK, " E<max_jerk>")
@ -314,13 +324,16 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
, PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
#endif
#if HAS_CLASSIC_JERK
, LIST_N(DOUBLE(LINEAR_AXES),
, LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),
SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z),
SP_I_STR, LINEAR_UNIT(planner.max_jerk.i),
SP_J_STR, LINEAR_UNIT(planner.max_jerk.j),
SP_K_STR, LINEAR_UNIT(planner.max_jerk.k)
SP_I_STR, I_AXIS_UNIT(planner.max_jerk.i),
SP_J_STR, J_AXIS_UNIT(planner.max_jerk.j),
SP_K_STR, K_AXIS_UNIT(planner.max_jerk.k),
SP_U_STR, U_AXIS_UNIT(planner.max_jerk.u),
SP_V_STR, V_AXIS_UNIT(planner.max_jerk.v),
SP_W_STR, W_AXIS_UNIT(planner.max_jerk.w)
)
#if HAS_CLASSIC_E_JERK
, SP_E_STR, LINEAR_UNIT(planner.max_jerk.e)

View File

@ -50,9 +50,12 @@
* W[linear] 0/1 Enable park & Z Raise
* X[linear] Park X (Requires TOOLCHANGE_PARK)
* Y[linear] Park Y (Requires TOOLCHANGE_PARK)
* I[linear] Park I (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 4)
* J[linear] Park J (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 5)
* K[linear] Park K (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 6)
* I[linear] Park I (Requires TOOLCHANGE_PARK and NUM_AXES >= 4)
* J[linear] Park J (Requires TOOLCHANGE_PARK and NUM_AXES >= 5)
* K[linear] Park K (Requires TOOLCHANGE_PARK and NUM_AXES >= 6)
* C[linear] Park U (Requires TOOLCHANGE_PARK and NUM_AXES >= 7)
* H[linear] Park V (Requires TOOLCHANGE_PARK and NUM_AXES >= 8)
* O[linear] Park W (Requires TOOLCHANGE_PARK and NUM_AXES >= 9)
* Z[linear] Z Raise
* F[speed] Fan Speed 0-255
* D[seconds] Fan time
@ -95,13 +98,22 @@ void GcodeSuite::M217() {
if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); }
#endif
#if HAS_I_AXIS
if (parser.seenval('I')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); }
if (parser.seenval('I')) { const int16_t v = parser.TERN(AXIS4_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); }
#endif
#if HAS_J_AXIS
if (parser.seenval('J')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); }
if (parser.seenval('J')) { const int16_t v = parser.TERN(AXIS5_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); }
#endif
#if HAS_K_AXIS
if (parser.seenval('K')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); }
if (parser.seenval('K')) { const int16_t v = parser.TERN(AXIS6_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); }
#endif
#if HAS_U_AXIS
if (parser.seenval('C')) { const int16_t v = parser.TERN(AXIS7_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); }
#endif
#if HAS_V_AXIS
if (parser.seenval('H')) { const int16_t v = parser.TERN(AXIS8_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); }
#endif
#if HAS_W_AXIS
if (parser.seenval('O')) { const int16_t v = parser.TERN(AXIS9_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); }
#endif
#endif
@ -167,24 +179,23 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) {
#endif
#if ENABLED(TOOLCHANGE_PARK)
{
SERIAL_ECHOPGM(" W", LINEAR_UNIT(toolchange_settings.enable_park));
SERIAL_ECHOPGM_P(
SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)
#if HAS_Y_AXIS
, SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)
#endif
#if HAS_I_AXIS
, SP_I_STR, LINEAR_UNIT(toolchange_settings.change_point.i)
#endif
#if HAS_J_AXIS
, SP_J_STR, LINEAR_UNIT(toolchange_settings.change_point.j)
#endif
#if HAS_K_AXIS
, SP_K_STR, LINEAR_UNIT(toolchange_settings.change_point.k)
#if SECONDARY_AXES >= 1
, LIST_N(DOUBLE(SECONDARY_AXES)
, SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i)
, SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j)
, SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k)
, SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u)
, PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v)
, PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w)
)
#endif
);
}
#endif
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)

View File

@ -24,7 +24,7 @@
#include "../../module/planner.h"
/**
* M92: Set axis steps-per-unit for one or more axes, X, Y, Z, [I, [J, [K]]] and E.
* M92: Set axis steps-per-unit for one or more axes, X, Y, Z, [I, [J, [K, [U, [V, [W,]]]]]] and E.
* (Follows the same syntax as G92)
*
* With multiple extruders use T to specify which one.
@ -92,14 +92,17 @@ void GcodeSuite::M92() {
void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) {
report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT));
SERIAL_ECHOPGM_P(LIST_N(DOUBLE(LINEAR_AXES),
SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES),
PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]),
SP_I_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]),
SP_J_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]),
SP_K_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]))
);
SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS])
));
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS]));
#endif

View File

@ -46,13 +46,16 @@ inline stepper_flags_t selected_axis_bits() {
selected.bits = selected.e_bits();
}
#endif
selected.bits |= LINEAR_AXIS_GANG(
selected.bits |= NUM_AXIS_GANG(
(parser.seen_test('X') << X_AXIS),
| (parser.seen_test('Y') << Y_AXIS),
| (parser.seen_test('Z') << Z_AXIS),
| (parser.seen_test(AXIS4_NAME) << I_AXIS),
| (parser.seen_test(AXIS5_NAME) << J_AXIS),
| (parser.seen_test(AXIS6_NAME) << K_AXIS)
| (parser.seen_test(AXIS6_NAME) << K_AXIS),
| (parser.seen_test(AXIS7_NAME) << U_AXIS),
| (parser.seen_test(AXIS8_NAME) << V_AXIS),
| (parser.seen_test(AXIS9_NAME) << W_AXIS)
);
return selected;
}
@ -69,7 +72,7 @@ void do_enable(const stepper_flags_t to_enable) {
ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap
// Enable all flagged axes
LOOP_LINEAR_AXES(a) {
LOOP_NUM_AXES(a) {
if (TEST(shall_enable, a)) {
stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis
DEBUG_ECHOLNPGM("Enabled ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits));
@ -89,7 +92,7 @@ void do_enable(const stepper_flags_t to_enable) {
if ((also_enabled &= ~(shall_enable | was_enabled))) {
SERIAL_CHAR('(');
LOOP_LINEAR_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' ');
LOOP_NUM_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(AXIS_CHAR(a), ' ');
#if HAS_EXTRUDERS
#define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' ');
REPEAT(EXTRUDERS, _EN_ALSO)
@ -125,13 +128,16 @@ void GcodeSuite::M17() {
stepper.enable_e_steppers();
}
#endif
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
if (parser.seen_test('X')) stepper.enable_axis(X_AXIS),
if (parser.seen_test('Y')) stepper.enable_axis(Y_AXIS),
if (parser.seen_test('Z')) stepper.enable_axis(Z_AXIS),
if (parser.seen_test(AXIS4_NAME)) stepper.enable_axis(I_AXIS),
if (parser.seen_test(AXIS5_NAME)) stepper.enable_axis(J_AXIS),
if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS)
if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS),
if (parser.seen_test(AXIS7_NAME)) stepper.enable_axis(U_AXIS),
if (parser.seen_test(AXIS8_NAME)) stepper.enable_axis(V_AXIS),
if (parser.seen_test(AXIS9_NAME)) stepper.enable_axis(W_AXIS)
);
}
}
@ -149,7 +155,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
if (!still_enabled) return;
// Attempt to disable all flagged axes
LOOP_LINEAR_AXES(a)
LOOP_NUM_AXES(a)
if (TEST(to_disable.bits, a)) {
DEBUG_ECHOPGM("Try to disable ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... ");
if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable
@ -178,7 +184,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
auto overlap_warning = [](const ena_mask_t axis_bits) {
SERIAL_ECHOPGM(" not disabled. Shared with");
LOOP_LINEAR_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]);
LOOP_NUM_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]);
#if HAS_EXTRUDERS
#define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N);
REPEAT(EXTRUDERS, _EN_STILLON)
@ -187,7 +193,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
};
// If any of the requested axes are still enabled, give a warning
LOOP_LINEAR_AXES(a) {
LOOP_NUM_AXES(a) {
if (TEST(still_enabled, a)) {
SERIAL_CHAR(axis_codes[a]);
overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]);
@ -238,13 +244,16 @@ void GcodeSuite::M18_M84() {
stepper.disable_e_steppers();
}
#endif
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
if (parser.seen_test('X')) stepper.disable_axis(X_AXIS),
if (parser.seen_test('Y')) stepper.disable_axis(Y_AXIS),
if (parser.seen_test('Z')) stepper.disable_axis(Z_AXIS),
if (parser.seen_test(AXIS4_NAME)) stepper.disable_axis(I_AXIS),
if (parser.seen_test(AXIS5_NAME)) stepper.disable_axis(J_AXIS),
if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS)
if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS),
if (parser.seen_test(AXIS7_NAME)) stepper.disable_axis(U_AXIS),
if (parser.seen_test(AXIS8_NAME)) stepper.disable_axis(V_AXIS),
if (parser.seen_test(AXIS9_NAME)) stepper.disable_axis(W_AXIS)
);
}
}

View File

@ -146,7 +146,7 @@
HOTEND_LOOP() {
DEBUG_ECHOPGM_P(SP_T_STR, e);
LOOP_LINEAR_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]);
LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]);
DEBUG_EOL();
}
DEBUG_EOL();

View File

@ -285,6 +285,25 @@ void GcodeSuite::M906() {
break;
#endif
#if AXIS_IS_L64XX(I)
case I_AXIS: L6470_SET_KVAL_HOLD(I); break;
#endif
#if AXIS_IS_L64XX(J)
case J_AXIS: L6470_SET_KVAL_HOLD(J); break;
#endif
#if AXIS_IS_L64XX(K)
case K_AXIS: L6470_SET_KVAL_HOLD(K); break;
#endif
#if AXIS_IS_L64XX(U)
case U_AXIS: L6470_SET_KVAL_HOLD(U); break;
#endif
#if AXIS_IS_L64XX(V)
case V_AXIS: L6470_SET_KVAL_HOLD(V); break;
#endif
#if AXIS_IS_L64XX(W)
case W_AXIS: L6470_SET_KVAL_HOLD(W); break;
#endif
#if AXIS_IS_L64XX(E0) || AXIS_IS_L64XX(E1) || AXIS_IS_L64XX(E2) || AXIS_IS_L64XX(E3) || AXIS_IS_L64XX(E4) || AXIS_IS_L64XX(E5) || AXIS_IS_L64XX(E6) || AXIS_IS_L64XX(E7)
case E_AXIS: {
const int8_t eindex = get_target_e_stepper_from_command(-2);
@ -346,6 +365,24 @@ void GcodeSuite::M906() {
#if AXIS_IS_L64XX(Z4)
L64XX_REPORT_CURRENT(Z4);
#endif
#if AXIS_IS_L64XX(I)
L64XX_REPORT_CURRENT(I);
#endif
#if AXIS_IS_L64XX(J)
L64XX_REPORT_CURRENT(J);
#endif
#if AXIS_IS_L64XX(K)
L64XX_REPORT_CURRENT(K);
#endif
#if AXIS_IS_L64XX(U)
L64XX_REPORT_CURRENT(U);
#endif
#if AXIS_IS_L64XX(V)
L64XX_REPORT_CURRENT(V);
#endif
#if AXIS_IS_L64XX(W)
L64XX_REPORT_CURRENT(W);
#endif
#if AXIS_IS_L64XX(E0)
L64XX_REPORT_CURRENT(E0);
#endif

View File

@ -39,7 +39,7 @@
#endif
/**
* M907: Set digital trimpot motor current using axis codes X [Y] [Z] [E]
* M907: Set digital trimpot motor current using axis codes X [Y] [Z] [I] [J] [K] [U] [V] [W] [E]
* B<current> - Special case for 4th (E) axis
* S<current> - Special case to set first 3 axes
*/
@ -49,15 +49,15 @@ void GcodeSuite::M907() {
if (!parser.seen("BS" LOGICAL_AXES_STRING))
return M907_report();
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.set_digipot_current(i, parser.value_int());
LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int());
if (parser.seenval('B')) stepper.set_digipot_current(4, parser.value_int());
if (parser.seenval('S')) LOOP_LE_N(i, 4) stepper.set_digipot_current(i, parser.value_int());
#elif HAS_MOTOR_CURRENT_PWM
if (!parser.seen(
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY)
"XY"
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W)
"XY" SECONDARY_AXIS_GANG("I", "J", "K", "U", "V", "W")
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
"Z"
@ -67,8 +67,12 @@ void GcodeSuite::M907() {
#endif
)) return M907_report();
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY)
if (parser.seenval('X') || parser.seenval('Y')) stepper.set_digipot_current(0, parser.value_int());
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W)
if (NUM_AXIS_GANG(
parser.seenval('X'), || parser.seenval('Y'), || false,
|| parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'),
|| parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W')
)) stepper.set_digipot_current(0, parser.value_int());
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int());
@ -81,7 +85,7 @@ void GcodeSuite::M907() {
#if HAS_MOTOR_CURRENT_I2C
// this one uses actual amps in floating point
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) digipot_i2c.set_current(i, parser.value_float());
LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float());
// Additional extruders use B,C,D for channels 4,5,6.
// TODO: Change these parameters because 'E' is used. B<index>?
#if HAS_EXTRUDERS
@ -95,7 +99,7 @@ void GcodeSuite::M907() {
const float dac_percent = parser.value_float();
LOOP_LE_N(i, 4) stepper_dac.set_current_percent(i, dac_percent);
}
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper_dac.set_current_percent(i, parser.value_float());
LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper_dac.set_current_percent(i, parser.value_float());
#endif
}
@ -104,15 +108,15 @@ void GcodeSuite::M907() {
void GcodeSuite::M907_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS));
#if HAS_MOTOR_CURRENT_PWM
SERIAL_ECHOLNPGM_P( // PWM-based has 3 values:
PSTR(" M907 X"), stepper.motor_current_setting[0] // X and Y
SERIAL_ECHOLNPGM_P( // PWM-based has 3 values:
PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K, U, V, W)
, SP_Z_STR, stepper.motor_current_setting[1] // Z
, SP_E_STR, stepper.motor_current_setting[2] // E
);
#elif HAS_MOTOR_CURRENT_SPI
SERIAL_ECHOPGM(" M907"); // SPI-based has 5 values:
LOOP_LOGICAL_AXES(q) { // X Y Z (I J K) E (map to X Y Z (I J K) E0 by default)
SERIAL_CHAR(' ', axis_codes[q]);
LOOP_LOGICAL_AXES(q) { // X Y Z (I J K U V W) E (map to X Y Z (I J K U V W) E0 by default)
SERIAL_CHAR(' ', IAXIS_CHAR(q));
SERIAL_ECHO(stepper.motor_current_setting[q]);
}
SERIAL_CHAR(' ', 'B'); // B (maps to E1 by default)

View File

@ -48,10 +48,14 @@ void GcodeSuite::G60() {
#if ENABLED(SAVED_POSITIONS_DEBUG)
{
DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :");
const xyze_pos_t &pos = stored_position[slot];
DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :");
DEBUG_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), PSTR(" : X"), pos.x, SP_Y_STR, pos.y, SP_Z_STR, pos.z, SP_I_STR, pos.i, SP_J_STR, pos.j, SP_K_STR, pos.k)
LIST_N(DOUBLE(NUM_AXES),
SP_X_LBL, pos.x, SP_Y_LBL, pos.y, SP_Z_LBL, pos.z,
SP_I_LBL, pos.i, SP_J_LBL, pos.j, SP_K_LBL, pos.k,
SP_U_LBL, pos.u, SP_V_LBL, pos.v, SP_W_LBL, pos.w
)
#if HAS_EXTRUDERS
, SP_E_LBL, pos.e
#endif

View File

@ -68,9 +68,9 @@ void GcodeSuite::G61() {
SYNC_E(stored_position[slot].e);
}
else {
if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))) {
if (parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W))) {
DEBUG_ECHOPGM(STR_RESTORING_POS " S", slot);
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
destination[i] = parser.seen(AXIS_CHAR(i))
? stored_position[slot][i] + parser.value_axis_units((AxisEnum)i)
: current_position[i];

View File

@ -52,6 +52,9 @@
* A<pos> = Override park position A (requires AXIS*_NAME 'A')
* B<pos> = Override park position B (requires AXIS*_NAME 'B')
* C<pos> = Override park position C (requires AXIS*_NAME 'C')
* U<pos> = Override park position U (requires AXIS*_NAME 'U')
* V<pos> = Override park position V (requires AXIS*_NAME 'V')
* W<pos> = Override park position W (requires AXIS*_NAME 'W')
* Z<linear> = Override Z raise
*
* With an LCD menu:
@ -64,17 +67,22 @@ void GcodeSuite::M125() {
xyz_pos_t park_point = NOZZLE_PARK_POINT;
// Move to filament change position or given position
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')),
if (parser.seenval('Y')) park_point.y = RAW_Y_POSITION(parser.linearval('Y')),
NOOP,
if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_I_POSITION(parser.linearval(AXIS4_NAME)),
if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_J_POSITION(parser.linearval(AXIS5_NAME)),
if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_K_POSITION(parser.linearval(AXIS6_NAME))
if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_X_POSITION(parser.linearval(AXIS4_NAME)),
if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_X_POSITION(parser.linearval(AXIS5_NAME)),
if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_X_POSITION(parser.linearval(AXIS6_NAME)),
if (parser.seenval(AXIS7_NAME)) park_point.u = RAW_X_POSITION(parser.linearval(AXIS7_NAME)),
if (parser.seenval(AXIS8_NAME)) park_point.v = RAW_X_POSITION(parser.linearval(AXIS8_NAME)),
if (parser.seenval(AXIS9_NAME)) park_point.w = RAW_X_POSITION(parser.linearval(AXIS9_NAME))
);
// Lift Z axis
if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
#if HAS_Z_AXIS
if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
#endif
#if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA)
park_point += hotend_offset[active_extruder];

View File

@ -54,8 +54,14 @@
*
* E[distance] - Retract the filament this far
* Z[distance] - Move the Z axis by this distance
* X[position] - Move to this X position, with Y
* Y[position] - Move to this Y position, with X
* X[position] - Move to this X position (instead of NOZZLE_PARK_POINT.x)
* Y[position] - Move to this Y position (instead of NOZZLE_PARK_POINT.y)
* I[position] - Move to this I position (instead of NOZZLE_PARK_POINT.i)
* J[position] - Move to this J position (instead of NOZZLE_PARK_POINT.j)
* K[position] - Move to this K position (instead of NOZZLE_PARK_POINT.k)
* C[position] - Move to this U position (instead of NOZZLE_PARK_POINT.u)
* H[position] - Move to this V position (instead of NOZZLE_PARK_POINT.v)
* O[position] - Move to this W position (instead of NOZZLE_PARK_POINT.w)
* U[distance] - Retract distance for removal (manual reload)
* L[distance] - Extrude distance for insertion (manual reload)
* B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer)
@ -117,26 +123,25 @@ void GcodeSuite::M600() {
xyz_pos_t park_point NOZZLE_PARK_POINT;
// Move XY axes to filament change position or given position
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
if (parser.seenval('X')) park_point.x = parser.linearval('X'),
if (parser.seenval('Y')) park_point.y = parser.linearval('Y'),
if (parser.seenval('Z')) park_point.z = parser.linearval('Z'), // Lift Z axis
if (parser.seenval(AXIS4_NAME)) park_point.i = parser.linearval(AXIS4_NAME),
if (parser.seenval(AXIS5_NAME)) park_point.j = parser.linearval(AXIS5_NAME),
if (parser.seenval(AXIS6_NAME)) park_point.k = parser.linearval(AXIS6_NAME)
if (parser.seenval('I')) park_point.i = parser.linearval('I'),
if (parser.seenval('J')) park_point.j = parser.linearval('J'),
if (parser.seenval('K')) park_point.k = parser.linearval('K'),
if (parser.seenval('C')) park_point.u = parser.linearval('C'), // U axis
if (parser.seenval('H')) park_point.v = parser.linearval('H'), // V axis
if (parser.seenval('O')) park_point.w = parser.linearval('O') // W axis
);
#if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA)
park_point += hotend_offset[active_extruder];
#endif
#if ENABLED(MMU2_MENUS)
// For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling
const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f;
#else
// Unload filament
const float unload_length = -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length));
#endif
// Unload filament
// For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling
const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f;
const int beep_count = parser.intval('B', -1
#ifdef FILAMENT_CHANGE_ALERT_BEEPS

View File

@ -85,6 +85,15 @@ static void set_stealth_status(const bool enable, const int8_t eindex) {
#if K_HAS_STEALTHCHOP
case K_AXIS: TMC_SET_STEALTH(K); break;
#endif
#if U_HAS_STEALTHCHOP
case U_AXIS: TMC_SET_STEALTH(U); break;
#endif
#if V_HAS_STEALTHCHOP
case V_AXIS: TMC_SET_STEALTH(V); break;
#endif
#if W_HAS_STEALTHCHOP
case W_AXIS: TMC_SET_STEALTH(W); break;
#endif
#if E_STEPPERS
case E_AXIS: {
@ -115,6 +124,9 @@ static void say_stealth_status() {
OPTCODE( I_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(I))
OPTCODE( J_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(J))
OPTCODE( K_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(K))
OPTCODE( U_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(U))
OPTCODE( V_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(V))
OPTCODE( W_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(W))
OPTCODE(E0_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E0))
OPTCODE(E1_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E1))
OPTCODE(E2_HAS_STEALTHCHOP, TMC_SAY_STEALTH_STATUS(E2))
@ -157,17 +169,23 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
chop_z = TERN0(Z_HAS_STEALTHCHOP, stepperZ.get_stored_stealthChop()),
chop_i = TERN0(I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop()),
chop_j = TERN0(J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop()),
chop_k = TERN0(K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop());
chop_k = TERN0(K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop()),
chop_u = TERN0(U_HAS_STEALTHCHOP, stepperU.get_stored_stealthChop()),
chop_v = TERN0(V_HAS_STEALTHCHOP, stepperV.get_stored_stealthChop()),
chop_w = TERN0(W_HAS_STEALTHCHOP, stepperW.get_stored_stealthChop());
if (chop_x || chop_y || chop_z || chop_i || chop_j || chop_k) {
if (chop_x || chop_y || chop_z || chop_i || chop_j || chop_k || chop_u || chop_v || chop_w) {
say_M569(forReplay);
LINEAR_AXIS_CODE(
NUM_AXIS_CODE(
if (chop_x) SERIAL_ECHOPGM_P(SP_X_STR),
if (chop_y) SERIAL_ECHOPGM_P(SP_Y_STR),
if (chop_z) SERIAL_ECHOPGM_P(SP_Z_STR),
if (chop_i) SERIAL_ECHOPGM_P(SP_I_STR),
if (chop_j) SERIAL_ECHOPGM_P(SP_J_STR),
if (chop_k) SERIAL_ECHOPGM_P(SP_K_STR)
if (chop_k) SERIAL_ECHOPGM_P(SP_K_STR),
if (chop_u) SERIAL_ECHOPGM_P(SP_U_STR),
if (chop_v) SERIAL_ECHOPGM_P(SP_V_STR),
if (chop_w) SERIAL_ECHOPGM_P(SP_W_STR)
);
SERIAL_EOL();
}
@ -190,6 +208,9 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
if (TERN0( I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_I_STR), true); }
if (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_J_STR), true); }
if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_K_STR), true); }
if (TERN0( U_HAS_STEALTHCHOP, stepperU.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_U_STR), true); }
if (TERN0( V_HAS_STEALTHCHOP, stepperV.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_V_STR), true); }
if (TERN0( W_HAS_STEALTHCHOP, stepperW.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_W_STR), true); }
if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, F("T0 E"), true); }
if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, F("T1 E"), true); }

View File

@ -44,6 +44,9 @@ static void tmc_print_current(TMC &st) {
* A[current] - Set mA current for A driver(s) (Requires AXIS*_NAME 'A')
* B[current] - Set mA current for B driver(s) (Requires AXIS*_NAME 'B')
* C[current] - Set mA current for C driver(s) (Requires AXIS*_NAME 'C')
* U[current] - Set mA current for U driver(s) (Requires AXIS*_NAME 'U')
* V[current] - Set mA current for V driver(s) (Requires AXIS*_NAME 'V')
* W[current] - Set mA current for W driver(s) (Requires AXIS*_NAME 'W')
* E[current] - Set mA current for E driver(s)
*
* I[index] - Axis sub-index (Omit or 0 for X, Y, Z; 1 for X2, Y2, Z2; 2 for Z3; 3 for Z4.)
@ -114,6 +117,15 @@ void GcodeSuite::M906() {
#if AXIS_IS_TMC(K)
case K_AXIS: TMC_SET_CURRENT(K); break;
#endif
#if AXIS_IS_TMC(U)
case U_AXIS: TMC_SET_CURRENT(U); break;
#endif
#if AXIS_IS_TMC(V)
case V_AXIS: TMC_SET_CURRENT(V); break;
#endif
#if AXIS_IS_TMC(W)
case W_AXIS: TMC_SET_CURRENT(W); break;
#endif
#if AXIS_IS_TMC(E0) || AXIS_IS_TMC(E1) || AXIS_IS_TMC(E2) || AXIS_IS_TMC(E3) || AXIS_IS_TMC(E4) || AXIS_IS_TMC(E5) || AXIS_IS_TMC(E6) || AXIS_IS_TMC(E7)
case E_AXIS: {
@ -181,6 +193,16 @@ void GcodeSuite::M906() {
#if AXIS_IS_TMC(K)
TMC_SAY_CURRENT(K);
#endif
#if AXIS_IS_TMC(U)
TMC_SAY_CURRENT(U);
#endif
#if AXIS_IS_TMC(V)
TMC_SAY_CURRENT(V);
#endif
#if AXIS_IS_TMC(W)
TMC_SAY_CURRENT(W);
#endif
#if AXIS_IS_TMC(E0)
TMC_SAY_CURRENT(E0);
#endif
@ -217,7 +239,8 @@ void GcodeSuite::M906_report(const bool forReplay/*=true*/) {
};
#if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z) \
|| AXIS_IS_TMC(I) || AXIS_IS_TMC(J) || AXIS_IS_TMC(K)
|| AXIS_IS_TMC(I) || AXIS_IS_TMC(J) || AXIS_IS_TMC(K) \
|| AXIS_IS_TMC(U) || AXIS_IS_TMC(V) || AXIS_IS_TMC(W)
say_M906(forReplay);
#if AXIS_IS_TMC(X)
SERIAL_ECHOPGM_P(SP_X_STR, stepperX.getMilliamps());
@ -237,6 +260,15 @@ void GcodeSuite::M906_report(const bool forReplay/*=true*/) {
#if AXIS_IS_TMC(K)
SERIAL_ECHOPGM_P(SP_K_STR, stepperK.getMilliamps());
#endif
#if AXIS_IS_TMC(U)
SERIAL_ECHOPGM_P(SP_U_STR, stepperU.getMilliamps());
#endif
#if AXIS_IS_TMC(V)
SERIAL_ECHOPGM_P(SP_V_STR, stepperV.getMilliamps());
#endif
#if AXIS_IS_TMC(W)
SERIAL_ECHOPGM_P(SP_W_STR, stepperW.getMilliamps());
#endif
SERIAL_EOL();
#endif

View File

@ -53,12 +53,21 @@
#if HAS_K_AXIS && M91x_USE(K)
#define M91x_USE_K 1
#endif
#if HAS_U_AXIS && M91x_USE(U)
#define M91x_USE_U 1
#endif
#if HAS_V_AXIS && M91x_USE(V)
#define M91x_USE_V 1
#endif
#if HAS_W_AXIS && M91x_USE(W)
#define M91x_USE_W 1
#endif
#if M91x_USE_E(0) || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4) || M91x_USE_E(5) || M91x_USE_E(6) || M91x_USE_E(7)
#define M91x_SOME_E 1
#endif
#if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_SOME_E
#if !M91x_SOME_X && !M91x_SOME_Y && !M91x_SOME_Z && !M91x_USE_I && !M91x_USE_J && !M91x_USE_K && !M91x_USE_U && !M91x_USE_V && !M91x_USE_W && !M91x_SOME_E
#error "MONITOR_DRIVER_STATUS requires at least one TMC2130, 2160, 2208, 2209, 2660, 5130, or 5160."
#endif
@ -109,6 +118,9 @@
TERN_(M91x_USE_I, tmc_report_otpw(stepperI));
TERN_(M91x_USE_J, tmc_report_otpw(stepperJ));
TERN_(M91x_USE_K, tmc_report_otpw(stepperK));
TERN_(M91x_USE_U, tmc_report_otpw(stepperU));
TERN_(M91x_USE_V, tmc_report_otpw(stepperV));
TERN_(M91x_USE_W, tmc_report_otpw(stepperW));
#if M91x_USE_E(0)
tmc_report_otpw(stepperE0);
#endif
@ -137,7 +149,7 @@
/**
* M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library
* Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4 and E[index].
* Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4, A, B, C, U, V, W, and E[index].
* If no axes are given, clear all.
*
* Examples:
@ -154,9 +166,12 @@
hasI = TERN0(M91x_USE_I, parser.seen(axis_codes.i)),
hasJ = TERN0(M91x_USE_J, parser.seen(axis_codes.j)),
hasK = TERN0(M91x_USE_K, parser.seen(axis_codes.k)),
hasU = TERN0(M91x_USE_U, parser.seen(axis_codes.u)),
hasV = TERN0(M91x_USE_V, parser.seen(axis_codes.v)),
hasW = TERN0(M91x_USE_W, parser.seen(axis_codes.w)),
hasE = TERN0(M91x_SOME_E, parser.seen(axis_codes.e));
const bool hasNone = !hasE && !hasX && !hasY && !hasZ && !hasI && !hasJ && !hasK;
const bool hasNone = !hasE && !hasX && !hasY && !hasZ && !hasI && !hasJ && !hasK && !hasU && !hasV && !hasW;
#if M91x_SOME_X
const int8_t xval = int8_t(parser.byteval(axis_codes.x, 0xFF));
@ -206,6 +221,18 @@
const int8_t kval = int8_t(parser.byteval(axis_codes.k, 0xFF));
if (hasNone || kval == 1 || (hasK && kval < 0)) tmc_clear_otpw(stepperK);
#endif
#if M91x_USE_U
const int8_t uval = int8_t(parser.byteval(axis_codes.u, 0xFF));
if (hasNone || uval == 1 || (hasU && uval < 0)) tmc_clear_otpw(stepperU);
#endif
#if M91x_USE_V
const int8_t vval = int8_t(parser.byteval(axis_codes.v, 0xFF));
if (hasNone || vval == 1 || (hasV && vval < 0)) tmc_clear_otpw(stepperV);
#endif
#if M91x_USE_W
const int8_t wval = int8_t(parser.byteval(axis_codes.w, 0xFF));
if (hasNone || wval == 1 || (hasW && wval < 0)) tmc_clear_otpw(stepperW);
#endif
#if M91x_SOME_E
const int8_t eval = int8_t(parser.byteval(axis_codes.e, 0xFF));
@ -296,6 +323,15 @@
#if K_HAS_STEALTHCHOP
case K_AXIS: TMC_SET_PWMTHRS(K,K); break;
#endif
#if U_HAS_STEALTHCHOP
case U_AXIS: TMC_SET_PWMTHRS(U,U); break;
#endif
#if V_HAS_STEALTHCHOP
case V_AXIS: TMC_SET_PWMTHRS(V,V); break;
#endif
#if W_HAS_STEALTHCHOP
case W_AXIS: TMC_SET_PWMTHRS(W,W); break;
#endif
#if E0_HAS_STEALTHCHOP || E1_HAS_STEALTHCHOP || E2_HAS_STEALTHCHOP || E3_HAS_STEALTHCHOP || E4_HAS_STEALTHCHOP || E5_HAS_STEALTHCHOP || E6_HAS_STEALTHCHOP || E7_HAS_STEALTHCHOP
case E_AXIS: {
@ -326,6 +362,9 @@
TERN_( I_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(I,I));
TERN_( J_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(J,J));
TERN_( K_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(K,K));
TERN_( U_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(U,U));
TERN_( V_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(V,V));
TERN_( W_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS(W,W));
TERN_(E0_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(0));
TERN_(E1_HAS_STEALTHCHOP, TMC_SAY_PWMTHRS_E(1));
@ -397,6 +436,18 @@
say_M913(forReplay);
SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.get_pwm_thrs());
#endif
#if U_HAS_STEALTHCHOP
say_M913(forReplay);
SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.get_pwm_thrs());
#endif
#if V_HAS_STEALTHCHOP
say_M913(forReplay);
SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.get_pwm_thrs());
#endif
#if W_HAS_STEALTHCHOP
say_M913(forReplay);
SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.get_pwm_thrs());
#endif
#if E0_HAS_STEALTHCHOP
say_M913(forReplay);
@ -451,7 +502,7 @@
bool report = true;
const uint8_t index = parser.byteval('I');
LOOP_LINEAR_AXES(i) if (parser.seen(AXIS_CHAR(i))) {
LOOP_NUM_AXES(i) if (parser.seen(AXIS_CHAR(i))) {
const int16_t value = parser.value_int();
report = false;
switch (i) {
@ -484,6 +535,15 @@
#if K_SENSORLESS
case K_AXIS: stepperK.homing_threshold(value); break;
#endif
#if U_SENSORLESS && AXIS_HAS_STALLGUARD(U)
case U_AXIS: stepperU.homing_threshold(value); break;
#endif
#if V_SENSORLESS && AXIS_HAS_STALLGUARD(V)
case V_AXIS: stepperV.homing_threshold(value); break;
#endif
#if W_SENSORLESS && AXIS_HAS_STALLGUARD(W)
case W_AXIS: stepperW.homing_threshold(value); break;
#endif
}
}
@ -499,6 +559,9 @@
TERN_(I_SENSORLESS, tmc_print_sgt(stepperI));
TERN_(J_SENSORLESS, tmc_print_sgt(stepperJ));
TERN_(K_SENSORLESS, tmc_print_sgt(stepperK));
TERN_(U_SENSORLESS, tmc_print_sgt(stepperU));
TERN_(V_SENSORLESS, tmc_print_sgt(stepperV));
TERN_(W_SENSORLESS, tmc_print_sgt(stepperW));
}
}
@ -561,6 +624,18 @@
say_M914(forReplay);
SERIAL_ECHOLNPGM_P(SP_K_STR, stepperK.homing_threshold());
#endif
#if U_SENSORLESS
say_M914(forReplay);
SERIAL_ECHOLNPGM_P(SP_U_STR, stepperU.homing_threshold());
#endif
#if V_SENSORLESS
say_M914(forReplay);
SERIAL_ECHOLNPGM_P(SP_V_STR, stepperV.homing_threshold());
#endif
#if W_SENSORLESS
say_M914(forReplay);
SERIAL_ECHOLNPGM_P(SP_W_STR, stepperW.homing_threshold());
#endif
}
#endif // USE_SENSORLESS

View File

@ -88,7 +88,10 @@ axis_bits_t GcodeSuite::axis_relative = 0 LOGICAL_AXIS_GANG(
| (ar_init.z << REL_Z),
| (ar_init.i << REL_I),
| (ar_init.j << REL_J),
| (ar_init.k << REL_K)
| (ar_init.k << REL_K),
| (ar_init.u << REL_U),
| (ar_init.v << REL_V),
| (ar_init.w << REL_W)
);
#if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE)
@ -179,7 +182,7 @@ void GcodeSuite::get_destination_from_command() {
#endif
// Get new XYZ position, whether absolute or relative
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) {
const float v = parser.value_axis_units((AxisEnum)i);
if (skip_move)

View File

@ -339,7 +339,7 @@
#endif
enum AxisRelative : uint8_t {
LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z, REL_I, REL_J, REL_K)
LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z, REL_I, REL_J, REL_K, REL_U, REL_V, REL_W)
#if HAS_EXTRUDERS
, E_MODE_ABS, E_MODE_REL
#endif
@ -365,7 +365,8 @@ public:
axis_relative = rel ? (0 LOGICAL_AXIS_GANG(
| _BV(REL_E),
| _BV(REL_X), | _BV(REL_Y), | _BV(REL_Z),
| _BV(REL_I), | _BV(REL_J), | _BV(REL_K)
| _BV(REL_I), | _BV(REL_J), | _BV(REL_K),
| _BV(REL_U), | _BV(REL_V), | _BV(REL_W)
)) : 0;
}
#if HAS_EXTRUDERS

View File

@ -39,7 +39,7 @@ bool GcodeSuite::select_coordinate_system(const int8_t _new) {
xyz_float_t new_offset{0};
if (WITHIN(_new, 0, MAX_COORDINATE_SYSTEMS - 1))
new_offset = coordinate_system[_new];
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
if (position_shift[i] != new_offset[i]) {
position_shift[i] = new_offset[i];
update_workspace_offset((AxisEnum)i);

View File

@ -29,7 +29,7 @@
#endif
/**
* G92: Set the Current Position to the given X [Y [Z [A [B [C [E]]]]]] values.
* G92: Set the Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E] values.
*
* Behind the scenes the G92 command may modify the Current Position
* or the Position Shift depending on settings and sub-commands.
@ -37,14 +37,14 @@
* Since E has no Workspace Offset, it is always set directly.
*
* Without Workspace Offsets (e.g., with NO_WORKSPACE_OFFSETS):
* G92 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [E]]]]]].
* G92 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E].
*
* Using Workspace Offsets (default Marlin behavior):
* G92 : Modify Workspace Offsets so the reported position shows the given X [Y [Z [A [B [C [E]]]]]].
* G92 : Modify Workspace Offsets so the reported position shows the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E].
* G92.1 : Zero XYZ Workspace Offsets (so the reported position = the native position).
*
* With POWER_LOSS_RECOVERY:
* G92.9 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [E]]]]]].
* G92.9 : Set NATIVE Current Position to the given X [Y [Z [A [B [C [U [V [W ]]]]]]]] [E].
*/
void GcodeSuite::G92() {
@ -64,7 +64,7 @@ void GcodeSuite::G92() {
#if ENABLED(CNC_COORDINATE_SYSTEMS) && !IS_SCARA
case 1: // G92.1 - Zero the Workspace Offset
LOOP_LINEAR_AXES(i) if (position_shift[i]) {
LOOP_NUM_AXES(i) if (position_shift[i]) {
position_shift[i] = 0;
update_workspace_offset((AxisEnum)i);
}

View File

@ -39,11 +39,17 @@
*/
void GcodeSuite::M206() {
if (!parser.seen_any()) return M206_report();
LOOP_LINEAR_AXES(i)
if (parser.seen(AXIS_CHAR(i)))
set_home_offset((AxisEnum)i, parser.value_linear_units());
NUM_AXIS_CODE(
if (parser.seen('X')) set_home_offset(X_AXIS, parser.value_linear_units()),
if (parser.seen('Y')) set_home_offset(Y_AXIS, parser.value_linear_units()),
if (parser.seen('Z')) set_home_offset(Z_AXIS, parser.value_linear_units()),
if (parser.seen(AXIS4_NAME)) set_home_offset(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()),
if (parser.seen(AXIS5_NAME)) set_home_offset(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()),
if (parser.seen(AXIS6_NAME)) set_home_offset(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()),
if (parser.seen(AXIS7_NAME)) set_home_offset(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()),
if (parser.seen(AXIS8_NAME)) set_home_offset(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()),
if (parser.seen(AXIS9_NAME)) set_home_offset(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)())
);
#if ENABLED(MORGAN_SCARA)
if (parser.seen('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta
if (parser.seen('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi
@ -56,13 +62,16 @@ void GcodeSuite::M206_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_HOME_OFFSET));
SERIAL_ECHOLNPGM_P(
#if IS_CARTESIAN
LIST_N(DOUBLE(LINEAR_AXES),
LIST_N(DOUBLE(NUM_AXES),
PSTR(" M206 X"), LINEAR_UNIT(home_offset.x),
SP_Y_STR, LINEAR_UNIT(home_offset.y),
SP_Z_STR, LINEAR_UNIT(home_offset.z),
SP_I_STR, LINEAR_UNIT(home_offset.i),
SP_J_STR, LINEAR_UNIT(home_offset.j),
SP_K_STR, LINEAR_UNIT(home_offset.k)
SP_I_STR, I_AXIS_UNIT(home_offset.i),
SP_J_STR, J_AXIS_UNIT(home_offset.j),
SP_K_STR, K_AXIS_UNIT(home_offset.k),
SP_U_STR, U_AXIS_UNIT(home_offset.u),
SP_V_STR, V_AXIS_UNIT(home_offset.v),
SP_W_STR, W_AXIS_UNIT(home_offset.w)
)
#else
PSTR(" M206 Z"), LINEAR_UNIT(home_offset.z)
@ -85,7 +94,7 @@ void GcodeSuite::M428() {
if (homing_needed_error()) return;
xyz_float_t diff;
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
diff[i] = base_home_pos((AxisEnum)i) - current_position[i];
if (!WITHIN(diff[i], -20, 20) && home_dir((AxisEnum)i) > 0)
diff[i] = -current_position[i];
@ -97,7 +106,7 @@ void GcodeSuite::M428() {
}
}
LOOP_LINEAR_AXES(i) set_home_offset((AxisEnum)i, diff[i]);
LOOP_NUM_AXES(i) set_home_offset((AxisEnum)i, diff[i]);
report_current_position();
LCD_MESSAGE(MSG_HOME_OFFSETS_APPLIED);
OKAY_BUZZ();

View File

@ -34,7 +34,7 @@
#include "../../core/debug_out.h"
#endif
void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=XYZE, const uint8_t precision=3) {
void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=LOGICAL_AXES, const uint8_t precision=3) {
char str[12];
LOOP_L_N(a, n) {
SERIAL_CHAR(' ', axis_codes[a], ':');
@ -47,7 +47,7 @@
void report_linear_axis_pos(const xyz_pos_t &pos, const uint8_t precision=3) {
char str[12];
LOOP_LINEAR_AXES(a) {
LOOP_NUM_AXES(a) {
SERIAL_CHAR(' ', AXIS_CHAR(a), ':');
SERIAL_ECHO(dtostrf(pos[a], 1, precision, str));
}
@ -134,6 +134,15 @@
#if AXIS_IS_L64XX(K)
REPORT_ABSOLUTE_POS(K);
#endif
#if AXIS_IS_L64XX(U)
REPORT_ABSOLUTE_POS(U);
#endif
#if AXIS_IS_L64XX(V)
REPORT_ABSOLUTE_POS(V);
#endif
#if AXIS_IS_L64XX(W)
REPORT_ABSOLUTE_POS(W);
#endif
#if AXIS_IS_L64XX(E0)
REPORT_ABSOLUTE_POS(E0);
#endif
@ -184,7 +193,10 @@
cartes.x, cartes.y, cartes.z,
planner.get_axis_position_mm(I_AXIS),
planner.get_axis_position_mm(J_AXIS),
planner.get_axis_position_mm(K_AXIS)
planner.get_axis_position_mm(K_AXIS),
planner.get_axis_position_mm(U_AXIS),
planner.get_axis_position_mm(V_AXIS),
planner.get_axis_position_mm(W_AXIS)
);
report_all_axis_pos(from_steppers);

View File

@ -65,8 +65,8 @@ void GcodeSuite::M115() {
"PROTOCOL_VERSION:" PROTOCOL_VERSION " "
"MACHINE_TYPE:" MACHINE_NAME " "
"EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " "
#if LINEAR_AXES != XYZ
"AXIS_COUNT:" STRINGIFY(LINEAR_AXES) " "
#if NUM_AXES != XYZ
"AXIS_COUNT:" STRINGIFY(NUM_AXES) " "
#endif
#ifdef MACHINE_UUID
"UUID:" MACHINE_UUID

View File

@ -49,13 +49,16 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
if (IsRunning()
#if ENABLED(NO_MOTION_BEFORE_HOMING)
&& !homing_needed_error(
LINEAR_AXIS_GANG(
NUM_AXIS_GANG(
(parser.seen_test('X') ? _BV(X_AXIS) : 0),
| (parser.seen_test('Y') ? _BV(Y_AXIS) : 0),
| (parser.seen_test('Z') ? _BV(Z_AXIS) : 0),
| (parser.seen_test(AXIS4_NAME) ? _BV(I_AXIS) : 0),
| (parser.seen_test(AXIS5_NAME) ? _BV(J_AXIS) : 0),
| (parser.seen_test(AXIS6_NAME) ? _BV(K_AXIS) : 0))
| (parser.seen_test(AXIS6_NAME) ? _BV(K_AXIS) : 0),
| (parser.seen_test(AXIS7_NAME) ? _BV(U_AXIS) : 0),
| (parser.seen_test(AXIS8_NAME) ? _BV(V_AXIS) : 0),
| (parser.seen_test(AXIS9_NAME) ? _BV(W_AXIS) : 0))
)
#endif
) {
@ -89,7 +92,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
if (MIN_AUTORETRACT <= MAX_AUTORETRACT) {
// When M209 Autoretract is enabled, convert E-only moves to firmware retract/recover moves
if (fwretract.autoretract_enabled && parser.seen_test('E')
&& !parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))
&& !parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W))
) {
const float echange = destination.e - current_position.e;
// Is this a retract or recover move?

View File

@ -48,8 +48,8 @@
#define MIN_ARC_SEGMENT_MM MAX_ARC_SEGMENT_MM
#endif
#define ARC_LIJK_CODE(L,I,J,K) CODE_N(SUB2(LINEAR_AXES),L,I,J,K)
#define ARC_LIJKE_CODE(L,I,J,K,E) ARC_LIJK_CODE(L,I,J,K); CODE_ITEM_E(E)
#define ARC_LIJKUVW_CODE(L,I,J,K,U,V,W) CODE_N(SUB2(NUM_AXES),L,I,J,K,U,V,W)
#define ARC_LIJKUVWE_CODE(L,I,J,K,U,V,W,E) ARC_LIJKUVW_CODE(L,I,J,K,U,V,W); CODE_ITEM_E(E)
/**
* Plan an arc in 2 dimensions, with linear motion in the other axes.
@ -82,11 +82,14 @@ void plan_arc(
rt_X = cart[axis_p] - center_P,
rt_Y = cart[axis_q] - center_Q;
ARC_LIJK_CODE(
ARC_LIJKUVW_CODE(
const float start_L = current_position[axis_l],
const float start_I = current_position.i,
const float start_J = current_position.j,
const float start_K = current_position.k
const float start_K = current_position.k,
const float start_U = current_position.u,
const float start_V = current_position.v,
const float start_W = current_position.w
);
// Angle of rotation between position and target from the circle center.
@ -122,11 +125,14 @@ void plan_arc(
min_segments = CEIL((MIN_CIRCLE_SEGMENTS) * portion_of_circle); // Minimum segments for the arc
}
ARC_LIJKE_CODE(
ARC_LIJKUVWE_CODE(
float travel_L = cart[axis_l] - start_L,
float travel_I = cart.i - start_I,
float travel_J = cart.j - start_J,
float travel_K = cart.k - start_K,
float travel_U = cart.u - start_U,
float travel_V = cart.v - start_V,
float travel_W = cart.w - start_W,
float travel_E = cart.e - current_position.e
);
@ -135,30 +141,39 @@ void plan_arc(
const float total_angular = abs_angular_travel + circles * RADIANS(360), // Total rotation with all circles and remainder
part_per_circle = RADIANS(360) / total_angular; // Each circle's part of the total
ARC_LIJKE_CODE(
ARC_LIJKUVWE_CODE(
const float per_circle_L = travel_L * part_per_circle, // L movement per circle
const float per_circle_I = travel_I * part_per_circle,
const float per_circle_J = travel_J * part_per_circle,
const float per_circle_K = travel_K * part_per_circle,
const float per_circle_U = travel_U * part_per_circle,
const float per_circle_V = travel_V * part_per_circle,
const float per_circle_W = travel_W * part_per_circle,
const float per_circle_E = travel_E * part_per_circle // E movement per circle
);
xyze_pos_t temp_position = current_position;
for (uint16_t n = circles; n--;) {
ARC_LIJKE_CODE( // Destination Linear Axes
ARC_LIJKUVWE_CODE( // Destination Linear Axes
temp_position[axis_l] += per_circle_L,
temp_position.i += per_circle_I,
temp_position.j += per_circle_J,
temp_position.k += per_circle_K,
temp_position.u += per_circle_U,
temp_position.v += per_circle_V,
temp_position.w += per_circle_W,
temp_position.e += per_circle_E // Destination E axis
);
plan_arc(temp_position, offset, clockwise, 0); // Plan a single whole circle
}
ARC_LIJKE_CODE(
ARC_LIJKUVWE_CODE(
travel_L = cart[axis_l] - current_position[axis_l],
travel_I = cart.i - current_position.i,
travel_J = cart.j - current_position.j,
travel_K = cart.k - current_position.k,
travel_U = cart.u - current_position.u,
travel_V = cart.v - current_position.v,
travel_W = cart.w - current_position.w,
travel_E = cart.e - current_position.e
);
}
@ -168,11 +183,14 @@ void plan_arc(
// Return if the move is near zero
if (flat_mm < 0.0001f
GANG_N(SUB2(LINEAR_AXES),
GANG_N(SUB2(NUM_AXES),
&& travel_L < 0.0001f,
&& travel_I < 0.0001f,
&& travel_J < 0.0001f,
&& travel_K < 0.0001f
&& travel_K < 0.0001f,
&& travel_U < 0.0001f,
&& travel_V < 0.0001f,
&& travel_W < 0.0001f
)
) return;
@ -236,11 +254,14 @@ void plan_arc(
cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation
#if DISABLED(AUTO_BED_LEVELING_UBL)
ARC_LIJK_CODE(
ARC_LIJKUVW_CODE(
const float per_segment_L = proportion * travel_L / segments,
const float per_segment_I = proportion * travel_I / segments,
const float per_segment_J = proportion * travel_J / segments,
const float per_segment_K = proportion * travel_K / segments
const float per_segment_K = proportion * travel_K / segments,
const float per_segment_U = proportion * travel_U / segments,
const float per_segment_V = proportion * travel_V / segments,
const float per_segment_W = proportion * travel_W / segments
);
#endif
@ -250,11 +271,14 @@ void plan_arc(
if (tooshort) segments++;
// Initialize all linear axes and E
ARC_LIJKE_CODE(
ARC_LIJKUVWE_CODE(
raw[axis_l] = current_position[axis_l],
raw.i = current_position.i,
raw.j = current_position.j,
raw.k = current_position.k,
raw.u = current_position.u,
raw.v = current_position.v,
raw.w = current_position.w,
raw.e = current_position.e
);
@ -303,11 +327,15 @@ void plan_arc(
// Update raw location
raw[axis_p] = center_P + rvec.a;
raw[axis_q] = center_Q + rvec.b;
ARC_LIJKE_CODE(
ARC_LIJKUVWE_CODE(
#if ENABLED(AUTO_BED_LEVELING_UBL)
raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K
raw[axis_l] = start_L,
raw.i = start_I, raw.j = start_J, raw.k = start_K,
raw.u = start_U, raw.v = start_V, raw.w = start_V
#else
raw[axis_l] += per_segment_L, raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K
raw[axis_l] += per_segment_L,
raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K,
raw.u += per_segment_U, raw.v += per_segment_V, raw.w += per_segment_W
#endif
, raw.e += extruder_per_segment
);
@ -325,7 +353,11 @@ void plan_arc(
// Ensure last segment arrives at target location.
raw = cart;
#if ENABLED(AUTO_BED_LEVELING_UBL)
ARC_LIJK_CODE(raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K);
ARC_LIJKUVW_CODE(
raw[axis_l] = start_L,
raw.i = start_I, raw.j = start_J, raw.k = start_K,
raw.u = start_U, raw.v = start_V, raw.w = start_W
);
#endif
apply_motion_limits(raw);
@ -337,7 +369,11 @@ void plan_arc(
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration));
#if ENABLED(AUTO_BED_LEVELING_UBL)
ARC_LIJK_CODE(raw[axis_l] = start_L, raw.i = start_I, raw.j = start_J, raw.k = start_K);
ARC_LIJKUVW_CODE(
raw[axis_l] = start_L,
raw.i = start_I, raw.j = start_J, raw.k = start_K,
raw.u = start_U, raw.v = start_V, raw.w = start_W
);
#endif
current_position = raw;
@ -380,7 +416,7 @@ void GcodeSuite::G2_G3(const bool clockwise) {
relative_mode = true;
#endif
get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power)
get_destination_from_command(); // Get X Y [Z[I[J[K...]]]] [E] F (and set cutter power)
TERN_(SF_ARC_FIX, relative_mode = relative_mode_backup);

View File

@ -69,7 +69,7 @@
*/
void GcodeSuite::M290() {
#if ENABLED(BABYSTEP_XY)
LOOP_LINEAR_AXES(a)
LOOP_NUM_AXES(a)
if (parser.seenval(AXIS_CHAR(a)) || (a == Z_AXIS && parser.seenval('S'))) {
const float offs = constrain(parser.value_axis_units((AxisEnum)a), -2, 2);
babystep.add_mm((AxisEnum)a, offs);
@ -87,7 +87,7 @@ void GcodeSuite::M290() {
}
#endif
if (!parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K)) || parser.seen('R')) {
if (!parser.seen(NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)) || parser.seen('R')) {
SERIAL_ECHO_START();
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)

View File

@ -248,7 +248,7 @@ void GCodeParser::parse(char *p) {
case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return;
#endif
LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':, case AXIS4_NAME:, case AXIS5_NAME:, case AXIS6_NAME:)
LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':, case AXIS4_NAME:, case AXIS5_NAME:, case AXIS6_NAME:, case AXIS7_NAME:, case AXIS8_NAME:, case AXIS9_NAME:)
case 'F':
if (motion_mode_codenum < 0) return;
command_letter = 'G';

View File

@ -309,13 +309,18 @@ public:
}
static float axis_unit_factor(const AxisEnum axis) {
return (
#if HAS_EXTRUDERS
axis >= E_AXIS && volumetric_enabled ? volumetric_unit_factor : linear_unit_factor
#else
linear_unit_factor
#endif
);
if (false
|| TERN0(AXIS4_ROTATES, axis == I_AXIS)
|| TERN0(AXIS5_ROTATES, axis == J_AXIS)
|| TERN0(AXIS6_ROTATES, axis == K_AXIS)
|| TERN0(AXIS7_ROTATES, axis == U_AXIS)
|| TERN0(AXIS8_ROTATES, axis == V_AXIS)
|| TERN0(AXIS9_ROTATES, axis == W_AXIS)
) return 1.0f;
#if HAS_EXTRUDERS
if (axis >= E_AXIS && volumetric_enabled) return volumetric_unit_factor;
#endif
return linear_unit_factor;
}
static float linear_value_to_mm(const_float_t v) { return v * linear_unit_factor; }
@ -340,6 +345,13 @@ public:
#define LINEAR_UNIT(V) parser.mm_to_linear_unit(V)
#define VOLUMETRIC_UNIT(V) parser.mm_to_volumetric_unit(V)
#define I_AXIS_UNIT(V) TERN(AXIS4_ROTATES, (V), LINEAR_UNIT(V))
#define J_AXIS_UNIT(V) TERN(AXIS5_ROTATES, (V), LINEAR_UNIT(V))
#define K_AXIS_UNIT(V) TERN(AXIS6_ROTATES, (V), LINEAR_UNIT(V))
#define U_AXIS_UNIT(V) TERN(AXIS7_ROTATES, (V), LINEAR_UNIT(V))
#define V_AXIS_UNIT(V) TERN(AXIS8_ROTATES, (V), LINEAR_UNIT(V))
#define W_AXIS_UNIT(V) TERN(AXIS9_ROTATES, (V), LINEAR_UNIT(V))
static float value_linear_units() { return linear_value_to_mm(value_float()); }
static float value_axis_units(const AxisEnum axis) { return axis_value_to_mm(axis, value_float()); }
static float value_per_axis_units(const AxisEnum axis) { return per_axis_value(axis, value_float()); }

View File

@ -49,7 +49,7 @@ inline bool G38_run_probe() {
#if MULTIPLE_PROBING > 1
// Get direction of move and retract
xyz_float_t retract_mm;
LOOP_LINEAR_AXES(i) {
LOOP_NUM_AXES(i) {
const float dist = destination[i] - current_position[i];
retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1);
}
@ -119,7 +119,7 @@ void GcodeSuite::G38(const int8_t subcode) {
;
// If any axis has enough movement, do the move
LOOP_LINEAR_AXES(i)
LOOP_NUM_AXES(i)
if (ABS(destination[i] - current_position[i]) >= G38_MINIMUM_MOVE) {
if (!parser.seenval('F')) feedrate_mm_s = homing_feedrate((AxisEnum)i);
// If G38.2 fails throw an error