♻️ Refactor Linear / Logical / Distinct Axes (#21953)
* More patches supporting EXTRUDERS 0 * Extend types in prep for more axes
This commit is contained in:
		
				
					committed by
					
						
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							f5f999d7bf
						
					
				
				
					commit
					4194cdda5b
				
			@@ -321,12 +321,23 @@ void GcodeSuite::G28() {
 | 
			
		||||
 | 
			
		||||
  #else
 | 
			
		||||
 | 
			
		||||
    #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
 | 
			
		||||
 | 
			
		||||
    const bool homeZ = parser.seen_test('Z'),
 | 
			
		||||
               needX = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(X_AXIS))),
 | 
			
		||||
               needY = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(Y_AXIS))),
 | 
			
		||||
               homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'),
 | 
			
		||||
               home_all = homeX == homeY && homeX == homeZ, // All or None
 | 
			
		||||
               doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ;
 | 
			
		||||
               LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing
 | 
			
		||||
                 needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false // UNUSED
 | 
			
		||||
               ),
 | 
			
		||||
               LINEAR_AXIS_LIST( // Home each axis if needed or flagged
 | 
			
		||||
                 homeX = needX || parser.seen_test('X'),
 | 
			
		||||
                 homeY = needY || parser.seen_test('Y'),
 | 
			
		||||
                 homeZZ = homeZ // UNUSED
 | 
			
		||||
               ),
 | 
			
		||||
               // Home-all if all or none are flagged
 | 
			
		||||
               home_all = true LINEAR_AXIS_GANG(&& homeX == homeX, && homeX == homeY, && homeX == homeZ),
 | 
			
		||||
               LINEAR_AXIS_LIST(doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ);
 | 
			
		||||
 | 
			
		||||
   UNUSED(needZ);
 | 
			
		||||
   UNUSED(homeZZ);
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(HOME_Z_FIRST)
 | 
			
		||||
 | 
			
		||||
