From 55b5971739a517f2c86abdcc4fb0ccb21385f84f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 18 Feb 2026 07:45:22 -0600 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Motion=20encapsulation=20(?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/MarlinCore.cpp | 4 +- Marlin/src/feature/pause.cpp | 24 +- Marlin/src/feature/runout.h | 4 +- Marlin/src/gcode/bedlevel/G35.cpp | 2 +- Marlin/src/gcode/bedlevel/G42.cpp | 2 +- Marlin/src/gcode/bedlevel/abl/G29.cpp | 12 +- Marlin/src/gcode/calibrate/G28.cpp | 67 ++--- Marlin/src/gcode/calibrate/G34_M422.cpp | 2 +- Marlin/src/gcode/calibrate/G425.cpp | 15 +- Marlin/src/gcode/config/M218.cpp | 12 +- Marlin/src/gcode/control/M605.cpp | 60 ++--- Marlin/src/gcode/feature/pause/M125.cpp | 2 +- Marlin/src/gcode/feature/pause/M600.cpp | 6 +- Marlin/src/gcode/geometry/M206_M428.cpp | 4 +- Marlin/src/gcode/motion/G0_G1.cpp | 2 +- Marlin/src/gcode/motion/G2_G3.cpp | 2 +- Marlin/src/gcode/motion/G5.cpp | 2 +- Marlin/src/gcode/motion/M290.cpp | 10 +- Marlin/src/gcode/probe/G38.cpp | 2 +- Marlin/src/gcode/temp/M104_M109.cpp | 4 +- Marlin/src/gcode/temp/M106_M107.cpp | 4 +- Marlin/src/inc/Conditionals-3-etc.h | 1 + Marlin/src/lcd/extui/ui_api.cpp | 18 +- Marlin/src/lcd/menu/menu.cpp | 6 +- Marlin/src/lcd/menu/menu_bed_tramming.cpp | 2 +- Marlin/src/lcd/menu/menu_configuration.cpp | 10 +- Marlin/src/lcd/menu/menu_motion.cpp | 6 +- Marlin/src/lcd/tft/ui_common.cpp | 4 +- Marlin/src/module/delta.cpp | 44 ++-- Marlin/src/module/motion.cpp | 163 +++++++----- Marlin/src/module/motion.h | 273 ++++++++++++--------- Marlin/src/module/planner.cpp | 2 +- Marlin/src/module/probe.cpp | 18 +- Marlin/src/module/scara.cpp | 18 +- Marlin/src/module/settings.cpp | 6 +- Marlin/src/module/stepper.cpp | 4 +- Marlin/src/module/stepper/indirection.h | 10 +- Marlin/src/module/tool_change.cpp | 49 ++-- 38 files changed, 448 insertions(+), 428 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 2eca094371..0d16b4ab59 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -732,9 +732,9 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) { #if ENABLED(DUAL_X_CARRIAGE) // handle delayed move timeout - if (delayed_move_time && ELAPSED(ms, delayed_move_time) && isRunning()) { + if (motion.delayed_move_time && ELAPSED(ms, motion.delayed_move_time) && isRunning()) { // travel moves have been received so enact them - delayed_move_time = UINT32_MAX; // force moves to be done + motion.delayed_move_time = UINT32_MAX; // force moves to be done motion.destination = motion.position; motion.prepare_line_to_destination(); planner.synchronize(); diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 1a188ca169..8027726e0c 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -235,8 +235,8 @@ bool load_filament(const float slow_load_length/*=0*/, const float fast_load_len #if ENABLED(DUAL_X_CARRIAGE) const int8_t saved_ext = motion.extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); + const bool saved_ext_dup_mode = motion.extruder_duplication; + motion.set_extruder_duplication(false, DXC_ext); #endif TERN_(BELTPRINTER, motion.blocking_move_xy(0.00, 50.00)); @@ -261,7 +261,7 @@ bool load_filament(const float slow_load_length/*=0*/, const float fast_load_len } #if ENABLED(DUAL_X_CARRIAGE) // Tie the two extruders movement back together. - set_duplication_enabled(saved_ext_dup_mode, saved_ext); + motion.set_extruder_duplication(saved_ext_dup_mode, saved_ext); #endif #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE) @@ -485,15 +485,15 @@ bool pause_print(const float retract, const xyz_pos_t &park_point, const bool sh #if ENABLED(DUAL_X_CARRIAGE) const int8_t saved_ext = motion.extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); + const bool saved_ext_dup_mode = motion.extruder_duplication; + motion.set_extruder_duplication(false, DXC_ext); #endif // Unload the filament, if specified if (unload_length) unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); - TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); + TERN_(DUAL_X_CARRIAGE, motion.set_extruder_duplication(saved_ext_dup_mode, saved_ext)); // Disable the Extruder for manual change disable_active_extruder(); @@ -545,8 +545,8 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep #if ENABLED(DUAL_X_CARRIAGE) const int8_t saved_ext = motion.extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); + const bool saved_ext_dup_mode = motion.extruder_duplication; + motion.set_extruder_duplication(false, DXC_ext); #endif // Wait for filament insert by user and press button @@ -613,7 +613,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep } marlin.idle_no_sleep(); } - TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); + TERN_(DUAL_X_CARRIAGE, motion.set_extruder_duplication(saved_ext_dup_mode, saved_ext)); } /** @@ -660,9 +660,9 @@ void resume_print( /* SERIAL_ECHOLNPGM( - "start of resume_print()\ndual_x_carriage_mode:", dual_x_carriage_mode, - "\nextruder_duplication_enabled:", extruder_duplication_enabled, - "\nactive_extruder:", motion.extruder, + "start of resume_print()\ndual_x_carriage_mode:", motion.idex_mode, + "\nmotion.extruder_duplication:", motion.extruder_duplication, + "\nmotion.extruder:", motion.extruder, "\n" ); //*/ diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index dec89c3791..5417fbd19d 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -303,8 +303,8 @@ class FilamentSensorBase { static bool poll_runout_state(const uint8_t extruder) { const uint8_t runout_states = poll_runout_states(); #if MULTI_FILAMENT_SENSOR - if ( !TERN0(DUAL_X_CARRIAGE, idex_is_duplicating()) - && !TERN0(MULTI_NOZZLE_DUPLICATION, extruder_duplication_enabled) + if ( !TERN0(DUAL_X_CARRIAGE, motion.idex_is_duplicating()) + && !TERN0(MULTI_NOZZLE_DUPLICATION, motion.extruder_duplication) ) return TEST(runout_states, extruder); // A specific extruder ran out #else UNUSED(extruder); diff --git a/Marlin/src/gcode/bedlevel/G35.cpp b/Marlin/src/gcode/bedlevel/G35.cpp index 0c9c4651e3..dd9553b508 100644 --- a/Marlin/src/gcode/bedlevel/G35.cpp +++ b/Marlin/src/gcode/bedlevel/G35.cpp @@ -84,7 +84,7 @@ void GcodeSuite::G35() { probe.use_probing_tool(); // Disable duplication mode on homing - TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); + TERN_(HAS_DUPLICATION_MODE, motion.set_extruder_duplication(false)); // Home only Z axis when X and Y is trusted, otherwise all axes, if needed before this procedure if (!motion.all_axes_trusted()) process_subcommands_now(F("G28Z")); diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index dec0ee2b5f..8383dd1a8d 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -42,7 +42,7 @@ * P : Flag to put the probe at the given point */ void GcodeSuite::G42() { - if (!MOTION_CONDITIONS) return; + if (motion.gcode_motion_ignored()) return; const bool hasI = parser.seenval('I'); const int8_t ix = hasI ? parser.value_int() : 0; diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 7cc821408c..0830725170 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -395,14 +395,16 @@ G29_TYPE GcodeSuite::G29() { #endif - #if ABL_USES_GRID - + #if HAS_VARIABLE_XY_PROBE_FEEDRATE constexpr feedRate_t min_probe_feedrate_mm_s = XY_PROBE_FEEDRATE_MIN; - xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_FEEDRATE)); - if (xy_probe_feedrate_mm_s < min_probe_feedrate_mm_s) { - xy_probe_feedrate_mm_s = min_probe_feedrate_mm_s; + motion.xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_FEEDRATE)); + if (motion.xy_probe_feedrate_mm_s < min_probe_feedrate_mm_s) { + motion.xy_probe_feedrate_mm_s = min_probe_feedrate_mm_s; SERIAL_ECHOLNPGM(GCODE_ERR_MSG("Feedrate (S) too low. (Using ", min_probe_feedrate_mm_s, ")")); } + #endif + + #if ABL_USES_GRID const float x_min = probe.min_x(), x_max = probe.max_x(), y_min = probe.min_y(), y_max = probe.max_y(); diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 97aa17c3f0..320d3434e8 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -81,16 +81,16 @@ motion.position.set(0.0, 0.0); motion.sync_plan_position(); - const int x_axis_home_dir = TOOL_X_HOME_DIR(motion.extruder); + const int x_axis_home_dir = motion.tool_x_home_dir(); // Use a higher diagonal feedrate so axes move at homing speed const float minfr = _MIN(motion.homing_feedrate(X_AXIS), motion.homing_feedrate(Y_AXIS)), fr_mm_s = HYPOT(minfr, minfr); // Set homing current to X and Y axis if defined - TERN_(X_HAS_HOME_CURRENT, set_homing_current(X_AXIS)); + TERN_(X_HAS_HOME_CURRENT, motion.set_homing_current(X_AXIS)); #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) - set_homing_current(Y_AXIS); + motion.set_homing_current(Y_AXIS); #endif #if ENABLED(SENSORLESS_HOMING) @@ -105,15 +105,15 @@ }; #endif - motion.blocking_move_xy(1.5 * max_length(X_AXIS) * x_axis_home_dir, 1.5 * max_length(Y_AXIS) * Y_HOME_DIR, fr_mm_s); + motion.blocking_move_xy(1.5 * motion.max_axis_length(X_AXIS) * x_axis_home_dir, 1.5 * motion.max_axis_length(Y_AXIS) * Y_HOME_DIR, fr_mm_s); endstops.validate_homing_move(); motion.position.set(0.0, 0.0); - TERN_(X_HAS_HOME_CURRENT, restore_homing_current(X_AXIS)); + TERN_(X_HAS_HOME_CURRENT, motion.restore_homing_current(X_AXIS)); #if Y_HAS_HOME_CURRENT && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) - restore_homing_current(Y_AXIS); + motion.restore_homing_current(Y_AXIS); #endif #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) @@ -153,7 +153,7 @@ if (DEBUGGING(LEVELING)) DEBUG_POS("home_z_safely", motion.destination); // Free the active extruder for movement - TERN_(DUAL_X_CARRIAGE, idex_set_parked(false)); + TERN_(DUAL_X_CARRIAGE, motion.idex_set_parked(false)); TERN_(SENSORLESS_HOMING, safe_delay(500)); // Short delay needed to settle @@ -264,8 +264,8 @@ void GcodeSuite::G28() { #if NUM_AXES #if ENABLED(DUAL_X_CARRIAGE) - bool IDEX_saved_duplication_state = extruder_duplication_enabled; - DualXMode IDEX_saved_mode = dual_x_carriage_mode; + bool IDEX_saved_duplication_state = motion.extruder_duplication; + DualXMode IDEX_saved_mode = motion.idex_mode; #endif motion.set_soft_endstop_loose(false); // Reset a leftover 'loose' motion state @@ -304,7 +304,7 @@ void GcodeSuite::G28() { tool_change(0, true); #endif - TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); + TERN_(HAS_DUPLICATION_MODE, motion.set_extruder_duplication(false)); motion.remember_feedrate_scaling_off(); @@ -415,27 +415,10 @@ void GcodeSuite::G28() { // Home X #if HAS_X_AXIS if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) { - #if ENABLED(DUAL_X_CARRIAGE) - - // Always home the 2nd (right) extruder first - motion.extruder = 1; - motion.homeaxis(X_AXIS); - - // Remember this extruder's position for later tool change - inactive_extruder_x = motion.position.x; - - // Home the 1st (left) extruder - motion.extruder = 0; - motion.homeaxis(X_AXIS); - - // Consider the active extruder to be in its "parked" position - idex_set_parked(); - + motion.idex_home_x(); #else - motion.homeaxis(X_AXIS); - #endif } #endif // HAS_X_AXIS @@ -502,7 +485,7 @@ void GcodeSuite::G28() { motion.sync_plan_position(); - #endif + #endif // !DELTA && !AXEL_TPARA /** * Preserve DXC mode across a G28 for IDEX printers in DXC_DUPLICATION_MODE. @@ -511,31 +494,13 @@ void GcodeSuite::G28() { * IDEX specific commands in it. */ #if ENABLED(DUAL_X_CARRIAGE) - - if (idex_is_duplicating()) { - + if (motion.idex_is_duplicating()) { TERN_(IMPROVE_HOMING_RELIABILITY, saved_motion_state = begin_slow_homing()); - - // Always home the 2nd (right) extruder first - motion.extruder = 1; - motion.homeaxis(X_AXIS); - - // Remember this extruder's position for later tool change - inactive_extruder_x = motion.position.x; - - // Home the 1st (left) extruder - motion.extruder = 0; - motion.homeaxis(X_AXIS); - - // Consider the active extruder to be parked - idex_set_parked(); - - dual_x_carriage_mode = IDEX_saved_mode; - set_duplication_enabled(IDEX_saved_duplication_state); - + motion.idex_home_x(); + motion.idex_mode = IDEX_saved_mode; + motion.set_extruder_duplication(IDEX_saved_duplication_state); TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); } - #endif // DUAL_X_CARRIAGE endstops.not_homing(); diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index a4544db1fb..d84b84031c 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -148,7 +148,7 @@ void GcodeSuite::G34() { gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G34)); #endif - TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); + TERN_(HAS_DUPLICATION_MODE, motion.set_extruder_duplication(false)); // Compute a worst-case clearance height to probe from. After the first // iteration this will be re-calculated based on the actual bed position diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index 177d99a05a..69ebba7bd3 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -177,8 +177,8 @@ inline void park_above_object(measurements_t &m, const float uncertainty) { inline void normalize_hotend_offsets() { for (uint8_t e = 1; e < HOTENDS; ++e) - hotend_offset[e] -= hotend_offset[0]; - hotend_offset[0].reset(); + motion.hotend_offset[e] -= motion.hotend_offset[0]; + motion.hotend_offset[0].reset(); } #endif @@ -568,7 +568,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // inline void report_hotend_offsets() { for (uint8_t e = 1; e < HOTENDS; ++e) - SERIAL_ECHOLNPGM_P(PSTR("T"), e, PSTR(" Hotend Offset X"), hotend_offset[e].x, SP_Y_STR, hotend_offset[e].y, SP_Z_STR, hotend_offset[e].z); + SERIAL_ECHOLNPGM_P(PSTR("T"), e, PSTR(" Hotend Offset X"), motion.hotend_offset[e].x, SP_Y_STR, motion.hotend_offset[e].y, SP_Z_STR, motion.hotend_offset[e].z); } #endif @@ -706,9 +706,10 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const // Adjust the hotend offset #if HAS_HOTEND_OFFSET - if (ENABLED(HAS_X_CENTER) && AXIS_CAN_CALIBRATE(X)) hotend_offset[extruder].x += m.pos_error.x; - if (ENABLED(HAS_Y_CENTER) && AXIS_CAN_CALIBRATE(Y)) hotend_offset[extruder].y += m.pos_error.y; - if (AXIS_CAN_CALIBRATE(Z)) hotend_offset[extruder].z += m.pos_error.z; + xyz_pos_t &hotoff = motion.active_hotend_offset(); + if (ENABLED(HAS_X_CENTER) && AXIS_CAN_CALIBRATE(X)) hotoff.x += m.pos_error.x; + if (ENABLED(HAS_Y_CENTER) && AXIS_CAN_CALIBRATE(Y)) hotoff.y += m.pos_error.y; + if (AXIS_CAN_CALIBRATE(Z)) hotoff.z += m.pos_error.z; normalize_hotend_offsets(); #endif @@ -761,7 +762,7 @@ inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty) inline void calibrate_all() { measurements_t m; - TERN_(HAS_HOTEND_OFFSET, reset_hotend_offsets()); + TERN_(HAS_HOTEND_OFFSET, motion.reset_hotend_offsets()); TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp index 69bb89d74c..85563dfee0 100644 --- a/Marlin/src/gcode/config/M218.cpp +++ b/Marlin/src/gcode/config/M218.cpp @@ -47,13 +47,13 @@ void GcodeSuite::M218() { if (target_extruder < 0) return; #if HAS_X_AXIS - if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units(); + if (parser.seenval('X')) motion.hotend_offset[target_extruder].x = parser.value_linear_units(); #endif #if HAS_Y_AXIS - if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units(); + if (parser.seenval('Y')) motion.hotend_offset[target_extruder].y = parser.value_linear_units(); #endif #if HAS_Z_AXIS - if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units(); + if (parser.seenval('Z')) motion.hotend_offset[target_extruder].z = parser.value_linear_units(); #endif #if ENABLED(DELTA) @@ -70,9 +70,9 @@ void GcodeSuite::M218_report(const bool forReplay/*=true*/) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M218 T"), e, - SP_X_STR, LINEAR_UNIT(hotend_offset[e].x), - SP_Y_STR, LINEAR_UNIT(hotend_offset[e].y), - SP_Z_STR, p_float_t(LINEAR_UNIT(hotend_offset[e].z), 3) + SP_X_STR, LINEAR_UNIT(motion.hotend_offset[e].x), + SP_Y_STR, LINEAR_UNIT(motion.hotend_offset[e].y), + SP_Z_STR, p_float_t(LINEAR_UNIT(motion.hotend_offset[e].z), 3) ); } } diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index f5d514bd3f..8a4a7712b0 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -64,12 +64,12 @@ planner.synchronize(); if (parser.seenval('S')) { - const DualXMode previous_mode = dual_x_carriage_mode; + const DualXMode previous_mode = motion.idex_mode; - dual_x_carriage_mode = (DualXMode)parser.value_byte(); - idex_set_mirrored_mode(false); + motion.idex_mode = (DualXMode)parser.value_byte(); + motion.idex_set_mirrored_mode(false); - switch (dual_x_carriage_mode) { + switch (motion.idex_mode) { case DXC_FULL_CONTROL_MODE: case DXC_AUTO_PARK_MODE: @@ -77,8 +77,8 @@ case DXC_DUPLICATION_MODE: // Set the X offset, but no less than the safety gap - if (parser.seenval('X')) duplicate_extruder_x_offset = _MAX(parser.value_linear_units(), (X2_MIN_POS) - (X1_MIN_POS)); - if (parser.seenval('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff(); + if (parser.seenval('X')) motion.duplicate_extruder_x_offset = _MAX(parser.value_linear_units(), (X2_MIN_POS) - (X1_MIN_POS)); + if (parser.seenval('R')) motion.duplicate_extruder_temp_offset = parser.value_celsius_diff(); // Always switch back to tool 0 if (motion.extruder != 0) tool_change(0); break; @@ -87,10 +87,10 @@ if (previous_mode != DXC_DUPLICATION_MODE) { SERIAL_ECHOLNPGM("Printer must be in DXC_DUPLICATION_MODE prior to "); SERIAL_ECHOLNPGM("specifying DXC_MIRRORED_MODE."); - dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + motion.idex_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; return; } - idex_set_mirrored_mode(true); + motion.idex_set_mirrored_mode(true); // Do a small 'jog' motion in the X axis xyze_pos_t dest = motion.position; dest.x -= 0.1f; @@ -101,50 +101,50 @@ } return; default: - dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + motion.idex_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; break; } - idex_set_parked(false); - set_duplication_enabled(false); + motion.idex_set_parked(false); + motion.set_extruder_duplication(false); #ifdef EVENT_GCODE_IDEX_AFTER_MODECHANGE process_subcommands_now(F(EVENT_GCODE_IDEX_AFTER_MODECHANGE)); #endif } else if (!parser.seen('W')) // if no S or W parameter, the DXC mode gets reset to the user's default - dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + motion.idex_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; #if ENABLED(DEBUG_DXC_MODE) if (parser.seen('W')) { DEBUG_ECHO_START(); DEBUG_ECHOPGM("Dual X Carriage Mode "); - switch (dual_x_carriage_mode) { + switch (motion.idex_mode) { case DXC_FULL_CONTROL_MODE: DEBUG_ECHOPGM("FULL_CONTROL"); break; case DXC_AUTO_PARK_MODE: DEBUG_ECHOPGM("AUTO_PARK"); break; case DXC_DUPLICATION_MODE: DEBUG_ECHOPGM("DUPLICATION"); break; case DXC_MIRRORED_MODE: DEBUG_ECHOPGM("MIRRORED"); break; } DEBUG_ECHOPGM("\nActive Ext: ", motion.extruder); - if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT ", F(" parked.")); + if (!motion.active_extruder_parked) DEBUG_ECHOPGM(" NOT ", F(" parked.")); DEBUG_ECHOLNPGM( - "\nactive_extruder_x_pos: ", motion.position.x, - "\ninactive_extruder_x: ", inactive_extruder_x, - "\nextruder_duplication_enabled: ", extruder_duplication_enabled, - "\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset, - "\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset, - "\ndelayed_move_time: ", delayed_move_time, - "\nX1 Home: ", x_home_pos(0), " X1_MIN_POS=", X1_MIN_POS, " X1_MAX_POS=", X1_MAX_POS, - "\nX2 Home: ", x_home_pos(1), " X2_MIN_POS=", X2_MIN_POS, " X2_MAX_POS=", X2_MAX_POS, + "\nmotion.position.x: ", motion.position.x, + "\nmotion.inactive_extruder_x: ", motion.inactive_extruder_x, + "\nmotion.extruder_duplication: ", motion.extruder_duplication, + "\nmotion.duplicate_extruder_x_offset: ", motion.duplicate_extruder_x_offset, + "\nmotion.duplicate_extruder_temp_offset: ", motion.duplicate_extruder_temp_offset, + "\nmotion.delayed_move_time: ", motion.delayed_move_time, + "\nX1 Home: ", motion.x_home_pos(0), " X1_MIN_POS=", X1_MIN_POS, " X1_MAX_POS=", X1_MAX_POS, + "\nX2 Home: ", motion.x_home_pos(1), " X2_MIN_POS=", X2_MIN_POS, " X2_MAX_POS=", X2_MAX_POS, "\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE), - "\toolchange_settings.z_raise=", toolchange_settings.z_raise, + "\ntoolchange_settings.z_raise=", toolchange_settings.z_raise, "\nDEFAULT_DUPLICATION_X_OFFSET=", DEFAULT_DUPLICATION_X_OFFSET ); HOTEND_LOOP() { DEBUG_ECHOPGM_P(SP_T_STR, e); - LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", C(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); + LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", C(AXIS_CHAR(a) | 0x20), "=", motion.hotend_offset[e][a]); DEBUG_EOL(); } DEBUG_EOL(); @@ -170,16 +170,16 @@ bool ena = false; if (parser.seen("EPS")) { planner.synchronize(); - if (parser.seenval('P')) duplication_e_mask = parser.value_int(); // Set the mask directly - else if (parser.seenval('E')) duplication_e_mask = _BV(parser.value_int() + 1) - 1; // Set the mask by E index - ena = (2 == parser.intval('S', extruder_duplication_enabled ? 2 : 0)); - set_duplication_enabled(ena && (duplication_e_mask >= 3)); + if (parser.seenval('P')) motion.duplication_e_mask = parser.value_int(); // Set the mask directly + else if (parser.seenval('E')) motion.duplication_e_mask = _BV(parser.value_int() + 1) - 1; // Set the mask by E index + ena = (2 == parser.intval('S', motion.extruder_duplication ? 2 : 0)); + motion.set_extruder_duplication(ena && (motion.duplication_e_mask >= 3)); } SERIAL_ECHO_START(); - SERIAL_ECHOPGM(STR_DUPLICATION_MODE, ON_OFF(extruder_duplication_enabled)); + SERIAL_ECHOPGM(STR_DUPLICATION_MODE, ON_OFF(motion.extruder_duplication)); if (ena) { SERIAL_ECHOPGM(" ( "); - HOTEND_LOOP() if (TEST(duplication_e_mask, e)) { SERIAL_ECHO(e); SERIAL_CHAR(' '); } + HOTEND_LOOP() if (TEST(motion.duplication_e_mask, e)) { SERIAL_ECHO(e); SERIAL_CHAR(' '); } SERIAL_CHAR(')'); } SERIAL_EOL(); diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp index 5ec7b3e01b..29b2973889 100644 --- a/Marlin/src/gcode/feature/pause/M125.cpp +++ b/Marlin/src/gcode/feature/pause/M125.cpp @@ -85,7 +85,7 @@ void GcodeSuite::M125() { #endif #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) - park_point += hotend_offset[motion.extruder]; + park_point += motion.active_hotend_offset(); #endif const bool sd_printing = card.isStillPrinting(); diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index 774c96e9f6..a7d55223c7 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -105,7 +105,7 @@ void GcodeSuite::M600() { if (!parser.seen_test('T')) { // If no tool index is specified, M600 was (probably) sent in response to filament runout. // In this case, for duplicating modes set DXC_ext to the extruder that ran out. #if MULTI_FILAMENT_SENSOR - if (idex_is_duplicating()) + if (motion.idex_is_duplicating()) DXC_ext = (READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT2_STATE) ? 1 : 0; #else DXC_ext = motion.extruder; @@ -127,7 +127,7 @@ void GcodeSuite::M600() { #if HAS_MULTI_EXTRUDER // Change toolhead if specified const uint8_t active_extruder_before_filament_change = motion.extruder; - if (motion.extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !idex_is_duplicating())) + if (motion.extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !motion.idex_is_duplicating())) tool_change(target_extruder); #endif @@ -150,7 +150,7 @@ void GcodeSuite::M600() { ); #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) - park_point += hotend_offset[motion.extruder]; + park_point += motion.active_hotend_offset(); #endif // Unload filament diff --git a/Marlin/src/gcode/geometry/M206_M428.cpp b/Marlin/src/gcode/geometry/M206_M428.cpp index 80771fb60c..e683d2b641 100644 --- a/Marlin/src/gcode/geometry/M206_M428.cpp +++ b/Marlin/src/gcode/geometry/M206_M428.cpp @@ -83,8 +83,8 @@ void GcodeSuite::M428() { xyz_float_t diff; LOOP_NUM_AXES(i) { - diff[i] = base_home_pos((AxisEnum)i) - motion.position[i]; - if (!WITHIN(diff[i], -20, 20) && home_dir((AxisEnum)i) > 0) + diff[i] = motion.base_home_pos((AxisEnum)i) - motion.position[i]; + if (!WITHIN(diff[i], -20, 20) && motion.home_dir((AxisEnum)i) > 0) diff[i] = -motion.position[i]; if (!WITHIN(diff[i], -20, 20)) { SERIAL_ERROR_MSG(STR_ERR_M428_TOO_FAR); diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index f2386841ca..1106ce0acc 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -47,7 +47,7 @@ * G0, G1: Coordinated movement of X Y Z E axes */ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { - if (!MOTION_CONDITIONS) return; + if (motion.gcode_motion_ignored()) return; TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index a885c3a17b..384a90fe6d 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -423,7 +423,7 @@ void plan_arc( * G3 X20 Y12 R14 ; CCW circle with r=14 ending at X20 Y12 */ void GcodeSuite::G2_G3(const bool clockwise) { - if (!MOTION_CONDITIONS) return; + if (motion.gcode_motion_ignored()) return; TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index 227ea0792e..6ffb65b959 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -44,7 +44,7 @@ * G5: Cubic B-spline */ void GcodeSuite::G5() { - if (!MOTION_CONDITIONS) return; + if (motion.gcode_motion_ignored()) return; #if ENABLED(CNC_WORKSPACE_PLANES) if (workspace_plane != PLANE_XY) { diff --git a/Marlin/src/gcode/motion/M290.cpp b/Marlin/src/gcode/motion/M290.cpp index e65478b059..4db6df32d7 100644 --- a/Marlin/src/gcode/motion/M290.cpp +++ b/Marlin/src/gcode/motion/M290.cpp @@ -42,8 +42,8 @@ } else { #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET) - hotend_offset[motion.extruder].z -= offs; - SERIAL_ECHO_MSG(STR_PROBE_OFFSET STR_Z ": ", hotend_offset[motion.extruder].z); + motion.active_hotend_offset().z -= offs; + SERIAL_ECHO_MSG(STR_PROBE_OFFSET STR_Z ": ", motion.active_hotend_offset().z); #endif } } @@ -95,13 +95,13 @@ void GcodeSuite::M290() { SERIAL_ECHOLNPGM_P( PSTR("Hotend "), motion.extruder #if ENABLED(BABYSTEP_XY) - , PSTR("Offset X"), hotend_offset[motion.extruder].x - , SP_Y_STR, hotend_offset[motion.extruder].y + , PSTR("Offset X"), motion.active_hotend_offset().x + , SP_Y_STR, motion.active_hotend_offset().y , SP_Z_STR #else , PSTR("Offset Z") #endif - , hotend_offset[motion.extruder].z + , motion.active_hotend_offset().z ); } #endif diff --git a/Marlin/src/gcode/probe/G38.cpp b/Marlin/src/gcode/probe/G38.cpp index 2bd8e10052..8a20c3685e 100644 --- a/Marlin/src/gcode/probe/G38.cpp +++ b/Marlin/src/gcode/probe/G38.cpp @@ -60,7 +60,7 @@ FORCE_INLINE bool G38_run_probe() { xyz_float_t retract_mm; LOOP_NUM_AXES(i) { const float dist = motion.destination[i] - motion.position[i]; - retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1); + retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : motion.home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1); } #endif diff --git a/Marlin/src/gcode/temp/M104_M109.cpp b/Marlin/src/gcode/temp/M104_M109.cpp index 79da98abff..31686c1208 100644 --- a/Marlin/src/gcode/temp/M104_M109.cpp +++ b/Marlin/src/gcode/temp/M104_M109.cpp @@ -111,8 +111,8 @@ void GcodeSuite::M104_M109(const bool isM109) { thermalManager.setTargetHotend(temp, target_extruder); #if ENABLED(DUAL_X_CARRIAGE) - if (idex_is_duplicating() && target_extruder == 0) - thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1); + if (motion.idex_is_duplicating() && target_extruder == 0) + thermalManager.setTargetHotend(temp ? temp + motion.duplicate_extruder_temp_offset : 0, 1); #endif #if ENABLED(PRINTJOB_TIMER_AUTOSTART) diff --git a/Marlin/src/gcode/temp/M106_M107.cpp b/Marlin/src/gcode/temp/M106_M107.cpp index 6d163ce648..2675f32391 100644 --- a/Marlin/src/gcode/temp/M106_M107.cpp +++ b/Marlin/src/gcode/temp/M106_M107.cpp @@ -93,7 +93,7 @@ void GcodeSuite::M106() { TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS)); - if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating + if (TERN0(DUAL_X_CARRIAGE, motion.idex_is_duplicating())) // pfan == 0 when duplicating thermalManager.set_fan_speed(1 - pfan, speed); } @@ -107,7 +107,7 @@ void GcodeSuite::M107() { thermalManager.set_fan_speed(pfan, 0); - if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating + if (TERN0(DUAL_X_CARRIAGE, motion.idex_is_duplicating())) // pfan == 0 when duplicating thermalManager.set_fan_speed(1 - pfan, 0); TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS)); diff --git a/Marlin/src/inc/Conditionals-3-etc.h b/Marlin/src/inc/Conditionals-3-etc.h index 68f34a7fd6..e09898f0cc 100644 --- a/Marlin/src/inc/Conditionals-3-etc.h +++ b/Marlin/src/inc/Conditionals-3-etc.h @@ -462,6 +462,7 @@ #endif #if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR) #define ABL_USES_GRID 1 + #define HAS_VARIABLE_XY_PROBE_FEEDRATE 1 #ifndef XY_PROBE_FEEDRATE_MIN #define XY_PROBE_FEEDRATE_MIN 60 // Minimum mm/min value for 'G29 S' #endif diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index d13d6b4d38..4d77d8373f 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -687,7 +687,7 @@ namespace ExtUI { #endif #if ENABLED(DUAL_X_CARRIAGE) - uint8_t getIDEX_Mode() { return dual_x_carriage_mode; } + uint8_t getIDEX_Mode() { return motion.idex_mode; } #endif #if HAS_PREHEAT @@ -765,7 +765,7 @@ namespace ExtUI { if (!linked_nozzles) { HOTEND_LOOP() if (e != motion.extruder) - hotend_offset[e][axis] += mm; + motion.hotend_offset[e][axis] += mm; TERN_(HAS_X_AXIS, normalizeNozzleOffset(X)); TERN_(HAS_Y_AXIS, normalizeNozzleOffset(Y)); @@ -818,12 +818,12 @@ namespace ExtUI { float getNozzleOffset_mm(const axis_t axis, const extruder_t extruder) { if (extruder - E0 >= HOTENDS) return 0; - return hotend_offset[extruder - E0][axis]; + return motion.hotend_offset[extruder - E0][axis]; } void setNozzleOffset_mm(const float value, const axis_t axis, const extruder_t extruder) { if (extruder - E0 >= HOTENDS) return; - hotend_offset[extruder - E0][axis] = value; + motion.hotend_offset[extruder - E0][axis] = value; } /** @@ -832,8 +832,8 @@ namespace ExtUI { * user to edit the offset the first nozzle). */ void normalizeNozzleOffset(const axis_t axis) { - const float offs = hotend_offset[0][axis]; - HOTEND_LOOP() hotend_offset[e][axis] -= offs; + const float offs = motion.hotend_offset[0][axis]; + HOTEND_LOOP() motion.hotend_offset[e][axis] -= offs; } #endif // HAS_HOTEND_OFFSET @@ -887,14 +887,14 @@ namespace ExtUI { y_target = MESH_MIN_Y + pos.y * (MESH_Y_DIST); if (x_target != motion.position.x || y_target != motion.position.y) { // If moving across bed, raise nozzle to safe height over bed - motion.feedrate_mm_s = z_probe_fast_mm_s; - motion.destination.set(motion.position.x, motion.position.y, Z_CLEARANCE_BETWEEN_PROBES); + motion.feedrate_mm_s = motion.z_probe_fast_mm_s; + motion.destination.set(motion.position.x, motion.position.y, Z_TWEEN_SAFE_CLEARANCE); motion.prepare_line_to_destination(); if (XY_PROBE_FEEDRATE_MM_S) motion.feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S; motion.destination.set(x_target, y_target); motion.prepare_line_to_destination(); } - motion.feedrate_mm_s = z_probe_fast_mm_s; + motion.feedrate_mm_s = motion.z_probe_fast_mm_s; motion.destination.z = z; motion.prepare_line_to_destination(); #else diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index c329382e45..e05279ae5c 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -317,7 +317,7 @@ void scroll_screen(const uint8_t limit, const bool is_menu) { const float diff = planner.mm_per_step[Z_AXIS] * babystep_increment, new_probe_offset = probe.offset.z + diff, new_offs = TERN(BABYSTEP_HOTEND_Z_OFFSET - , do_probe ? new_probe_offset : hotend_offset[motion.extruder].z - diff + , do_probe ? new_probe_offset : motion.active_hotend_offset().z - diff , new_probe_offset ); if (WITHIN(new_offs, PROBE_OFFSET_ZMIN, PROBE_OFFSET_ZMAX)) { @@ -327,7 +327,7 @@ void scroll_screen(const uint8_t limit, const bool is_menu) { if (do_probe) probe.offset.z = new_offs; else - TERN(BABYSTEP_HOTEND_Z_OFFSET, hotend_offset[motion.extruder].z = new_offs, NOOP); + TERN(BABYSTEP_HOTEND_Z_OFFSET, motion.active_hotend_offset().z = new_offs, NOOP); ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); } @@ -339,7 +339,7 @@ void scroll_screen(const uint8_t limit, const bool is_menu) { } else { #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET) - MenuEditItemBase::draw_edit_screen(GET_TEXT_F(MSG_HOTEND_OFFSET_Z), ftostr54sign(hotend_offset[motion.extruder].z)); + MenuEditItemBase::draw_edit_screen(GET_TEXT_F(MSG_HOTEND_OFFSET_Z), ftostr54sign(motion.active_hotend_offset().z)); #endif } } diff --git a/Marlin/src/lcd/menu/menu_bed_tramming.cpp b/Marlin/src/lcd/menu/menu_bed_tramming.cpp index 4056b16dd9..341a7d4fa4 100644 --- a/Marlin/src/lcd/menu/menu_bed_tramming.cpp +++ b/Marlin/src/lcd/menu/menu_bed_tramming.cpp @@ -234,7 +234,7 @@ static void _lcd_goto_next_corner() { bool _lcd_bed_tramming_probe(const bool verify=false) { if (verify) motion.do_z_clearance_by(BED_TRAMMING_Z_HOP); // Do clearance if needed TERN_(BLTOUCH, if (!bltouch.high_speed_mode) bltouch.deploy()); // Deploy in LOW SPEED MODE on every probe action - motion.blocking_move_z(last_z - BED_TRAMMING_PROBE_TOLERANCE, z_probe_slow_mm_s); // Move down to lower tolerance + motion.blocking_move_z(last_z - BED_TRAMMING_PROBE_TOLERANCE, motion.z_probe_slow_mm_s); // Move down to lower tolerance if (TEST(endstops.trigger_state(), Z_MIN_PROBE)) { // Probe triggered? endstops.hit_on_purpose(); motion.set_current_from_steppers_for_axis(Z_AXIS); diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index 13bcb0706f..13a8893cc2 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -241,12 +241,12 @@ void menu_advanced_settings(); START_MENU(); BACK_ITEM(MSG_CONFIGURATION); #if ENABLED(DUAL_X_CARRIAGE) - EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_HOTEND_OFFSET_N, &hotend_offset[1].x, float(X2_HOME_POS - 25), float(X2_HOME_POS + 25), _recalc_offsets); + EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_HOTEND_OFFSET_N, &motion.hotend_offset[1].x, float(X2_HOME_POS - 25), float(X2_HOME_POS + 25), _recalc_offsets); #else - EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_HOTEND_OFFSET_N, &hotend_offset[1].x, -99.0f, 99.0f, _recalc_offsets); + EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_HOTEND_OFFSET_N, &motion.hotend_offset[1].x, -99.0f, 99.0f, _recalc_offsets); #endif - EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_HOTEND_OFFSET_N, &hotend_offset[1].y, -99.0f, 99.0f, _recalc_offsets); - EDIT_ITEM_FAST_N(float42_52, Z_AXIS, MSG_HOTEND_OFFSET_N, &hotend_offset[1].z, -10.0f, 10.0f, _recalc_offsets); + EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_HOTEND_OFFSET_N, &motion.hotend_offset[1].y, -99.0f, 99.0f, _recalc_offsets); + EDIT_ITEM_FAST_N(float42_52, Z_AXIS, MSG_HOTEND_OFFSET_N, &motion.hotend_offset[1].z, -10.0f, 10.0f, _recalc_offsets); #if ENABLED(EEPROM_SETTINGS) ACTION_ITEM(MSG_STORE_EEPROM, ui.store_settings); #endif @@ -293,7 +293,7 @@ void menu_advanced_settings(); ); GCODES_ITEM(MSG_IDEX_MODE_FULL_CTRL, F("M605S0\nG28X")); - EDIT_ITEM(float42_52, MSG_IDEX_DUPE_GAP, &duplicate_extruder_x_offset, (X2_MIN_POS) - (X1_MIN_POS), (X_BED_SIZE) - 20); + EDIT_ITEM(float42_52, MSG_IDEX_DUPE_GAP, &motion.duplicate_extruder_x_offset, (X2_MIN_POS) - (X1_MIN_POS), (X_BED_SIZE) - 20); END_MENU(); } diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 3a825afc0d..8d3682e76b 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -150,7 +150,7 @@ void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int BACK_ITEM(MSG_MOVE_AXIS); - #define __LINEAR_LIMIT(D) ((D) < max_length(axis) / 2 + 1) + #define __LINEAR_LIMIT(D) ((D) < motion.max_axis_length(axis) / 2 + 1) #if HAS_EXTRUDERS #ifndef EXTRUDE_MAXLENGTH #define EXTRUDE_MAXLENGTH 50 @@ -159,9 +159,9 @@ void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int #else #define _LINEAR_LIMIT __LINEAR_LIMIT #endif - #define __MOVE_SUB(L,T,D) if (rotational[axis] || _LINEAR_LIMIT(D)) SUBMENU_S(F(T), L, []{ _goto_manual_move(D); }) + #define __MOVE_SUB(L,T,D) if (motion.rotational[axis] || _LINEAR_LIMIT(D)) SUBMENU_S(F(T), L, []{ _goto_manual_move(D); }) - if (rotational[axis]) { + if (motion.rotational[axis]) { #ifdef MANUAL_MOVE_DISTANCE_DEG #define _MOVE_DEG(D) __MOVE_SUB(MSG_MOVE_N_DEG, STRINGIFY(D), D); MAP(_MOVE_DEG, MANUAL_MOVE_DISTANCE_DEG) diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp index 9113aafdad..fa71897652 100644 --- a/Marlin/src/lcd/tft/ui_common.cpp +++ b/Marlin/src/lcd/tft/ui_common.cpp @@ -86,7 +86,7 @@ void moveAxis(const AxisEnum axis, const int8_t direction) { const float bsDiff = planner.mm_per_step[Z_AXIS] * babystep_increment, new_probe_offset = probe.offset.z + bsDiff, new_offs = TERN(BABYSTEP_HOTEND_Z_OFFSET - , do_probe ? new_probe_offset : hotend_offset[motion.extruder].z - bsDiff + , do_probe ? new_probe_offset : motion.active_hotend_offset().z - bsDiff , new_probe_offset ); if (WITHIN(new_offs, PROBE_OFFSET_ZMIN, PROBE_OFFSET_ZMAX)) { @@ -94,7 +94,7 @@ void moveAxis(const AxisEnum axis, const int8_t direction) { if (do_probe) probe.offset.z = new_offs; else - TERN(BABYSTEP_HOTEND_Z_OFFSET, hotend_offset[motion.extruder].z = new_offs, NOOP); + TERN(BABYSTEP_HOTEND_Z_OFFSET, motion.active_hotend_offset().z = new_offs, NOOP); drawMessage_P(NUL_STR); // Clear the error } else diff --git a/Marlin/src/module/delta.cpp b/Marlin/src/module/delta.cpp index b9e70f5e5a..f735200108 100644 --- a/Marlin/src/module/delta.cpp +++ b/Marlin/src/module/delta.cpp @@ -112,8 +112,8 @@ void recalc_delta_settings() { void inverse_kinematics(const xyz_pos_t &raw) { #if HAS_HOTEND_OFFSET // Delta hotend offsets must be applied in Cartesian space with no "spoofing" - xyz_pos_t pos = { raw.x - hotend_offset[motion.extruder].x, - raw.y - hotend_offset[motion.extruder].y, + xyz_pos_t pos = { raw.x - motion.active_hotend_offset().x, + raw.y - motion.active_hotend_offset().y, raw.z }; DELTA_IK(pos); //DELTA_DEBUG(pos); @@ -226,22 +226,22 @@ void home_delta() { // Disable stealthChop if used. Enable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) - TERN_(X_SENSORLESS, sensorless_t stealth_states_x = start_sensorless_homing_per_axis(X_AXIS)); - TERN_(Y_SENSORLESS, sensorless_t stealth_states_y = start_sensorless_homing_per_axis(Y_AXIS)); - TERN_(Z_SENSORLESS, sensorless_t stealth_states_z = start_sensorless_homing_per_axis(Z_AXIS)); - TERN_(I_SENSORLESS, sensorless_t stealth_states_i = start_sensorless_homing_per_axis(I_AXIS)); - TERN_(J_SENSORLESS, sensorless_t stealth_states_j = start_sensorless_homing_per_axis(J_AXIS)); - TERN_(K_SENSORLESS, sensorless_t stealth_states_k = start_sensorless_homing_per_axis(K_AXIS)); - TERN_(U_SENSORLESS, sensorless_t stealth_states_u = start_sensorless_homing_per_axis(U_AXIS)); - TERN_(V_SENSORLESS, sensorless_t stealth_states_v = start_sensorless_homing_per_axis(V_AXIS)); - TERN_(W_SENSORLESS, sensorless_t stealth_states_w = start_sensorless_homing_per_axis(W_AXIS)); + TERN_(X_SENSORLESS, sensorless_t stealth_states_x = motion.sensorless_axis_homing_start(X_AXIS)); + TERN_(Y_SENSORLESS, sensorless_t stealth_states_y = motion.sensorless_axis_homing_start(Y_AXIS)); + TERN_(Z_SENSORLESS, sensorless_t stealth_states_z = motion.sensorless_axis_homing_start(Z_AXIS)); + TERN_(I_SENSORLESS, sensorless_t stealth_states_i = motion.sensorless_axis_homing_start(I_AXIS)); + TERN_(J_SENSORLESS, sensorless_t stealth_states_j = motion.sensorless_axis_homing_start(J_AXIS)); + TERN_(K_SENSORLESS, sensorless_t stealth_states_k = motion.sensorless_axis_homing_start(K_AXIS)); + TERN_(U_SENSORLESS, sensorless_t stealth_states_u = motion.sensorless_axis_homing_start(U_AXIS)); + TERN_(V_SENSORLESS, sensorless_t stealth_states_v = motion.sensorless_axis_homing_start(V_AXIS)); + TERN_(W_SENSORLESS, sensorless_t stealth_states_w = motion.sensorless_axis_homing_start(W_AXIS)); #if SENSORLESS_STALLGUARD_DELAY safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle #endif #endif // Set homing current for all motors - TERN_(HAS_HOMING_CURRENT, set_homing_current(Z_AXIS)); + TERN_(HAS_HOMING_CURRENT, motion.set_homing_current(Z_AXIS)); // Move all carriages together linearly until an endstop is hit. motion.position.z = DIFF_TERN(HAS_BED_PROBE, delta_height + 10, probe.offset.z); @@ -250,19 +250,19 @@ void home_delta() { TERN_(HAS_DELTA_SENSORLESS_PROBING, endstops.report_states()); // Restore the homing current for all motors - TERN_(HAS_HOMING_CURRENT, restore_homing_current(Z_AXIS)); + TERN_(HAS_HOMING_CURRENT, motion.restore_homing_current(Z_AXIS)); // Re-enable stealthChop if used. Disable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) - TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x)); - TERN_(Y_SENSORLESS, end_sensorless_homing_per_axis(Y_AXIS, stealth_states_y)); - TERN_(Z_SENSORLESS, end_sensorless_homing_per_axis(Z_AXIS, stealth_states_z)); - TERN_(I_SENSORLESS, end_sensorless_homing_per_axis(I_AXIS, stealth_states_i)); - TERN_(J_SENSORLESS, end_sensorless_homing_per_axis(J_AXIS, stealth_states_j)); - TERN_(K_SENSORLESS, end_sensorless_homing_per_axis(K_AXIS, stealth_states_k)); - TERN_(U_SENSORLESS, end_sensorless_homing_per_axis(U_AXIS, stealth_states_u)); - TERN_(V_SENSORLESS, end_sensorless_homing_per_axis(V_AXIS, stealth_states_v)); - TERN_(W_SENSORLESS, end_sensorless_homing_per_axis(W_AXIS, stealth_states_w)); + TERN_(X_SENSORLESS, motion.sensorless_axis_homing_end(X_AXIS, stealth_states_x)); + TERN_(Y_SENSORLESS, motion.sensorless_axis_homing_end(Y_AXIS, stealth_states_y)); + TERN_(Z_SENSORLESS, motion.sensorless_axis_homing_end(Z_AXIS, stealth_states_z)); + TERN_(I_SENSORLESS, motion.sensorless_axis_homing_end(I_AXIS, stealth_states_i)); + TERN_(J_SENSORLESS, motion.sensorless_axis_homing_end(J_AXIS, stealth_states_j)); + TERN_(K_SENSORLESS, motion.sensorless_axis_homing_end(K_AXIS, stealth_states_k)); + TERN_(U_SENSORLESS, motion.sensorless_axis_homing_end(U_AXIS, stealth_states_u)); + TERN_(V_SENSORLESS, motion.sensorless_axis_homing_end(V_AXIS, stealth_states_v)); + TERN_(W_SENSORLESS, motion.sensorless_axis_homing_end(W_AXIS, stealth_states_w)); #if SENSORLESS_STALLGUARD_DELAY safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle #endif diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 326b65a2c6..e7c18f36a2 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -78,6 +78,9 @@ Motion motion; // Relative Mode. Enable with G91, disable with G90. bool Motion::relative_mode; // = false +// Flags for rotational axes +constexpr AxisFlags Motion::rotational; + // The active extruder (tool). Set with T command. #if HAS_MULTI_EXTRUDER uint8_t Motion::extruder = 0; // = 0 @@ -134,10 +137,14 @@ xyz_pos_t Motion::cartes; float Motion::e_move_accumulator; // = 0 #endif +#if ENABLED(DUAL_X_CARRIAGE) + DualXMode Motion::idex_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; +#endif + // Extruder offsets #if HAS_HOTEND_OFFSET - xyz_pos_t hotend_offset[HOTENDS]; // Initialized by settings.load - void reset_hotend_offsets() { + xyz_pos_t Motion::hotend_offset[HOTENDS]; // Initialized by settings.load + void Motion::reset_hotend_offsets() { constexpr float tmp[3][HOTENDS] = { HOTEND_OFFSET_X, HOTEND_OFFSET_Y, HOTEND_OFFSET_Z }; static_assert( !tmp[X_AXIS][0] && !tmp[Y_AXIS][0] && !tmp[Z_AXIS][0], @@ -147,6 +154,10 @@ xyz_pos_t Motion::cartes; HOTEND_LOOP() LOOP_ABC(a) hotend_offset[e][a] = tmp[a][e]; TERN_(DUAL_X_CARRIAGE, hotend_offset[1].x = _MAX(X2_HOME_POS, X2_MAX_POS)); } +#elif HOTENDS + constexpr xyz_pos_t Motion::hotend_offset[HOTENDS]; +#else + constexpr xyz_pos_t Motion::hotend_offset[1]; #endif // The feedrate for the current move, often used as the default if @@ -203,8 +214,15 @@ int16_t Motion::feedrate_percentage = 100; xyz_pos_t Motion::workspace_offset{0}; #endif -#if ABL_USES_GRID - feedRate_t xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_FEEDRATE); +#if HAS_VARIABLE_XY_PROBE_FEEDRATE + feedRate_t Motion::xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_FEEDRATE); +#endif + +#ifdef Z_PROBE_FEEDRATE_SLOW + constexpr feedRate_t Motion::z_probe_slow_mm_s; +#endif +#ifdef Z_PROBE_FEEDRATE_FAST + constexpr feedRate_t Motion::z_probe_fast_mm_s; #endif /** @@ -280,7 +298,7 @@ void Motion::report_position_projected() { * Set motors to their homing / probing currents. * Currents are saved first so they can be restored afterward. */ - void set_homing_current(const AxisEnum axis) { + void Motion::set_homing_current(const AxisEnum axis) { #define HOMING_CURRENT(A) TERN(EDITABLE_HOMING_CURRENT, homing_current_mA.A, A##_CURRENT_HOME) @@ -439,7 +457,7 @@ void Motion::report_position_projected() { * Restore motors to their previously-stored currents. * Always call set_homing_current() first! */ - void restore_homing_current(const AxisEnum axis) { + void Motion::restore_homing_current(const AxisEnum axis) { // Restore the saved current #define _RESTORE_CURRENT(A) \ @@ -746,7 +764,7 @@ void Motion::quickstop_stepper() { */ void Motion::sync_plan_position() { if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", position); - planner.set_position_mm(motion.position); + planner.set_position_mm(position); //SERIAL_ECHOLNPGM("Sync_plan_position: ", position.x, ", ", position.y, ", ", position.z); //SERIAL_EOL(); } @@ -816,6 +834,10 @@ void Motion::set_current_from_steppers_for_axis(const AxisEnum axis) { position[axis] = pos[axis]; } +bool Motion::gcode_motion_ignored() { + return !marlin.isRunning() || TERN0(NO_MOTION_BEFORE_HOMING, homing_needed_error()); +} + /** * Move the planner to the current position from wherever it last moved * (or from wherever it has been told it is located). @@ -1264,7 +1286,7 @@ void Motion::restore_feedrate_and_scaling() { // retain the same physical limit when other tools are selected. if (new_tool_index == old_tool_index || axis == Z_AXIS) { // The Z axis is "special" and shouldn't be modified - const float offs = (axis == Z_AXIS) ? 0 : hotend_offset[extruder][axis]; + const float offs = (axis == Z_AXIS) ? 0 : active_hotend_offset()[axis]; soft_endstop.min[axis] = base_min_pos(axis) + offs; soft_endstop.max[axis] = base_max_pos(axis) + offs; } @@ -1303,7 +1325,7 @@ void Motion::restore_feedrate_and_scaling() { #if ALL(HAS_HOTEND_OFFSET, DELTA) // The effector center position will be the target minus the hotend offset. - const xy_pos_t offs = hotend_offset[extruder]; + const xy_pos_t offs = active_hotend_offset(); #elif ENABLED(POLARGRAPH) // POLARGRAPH uses draw_area_* below... #elif ENABLED(POLAR) @@ -1774,50 +1796,37 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE #endif // !IS_KINEMATIC #if HAS_DUPLICATION_MODE - bool extruder_duplication_enabled; + bool Motion::extruder_duplication; #if ENABLED(MULTI_NOZZLE_DUPLICATION) - uint8_t duplication_e_mask; // = 0 + uint8_t Motion::duplication_e_mask; // = 0 #endif #endif #if ENABLED(DUAL_X_CARRIAGE) - DualXMode dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; - float inactive_extruder_x = X2_MAX_POS, // Used in mode 0 & 1 - duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // Used in mode 2 & 3 - xyz_pos_t raised_parked_position; // Used in mode 1 - bool active_extruder_parked = false; // Used in mode 1, 2 & 3 - millis_t delayed_move_time = 0; // Used in mode 1 - celsius_t duplicate_extruder_temp_offset = 0; // Used in mode 2 & 3 - bool idex_mirrored_mode = false; // Used in mode 3 + float Motion::inactive_extruder_x = X2_MAX_POS, // Used in mode 0 & 1 + Motion::duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // Used in mode 2 & 3 + bool Motion::idex_mirrored_mode = false; // Used in mode 3 + xyz_pos_t Motion::raised_parked_position; // Used in mode 1 + bool Motion::active_extruder_parked = false; // Used in mode 1, 2 & 3 + millis_t Motion::delayed_move_time = 0; // Used in mode 1 + celsius_t Motion::duplicate_extruder_temp_offset = 0; // Used in mode 2 & 3 - float x_home_pos(const uint8_t extruder) { - if (extruder == 0) return X_HOME_POS; - - /** - * In dual carriage mode the extruder offset provides an override of the - * second X-carriage position when homed - otherwise X2_HOME_POS is used. - * This allows soft recalibration of the second extruder home position - * (with M218 T1 Xn) without firmware reflash. - */ - return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS; + void Motion::set_extruder_duplication(const bool dupe, const int8_t tool_index/*=-1*/) { + _set_duplication_enabled(dupe); + if (tool_index >= 0) extruder = tool_index; + stepper.apply_directions(); } - void idex_set_mirrored_mode(const bool mirr) { + void Motion::idex_set_mirrored_mode(const bool mirr) { idex_mirrored_mode = mirr; stepper.apply_directions(); } - void set_duplication_enabled(const bool dupe, const int8_t tool_index/*=-1*/) { - extruder_duplication_enabled = dupe; - if (tool_index >= 0) motion.extruder = tool_index; - stepper.apply_directions(); - } - - void idex_set_parked(const bool park/*=true*/) { + void Motion::idex_set_parked(const bool park/*=true*/) { delayed_move_time = 0; active_extruder_parked = park; - if (park) raised_parked_position = motion.position; // Remember current raised toolhead position for use by unpark + if (park) raised_parked_position = position; // Remember current raised toolhead position for use by unpark } /** @@ -1825,20 +1834,20 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE * * Return true if position[] was set to destination[] */ - inline bool dual_x_carriage_unpark() { + bool Motion::unpark_before_move() { if (active_extruder_parked) { - switch (dual_x_carriage_mode) { + switch (idex_mode) { case DXC_FULL_CONTROL_MODE: break; case DXC_AUTO_PARK_MODE: { - if (motion.position.e == motion.destination.e) { + if (position.e == destination.e) { // This is a travel move (with no extrusion) // Skip it, but keep track of the current position // (so it can be used as the start of the next non-travel move) if (delayed_move_time != UINT32_MAX) { - motion.position = motion.destination; - NOLESS(raised_parked_position.z, motion.destination.z); + position = destination; + NOLESS(raised_parked_position.z, destination.z); delayed_move_time = millis() + 1000UL; return true; } @@ -1848,13 +1857,13 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // const feedRate_t fr_zfast = planner.settings.max_feedrate_mm_s[Z_AXIS]; // 1. Move to the raised parked XYZ. Presumably the tool is already at XY. - xyze_pos_t raised = raised_parked_position; raised.e = motion.position.e; + xyze_pos_t raised = raised_parked_position; raised.e = position.e; if (planner.buffer_line(raised, fr_zfast)) { // 2. Move to the current native XY and raised Z. Presumably this is a null move. - xyze_pos_t curpos = motion.position; curpos.z = raised_parked_position.z; + xyze_pos_t curpos = position; curpos.z = raised_parked_position.z; if (planner.buffer_line(curpos, PLANNER_XY_FEEDRATE_MM_S)) { // 3. Lower Z back down - motion.goto_current_position(fr_zfast); + goto_current_position(fr_zfast); } } stepper.apply_directions(); @@ -1865,17 +1874,17 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE case DXC_MIRRORED_MODE: case DXC_DUPLICATION_MODE: - if (motion.extruder == 0) { - set_duplication_enabled(false); // Clear stale duplication state + if (extruder == 0) { + set_extruder_duplication(false); // Clear stale duplication state // Restore planner to parked head (T1) X position - float x0_pos = motion.position.x; - xyze_pos_t pos_now = motion.position; + float x0_pos = position.x; + xyze_pos_t pos_now = position; pos_now.x = inactive_extruder_x; planner.set_position_mm(pos_now); // Keep the same X or add the duplication X offset xyze_pos_t new_pos = pos_now; - if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) + if (idex_mode == DXC_DUPLICATION_MODE) new_pos.x = x0_pos + duplicate_extruder_x_offset; else new_pos.x = _MIN(X_BED_SIZE - x0_pos, X_MAX_POS); @@ -1885,10 +1894,10 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE if (!planner.buffer_line(new_pos, planner.settings.max_feedrate_mm_s[X_AXIS], 1)) break; planner.synchronize(); - motion.sync_plan_position(); // Extra sync for good measure - set_duplication_enabled(true); // Enable Duplication - idex_set_parked(false); // No longer parked - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("set_duplication_enabled(true)\nidex_set_parked(false)"); + sync_plan_position(); // Extra sync for good measure + set_extruder_duplication(true); // Enable Duplication + idex_set_parked(false); // No longer parked + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("set_extruder_duplication(true)\nidex_set_parked(false)"); } else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Active extruder not 0"); break; @@ -1897,6 +1906,22 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE return false; } + void Motion::idex_home_x() { + // Always home the 2nd (right) extruder first + extruder = 1; + homeaxis(X_AXIS); + + // Remember this extruder's position for later tool change + inactive_extruder_x = position.x; + + // Home the 1st (left) extruder + extruder = 0; + homeaxis(X_AXIS); + + // Consider the active extruder to be in its "parked" position + idex_set_parked(); + } + #endif // DUAL_X_CARRIAGE /** @@ -1950,7 +1975,7 @@ void Motion::prepare_line_to_destination() { #endif // PREVENT_COLD_EXTRUSION || PREVENT_LENGTHY_EXTRUDE - if (TERN0(DUAL_X_CARRIAGE, dual_x_carriage_unpark())) return; + if (unpark_before_move()) return; if ( #if UBL_SEGMENTED @@ -2028,7 +2053,7 @@ void Motion::prepare_line_to_destination() { /** * Set sensorless homing if the axis has it, accounting for Core Kinematics. */ - sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis) { + sensorless_t Motion::sensorless_axis_homing_start(const AxisEnum axis) { sensorless_t stealth_states { false }; switch (axis) { @@ -2124,7 +2149,7 @@ void Motion::prepare_line_to_destination() { return stealth_states; } - void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth) { + void Motion::sensorless_axis_homing_end(const AxisEnum axis, sensorless_t enable_stealth) { switch (axis) { default: break; #if X_SENSORLESS @@ -2235,7 +2260,7 @@ void Motion::prepare_line_to_destination() { // Only do some things when moving towards an endstop const int8_t axis_home_dir = TERN0(DUAL_X_CARRIAGE, axis == X_AXIS) - ? TOOL_X_HOME_DIR(extruder) : home_dir(axis); + ? tool_x_home_dir() : home_dir(axis); const bool is_home_dir = (axis_home_dir > 0) == (distance > 0); #if ENABLED(SENSORLESS_HOMING) @@ -2260,12 +2285,12 @@ void Motion::prepare_line_to_destination() { // Disable stealthChop if used. Enable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) - stealth_states = start_sensorless_homing_per_axis(axis); + stealth_states = sensorless_axis_homing_start(axis); #if SENSORLESS_STALLGUARD_DELAY safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle #endif #endif - } + } // is_home_dir #if ANY(MORGAN_SCARA, MP_SCARA) // Tell the planner the axis is at 0 @@ -2301,13 +2326,15 @@ void Motion::prepare_line_to_destination() { // Re-enable stealthChop if used. Disable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) - end_sensorless_homing_per_axis(axis, stealth_states); + sensorless_axis_homing_end(axis, stealth_states); #if SENSORLESS_STALLGUARD_DELAY safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle #endif #endif - } - } + + } // is_home_dir + + } // do_homing_move /** * Set an axis to be unhomed. (Unless we are on a machine - e.g. a cheap Chinese CNC machine - @@ -2333,7 +2360,7 @@ void Motion::prepare_line_to_destination() { * phase position. Trinamic drivers use a stepper phase table with 1024 values * spanning 4 full steps with 256 positions each (ergo, 1024 positions). */ - void backout_to_tmc_homing_phase(const AxisEnum axis) { + void Motion::backout_to_tmc_homing_phase(const AxisEnum axis) { const xyz_long_t home_phase = TMC_HOME_PHASE; // check if home phase is disabled for this axis. @@ -2477,7 +2504,7 @@ void Motion::prepare_line_to_destination() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(">>> homeaxis(", C(AXIS_CHAR(axis)), ")"); const int axis_home_dir = TERN0(DUAL_X_CARRIAGE, axis == X_AXIS) - ? TOOL_X_HOME_DIR(extruder) : home_dir(axis); + ? tool_x_home_dir() : home_dir(axis); // // Homing Z with a probe? Raise Z (maybe) and deploy the Z probe. @@ -2556,7 +2583,7 @@ void Motion::prepare_line_to_destination() { // // Fast move towards endstop until triggered // - const float move_length = 1.5f * max_length(TERN(DELTA, Z_AXIS, axis)) * axis_home_dir; + const float move_length = 1.5f * max_axis_length(TERN(DELTA, Z_AXIS, axis)) * axis_home_dir; if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Home Fast: ", move_length, "mm"); do_homing_move(axis, move_length, 0.0, !use_probe_bump); @@ -2843,7 +2870,7 @@ void Motion::set_axis_is_at_home(const AxisEnum axis) { set_axis_homed(axis); #if ENABLED(DUAL_X_CARRIAGE) - if (axis == X_AXIS && (extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) { + if (axis == X_AXIS && (extruder == 1 || idex_mode == DXC_DUPLICATION_MODE)) { position.x = SUM_TERN(HAS_HOME_OFFSET, x_home_pos(extruder), home_offset.x); return; } diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 096d9cf3a6..242606b228 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -68,6 +68,22 @@ constexpr float fslop = 0.0001; }; #endif +/** + * Dual X Carriage + */ +#if ENABLED(DUAL_X_CARRIAGE) + enum DualXMode : char { + DXC_FULL_CONTROL_MODE, + DXC_AUTO_PARK_MODE, + DXC_DUPLICATION_MODE, + DXC_MIRRORED_MODE + }; +#endif + +#if USE_SENSORLESS + struct sensorless_t; +#endif + /** * Homing and Trusted Axes */ @@ -78,6 +94,13 @@ class Motion { public: static bool relative_mode; // Relative Mode - G90/G91 + // Flags for rotational axes + static constexpr AxisFlags rotational{0 LOGICAL_AXIS_GANG( + | 0, | 0, | 0, | 0, + | (ENABLED(AXIS4_ROTATES)< #else @@ -102,6 +125,21 @@ public: static abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset #endif + #if HAS_HOTEND_OFFSET + static xyz_pos_t hotend_offset[HOTENDS]; + static void reset_hotend_offsets(); + #elif HOTENDS + static constexpr xyz_pos_t hotend_offset[HOTENDS] = { { TERN_(HAS_X_AXIS, 0) } }; + #else + static constexpr xyz_pos_t hotend_offset[1] = { { TERN_(HAS_X_AXIS, 0) } }; + #endif + + #if HAS_HOTEND_OFFSET + static xyz_pos_t& active_hotend_offset() { return hotend_offset[extruder]; } + #else + static const xyz_pos_t& active_hotend_offset() { return hotend_offset[extruder]; } + #endif + #if ENABLED(LCD_SHOW_E_TOTAL) static float e_move_accumulator; #endif @@ -175,6 +213,93 @@ public: static void set_home_offset(const AxisEnum axis, const float v) { home_offset[axis] = v; } #endif + #if HAS_DUPLICATION_MODE + static bool extruder_duplication; // Used in Dual X mode 2 + static void _set_duplication_enabled(const bool dupe) { extruder_duplication = dupe; } + #endif + + #if ENABLED(DUAL_X_CARRIAGE) + static DualXMode idex_mode; + static bool idex_is_duplicating() { return idex_mode >= DXC_DUPLICATION_MODE; } + + static float inactive_extruder_x, // Used in mode 0 & 1 + duplicate_extruder_x_offset; // Used in mode 2 & 3 + + static bool active_extruder_parked; // Used in mode 1, 2 & 3 + static millis_t delayed_move_time; // Used in mode 1 + static celsius_t duplicate_extruder_temp_offset; // Used in mode 2 & 3 + + static bool idex_mirrored_mode; // Used in mode 3 + static void idex_set_mirrored_mode(const bool mirr); + + static float x_home_pos(const uint8_t tool) { + if (tool == 0) return X_HOME_POS; + + /** + * In dual carriage mode the extruder offset provides an override of the + * second X-carriage position when homed - otherwise X2_HOME_POS is used. + * This allows soft recalibration of the second extruder home position + * (with M218 T1 Xn) without firmware reflash. + */ + return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS; + } + static void idex_set_parked(const bool park=true); + static bool unpark_before_move(); + static void set_extruder_duplication(const bool dupe, const int8_t tool_index=-1); + static void idex_home_x(); + #else + static bool unpark_before_move() { return false; } + #if ENABLED(MULTI_NOZZLE_DUPLICATION) + static uint8_t duplication_e_mask; + static void set_extruder_duplication(const bool dupe) { _set_duplication_enabled(dupe); } + #endif + #endif + + // + // Probing + // + #if HAS_VARIABLE_XY_PROBE_FEEDRATE + static feedRate_t xy_probe_feedrate_mm_s; // Set with 'G29 S' for ABL LINEAR/BILINEAR. TODO: Store to EEPROM. + #endif + #ifdef Z_PROBE_FEEDRATE_SLOW + static constexpr feedRate_t z_probe_slow_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW); + #endif + #ifdef Z_PROBE_FEEDRATE_FAST + static constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST); + #endif + + #ifdef __IMXRT1062__ + #define DEFS_PROGMEM + #else + #define DEFS_PROGMEM PROGMEM + #endif + + static float pgm_read_any(const float *p) { return TERN(__IMXRT1062__, *p, pgm_read_float(p)); } + static int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm_read_byte(p)); } + + #define XYZ_DEFS(T, NAME, OPT) \ + static T NAME(const AxisEnum axis) { \ + static constexpr XYZval NAME##_P DEFS_PROGMEM = NUM_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT, U_##OPT, V_##OPT, W_##OPT); \ + return pgm_read_any(&NAME##_P[axis]); \ + } + XYZ_DEFS(float, base_min_pos, MIN_POS); // base_min_pos(axis) + XYZ_DEFS(float, base_max_pos, MAX_POS); // base_max_pos(axis) + XYZ_DEFS(float, base_home_pos, HOME_POS); // base_home_pos(axis) + XYZ_DEFS(float, max_axis_length, MAX_LENGTH); // max_axis_length(axis) + XYZ_DEFS(int8_t, home_dir, HOME_DIR); // home_dir(axis) + + static float home_bump_mm(const AxisEnum axis) { + static const xyz_pos_t home_bump_mm_P DEFS_PROGMEM = HOMING_BUMP_MM; + return pgm_read_any(&home_bump_mm_P[axis]); + } + + #if HAS_X_AXIS + static int8_t tool_x_home_dir(const uint8_t tool=extruder) { + UNUSED(tool); + return TERN(DUAL_X_CARRIAGE, tool ? 1 : -1, X_HOME_DIR); + } + #endif + // // Workspace offsets // @@ -251,6 +376,9 @@ public: * Cleared whenever a stepper powers off, potentially losing its position. */ #if HAS_ENDSTOPS + #ifdef TMC_HOME_PHASE + static void backout_to_tmc_homing_phase(const AxisEnum axis); + #endif static main_axes_bits_t axes_homed, axes_trusted; static void homeaxis(const AxisEnum axis); static void set_axis_never_homed(const AxisEnum axis); @@ -281,6 +409,8 @@ public: static void home_if_needed(const bool keeplev=false); + static bool gcode_motion_ignored(); + // // Software Endstops // @@ -503,7 +633,23 @@ public: static void quickresume_stepper(); #endif // REALTIME_REPORTING_COMMANDS + // + // Trinamic Stepper Drivers + // + #if USE_SENSORLESS + static sensorless_t sensorless_axis_homing_start(const AxisEnum axis); + static void sensorless_axis_homing_end(const AxisEnum axis, sensorless_t enable_stealth); + #endif + + #if HAS_HOMING_CURRENT + static void set_homing_current(const AxisEnum axis); + static void restore_homing_current(const AxisEnum axis); + #endif + private: + #if ENABLED(DUAL_X_CARRIAGE) + static xyz_pos_t raised_parked_position; // Used in mode 1 + #endif #if SECONDARY_AXES static void secondary_axis_moves(SECONDARY_AXIS_ARGS_LC(const float), const feedRate_t fr_mm_s); #endif @@ -519,137 +665,20 @@ private: }; // class Motion -// Determine XY_PROBE_FEEDRATE_MM_S - The feedrate used between Probe Points -#if ABL_USES_GRID +// Specify read-only XY_PROBE_FEEDRATE_MM_S, feed rate between Probe Points. +#if HAS_VARIABLE_XY_PROBE_FEEDRATE // ABL LINEAR and BILINEAR use 'G29 S' value, or MMM_TO_MMS(XY_PROBE_FEEDRATE) - extern feedRate_t xy_probe_feedrate_mm_s; - #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s + #define XY_PROBE_FEEDRATE_MM_S motion.xy_probe_feedrate_mm_s #elif defined(XY_PROBE_FEEDRATE) + // Probe feedrate can be hard-coded by configuration #define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_FEEDRATE) #else + // Defer to Planner XY max feedrate, or 60 mm/s #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE_MM_S #endif -#ifdef Z_PROBE_FEEDRATE_SLOW - constexpr feedRate_t z_probe_slow_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW); -#endif -#ifdef Z_PROBE_FEEDRATE_FAST - constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST); -#endif - -#ifdef __IMXRT1062__ - #define DEFS_PROGMEM -#else - #define DEFS_PROGMEM PROGMEM -#endif - -inline float pgm_read_any(const float *p) { return TERN(__IMXRT1062__, *p, pgm_read_float(p)); } -inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm_read_byte(p)); } - -#define XYZ_DEFS(T, NAME, OPT) \ - inline T NAME(const AxisEnum axis) { \ - static constexpr XYZval NAME##_P DEFS_PROGMEM = NUM_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT, U_##OPT, V_##OPT, W_##OPT); \ - return pgm_read_any(&NAME##_P[axis]); \ - } -XYZ_DEFS(float, base_min_pos, MIN_POS); // base_min_pos(axis) -XYZ_DEFS(float, base_max_pos, MAX_POS); // base_max_pos(axis) -XYZ_DEFS(float, base_home_pos, HOME_POS); // base_home_pos(axis) -XYZ_DEFS(float, max_length, MAX_LENGTH); // max_length(axis) -XYZ_DEFS(int8_t, home_dir, HOME_DIR); // home_dir(axis) - -// Flags for rotational axes -constexpr AxisFlags rotational{0 LOGICAL_AXIS_GANG( - | 0, | 0, | 0, | 0, - | (ENABLED(AXIS4_ROTATES)<= DXC_DUPLICATION_MODE; } - - float x_home_pos(const uint8_t extruder); - - #define TOOL_X_HOME_DIR(T) ((T) ? 1 : -1) - - void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1); - void idex_set_mirrored_mode(const bool mirr); - void idex_set_parked(const bool park=true); - -#else - - #if ENABLED(MULTI_NOZZLE_DUPLICATION) - extern uint8_t duplication_e_mask; - enum DualXMode : char { DXC_DUPLICATION_MODE = 2 }; - FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; } - #endif - - #define TOOL_X_HOME_DIR(T) X_HOME_DIR - -#endif - -// -// Trinamic Stepper Drivers -// -#if USE_SENSORLESS - struct sensorless_t; - sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis); - void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth); -#endif - -#if HAS_HOMING_CURRENT - void set_homing_current(const AxisEnum axis); - void restore_homing_current(const AxisEnum axis); -#endif - extern Motion motion; // External conversion methods (motion.h) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index ad727ce21f..8f3815a3fc 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2151,7 +2151,7 @@ bool Planner::_populate_block( #define E_STEPPER_INDEX(E) TERN(HAS_SWITCHING_EXTRUDER, (E) / 2, E) // Enable all (i.e., both) E steppers for IDEX-style duplication, but only active E steppers for multi-nozzle (i.e., single wide X carriage) duplication - #define _IS_DUPE(N) TERN0(HAS_DUPLICATION_MODE, (extruder_duplication_enabled && TERN1(MULTI_NOZZLE_DUPLICATION, TEST(duplication_e_mask, N)))) + #define _IS_DUPE(N) TERN0(HAS_DUPLICATION_MODE, (motion.extruder_duplication && TERN1(MULTI_NOZZLE_DUPLICATION, TEST(motion.duplication_e_mask, N)))) #define ENABLE_ONE_E(N) do{ \ if (N == E_STEPPER_INDEX(extruder) || _IS_DUPE(N)) { /* N is 'extruder', or N is duplicating */ \ diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 2f80a7044f..b3c7fa6f88 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -552,7 +552,7 @@ bool Probe::set_deployed(const bool deploy, const bool no_return/*=false*/) { #endif if (z_raise_wanted) { - const float zdest = DIFF_TERN(HAS_HOTEND_OFFSET, Z_CLEARANCE_DEPLOY_PROBE, hotend_offset[motion.extruder].z); + const float zdest = DIFF_TERN(HAS_HOTEND_OFFSET, Z_CLEARANCE_DEPLOY_PROBE, motion.active_hotend_offset().z); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z to ", zdest); motion.do_z_clearance(zdest); } @@ -780,7 +780,7 @@ bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s) { float Probe::run_z_probe(const bool sanity_check/*=true*/, const float z_min_point/*=Z_PROBE_LOW_POINT*/, const float z_clearance/*=Z_TWEEN_SAFE_CLEARANCE*/) { DEBUG_SECTION(log_probe, "Probe::run_z_probe", DEBUGGING(LEVELING)); - const float zoffs = SUM_TERN(HAS_HOTEND_OFFSET, -offset.z, hotend_offset[motion.extruder].z); + const float zoffs = SUM_TERN(HAS_HOTEND_OFFSET, -offset.z, motion.active_hotend_offset().z); auto try_to_probe = [&](PGM_P const plbl, const float z_probe_low_point, const feedRate_t fr_mm_s, const bool scheck) -> bool { constexpr float error_tolerance = Z_PROBE_ERROR_TOLERANCE; @@ -819,7 +819,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/, const float z_min_poi if (TERN0(PROBE_TARE, tare())) return NAN; // Do a first probe at the fast speed - if (try_to_probe(PSTR("FAST"), z_probe_low_point, z_probe_fast_mm_s, sanity_check)) return NAN; + if (try_to_probe(PSTR("FAST"), z_probe_low_point, motion.z_probe_fast_mm_s, sanity_check)) return NAN; const float z1 = DIFF_TERN(HAS_DELTA_SENSORLESS_PROBING, motion.position.z, largest_sensorless_adj); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("1st Probe Z:", z1); @@ -834,7 +834,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/, const float z_min_poi const float z = (Z_CLEARANCE_DEPLOY_PROBE) + 5.0f + _MAX(zoffs, 0.0f); if (motion.position.z > z) { // Probe down fast. If the probe never triggered, raise for probe clearance - if (!probe_down_to_z(z, z_probe_fast_mm_s)) + if (!probe_down_to_z(z, motion.z_probe_fast_mm_s)) motion.do_z_clearance(z_clearance); } #endif @@ -859,7 +859,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/, const float z_min_poi // Probe downward slowly to find the bed if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Slow Probe:"); - if (try_to_probe(PSTR("SLOW"), z_probe_low_point, z_probe_slow_mm_s, sanity_check)) return NAN; + if (try_to_probe(PSTR("SLOW"), z_probe_low_point, motion.z_probe_slow_mm_s, sanity_check)) return NAN; TERN_(MEASURE_BACKLASH_WHEN_PROBING, backlash.measure_with_probe()); @@ -928,7 +928,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/, const float z_min_poi #endif - return DIFF_TERN(HAS_HOTEND_OFFSET, measured_z, hotend_offset[motion.extruder].z); + return DIFF_TERN(HAS_HOTEND_OFFSET, measured_z, motion.active_hotend_offset().z); } #if DO_TOOLCHANGE_FOR_PROBING @@ -1007,7 +1007,7 @@ float Probe::probe_at_point( if (DEBUGGING(LEVELING)) DEBUG_ECHOPGM("Move to probe"); if (probe_relative) { // Get the nozzle position, adjust for active hotend if not 0 if (DEBUGGING(LEVELING)) DEBUG_ECHOPGM("-relative"); - npos -= DIFF_TERN(HAS_HOTEND_OFFSET, offset_xy, xy_pos_t(hotend_offset[motion.extruder])); + npos -= DIFF_TERN(HAS_HOTEND_OFFSET, offset_xy, motion.active_hotend_offset()); } if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" point"); @@ -1015,7 +1015,7 @@ float Probe::probe_at_point( motion.blocking_move(npos, feedRate_t(XY_PROBE_FEEDRATE_MM_S)); // Change Z motor current to homing current - TERN_(PROBING_USE_CURRENT_HOME, set_homing_current(Z_AXIS)); + TERN_(PROBING_USE_CURRENT_HOME, motion.set_homing_current(Z_AXIS)); float measured_z; @@ -1075,7 +1075,7 @@ float Probe::probe_at_point( #endif // !BD_SENSOR // Restore the Z homing current - TERN_(PROBING_USE_CURRENT_HOME, restore_homing_current(Z_AXIS)); + TERN_(PROBING_USE_CURRENT_HOME, motion.restore_homing_current(Z_AXIS)); return measured_z; } diff --git a/Marlin/src/module/scara.cpp b/Marlin/src/module/scara.cpp index abe21b87b4..69f9132e1d 100644 --- a/Marlin/src/module/scara.cpp +++ b/Marlin/src/module/scara.cpp @@ -305,21 +305,21 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; // Disable stealthChop if used. Enable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) #if X_SENSORLESS - sensorless_t stealth_states_x = start_sensorless_homing_per_axis(X_AXIS); + sensorless_t stealth_states_x = motion.sensorless_axis_homing_start(X_AXIS); #endif #if Y_SENSORLESS - sensorless_t stealth_states_y = start_sensorless_homing_per_axis(Y_AXIS); + sensorless_t stealth_states_y = motion.sensorless_axis_homing_start(Y_AXIS); #endif #if Z_SENSORLESS - sensorless_t stealth_states_z = start_sensorless_homing_per_axis(Z_AXIS); + sensorless_t stealth_states_z = motion.sensorless_axis_homing_start(Z_AXIS); #endif #endif // Set the homing current for all motors - TERN_(HAS_HOMING_CURRENT, set_homing_current(Z_AXIS)); + TERN_(HAS_HOMING_CURRENT, motion.set_homing_current(Z_AXIS)); // Move to home, should move Z, Y, then X. Move X to near 0 (to avoid div by zero - // and sign/angle stability around 0 for trigonometric functions), Y to 0 and Z to max_length + // and sign/angle stability around 0 for trigonometric functions), Y to 0 and Z to Z_MAX_LENGTH constexpr xyz_pos_t homing_pos_dir = apply_T_W_offset(xyz_pos_t({ 1, 0, Z_MAX_LENGTH })); motion.position.set(homing_pos_dir.x, homing_pos_dir.y, homing_pos_dir.z); @@ -327,13 +327,13 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; planner.synchronize(); // Restore the homing current for all motors - TERN_(HAS_HOMING_CURRENT, restore_homing_current(Z_AXIS)); + TERN_(HAS_HOMING_CURRENT, motion.restore_homing_current(Z_AXIS)); // Re-enable stealthChop if used. Disable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) - TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x)); - TERN_(Y_SENSORLESS, end_sensorless_homing_per_axis(Y_AXIS, stealth_states_y)); - TERN_(Z_SENSORLESS, end_sensorless_homing_per_axis(Z_AXIS, stealth_states_z)); + TERN_(X_SENSORLESS, motion.sensorless_axis_homing_end(X_AXIS, stealth_states_x)); + TERN_(Y_SENSORLESS, motion.sensorless_axis_homing_end(Y_AXIS, stealth_states_y)); + TERN_(Z_SENSORLESS, motion.sensorless_axis_homing_end(Z_AXIS, stealth_states_z)); #endif endstops.validate_homing_move(); diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 455407105c..261f1aa937 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -960,7 +960,7 @@ void MarlinSettings::postprocess() { #if HAS_HOTEND_OFFSET // Skip hotend 0 which must be 0 for (uint8_t e = 1; e < HOTENDS; ++e) - EEPROM_WRITE(hotend_offset[e]); + EEPROM_WRITE(motion.hotend_offset[e]); #endif } @@ -2031,7 +2031,7 @@ void MarlinSettings::postprocess() { #if HAS_HOTEND_OFFSET // Skip hotend 0 which must be 0 for (uint8_t e = 1; e < HOTENDS; ++e) - EEPROM_READ(hotend_offset[e]); + EEPROM_READ(motion.hotend_offset[e]); #endif } @@ -3373,7 +3373,7 @@ void MarlinSettings::reset() { // // Hotend Offsets // - TERN_(HAS_HOTEND_OFFSET, reset_hotend_offsets()); + TERN_(HAS_HOTEND_OFFSET, motion.reset_hotend_offsets()); // // Spindle Acceleration diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 701d3f09b5..b92d898157 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -436,11 +436,11 @@ xyze_int8_t Stepper::count_direction{0}; #endif #elif ENABLED(DUAL_X_CARRIAGE) #define X_APPLY_DIR(FWD,ALWAYS) do{ \ - if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(FWD); X2_DIR_WRITE((FWD) ^ idex_mirrored_mode); } \ + if (motion.extruder_duplication || ALWAYS) { X_DIR_WRITE(FWD); X2_DIR_WRITE((FWD) ^ motion.idex_mirrored_mode); } \ else if (last_moved_extruder) X2_DIR_WRITE(FWD); else X_DIR_WRITE(FWD); \ }while(0) #define X_APPLY_STEP(STATE,ALWAYS) do{ \ - if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(STATE); X2_STEP_WRITE(STATE); } \ + if (motion.extruder_duplication || ALWAYS) { X_STEP_WRITE(STATE); X2_STEP_WRITE(STATE); } \ else if (last_moved_extruder) X2_STEP_WRITE(STATE); else X_STEP_WRITE(STATE); \ }while(0) #elif HAS_X_AXIS diff --git a/Marlin/src/module/stepper/indirection.h b/Marlin/src/module/stepper/indirection.h index ea162b4949..188b619fb4 100644 --- a/Marlin/src/module/stepper/indirection.h +++ b/Marlin/src/module/stepper/indirection.h @@ -38,7 +38,7 @@ * E Special Cases * - SINGLENOZZLE: All Extruders have a single nozzle so there is one heater and no XYZ offset. * - Switching Extruder: One stepper is used for each pair of nozzles with a switching mechanism. - * - Duplication Mode: Two or more steppers move in sync when `extruder_duplication_enabled` is set. + * - Duplication Mode: Two or more steppers move in sync when `motion.extruder_duplication` is set. * With MULTI_NOZZLE_DUPLICATION a `duplication_e_mask` is also used. * - Průša MMU1: One stepper is used with a switching mechanism. Odd numbered E indexes are reversed. * - Průša MMU2: One stepper is used with a switching mechanism. @@ -774,7 +774,7 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #if HAS_DUPLICATION_MODE #if ENABLED(MULTI_NOZZLE_DUPLICATION) - #define DUPE(N,T,V) do{ if (TEST(duplication_e_mask, N)) E##N##_##T##_WRITE(V); }while(0); + #define DUPE(N,T,V) do{ if (TEST(motion.duplication_e_mask, N)) E##N##_##T##_WRITE(V); }while(0); #else #define DUPE(N,T,V) E##N##_##T##_WRITE(V); #endif @@ -782,9 +782,9 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset #define NDIR(N) DUPE(N,DIR,HIGH); #define RDIR(N) DUPE(N,DIR,LOW ); - #define E_STEP_WRITE(E,V) do{ if (extruder_duplication_enabled) { REPEAT2(E_STEPPERS, DUPE, STEP, V); } else _E_STEP_WRITE(E,V); }while(0) - #define FWD_E_DIR(E) do{ if (extruder_duplication_enabled) { REPEAT(E_STEPPERS, NDIR); } else _FWD_E_DIR(E); }while(0) - #define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { REPEAT(E_STEPPERS, RDIR); } else _REV_E_DIR(E); }while(0) + #define E_STEP_WRITE(E,V) do{ if (motion.extruder_duplication) { REPEAT2(E_STEPPERS, DUPE, STEP, V); } else _E_STEP_WRITE(E,V); }while(0) + #define FWD_E_DIR(E) do{ if (motion.extruder_duplication) { REPEAT(E_STEPPERS, NDIR); } else _FWD_E_DIR(E); }while(0) + #define REV_E_DIR(E) do{ if (motion.extruder_duplication) { REPEAT(E_STEPPERS, RDIR); } else _REV_E_DIR(E); }while(0) #else diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index 94e83983d9..7446eb93f3 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -171,7 +171,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. const float oldx = motion.position.x, grabpos = mpe_settings.parking_xpos[new_tool] + (new_tool ? mpe_settings.grab_distance : -mpe_settings.grab_distance), - offsetcompensation = TERN0(HAS_HOTEND_OFFSET, hotend_offset[motion.extruder].x * mpe_settings.compensation_factor); + offsetcompensation = TERN0(HAS_HOTEND_OFFSET, motion.active_hotend_offset().x * mpe_settings.compensation_factor); if (motion.homing_needed_error(_BV(X_AXIS))) return; @@ -295,7 +295,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. constexpr float parkingposx[] = PARKING_EXTRUDER_PARKING_X; #if HAS_HOTEND_OFFSET - const float x_offset = hotend_offset[motion.extruder].x; + const float x_offset = motion.active_hotend_offset().x; #else constexpr float x_offset = 0; #endif @@ -364,7 +364,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. // STEP 6 - motion.position.x = DIFF_TERN(HAS_HOTEND_OFFSET, midpos, hotend_offset[new_tool].x); + motion.position.x = DIFF_TERN(HAS_HOTEND_OFFSET, midpos, motion.hotend_offset[new_tool].x); DEBUG_SYNCHRONIZE(); DEBUG_POS("(6) Move midway between hotends", motion.position); @@ -732,7 +732,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. constexpr float toolheadposx[] = SWITCHING_TOOLHEAD_X_POS; const float placexpos = toolheadposx[motion.extruder], grabxpos = toolheadposx[new_tool]; - const xyz_pos_t &hoffs = hotend_offset[motion.extruder]; + const xyz_pos_t &hoffs = motion.active_hotend_offset(); /** * 1. Raise Z-Axis to give enough clearance @@ -815,7 +815,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. // 9. Apply Z hotend offset to current position DEBUG_POS("(9) Applying Z-offset", motion.position); - motion.position.z += hoffs.z - hotend_offset[new_tool].z; + motion.position.z += hoffs.z - motion.hotend_offset[new_tool].z; DEBUG_POS("EMST Tool-Change done.", motion.position); } @@ -842,7 +842,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. inline void dualx_tool_change(const uint8_t new_tool, bool &no_move) { DEBUG_ECHOPGM("Dual X Carriage Mode "); - switch (dual_x_carriage_mode) { + switch (motion.idex_mode) { case DXC_FULL_CONTROL_MODE: DEBUG_ECHOLNPGM("FULL_CONTROL"); break; case DXC_AUTO_PARK_MODE: DEBUG_ECHOLNPGM("AUTO_PARK"); break; case DXC_DUPLICATION_MODE: DEBUG_ECHOLNPGM("DUPLICATION"); break; @@ -850,13 +850,13 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. } // Get the home position of the currently-active tool - const float xhome = x_home_pos(motion.extruder); + const float xhome = motion.x_home_pos(motion.extruder); - if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE // If Auto-Park mode is enabled + if (motion.idex_mode == DXC_AUTO_PARK_MODE // If Auto-Park mode is enabled && marlin.isRunning() && !no_move // ...and movement is permitted - && (delayed_move_time || motion.position.x != xhome) // ...and delayed_move_time is set OR not "already parked"... + && (motion.delayed_move_time || motion.position.x != xhome) // ...and delayed_move_time is set OR not "already parked"... ) { - DEBUG_ECHOLNPGM("MoveX to ", xhome); + DEBUG_ECHOLNPGM("Move X to ", xhome); motion.position.x = xhome; motion.goto_current_position(planner.settings.max_feedrate_mm_s[X_AXIS]); // Park the current head planner.synchronize(); @@ -870,16 +870,16 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. DEBUG_POS("New Extruder", motion.position); - switch (dual_x_carriage_mode) { + switch (motion.idex_mode) { case DXC_FULL_CONTROL_MODE: // New current position is the position of the activated extruder - motion.position.x = inactive_extruder_x; + motion.position.x = motion.inactive_extruder_x; // Save the inactive extruder's position (from the old motion.position) - inactive_extruder_x = motion.destination.x; + motion.inactive_extruder_x = motion.destination.x; DEBUG_ECHOLNPGM("DXC Full Control curr.x=", motion.position.x, " dest.x=", motion.destination.x); break; case DXC_AUTO_PARK_MODE: - idex_set_parked(); + motion.idex_set_parked(); break; default: break; @@ -888,7 +888,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0. // Ensure X axis DIR pertains to the correct carriage stepper.apply_directions(); - DEBUG_ECHOLNPGM("Active extruder parked: ", active_extruder_parked ? "yes" : "no"); + DEBUG_ECHOLNPGM("Active extruder parked: ", motion.active_extruder_parked ? "yes" : "no"); DEBUG_POS("New extruder (parked)", motion.position); } @@ -1150,7 +1150,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { planner.synchronize(); #if ENABLED(DUAL_X_CARRIAGE) // Only T0 allowed if the Printer is in DXC_DUPLICATION_MODE or DXC_MIRRORED_MODE - if (new_tool != 0 && idex_is_duplicating()) + if (new_tool != 0 && motion.idex_is_duplicating()) return invalid_extruder_error(new_tool); #endif @@ -1164,12 +1164,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { TERN_(HAS_MARLINUI_MENU, if (!no_move) ui.update()); - #if ENABLED(DUAL_X_CARRIAGE) - const bool idex_full_control = dual_x_carriage_mode == DXC_FULL_CONTROL_MODE; - #else - constexpr bool idex_full_control = false; - #endif - + const bool idex_full_control = TERN0(DUAL_X_CARRIAGE, motion.idex_mode == DXC_FULL_CONTROL_MODE); const uint8_t old_tool = motion.extruder; const bool can_move_away = !no_move && !idex_full_control; @@ -1267,7 +1262,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif #if HAS_HOTEND_OFFSET - xyz_pos_t diff = hotend_offset[new_tool] - hotend_offset[old_tool]; + xyz_pos_t diff = motion.hotend_offset[new_tool] - motion.hotend_offset[old_tool]; TERN_(DUAL_X_CARRIAGE, diff.x = 0); #else constexpr xyz_pos_t diff{0}; @@ -1402,7 +1397,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { } #endif - TERN_(DUAL_X_CARRIAGE, idex_set_parked(false)); + TERN_(DUAL_X_CARRIAGE, motion.idex_set_parked(false)); } // should_move #if HAS_SWITCHING_NOZZLE @@ -1446,7 +1441,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { xyz_pos_t old_workspace_offset; if (new_tool > 0) { old_workspace_offset = motion.workspace_offset; - const xyz_pos_t &he = hotend_offset[new_tool]; + const xyz_pos_t &he = motion.hotend_offset[new_tool]; TERN_(TC_GCODE_USE_GLOBAL_X, motion.workspace_offset.x -= he.x); TERN_(TC_GCODE_USE_GLOBAL_Y, motion.workspace_offset.y -= he.y); TERN_(TC_GCODE_USE_GLOBAL_Z, motion.workspace_offset.z -= he.z); @@ -1489,7 +1484,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { // so that nozzle does not lower below print surface if new hotend Z offset is higher than old hotend Z offset. #if ANY(MECHANICAL_SWITCHING_EXTRUDER, MECHANICAL_SWITCHING_NOZZLE) #if HAS_HOTEND_OFFSET - xyz_pos_t diff = hotend_offset[new_tool] - hotend_offset[old_tool]; + xyz_pos_t diff = motion.hotend_offset[new_tool] - motion.hotend_offset[old_tool]; TERN_(DUAL_X_CARRIAGE, diff.x = 0); #else constexpr xyz_pos_t diff{0}; @@ -1509,7 +1504,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif #ifdef EVENT_GCODE_AFTER_TOOLCHANGE - if (TERN1(DUAL_X_CARRIAGE, dual_x_carriage_mode == DXC_AUTO_PARK_MODE)) + if (TERN1(DUAL_X_CARRIAGE, motion.idex_mode == DXC_AUTO_PARK_MODE)) gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_TOOLCHANGE)); #endif