From 1988c2eadc61c1bdce97f6a91db43a39393631bb Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 21 Nov 2021 21:29:27 +0100 Subject: [PATCH] rotational axes in degrees, feedrate interpretation like LinuxCNC. The time a move with feedrate F takes is now as follows: if any of X, Y, Z move (whether other axes are moved or not) t = sqrt(dX^2 + dY^2 + dZ^2)/F else, if none of XYZ move but any secondary linear axes move (wether rotational axes are moved or not): t = sqrt(dU^2 + dV^2 + dW^2)/F else, if only rotary axes are moved: t = sqrt(dA^2 + dB^2 + dC^2)/F --- Marlin/Configuration.h | 32 ++--- Marlin/Configuration_adv.h | 20 ++-- Marlin/src/core/language.h | 70 +---------- Marlin/src/gcode/config/M200-M205.cpp | 3 +- Marlin/src/gcode/config/M217.cpp | 72 ++++++++++-- Marlin/src/gcode/config/M92.cpp | 1 + Marlin/src/gcode/geometry/M206_M428.cpp | 61 +++++++++- Marlin/src/gcode/parser.h | 60 ++++++++-- Marlin/src/inc/Conditionals_post.h | 2 + Marlin/src/inc/SanityCheck.h | 2 + Marlin/src/module/planner.cpp | 149 ++++++++++++++++++------ 11 files changed, 325 insertions(+), 147 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index fe0937349102f..3c6c555f8028c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -150,7 +150,7 @@ //#define MACHINE_UUID "00000000-0000-0000-0000-000000000000" /** - * Define the number of coordinated linear axes. + * Define the number of coordinated axes. * See /~https://github.com/DerAndere1/Marlin/wiki * Each linear axis gets its own stepper control and endstop: * @@ -179,22 +179,28 @@ * I (AXIS4), J (AXIS5), K (AXIS6), U (AXIS7), V (AXIS8), W (AXIS9). */ #if LINEAR_AXES >= 4 + #define HAS_ROTATIONAL_AXIS4 0 #define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W'] #endif #if LINEAR_AXES >= 5 - #define AXIS5_NAME 'B' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define HAS_ROTATIONAL_AXIS5 0 + #define AXIS5_NAME 'B' // :['B', 'C', 'U', 'V', 'W'] #endif #if LINEAR_AXES >= 6 - #define AXIS6_NAME 'C' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define HAS_ROTATIONAL_AXIS6 1 + #define AXIS6_NAME 'C' // :['C', 'U', 'V', 'W'] #endif #if LINEAR_AXES >= 7 - #define AXIS7_NAME 'U' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define HAS_ROTATIONAL_AXIS7 0 + #define AXIS7_NAME 'U' // :['U', 'V', 'W'] #endif #if LINEAR_AXES >= 8 - #define AXIS8_NAME 'V' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define HAS_ROTATIONAL_AXIS8 0 + #define AXIS8_NAME 'V' // :['V', 'W'] #endif #if LINEAR_AXES >= 9 - #define AXIS9_NAME 'W' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define HAS_ROTATIONAL_AXIS9 0 + #define AXIS9_NAME 'W' // :['W'] #endif // @section extruder @@ -959,14 +965,14 @@ //#define DISTINCT_E_FACTORS /** - * Default Axis Steps Per Unit (steps/mm) + * Default Axis Steps Per Unit (steps/mm for linear axes, steps/° for rotational axes) * Override with M92 * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ #define DEFAULT_AXIS_STEPS_PER_UNIT { 80, 80, 400, 500 } /** - * Default Max Feed Rate (mm/s) + * Default Max Feed Rate (mm/s for linear axes, °/s for rotational axes) * Override with M203 * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ @@ -978,7 +984,7 @@ #endif /** - * Default Max Acceleration (change/s) change = mm/s + * Default Max Acceleration (speed change with time) (mm/(s^2) for linear axes, °/(s^2) for rotational axes) * (Maximum start speed for accelerated moves) * Override with M201 * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] @@ -991,7 +997,7 @@ #endif /** - * Default Acceleration (change/s) change = mm/s + * Default Acceleration (speed change with time) (mm/(s^2) for linear axes, °/(s^2) for rotational axes) * Override with M204 * * M204 P Acceleration @@ -1003,7 +1009,7 @@ #define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z acceleration for travel (non printing) moves /** - * Default Jerk limits (mm/s) + * Default Jerk limits (mm/(s^2)) * Override with M205 X Y Z E * * "Jerk" specifies the minimum speed change that requires acceleration. @@ -1432,7 +1438,7 @@ #define X_BED_SIZE 200 #define Y_BED_SIZE 200 -// Travel limits (mm) after homing, corresponding to endstop positions. +// Travel limits (mm for linear axes, ° for rotational axes) after homing, corresponding to endstop positions. #define X_MIN_POS 0 #define Y_MIN_POS 0 #define Z_MIN_POS 0 @@ -1819,7 +1825,7 @@ #define Z_SAFE_HOMING_Y_POINT Y_CENTER // Y point for Z homing #endif -// Homing speeds (mm/min) +// Homing speeds (mm/min for linear axes, °/min for rotational axes) #define HOMING_FEEDRATE_MM_M { (50*60), (50*60), (4*60) } // Validate that endstops are triggered on homing moves diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index fa8d655f14224..00302e324a4a5 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -828,12 +828,12 @@ * the position of the toolhead relative to the workspace. */ -//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (mm) Backoff from endstops before sensorless homing +//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (mm for linear axes, ° for rotational axes) Backoff from endstops before sensorless homing -#define HOMING_BUMP_MM { 5, 5, 2 } // (mm) Backoff from endstops after first bump +#define HOMING_BUMP_MM { 5, 5, 2 } // (mm for linear axes, ° for rotational axes) Backoff from endstops after first bump #define HOMING_BUMP_DIVISOR { 2, 2, 4 } // Re-Bump Speed Divisor (Divides the Homing Feedrate) -//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (mm) Backoff from endstops after homing +//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (mm for linear axes, ° for rotational axes) Backoff from endstops after homing //#define QUICK_HOME // If G28 contains XY do a diagonal move first //#define HOME_Y_BEFORE_X // If G28 contains XY home Y before X @@ -1038,8 +1038,8 @@ #define DISABLE_INACTIVE_E true // Default Minimum Feedrates for printing and travel moves -#define DEFAULT_MINIMUMFEEDRATE 0.0 // (mm/s) Minimum feedrate. Set with M205 S. -#define DEFAULT_MINTRAVELFEEDRATE 0.0 // (mm/s) Minimum travel feedrate. Set with M205 T. +#define DEFAULT_MINIMUMFEEDRATE 0.0 // (mm/s. °/s for moves involving only rotational axes) Minimum feedrate. Set with M205 S. +#define DEFAULT_MINTRAVELFEEDRATE 0.0 // (mm/s. °/s for moves involving only rotational axes) Minimum travel feedrate. Set with M205 T. // Minimum time that a segment needs to take as the buffer gets emptied #define DEFAULT_MINSEGMENTTIME 20000 // (µs) Set with M205 B. @@ -1075,7 +1075,7 @@ #if ENABLED(BACKLASH_COMPENSATION) // Define values for backlash distance and correction. // If BACKLASH_GCODE is enabled these values are the defaults. - #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (mm) One value for each linear axis + #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (mm for linear axes, ° for rotational axes) One value for each linear axis #define BACKLASH_CORRECTION 0.0 // 0.0 = no correction; 1.0 = full correction // Add steps for motor direction changes on CORE kinematics @@ -3067,10 +3067,10 @@ #define Z2_HYBRID_THRESHOLD 3 #define Z3_HYBRID_THRESHOLD 3 #define Z4_HYBRID_THRESHOLD 3 - #define I_HYBRID_THRESHOLD 3 - #define J_HYBRID_THRESHOLD 3 - #define K_HYBRID_THRESHOLD 3 - #define U_HYBRID_THRESHOLD 3 + #define I_HYBRID_THRESHOLD 3 // [mm/s for linear axis, °/s for rotational axis] + #define J_HYBRID_THRESHOLD 3 // [mm/s for linear axis, °/s for rotational axis] + #define K_HYBRID_THRESHOLD 3 // [mm/s for linear axis, °/s for rotational axis] + #define U_HYBRID_THRESHOLD 3 // [mm/s] #define V_HYBRID_THRESHOLD 3 #define W_HYBRID_THRESHOLD 3 #define E0_HYBRID_THRESHOLD 30 diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index da0fc3e975cbe..b4216545205ab 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -407,11 +407,7 @@ #endif #if LINEAR_AXES >= 5 - #if AXIS5_NAME == 'A' - #define AXIS5_STR "A" - #define STR_J_MIN "a_min" - #define STR_J_MAX "a_max" - #elif AXIS5_NAME == 'B' + #if AXIS5_NAME == 'B' #define AXIS5_STR "B" #define STR_J_MIN "b_min" #define STR_J_MAX "b_max" @@ -439,15 +435,7 @@ #endif #if LINEAR_AXES >= 6 - #if AXIS6_NAME == 'A' - #define AXIS6_STR "A" - #define STR_K_MIN "a_min" - #define STR_K_MAX "a_max" - #elif AXIS6_NAME == 'B' - #define AXIS6_STR "B" - #define STR_K_MIN "b_min" - #define STR_K_MAX "b_max" - #elif AXIS6_NAME == 'C' + #if AXIS6_NAME == 'C' #define AXIS6_STR "C" #define STR_K_MIN "c_min" #define STR_K_MAX "c_max" @@ -471,19 +459,7 @@ #endif #if LINEAR_AXES >= 7 - #if AXIS7_NAME == 'A' - #define AXIS7_STR "A" - #define STR_U_MIN "a_min" - #define STR_U_MAX "a_max" - #elif AXIS7_NAME == 'B' - #define AXIS7_STR "B" - #define STR_U_MIN "b_min" - #define STR_U_MAX "b_max" - #elif AXIS7_NAME == 'C' - #define AXIS7_STR "C" - #define STR_U_MIN "c_min" - #define STR_U_MAX "c_max" - #elif AXIS7_NAME == 'U' + #if AXIS7_NAME == 'U' #define AXIS7_STR "U" #define STR_U_MIN "u_min" #define STR_U_MAX "u_max" @@ -503,23 +479,7 @@ #endif #if LINEAR_AXES >= 8 - #if AXIS8_NAME == 'A' - #define AXIS8_STR "A" - #define STR_V_MIN "a_min" - #define STR_V_MAX "a_max" - #elif AXIS8_NAME == 'B' - #define AXIS8_STR "B" - #define STR_V_MIN "b_min" - #define STR_V_MAX "b_max" - #elif AXIS8_NAME == 'C' - #define AXIS8_STR "C" - #define STR_V_MIN "c_min" - #define STR_V_MAX "c_max" - #elif AXIS8_NAME == 'U' - #define AXIS8_STR "U" - #define STR_V_MIN "u_min" - #define STR_V_MAX "u_max" - #elif AXIS8_NAME == 'V' + #if AXIS8_NAME == 'V' #define AXIS8_STR "V" #define STR_V_MIN "v_min" #define STR_V_MAX "v_max" @@ -535,27 +495,7 @@ #endif #if LINEAR_AXES >= 9 - #if AXIS9_NAME == 'A' - #define AXIS9_STR "A" - #define STR_W_MIN "a_min" - #define STR_W_MAX "a_max" - #elif AXIS9_NAME == 'B' - #define AXIS9_STR "B" - #define STR_W_MIN "b_min" - #define STR_W_MAX "b_max" - #elif AXIS9_NAME == 'C' - #define AXIS9_STR "C" - #define STR_W_MIN "c_min" - #define STR_W_MAX "c_max" - #elif AXIS9_NAME == 'U' - #define AXIS9_STR "U" - #define STR_W_MIN "u_min" - #define STR_W_MAX "u_max" - #elif AXIS9_NAME == 'V' - #define AXIS9_STR "V" - #define STR_W_MIN "v_min" - #define STR_W_MAX "v_max" - #elif AXIS9_NAME == 'W' + #if AXIS9_NAME == 'W' #define AXIS9_STR "W" #define STR_W_MIN "w_min" #define STR_W_MAX "w_max" diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index 76e3b860011aa..cb823ea7bff4c 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -134,6 +134,7 @@ void GcodeSuite::M201() { void GcodeSuite::M201_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); + // TODO (DerAndere): Add support for rotational axes with distance in degrees SERIAL_ECHOLNPGM_P( LIST_N(DOUBLE(LINEAR_AXES), PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), @@ -281,7 +282,7 @@ void GcodeSuite::M205() { if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()), if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()), if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()), + if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()), // TODO (DerAndere): Rotational axes in degrees if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.value_linear_units()), if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.value_linear_units()), if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.value_linear_units()), diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp index e627b33f3377e..429a76b7ca427 100644 --- a/Marlin/src/gcode/config/M217.cpp +++ b/Marlin/src/gcode/config/M217.cpp @@ -96,22 +96,46 @@ void GcodeSuite::M217() { if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } #if LINEAR_AXES >= 4 - if (parser.seenval('I')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } + #if HAS_ROTATIONAL_AXIS4 + if (parser.seenval('I')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } + #else + if (parser.seenval('I')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } // TODO (DerAndere): Rotational axes in degrees + #endif #endif #if LINEAR_AXES >= 5 - if (parser.seenval('J')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } + #if HAS_ROTATIONAL_AXIS5 + if (parser.seenval('J')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } + #else + if (parser.seenval('J')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } + #endif #endif #if LINEAR_AXES >= 6 - if (parser.seenval('K')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + #if HAS_ROTATIONAL_AXIS6 + if (parser.seenval('K')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + #else + if (parser.seenval('K')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + #endif #endif #if LINEAR_AXES >= 7 - if (parser.seenval('C')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); } + #if HAS_ROTATIONAL_AXIS7 + if (parser.seenval('C')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); } + #else + if (parser.seenval('C')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); } + #endif #endif #if LINEAR_AXES >= 8 - if (parser.seenval('H')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); } + #if HAS_ROTATIONAL_AXIS8 + if (parser.seenval('H')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); } + #else + if (parser.seenval('H')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); } + #endif #endif #if LINEAR_AXES >= 9 - if (parser.seenval('O')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); } + #if HAS_ROTATIONAL_AXIS9 + if (parser.seenval('O')) { const int16_t v = parser.value_int(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); } + #else + if (parser.seenval('O')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); } + #endif #endif #endif @@ -179,22 +203,46 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) { SERIAL_ECHOPGM_P(SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)); SERIAL_ECHOPGM_P(SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)); #if LINEAR_AXES >= 4 - SERIAL_ECHOPGM_P(" I", LINEAR_UNIT(toolchange_settings.change_point.i)); + #if HAS_ROTATIONAL_AXIS4 + SERIAL_ECHOPGM_P(" I", toolchange_settings.change_point.i); + #else + SERIAL_ECHOPGM_P(" I", LINEAR_UNIT(toolchange_settings.change_point.i)); + #endif #endif #if LINEAR_AXES >= 5 - SERIAL_ECHOPGM_P(" J", LINEAR_UNIT(toolchange_settings.change_point.j)); + #if HAS_ROTATIONAL_AXIS5 + SERIAL_ECHOPGM_P(" J", toolchange_settings.change_point.j); + #else + SERIAL_ECHOPGM_P(" J", LINEAR_UNIT(toolchange_settings.change_point.j)); + #endif #endif #if LINEAR_AXES >= 6 - SERIAL_ECHOPGM_P(" K", LINEAR_UNIT(toolchange_settings.change_point.k)); + #if HAS_ROTATIONAL_AXIS6 + SERIAL_ECHOPGM_P(" K", toolchange_settings.change_point.k); + #else + SERIAL_ECHOPGM_P(" K", LINEAR_UNIT(toolchange_settings.change_point.k)); + #endif #endif #if LINEAR_AXES >= 7 - SERIAL_ECHOPGM_P(" C", LINEAR_UNIT(toolchange_settings.change_point.u)); + #if HAS_ROTATIONAL_AXIS7 + SERIAL_ECHOPGM_P(" C", toolchange_settings.change_point.u); + #else + SERIAL_ECHOPGM_P(" C", LINEAR_UNIT(toolchange_settings.change_point.u)); + #endif #endif #if LINEAR_AXES >= 8 - SERIAL_ECHOPGM_P(" H", LINEAR_UNIT(toolchange_settings.change_point.v)); + #if HAS_ROTATIONAL_AXIS8 + SERIAL_ECHOPGM_P(" H", toolchange_settings.change_point.v); + #else + SERIAL_ECHOPGM_P(" H", LINEAR_UNIT(toolchange_settings.change_point.v)); + #endif #endif #if LINEAR_AXES >= 9 - SERIAL_ECHOPGM_P(" O", LINEAR_UNIT(toolchange_settings.change_point.w)); + #if HAS_ROTATIONAL_AXIS9 + SERIAL_ECHOPGM_P(" O", toolchange_settings.change_point.w); + #else + SERIAL_ECHOPGM_P(" O", LINEAR_UNIT(toolchange_settings.change_point.w)); + #endif #endif #endif diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index d424644f88c51..8d6ae45a53e0d 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -92,6 +92,7 @@ void GcodeSuite::M92() { void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) { report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); + // TODO (DerAndere): Add support for rotational axes with distance in degrees SERIAL_ECHOPGM_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]), diff --git a/Marlin/src/gcode/geometry/M206_M428.cpp b/Marlin/src/gcode/geometry/M206_M428.cpp index 0b720f7b6fb9c..6273b46f7e678 100644 --- a/Marlin/src/gcode/geometry/M206_M428.cpp +++ b/Marlin/src/gcode/geometry/M206_M428.cpp @@ -40,9 +40,64 @@ void GcodeSuite::M206() { if (!parser.seen_any()) return M206_report(); - LOOP_LINEAR_AXES(i) - if (parser.seen(AXIS_CHAR(i))) - set_home_offset((AxisEnum)i, parser.value_linear_units()); + if (parser.seen('X')) + set_home_offset(X_AXIS, parser.value_linear_units()); + #if HAS_Y_AXIS + if (parser.seen('Y')) + set_home_offset(Y_AXIS, parser.value_linear_units()); + #endif + #if HAS_Z_AXIS + if (parser.seen('Z')) + set_home_offset(Y_AXIS, parser.value_linear_units()); + #endif + #if LINEAR_AXES >= 4 + if (parser.seen(AXIS4_NAME)) + #if HAS_ROTATIONAL_AXIS4 + set_home_offset(I_AXIS, parser.value_float()); + #else + set_home_offset(I_AXIS, parser.value_linear_units()); + #endif + #endif + #if LINEAR_AXES >= 5 + if (parser.seen(AXIS5_NAME)) + #if HAS_ROTATIONAL_AXIS5 + set_home_offset(J_AXIS, parser.value_float()); + #else + set_home_offset(J_AXIS, parser.value_linear_units()); + #endif + #endif + #if LINEAR_AXES >= 6 + if (parser.seen(AXIS6_NAME)) + #if HAS_ROTATIONAL_AXIS6 + set_home_offset(K_AXIS, parser.value_float()); + #else + set_home_offset(K_AXIS, parser.value_linear_units()); + #endif + #endif + #if LINEAR_AXES >= 7 + if (parser.seen(AXIS7_NAME)) + #if HAS_ROTATIONAL_AXIS7 + set_home_offset(U_AXIS, parser.value_float()); + #else + set_home_offset(U_AXIS, parser.value_linear_units()); + #endif + #endif + #if LINEAR_AXES >= 8 + if (parser.seen(AXIS8_NAME)) + #if HAS_ROTATIONAL_AXIS8 + set_home_offset(V_AXIS, parser.value_float()); + #else + set_home_offset(V_AXIS, parser.value_linear_units()); + #endif + #endif + #if LINEAR_AXES >= 9 + if (parser.seen(AXIS9_NAME)) + #if HAS_ROTATIONAL_AXIS9 + set_home_offset(W_AXIS, parser.value_float()); + #else + set_home_offset(W_AXIS, parser.value_linear_units()); + #endif + #endif #if ENABLED(MORGAN_SCARA) if (parser.seen('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 83fda5483608d..43242fad78132 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -309,13 +309,59 @@ class GCodeParser { } static inline float axis_unit_factor(const AxisEnum axis) { - return ( - #if HAS_EXTRUDERS - axis >= E_AXIS && volumetric_enabled ? volumetric_unit_factor : linear_unit_factor - #else - linear_unit_factor - #endif - ); + float unit_factor; + #if HAS_EXTRUDERS + if (axis >= E_AXIS && volumetric_enabled + #if HAS_ROTATIONAL_AXES + && axis != I_AXIS + #if HAS_ROTATIONAL_AXIS5 + && axis != J_AXIS + #endif + #if HAS_ROTATIONAL_AXIS6 + && axis != K_AXIS + #endif + #if HAS_ROTATIONAL_AXIS7 + && axis != U_AXIS + #endif + #if HAS_ROTATIONAL_AXIS8 + && axis != V_AXIS + #endif + #if HAS_ROTATIONAL_AXIS9 + && axis != W_AXIS + #endif + #endif + ) { + unit_factor = volumetric_unit_factor; + } + #endif + #if HAS_ROTATIONAL_AXES + if (axis == I_AXIS + #if HAS_ROTATIONAL_AXIS5 + || axis == J_AXIS + #endif + #if HAS_ROTATIONAL_AXIS6 + || axis == K_AXIS + #endif + #if HAS_ROTATIONAL_AXIS7 + || axis == U_AXIS + #endif + #if HAS_ROTATIONAL_AXIS8 + || axis == V_AXIS + #endif + #if HAS_ROTATIONAL_AXIS9 + || axis == W_AXIS + #endif + + ) { + unit_factor = 1.0f; + } + #endif + #if HAS_EXTRUDERS || HAS_ROTATIONAL_AXES + else unit_factor = linear_unit_factor; + #else + unit_factor = linear_unit_factor; + #endif + return unit_factor; } static inline float linear_value_to_mm(const_float_t v) { return v * linear_unit_factor; } diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index ad8098761aec2..e1a0d38f00b84 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -97,6 +97,8 @@ #define AXIS9_NAME 'W' #endif +#define HAS_ROTATIONAL_AXES (HAS_ROTATIONAL_AXIS4 || HAS_ROTATIONAL_AXIS5 || HAS_ROTATIONAL_AXIS6 || HAS_ROTATIONAL_AXIS7 || HAS_ROTATIONAL_AXIS8 || HAS_ROTATIONAL_AXIS9) + #define X_MAX_LENGTH (X_MAX_POS - (X_MIN_POS)) #if HAS_Y_AXIS #define Y_MAX_LENGTH (Y_MAX_POS - (Y_MIN_POS)) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 30661c9fcb8d2..42236dd12ed64 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1427,6 +1427,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #error "DIRECT_STEPPING currently requires LINEAR_AXES 3" #elif ENABLED(FOAMCUTTER_XYUV) && LINEAR_AXES < 5 #error "FOAMCUTTER_XYUV requires LINEAR_AXES >= 5." +#elif ENABLED(LINEAR_ADVANCE) && LINEAR_AXES >= 4 + #error "LINEAR_ADVANCE currently requires LINEAR_AXES <= 3." #endif /** diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 9e1a17ac44f9c..828c6666edd47 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1957,6 +1957,14 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction #endif + #elif ENABLED(MARKFORGED_XY) + if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction + if (db < 0) SBI(dm, B_AXIS); // Motor B direction + #elif ENABLED(MARKFORGED_YX) + if (da < 0) SBI(dm, A_AXIS); // Motor A direction + if (db + da < 0) SBI(dm, B_AXIS); // Motor B direction + #endif + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) #if LINEAR_AXES >= 4 if (di < 0) SBI(dm, I_AXIS); #endif @@ -1975,12 +1983,6 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #if LINEAR_AXES >= 9 if (dw < 0) SBI(dm, W_AXIS); #endif - #elif ENABLED(MARKFORGED_XY) - if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction - if (db < 0) SBI(dm, B_AXIS); // Motor B direction - #elif ENABLED(MARKFORGED_YX) - if (da < 0) SBI(dm, A_AXIS); // Motor A direction - if (db + da < 0) SBI(dm, B_AXIS); // Motor B direction #else LINEAR_AXIS_CODE( if (da < 0) SBI(dm, X_AXIS), @@ -2113,6 +2115,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move, TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator += steps_dist_mm.e); + #if HAS_ROTATIONAL_AXES + bool cartesian_move = true; + #endif + if (true LINEAR_AXIS_GANG( && block->steps.a < MIN_STEPS_PER_SEGMENT, && block->steps.b < MIN_STEPS_PER_SEGMENT, @@ -2131,40 +2137,111 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (millimeters) block->millimeters = millimeters; else { - block->millimeters = SQRT( + // Distance for interpretation of feedrate in accordance with LinuxCNC + #if ENABLED(FOAMCUTTER_XYUV) && LINEAR_AXES == 5 + // Return the largest distance move from either X/Y or I/J plane + block->millimeters = SQRT( + _MAX(sq(steps_dist_mm.x) + sq(steps_dist_mm.y), sq(steps_dist_mm.i) + sq(steps_dist_mm.j)) + #elif LINEAR_AXES >= 4 + float distance_sqr = ( + #else + block->millimeters = SQRT( + #endif #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) - LINEAR_AXIS_GANG( - sq(steps_dist_mm.head.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), - + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w) - ) + sq(steps_dist_mm.head.x) + #if HAS_Y_AXIS + + sq(steps_dist_mm.head.y) + #endif + #if HAS_Z_AXIS + + sq(steps_dist_mm.z) + #endif #elif CORE_IS_XZ - LINEAR_AXIS_GANG( - sq(steps_dist_mm.head.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.head.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), - + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w) - ) + sq(steps_dist_mm.head.x) + #if HAS_Y_AXIS + + sq(steps_dist_mm.y) + #endif + #if HAS_Z_AXIS + + sq(steps_dist_mm.head.z) + #endif #elif CORE_IS_YZ - LINEAR_AXIS_GANG( - sq(steps_dist_mm.x) + sq(steps_dist_mm.head.y) + sq(steps_dist_mm.head.z) - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), - + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w) - ) - #elif ENABLED(FOAMCUTTER_XYUV) - // Return the largest distance move from either X/Y or I/J plane - #if LINEAR_AXES >= 5 - _MAX(sq(steps_dist_mm.x) + sq(steps_dist_mm.y), sq(steps_dist_mm.i) + sq(steps_dist_mm.j)) - #else - sq(steps_dist_mm.x) + sq(steps_dist_mm.y) + sq(steps_dist_mm.x) + #if HAS_Y_AXIS + + sq(steps_dist_mm.head.y) + #endif + #if HAS_Z_AXIS + + sq(steps_dist_mm.head.z) + #endif + #elif ENABLED(FOAMCUTTER_XYUV) // foamcutter with only two axes: X, Y. For foamcutter with XYUV axes: see above. + sq(steps_dist_mm.x) + #if HAS_Y_AXIS + + sq(steps_dist_mm.y) #endif #else - LINEAR_AXIS_GANG( - sq(steps_dist_mm.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.z), - + sq(steps_dist_mm.i), + sq(steps_dist_mm.j), + sq(steps_dist_mm.k), - + sq(steps_dist_mm.u), + sq(steps_dist_mm.v), + sq(steps_dist_mm.w) - ) + sq(steps_dist_mm.x) + #if HAS_Y_AXIS + + sq(steps_dist_mm.y) + #endif + #if HAS_Z_AXIS + + sq(steps_dist_mm.z) + #endif #endif ); + + #if LINEAR_AXES >= 4 && !defined(FOAMCUTTER_XYUV) + if (NEAR_ZERO(distance_sqr)) { + // Move does not involve any primary linear axes (xyz) but might involve secondary linear axes + distance_sqr = (0.0 + #if LINEAR_AXES >= 4 && !HAS_ROTATIONAL_AXIS4 + + sq(steps_dist_mm.i) + #endif + #if LINEAR_AXES >= 5 && !HAS_ROTATIONAL_AXIS5 + + sq(steps_dist_mm.j) + #endif + #if LINEAR_AXES >= 6 && !HAS_ROTATIONAL_AXIS6 + + sq(steps_dist_mm.k) + #endif + #if LINEAR_AXES >= 7 && !HAS_ROTATIONAL_AXIS7 + + sq(steps_dist_mm.u) + #endif + #if LINEAR_AXES >= 8 && !HAS_ROTATIONAL_AXIS8 + + sq(steps_dist_mm.v) + #endif + #if LINEAR_AXES >= 9 && !HAS_ROTATIONAL_AXIS9 + + sq(steps_dist_mm.w) + #endif + ); + } + #endif + + #if HAS_ROTATIONAL_AXES + if (NEAR_ZERO(distance_sqr)) { + // Move involves only rotational axes. Calculate angular distance in accordance with LinuxCNC + cartesian_move = false; + distance_sqr = (sq(steps_dist_mm.i) + #if HAS_ROTATIONAL_AXIS5 + + sq(steps_dist_mm.j) + #endif + #if HAS_ROTATIONAL_AXIS6 + + sq(steps_dist_mm.k) + #endif + #if HAS_ROTATIONAL_AXIS7 + + sq(steps_dist_mm.u) + #endif + #if HAS_ROTATIONAL_AXIS8 + + sq(steps_dist_mm.v) + #endif + #if HAS_ROTATIONAL_AXIS9 + + sq(steps_dist_mm.w) + #endif + ); + } + else + cartesian_move = true; + #endif + + #if ((LINEAR_AXES >= 4 && !defined(FOAMCUTTER_XYUV)) || HAS_ROTATIONAL_AXES) + block->millimeters = SQRT(distance_sqr); + #endif } /** @@ -2326,7 +2403,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill #if EITHER(SLOWDOWN, HAS_WIRED_LCD) || defined(XY_FREQUENCY_LIMIT) - // Segment time im micro seconds + // Segment time in microseconds int32_t segment_time_us = LROUND(1000000.0f / inverse_secs); #endif @@ -2365,7 +2442,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, filwidth.advance_e(steps_dist_mm.e); #endif - // Calculate and limit speed in mm/sec + // Calculate and limit speed in mm/sec for linear axes and in degrees/sec for rotational axes xyze_float_t current_speed; float speed_factor = 1.0f; // factor <1 decreases speed @@ -2486,7 +2563,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, accel = CEIL((esteps ? settings.acceleration : settings.travel_acceleration) * steps_per_mm); #if ENABLED(LIN_ADVANCE) - + // TODO (DerAndere): Add support for LINEAR_AXES >= 4 #define MAX_E_JERK(N) TERN(HAS_LINEAR_E_JERK, max_e_jerk[E_INDEX_N(N)], max_jerk.e) /**