@@ -336,7 +347,7 @@ void GcodeSuite::G28() {
 | 
			
		||||
 | 
			
		||||
    const float z_homing_height = parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT;
 | 
			
		||||
 | 
			
		||||
    if (z_homing_height && (doX || doY || TERN0(Z_SAFE_HOMING, doZ))) {
 | 
			
		||||
    if (z_homing_height && (0 LINEAR_AXIS_GANG(|| doX, || doY, || TERN0(Z_SAFE_HOMING, doZ)))) {
 | 
			
		||||
      // Raise Z before homing any other axes and z is not already high enough (never lower z)
 | 
			
		||||
      if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Raise Z (before homing) by ", z_homing_height);
 | 
			
		||||
      do_z_clearance(z_homing_height);
 | 
			
		||||
@@ -469,7 +480,7 @@ void GcodeSuite::G28() {
 | 
			
		||||
    #if HAS_CURRENT_HOME(Y2)
 | 
			
		||||
      stepperY2.rms_current(tmc_save_current_Y2);
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
  #endif // HAS_HOMING_CURRENT
 | 
			
		||||
 | 
			
		||||
  ui.refresh();
 | 
			
		||||
 | 
			
		||||
@@ -490,7 +501,7 @@ void GcodeSuite::G28() {
 | 
			
		||||
    static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
 | 
			
		||||
      X_AXIS, Y_AXIS, Z_AXIS,
 | 
			
		||||
      X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS,
 | 
			
		||||
      E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS
 | 
			
		||||
      E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS
 | 
			
		||||
    };
 | 
			
		||||
    for (uint8_t j = 1; j <= L64XX::chain[0]; j++) {
 | 
			
		||||
      const uint8_t cv = L64XX::chain[j];
 | 
			
		||||
 
 | 
			
		||||
@@ -307,9 +307,11 @@ 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
 | 
			
		||||
  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;
 | 
			
		||||
  LINEAR_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
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if ENABLED(CALIBRATION_REPORTING)
 | 
			
		||||
@@ -455,7 +457,9 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
 | 
			
		||||
      // New scope for TEMPORARY_BACKLASH_CORRECTION
 | 
			
		||||
      TEMPORARY_BACKLASH_CORRECTION(all_on);
 | 
			
		||||
      TEMPORARY_BACKLASH_SMOOTHING(0.0f);
 | 
			
		||||
      const xyz_float_t move = { AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3 };
 | 
			
		||||
      const xyz_float_t move = LINEAR_AXIS_ARRAY(
 | 
			
		||||
        AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3
 | 
			
		||||
      );
 | 
			
		||||
      current_position += move; calibration_move();
 | 
			
		||||
      current_position -= move; calibration_move();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -48,10 +48,12 @@ void GcodeSuite::M425() {
 | 
			
		||||
 | 
			
		||||
  auto axis_can_calibrate = [](const uint8_t a) {
 | 
			
		||||
    switch (a) {
 | 
			
		||||
      default:
 | 
			
		||||
      case X_AXIS: return AXIS_CAN_CALIBRATE(X);
 | 
			
		||||
      case Y_AXIS: return AXIS_CAN_CALIBRATE(Y);
 | 
			
		||||
      case Z_AXIS: return AXIS_CAN_CALIBRATE(Z);
 | 
			
		||||
      default: return false;
 | 
			
		||||
      LINEAR_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)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ void GcodeSuite::M201() {
 | 
			
		||||
 | 
			
		||||
  LOOP_LOGICAL_AXES(i) {
 | 
			
		||||
    if (parser.seenval(axis_codes[i])) {
 | 
			
		||||
      const uint8_t a = (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i);
 | 
			
		||||
      const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
 | 
			
		||||
      planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -106,7 +106,7 @@ void GcodeSuite::M203() {
 | 
			
		||||
 | 
			
		||||
  LOOP_LOGICAL_AXES(i)
 | 
			
		||||
    if (parser.seenval(axis_codes[i])) {
 | 
			
		||||
      const uint8_t a = (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i);
 | 
			
		||||
      const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
 | 
			
		||||
      planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -165,17 +165,16 @@ void GcodeSuite::M205() {
 | 
			
		||||
    }
 | 
			
		||||
  #endif
 | 
			
		||||
  #if HAS_CLASSIC_JERK
 | 
			
		||||
    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 (parser.seenval('Z')) {
 | 
			
		||||
      planner.set_max_jerk(Z_AXIS, parser.value_linear_units());
 | 
			
		||||
      #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
 | 
			
		||||
        if (planner.max_jerk.z <= 0.1f)
 | 
			
		||||
          SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
 | 
			
		||||
      #endif
 | 
			
		||||
    }
 | 
			
		||||
    #if HAS_CLASSIC_E_JERK
 | 
			
		||||
      if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units());
 | 
			
		||||
    bool seenZ = false;
 | 
			
		||||
    LOGICAL_AXIS_CODE(
 | 
			
		||||
      if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()),
 | 
			
		||||
      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 HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
 | 
			
		||||
      if (seenZ && planner.max_jerk.z <= 0.1f)
 | 
			
		||||
        SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
  #endif // HAS_CLASSIC_JERK
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,12 @@
 | 
			
		||||
 | 
			
		||||
void report_M92(const bool echo=true, const int8_t e=-1) {
 | 
			
		||||
  if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' ');
 | 
			
		||||
  SERIAL_ECHOPAIR_P(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]));
 | 
			
		||||
  #if DISABLED(DISTINCT_E_FACTORS)
 | 
			
		||||
  SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_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])
 | 
			
		||||
  ));
 | 
			
		||||
  #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
 | 
			
		||||
    SERIAL_ECHOPAIR_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS]));
 | 
			
		||||
  #endif
 | 
			
		||||
  SERIAL_EOL();
 | 
			
		||||
@@ -64,25 +66,28 @@ void GcodeSuite::M92() {
 | 
			
		||||
  if (target_extruder < 0) return;
 | 
			
		||||
 | 
			
		||||
  // No arguments? Show M92 report.
 | 
			
		||||
  if (!parser.seen("XYZE" TERN_(MAGIC_NUMBERS_GCODE, "HL")))
 | 
			
		||||
    return report_M92(true, target_extruder);
 | 
			
		||||
  if (!parser.seen(
 | 
			
		||||
    LOGICAL_AXIS_GANG("E", "X", "Y", "Z")
 | 
			
		||||
    TERN_(MAGIC_NUMBERS_GCODE, "HL")
 | 
			
		||||
  )) return report_M92(true, target_extruder);
 | 
			
		||||
 | 
			
		||||
  LOOP_LOGICAL_AXES(i) {
 | 
			
		||||
    if (parser.seenval(axis_codes[i])) {
 | 
			
		||||
      if (i == E_AXIS) {
 | 
			
		||||
        const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder)));
 | 
			
		||||
        if (value < 20) {
 | 
			
		||||
          float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab.
 | 
			
		||||
          #if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK
 | 
			
		||||
            planner.max_jerk.e *= factor;
 | 
			
		||||
          #endif
 | 
			
		||||
          planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor;
 | 
			
		||||
          planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor;
 | 
			
		||||
        }
 | 
			
		||||
        planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value;
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
      if (TERN1(HAS_EXTRUDERS, i != E_AXIS))
 | 
			
		||||
        planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i);
 | 
			
		||||
      else {
 | 
			
		||||
        #if HAS_EXTRUDERS
 | 
			
		||||
          const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder)));
 | 
			
		||||
          if (value < 20) {
 | 
			
		||||
            float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab.
 | 
			
		||||
            #if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK
 | 
			
		||||
              planner.max_jerk.e *= factor;
 | 
			
		||||
            #endif
 | 
			
		||||
            planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor;
 | 
			
		||||
            planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor;
 | 
			
		||||
          }
 | 
			
		||||
          planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value;
 | 
			
		||||
        #endif
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,11 +33,13 @@
 | 
			
		||||
 * M17: Enable stepper motors
 | 
			
		||||
 */
 | 
			
		||||
