diff options
author | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
---|---|---|
committer | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
commit | e8701195e66f2d27ffe17fb514eae8173795aaf7 (patch) | |
tree | 9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/module/motion.h | |
download | kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip |
Initial commit
Diffstat (limited to 'Marlin/src/module/motion.h')
-rw-r--r-- | Marlin/src/module/motion.h | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h new file mode 100644 index 0000000..887da1a --- /dev/null +++ b/Marlin/src/module/motion.h @@ -0,0 +1,465 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * motion.h + * + * High-level motion commands to feed the planner + * Some of these methods may migrate to the planner class. + */ + +#include "../inc/MarlinConfig.h" + +#if IS_SCARA + #include "scara.h" +#endif + +// Error margin to work around float imprecision +constexpr float fslop = 0.0001; + +extern bool relative_mode; + +extern xyze_pos_t current_position, // High-level current tool position + destination; // Destination for a move + +// G60/G61 Position Save and Return +#if SAVED_POSITIONS + extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3]; + extern xyz_pos_t stored_position[SAVED_POSITIONS]; +#endif + +// Scratch space for a cartesian result +extern xyz_pos_t cartes; + +// Until kinematics.cpp is created, declare this here +#if IS_KINEMATIC + extern abc_pos_t delta; +#endif + +#if HAS_ABL_NOT_UBL + extern feedRate_t xy_probe_feedrate_mm_s; + #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s +#elif defined(XY_PROBE_SPEED) + #define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_SPEED) +#else + #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE() +#endif + +constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_SPEED_FAST); + +/** + * Feed rates are often configured with mm/m + * but the planner and stepper like mm/s units. + */ +constexpr xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M; +FORCE_INLINE feedRate_t homing_feedrate(const AxisEnum a) { + float v; + #if ENABLED(DELTA) + v = homing_feedrate_mm_m.z; + #else + switch (a) { + case X_AXIS: v = homing_feedrate_mm_m.x; break; + case Y_AXIS: v = homing_feedrate_mm_m.y; break; + case Z_AXIS: + default: v = homing_feedrate_mm_m.z; + } + #endif + return MMM_TO_MMS(v); +} + +feedRate_t get_homing_bump_feedrate(const AxisEnum axis); + +/** + * The default feedrate for many moves, set by the most recent move + */ +extern feedRate_t feedrate_mm_s; + +/** + * Feedrate scaling is applied to all G0/G1, G2/G3, and G5 moves + */ +extern int16_t feedrate_percentage; +#define MMS_SCALED(V) ((V) * 0.01f * feedrate_percentage) + +// The active extruder (tool). Set with T<extruder> command. +#if HAS_MULTI_EXTRUDER + extern uint8_t active_extruder; +#else + constexpr uint8_t active_extruder = 0; +#endif + +#if ENABLED(LCD_SHOW_E_TOTAL) + extern float e_move_accumulator; +#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 const XYZval<T> NAME##_P DEFS_PROGMEM = { X_##OPT, Y_##OPT, Z_##OPT }; \ + return pgm_read_any(&NAME##_P[axis]); \ + } +XYZ_DEFS(float, base_min_pos, MIN_POS); +XYZ_DEFS(float, base_max_pos, MAX_POS); +XYZ_DEFS(float, base_home_pos, HOME_POS); +XYZ_DEFS(float, max_length, MAX_LENGTH); +XYZ_DEFS(int8_t, home_dir, HOME_DIR); + +inline 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_WORKSPACE_OFFSET + void update_workspace_offset(const AxisEnum axis); +#else + inline void update_workspace_offset(const AxisEnum) {} +#endif + +#if HAS_HOTEND_OFFSET + extern xyz_pos_t hotend_offset[HOTENDS]; + void reset_hotend_offsets(); +#elif HOTENDS + constexpr xyz_pos_t hotend_offset[HOTENDS] = { { 0 } }; +#else + constexpr xyz_pos_t hotend_offset[1] = { { 0 } }; +#endif + +#if HAS_SOFTWARE_ENDSTOPS + + typedef struct { + bool _enabled, _loose; + bool enabled() { return _enabled && !_loose; } + + xyz_pos_t min, max; + void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) { + amin = -100000; amax = 100000; // "No limits" + #if HAS_SOFTWARE_ENDSTOPS + if (enabled()) switch (axis) { + case X_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x); + TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x); + break; + case Y_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_Y, amin = min.y); + TERN_(MAX_SOFTWARE_ENDSTOP_Y, amax = max.y); + break; + case Z_AXIS: + TERN_(MIN_SOFTWARE_ENDSTOP_Z, amin = min.z); + TERN_(MAX_SOFTWARE_ENDSTOP_Z, amax = max.z); + default: break; + } + #endif + } + } soft_endstops_t; + + extern soft_endstops_t soft_endstop; + void apply_motion_limits(xyz_pos_t &target); + void update_software_endstops(const AxisEnum axis + #if HAS_HOTEND_OFFSET + , const uint8_t old_tool_index=0, const uint8_t new_tool_index=0 + #endif + ); + #define SET_SOFT_ENDSTOP_LOOSE(loose) (soft_endstop._loose = loose) + +#else // !HAS_SOFTWARE_ENDSTOPS + + typedef struct { + bool enabled() { return false; } + void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) { + // No limits + amin = current_position[axis] - 1000; + amax = current_position[axis] + 1000; + } + } soft_endstops_t; + extern soft_endstops_t soft_endstop; + #define apply_motion_limits(V) NOOP + #define update_software_endstops(...) NOOP + #define SET_SOFT_ENDSTOP_LOOSE(V) NOOP + +#endif // !HAS_SOFTWARE_ENDSTOPS + +void report_real_position(); +void report_current_position(); +void report_current_position_projected(); + +void get_cartesian_from_steppers(); +void set_current_from_steppers_for_axis(const AxisEnum axis); + +void quickstop_stepper(); + +/** + * sync_plan_position + * + * Set the planner/stepper positions directly from current_position with + * no kinematic translation. Used for homing axes and cartesian/core syncing. + */ +void sync_plan_position(); +void sync_plan_position_e(); + +/** + * Move the planner to the current position from wherever it last moved + * (or from wherever it has been told it is located). + */ +void line_to_current_position(const feedRate_t &fr_mm_s=feedrate_mm_s); + +#if EXTRUDERS + void unscaled_e_move(const float &length, const feedRate_t &fr_mm_s); +#endif + +void prepare_line_to_destination(); + +void _internal_move_to_destination(const feedRate_t &fr_mm_s=0.0f + #if IS_KINEMATIC + , const bool is_fast=false + #endif +); + +inline void prepare_internal_move_to_destination(const feedRate_t &fr_mm_s=0.0f) { + _internal_move_to_destination(fr_mm_s); +} + +#if IS_KINEMATIC + void prepare_fast_move_to_destination(const feedRate_t &scaled_fr_mm_s=MMS_SCALED(feedrate_mm_s)); + + inline void prepare_internal_fast_move_to_destination(const feedRate_t &fr_mm_s=0.0f) { + _internal_move_to_destination(fr_mm_s, true); + } +#endif + +/** + * Blocking movement and shorthand functions + */ +void do_blocking_move_to(const float rx, const float ry, const float rz, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to(const xy_pos_t &raw, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to(const xyz_pos_t &raw, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to(const xyze_pos_t &raw, const feedRate_t &fr_mm_s=0.0f); + +void do_blocking_move_to_x(const float &rx, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to_y(const float &ry, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to_z(const float &rz, const feedRate_t &fr_mm_s=0.0f); + +void do_blocking_move_to_xy(const float &rx, const float &ry, const feedRate_t &fr_mm_s=0.0f); +void do_blocking_move_to_xy(const xy_pos_t &raw, const feedRate_t &fr_mm_s=0.0f); +FORCE_INLINE void do_blocking_move_to_xy(const xyz_pos_t &raw, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); } +FORCE_INLINE void do_blocking_move_to_xy(const xyze_pos_t &raw, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); } + +void do_blocking_move_to_xy_z(const xy_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f); +FORCE_INLINE void do_blocking_move_to_xy_z(const xyz_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); } +FORCE_INLINE void do_blocking_move_to_xy_z(const xyze_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); } + +void remember_feedrate_and_scaling(); +void remember_feedrate_scaling_off(); +void restore_feedrate_and_scaling(); + +void do_z_clearance(const float &zclear, const bool z_trusted=true, const bool raise_on_untrusted=true, const bool lower_allowed=false); + +/** + * Homing and Trusted Axes + */ +constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS); +extern uint8_t axis_homed, axis_trusted; + +void homeaxis(const AxisEnum axis); +void set_axis_is_at_home(const AxisEnum axis); +void set_axis_never_homed(const AxisEnum axis); +uint8_t axes_should_home(uint8_t axis_bits=0x07); +bool homing_needed_error(uint8_t axis_bits=0x07); + +FORCE_INLINE bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); } +FORCE_INLINE bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); } +FORCE_INLINE bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; } +FORCE_INLINE bool no_axes_homed() { return !axis_homed; } +FORCE_INLINE bool all_axes_homed() { return xyz_bits == (axis_homed & xyz_bits); } +FORCE_INLINE bool homing_needed() { return !all_axes_homed(); } +FORCE_INLINE bool all_axes_trusted() { return xyz_bits == (axis_trusted & xyz_bits); } +FORCE_INLINE void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); } +FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); } +FORCE_INLINE void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); } +FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); } +FORCE_INLINE void set_all_homed() { axis_homed = axis_trusted = xyz_bits; } +FORCE_INLINE void set_all_unhomed() { axis_homed = axis_trusted = 0; } + +#if ENABLED(NO_MOTION_BEFORE_HOMING) + #define MOTION_CONDITIONS (IsRunning() && !homing_needed_error()) +#else + #define MOTION_CONDITIONS IsRunning() +#endif + +#define BABYSTEP_ALLOWED() ((ENABLED(BABYSTEP_WITHOUT_HOMING) || all_axes_trusted()) && (ENABLED(BABYSTEP_ALWAYS_AVAILABLE) || printer_busy())) + +/** + * Workspace offsets + */ +#if HAS_HOME_OFFSET || HAS_POSITION_SHIFT + #if HAS_HOME_OFFSET + extern xyz_pos_t home_offset; + #endif + #if HAS_POSITION_SHIFT + extern xyz_pos_t position_shift; + #endif + #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT + extern xyz_pos_t workspace_offset; + #define _WS workspace_offset + #elif HAS_HOME_OFFSET + #define _WS home_offset + #else + #define _WS position_shift + #endif + #define NATIVE_TO_LOGICAL(POS, AXIS) ((POS) + _WS[AXIS]) + #define LOGICAL_TO_NATIVE(POS, AXIS) ((POS) - _WS[AXIS]) + FORCE_INLINE void toLogical(xy_pos_t &raw) { raw += _WS; } + FORCE_INLINE void toLogical(xyz_pos_t &raw) { raw += _WS; } + FORCE_INLINE void toLogical(xyze_pos_t &raw) { raw += _WS; } + FORCE_INLINE void toNative(xy_pos_t &raw) { raw -= _WS; } + FORCE_INLINE void toNative(xyz_pos_t &raw) { raw -= _WS; } + FORCE_INLINE void toNative(xyze_pos_t &raw) { raw -= _WS; } +#else + #define NATIVE_TO_LOGICAL(POS, AXIS) (POS) + #define LOGICAL_TO_NATIVE(POS, AXIS) (POS) + FORCE_INLINE void toLogical(xy_pos_t&) {} + FORCE_INLINE void toLogical(xyz_pos_t&) {} + FORCE_INLINE void toLogical(xyze_pos_t&) {} + FORCE_INLINE void toNative(xy_pos_t&) {} + FORCE_INLINE void toNative(xyz_pos_t&) {} + FORCE_INLINE void toNative(xyze_pos_t&) {} +#endif +#define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS) +#define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS) +#define LOGICAL_Z_POSITION(POS) NATIVE_TO_LOGICAL(POS, Z_AXIS) +#define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS) +#define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS) +#define RAW_Z_POSITION(POS) LOGICAL_TO_NATIVE(POS, Z_AXIS) + +/** + * position_is_reachable family of functions + */ + +#if IS_KINEMATIC // (DELTA or SCARA) + + #if HAS_SCARA_OFFSET + extern abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset + #endif + + // Return true if the given point is within the printable area + inline bool position_is_reachable(const float &rx, const float &ry, const float inset=0) { + #if ENABLED(DELTA) + return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset + fslop); + #elif IS_SCARA + const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y); + return ( + R2 <= sq(L1 + L2) - inset + #if MIDDLE_DEAD_ZONE_R > 0 + && R2 >= sq(float(MIDDLE_DEAD_ZONE_R)) + #endif + ); + #endif + } + + inline bool position_is_reachable(const xy_pos_t &pos, const float inset=0) { + return position_is_reachable(pos.x, pos.y, inset); + } + +#else // CARTESIAN + + // Return true if the given position is within the machine bounds. + inline bool position_is_reachable(const float &rx, const float &ry) { + if (!WITHIN(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false; + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder) + return WITHIN(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop); + else + return WITHIN(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop); + #else + return WITHIN(rx, X_MIN_POS - fslop, X_MAX_POS + fslop); + #endif + } + inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); } + +#endif // CARTESIAN + +/** + * Duplication mode + */ +#if HAS_DUPLICATION_MODE + extern bool extruder_duplication_enabled; // Used in Dual X mode 2 +#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 + }; + + extern DualXMode dual_x_carriage_mode; + extern float inactive_extruder_x, // Used in mode 0 & 1 + duplicate_extruder_x_offset; // Used in mode 2 & 3 + extern xyz_pos_t raised_parked_position; // Used in mode 1 + extern bool active_extruder_parked; // Used in mode 1, 2 & 3 + extern millis_t delayed_move_time; // Used in mode 1 + extern int16_t duplicate_extruder_temp_offset; // Used in mode 2 & 3 + extern bool idex_mirrored_mode; // Used in mode 3 + + FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; } + + float x_home_pos(const uint8_t extruder); + + FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; } + + 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 + + FORCE_INLINE int x_home_dir(const uint8_t) { return home_dir(X_AXIS); } + +#endif + +#if HAS_M206_COMMAND + void set_home_offset(const AxisEnum axis, const float v); +#endif + +#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 |