void GcodeSuite::M17() {
 | 
			
		||||
  if (parser.seen("XYZE")) {
 | 
			
		||||
    if (parser.seen_test('X')) ENABLE_AXIS_X();
 | 
			
		||||
    if (parser.seen_test('Y')) ENABLE_AXIS_Y();
 | 
			
		||||
    if (parser.seen_test('Z')) ENABLE_AXIS_Z();
 | 
			
		||||
    if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers();
 | 
			
		||||
  if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) {
 | 
			
		||||
    LOGICAL_AXIS_CODE(
 | 
			
		||||
      if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(),
 | 
			
		||||
      if (parser.seen_test('X'))        ENABLE_AXIS_X(),
 | 
			
		||||
      if (parser.seen_test('Y'))        ENABLE_AXIS_Y(),
 | 
			
		||||
      if (parser.seen_test('Z'))        ENABLE_AXIS_Z()
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    LCD_MESSAGEPGM(MSG_NO_MOVE);
 | 
			
		||||
@@ -54,12 +56,14 @@ void GcodeSuite::M18_M84() {
 | 
			
		||||
    stepper_inactive_time = parser.value_millis_from_seconds();
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    if (parser.seen("XYZE")) {
 | 
			
		||||
    if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) {
 | 
			
		||||
      planner.synchronize();
 | 
			
		||||
      if (parser.seen_test('X')) DISABLE_AXIS_X();
 | 
			
		||||
      if (parser.seen_test('Y')) DISABLE_AXIS_Y();
 | 
			
		||||
      if (parser.seen_test('Z')) DISABLE_AXIS_Z();
 | 
			
		||||
      if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers();
 | 
			
		||||
      LOGICAL_AXIS_CODE(
 | 
			
		||||
        if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(),
 | 
			
		||||
        if (parser.seen_test('X'))        DISABLE_AXIS_X(),
 | 
			
		||||
        if (parser.seen_test('Y'))        DISABLE_AXIS_Y(),
 | 
			
		||||
        if (parser.seen_test('Z'))        DISABLE_AXIS_Z()
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      planner.finish_and_disable();
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ void GcodeSuite::G61(void) {
 | 
			
		||||
    SYNC_E(stored_position[slot].e);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    if (parser.seen("XYZ")) {
 | 
			
		||||
    if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z"))) {
 | 
			
		||||
      DEBUG_ECHOPAIR(STR_RESTORING_POS " S", slot);
 | 
			
		||||
      LOOP_LINEAR_AXES(i) {
 | 
			
		||||
        destination[i] = parser.seen(AXIS_CHAR(i))
 | 
			
		||||
@@ -81,10 +81,12 @@ void GcodeSuite::G61(void) {
 | 
			
		||||
      // Move to the saved position
 | 
			
		||||
      prepare_line_to_destination();
 | 
			
		||||
    }
 | 
			
		||||
    if (parser.seen_test('E')) {
 | 
			
		||||
      DEBUG_ECHOLNPAIR(STR_RESTORING_POS " S", slot, " E", current_position.e, "=>", stored_position[slot].e);
 | 
			
		||||
      SYNC_E(stored_position[slot].e);
 | 
			
		||||
    }
 | 
			
		||||
    #if HAS_EXTRUDERS
 | 
			
		||||
      if (parser.seen_test('E')) {
 | 
			
		||||
        DEBUG_ECHOLNPAIR(STR_RESTORING_POS " S", slot, " E", current_position.e, "=>", stored_position[slot].e);
 | 
			
		||||
        SYNC_E(stored_position[slot].e);
 | 
			
		||||
      }
 | 
			
		||||
    #endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  feedrate_mm_s = saved_feedrate;
 | 
			
		||||
 
 | 
			
		||||
@@ -49,13 +49,21 @@ void GcodeSuite::M122() {
 | 
			
		||||
      tmc_set_report_interval(interval);
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    if (parser.seen_test('V'))
 | 
			
		||||
      tmc_get_registers(print_axis.x, print_axis.y, print_axis.z, print_axis.e);
 | 
			
		||||
    else
 | 
			
		||||
      tmc_report_all(print_axis.x, print_axis.y, print_axis.z, print_axis.e);
 | 
			
		||||
    if (parser.seen_test('V')) {
 | 
			
		||||
      tmc_get_registers(
 | 
			
		||||
        LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      tmc_report_all(
 | 
			
		||||
        LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  test_tmc_connection(print_axis.x, print_axis.y, print_axis.z, print_axis.e);
 | 
			
		||||
  test_tmc_connection(
 | 
			
		||||
    LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z)
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // HAS_TRINAMIC_CONFIG
 | 
			
		||||
 
 | 
			
		||||
@@ -74,11 +74,11 @@ millis_t GcodeSuite::previous_move_ms = 0,
 | 
			
		||||
 | 
			
		||||
// Relative motion mode for each logical axis
 | 
			
		||||
static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES;
 | 
			
		||||
uint8_t GcodeSuite::axis_relative = (
 | 
			
		||||
    (ar_init.x ? _BV(REL_X) : 0)
 | 
			
		||||
  | (ar_init.y ? _BV(REL_Y) : 0)
 | 
			
		||||
  | (ar_init.z ? _BV(REL_Z) : 0)
 | 
			
		||||
  | (ar_init.e ? _BV(REL_E) : 0)
 | 
			
		||||
uint8_t GcodeSuite::axis_relative = 0 LOGICAL_AXIS_GANG(
 | 
			
		||||
  | (ar_init.e << REL_E),
 | 
			
		||||
  | (ar_init.x << REL_X),
 | 
			
		||||
  | (ar_init.y << REL_Y),
 | 
			
		||||
  | (ar_init.z << REL_Z)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE)
 | 
			
		||||
@@ -161,13 +161,15 @@ void GcodeSuite::get_destination_from_command() {
 | 
			
		||||
      destination[i] = current_position[i];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get new E position, whether absolute or relative
 | 
			
		||||
  if ( (seen.e = parser.seenval('E')) ) {
 | 
			
		||||
    const float v = parser.value_axis_units(E_AXIS);
 | 
			
		||||
    destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    destination.e = current_position.e;
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    // Get new E position, whether absolute or relative
 | 
			
		||||
    if ( (seen.e = parser.seenval('E')) ) {
 | 
			
		||||
      const float v = parser.value_axis_units(E_AXIS);
 | 
			
		||||
      destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      destination.e = current_position.e;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS)
 | 
			
		||||
    // Only update power loss recovery on moves with E
 | 
			
		||||
 
 | 
			
		||||
@@ -314,7 +314,12 @@
 | 
			
		||||
  #define HAS_FAST_MOVES 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum AxisRelative : uint8_t { REL_X, REL_Y, REL_Z, REL_E, E_MODE_ABS, E_MODE_REL };
 | 
			
		||||
enum AxisRelative : uint8_t {
 | 
			
		||||
  LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z)
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    , E_MODE_ABS, E_MODE_REL
 | 
			
		||||
  #endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const char G28_STR[];
 | 
			
		||||
 | 
			
		||||
@@ -324,23 +329,27 @@ public:
 | 
			
		||||
  static uint8_t axis_relative;
 | 
			
		||||
 | 
			
		||||
  static inline bool axis_is_relative(const AxisEnum a) {
 | 
			
		||||
    if (a == E_AXIS) {
 | 
			
		||||
      if (TEST(axis_relative, E_MODE_REL)) return true;
 | 
			
		||||
      if (TEST(axis_relative, E_MODE_ABS)) return false;
 | 
			
		||||
    }
 | 
			
		||||
    #if HAS_EXTRUDERS
 | 
			
		||||
      if (a == E_AXIS) {
 | 
			
		||||
        if (TEST(axis_relative, E_MODE_REL)) return true;
 | 
			
		||||
        if (TEST(axis_relative, E_MODE_ABS)) return false;
 | 
			
		||||
      }
 | 
			
		||||
    #endif
 | 
			
		||||
    return TEST(axis_relative, a);
 | 
			
		||||
  }
 | 
			
		||||
  static inline void set_relative_mode(const bool rel) {
 | 
			
		||||
    axis_relative = rel ? _BV(REL_X) | _BV(REL_Y) | _BV(REL_Z) | _BV(REL_E) : 0;
 | 
			
		||||
  }
 | 
			
		||||
  static inline void set_e_relative() {
 | 
			
		||||
    CBI(axis_relative, E_MODE_ABS);
 | 
			
		||||
    SBI(axis_relative, E_MODE_REL);
 | 
			
		||||
  }
 | 
			
		||||
  static inline void set_e_absolute() {
 | 
			
		||||
    CBI(axis_relative, E_MODE_REL);
 | 
			
		||||
    SBI(axis_relative, E_MODE_ABS);
 | 
			
		||||
    axis_relative = rel ? (0 LOGICAL_AXIS_GANG(| _BV(REL_E), | _BV(REL_X), | _BV(REL_Y), | _BV(REL_Z))) : 0;
 | 
			
		||||
  }
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    static inline void set_e_relative() {
 | 
			
		||||
      CBI(axis_relative, E_MODE_ABS);
 | 
			
		||||
      SBI(axis_relative, E_MODE_REL);
 | 
			
		||||
    }
 | 
			
		||||
    static inline void set_e_absolute() {
 | 
			
		||||
      CBI(axis_relative, E_MODE_REL);
 | 
			
		||||
      SBI(axis_relative, E_MODE_ABS);
 | 
			
		||||
    }
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(CNC_WORKSPACE_PLANES)
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,10 @@
 | 
			
		||||
 */
 | 
			
		||||
void GcodeSuite::G92() {
 | 
			
		||||
 | 
			
		||||
  bool sync_E = false, sync_XYZE = false;
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    bool sync_E = false;
 | 
			
		||||
  #endif
 | 
			
		||||
  bool sync_XYZE = false;
 | 
			
		||||
 | 
			
		||||
  #if USE_GCODE_SUBCODES
 | 
			
		||||
    const uint8_t subcode_G92 = parser.subcode;
 | 
			
		||||
@@ -72,7 +75,11 @@ void GcodeSuite::G92() {
 | 
			
		||||
      case 9:                                                         // G92.9 - Set Current Position directly (like Marlin 1.0)
 | 
			
		||||
        LOOP_LOGICAL_AXES(i) {
 | 
			
		||||
          if (parser.seenval(axis_codes[i])) {
 | 
			
		||||
            if (i == E_AXIS) sync_E = true; else sync_XYZE = true;
 | 
			
		||||
            if (TERN1(HAS_EXTRUDERS, i != E_AXIS))
 | 
			
		||||
              sync_XYZE = true;
 | 
			
		||||
            else {
 | 
			
		||||
              TERN_(HAS_EXTRUDERS, sync_E = true);
 | 
			
		||||
            }
 | 
			
		||||
            current_position[i] = parser.value_axis_units((AxisEnum)i);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
@@ -83,20 +90,26 @@ void GcodeSuite::G92() {
 | 
			
		||||
      LOOP_LOGICAL_AXES(i) {
 | 
			
		||||
        if (parser.seenval(axis_codes[i])) {
 | 
			
		||||
          const float l = parser.value_axis_units((AxisEnum)i),       // Given axis coordinate value, converted to millimeters
 | 
			
		||||
                      v = i == E_AXIS ? l : LOGICAL_TO_NATIVE(l, i),  // Axis position in NATIVE space (applying the existing offset)
 | 
			
		||||
                      v = TERN0(HAS_EXTRUDERS, i == E_AXIS) ? l : LOGICAL_TO_NATIVE(l, i),  // Axis position in NATIVE space (applying the existing offset)
 | 
			
		||||
                      d = v - current_position[i];                    // How much is the current axis position altered by?
 | 
			
		||||
          if (!NEAR_ZERO(d)) {
 | 
			
		||||
            #if HAS_POSITION_SHIFT && !IS_SCARA                       // When using workspaces...
 | 
			
		||||
              if (i == E_AXIS) {
 | 
			
		||||
                sync_E = true;
 | 
			
		||||
                current_position.e = v;                               // ...E is still set directly
 | 
			
		||||
              }
 | 
			
		||||
              else {
 | 
			
		||||
                position_shift[i] += d;                               // ...but other axes offset the workspace.
 | 
			
		||||
              if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) {
 | 
			
		||||
                position_shift[i] += d;                               // ...most axes offset the workspace...
 | 
			
		||||
                update_workspace_offset((AxisEnum)i);
 | 
			
		||||
              }
 | 
			
		||||
              else {
 | 
			
		||||
                #if HAS_EXTRUDERS
 | 
			
		||||
                  sync_E = true;
 | 
			
		||||
                  current_position.e = v;                             // ...but E is set directly
 | 
			
		||||
                #endif
 | 
			
		||||
              }
 | 
			
		||||
            #else                                                     // Without workspaces...
 | 
			
		||||
              if (i == E_AXIS) sync_E = true; else sync_XYZE = true;
 | 
			
		||||
              if (TERN1(HAS_EXTRUDERS, i != E_AXIS))
 | 
			
		||||
                sync_XYZE = true;
 | 
			
		||||
              else {
 | 
			
		||||
                TERN_(HAS_EXTRUDERS, sync_E = true);
 | 
			
		||||
              }
 | 
			
		||||
              current_position[i] = v;                                // ...set Current Position directly (like Marlin 1.0)
 | 
			
		||||
            #endif
 | 
			
		||||
          }
 | 
			
		||||
@@ -111,8 +124,10 @@ void GcodeSuite::G92() {
 | 
			
		||||
      coordinate_system[active_coordinate_system] = position_shift;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  if   (sync_XYZE) sync_plan_position();
 | 
			
		||||
  else if (sync_E) sync_plan_position_e();
 | 
			
		||||
  if (sync_XYZE) sync_plan_position();
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    else if (sync_E) sync_plan_position_e();
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  IF_DISABLED(DIRECT_STEPPING, report_current_position());
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -170,7 +170,7 @@
 | 
			
		||||
 | 
			
		||||
    SERIAL_ECHOPGM("FromStp:");
 | 
			
		||||
    get_cartesian_from_steppers();  // writes 'cartes' (with forward kinematics)
 | 
			
		||||
    xyze_pos_t from_steppers = { cartes.x, cartes.y, cartes.z, planner.get_axis_position_mm(E_AXIS) };
 | 
			
		||||
    xyze_pos_t from_steppers = LOGICAL_AXIS_ARRAY(planner.get_axis_position_mm(E_AXIS), cartes.x, cartes.y, cartes.z);
 | 
			
		||||
    report_all_axis_pos(from_steppers);
 | 
			
		||||
 | 
			
		||||
    const xyze_float_t diff = from_steppers - leveled;
 | 
			
		||||
 
 | 
			
		||||
@@ -49,9 +49,11 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
 | 
			
		||||
  if (IsRunning()
 | 
			
		||||
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
 | 
			
		||||
      && !homing_needed_error(
 | 
			
		||||
          (parser.seen_test('X') ? _BV(X_AXIS) : 0)
 | 
			
		||||
        | (parser.seen_test('Y') ? _BV(Y_AXIS) : 0)
 | 
			
		||||
        | (parser.seen_test('Z') ? _BV(Z_AXIS) : 0) )
 | 
			
		||||
        LINEAR_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))
 | 
			
		||||
      )
 | 
			
		||||
    #endif
 | 
			
		||||
  ) {
 | 
			
		||||
    TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING));
 | 
			
		||||
@@ -83,7 +85,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('E') && !parser.seen("XYZ")) {
 | 
			
		||||
        if (fwretract.autoretract_enabled && parser.seen_test('E') && !parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z"))) {
 | 
			
		||||
          const float echange = destination.e - current_position.e;
 | 
			
		||||
          // Is this a retract or recover move?
 | 
			
		||||
          if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -109,23 +109,32 @@ void plan_arc(
 | 
			
		||||
    #endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  float linear_travel = cart[l_axis] - start_L,
 | 
			
		||||
        extruder_travel = cart.e - current_position.e;
 | 
			
		||||
  float linear_travel = cart[l_axis] - start_L;
 | 
			
		||||
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    float extruder_travel = cart.e - current_position.e;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  // If circling around...
 | 
			
		||||
  if (ENABLED(ARC_P_CIRCLES) && circles) {
 | 
			
		||||
    const float total_angular = 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
 | 
			
		||||
                 l_per_circle = linear_travel * part_per_circle,          // L movement per circle
 | 
			
		||||
                 e_per_circle = extruder_travel * part_per_circle;        // E movement per circle
 | 
			
		||||
                 l_per_circle = linear_travel * part_per_circle;          // L movement per circle
 | 
			
		||||
 | 
			
		||||
    #if HAS_EXTRUDERS
 | 
			
		||||
      const float e_per_circle = extruder_travel * part_per_circle;       // E movement per circle
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    xyze_pos_t temp_position = current_position;                          // for plan_arc to compare to current_position
 | 
			
		||||
    for (uint16_t n = circles; n--;) {
 | 
			
		||||
      temp_position.e += e_per_circle;                                    // Destination E axis
 | 
			
		||||
      TERN_(HAS_EXTRUDERS, temp_position.e += e_per_circle);              // Destination E axis
 | 
			
		||||
      temp_position[l_axis] += l_per_circle;                              // Destination L axis
 | 
			
		||||
      plan_arc(temp_position, offset, clockwise, 0);                      // Plan a single whole circle
 | 
			
		||||
    }
 | 
			
		||||
    linear_travel = cart[l_axis] - current_position[l_axis];
 | 
			
		||||
    extruder_travel = cart.e - current_position.e;
 | 
			
		||||
    #if HAS_EXTRUDERS
 | 
			
		||||
      extruder_travel = cart.e - current_position.e;
 | 
			
		||||
    #endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const float flat_mm = radius * angular_travel,
 | 
			
		||||
@@ -179,16 +188,19 @@ void plan_arc(
 | 
			
		||||
  xyze_pos_t raw;
 | 
			
		||||
  const float theta_per_segment = angular_travel / segments,
 | 
			
		||||
              linear_per_segment = linear_travel / segments,
 | 
			
		||||
              extruder_per_segment = extruder_travel / segments,
 | 
			
		||||
              sq_theta_per_segment = sq(theta_per_segment),
 | 
			
		||||
              sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6,
 | 
			
		||||
              cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation
 | 
			
		||||
 | 
			
		||||
  #if HAS_EXTRUDERS
 | 
			
		||||
    const float extruder_per_segment = extruder_travel / segments;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  // Initialize the linear axis
 | 
			
		||||
  raw[l_axis] = current_position[l_axis];
 | 
			
		||||
 | 
			
		||||
  // Initialize the extruder axis
 | 
			
		||||
  raw.e = current_position.e;
 | 
			
		||||
  TERN_(HAS_EXTRUDERS, raw.e = current_position.e);
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(SCARA_FEEDRATE_SCALING)
 | 
			
		||||
    const float inv_duration = scaled_fr_mm_s / seg_length;
 | 
			
		||||
@@ -240,7 +252,8 @@ void plan_arc(
 | 
			
		||||
    #else
 | 
			
		||||
      raw[l_axis] += linear_per_segment;
 | 
			
		||||
    #endif
 | 
			
		||||
    raw.e += extruder_per_segment;
 | 
			
		||||
 | 
			
		||||
    TERN_(HAS_EXTRUDERS, raw.e += extruder_per_segment);
 | 
			
		||||
 | 
			
		||||
    apply_motion_limits(raw);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ void GcodeSuite::M290() {
 | 
			
		||||
    }
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  if (!parser.seen("XYZ") || parser.seen('R')) {
 | 
			
		||||
  if (!parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z")) || parser.seen('R')) {
 | 
			
		||||
    SERIAL_ECHO_START();
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
 | 
			
		||||
 
 | 
			
		||||
@@ -248,7 +248,8 @@ void GCodeParser::parse(char *p) {
 | 
			
		||||
        case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return;
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      case 'X' ... 'Z': case 'E' ... 'F':
 | 
			
		||||
      LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':)
 | 
			
		||||
      case 'F':
 | 
			
		||||
        if (motion_mode_codenum < 0) return;
 | 
			
		||||
        command_letter = 'G';
 | 
			
		||||
        codenum = motion_mode_codenum;
 | 
			
		||||
 
 | 
			
		||||
@@ -226,7 +226,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  // Seen any axis parameter
 | 
			
		||||
  static inline bool seen_axis() {
 | 
			
		||||
    return seen("XYZE");
 | 
			
		||||
    return seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(GCODE_QUOTED_STRINGS)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user