|
|
@ -56,6 +56,8 @@ |
|
|
|
* G12 - Clean tool |
|
|
|
* G20 - Set input units to inches |
|
|
|
* G21 - Set input units to millimeters |
|
|
|
* G26 - Mesh Validation Pattern (Requires UBL_G26_MESH_EDITING) |
|
|
|
* G27 - Park Nozzle (Requires NOZZLE_PARK_FEATURE) |
|
|
|
* G28 - Home one or more axes |
|
|
|
* G29 - Detailed Z probe, probes the bed at 3 or more points. Will fail if you haven't homed yet. |
|
|
|
* G30 - Single Z probe, probes bed at X Y location (defaults to current XY location) |
|
|
@ -97,14 +99,15 @@ |
|
|
|
* M76 - Pause the print job timer. |
|
|
|
* M77 - Stop the print job timer. |
|
|
|
* M78 - Show statistical information about the print jobs. (Requires PRINTCOUNTER) |
|
|
|
* M80 - Turn on Power Supply. (Requires POWER_SUPPLY) |
|
|
|
* M81 - Turn off Power Supply. (Requires POWER_SUPPLY) |
|
|
|
* M80 - Turn on Power Supply. (Requires POWER_SUPPLY > 0) |
|
|
|
* M81 - Turn off Power Supply. (Requires POWER_SUPPLY > 0) |
|
|
|
* M82 - Set E codes absolute (default). |
|
|
|
* M83 - Set E codes relative while in Absolute (G90) mode. |
|
|
|
* M84 - Disable steppers until next move, or use S<seconds> to specify an idle |
|
|
|
* duration after which steppers should turn off. S0 disables the timeout. |
|
|
|
* M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default) |
|
|
|
* M92 - Set planner.axis_steps_per_mm for one or more axes. |
|
|
|
* M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER) |
|
|
|
* M104 - Set extruder target temp. |
|
|
|
* M105 - Report current temperatures. |
|
|
|
* M106 - Fan on. |
|
|
@ -210,7 +213,6 @@ |
|
|
|
* M364 - SCARA calibration: Move to cal-position PSIC (90 deg to Theta calibration position) |
|
|
|
* |
|
|
|
* ************ Custom codes - This can change to suit future G-code regulations |
|
|
|
* M100 - Watch Free Memory (For Debugging). (Requires M100_FREE_MEMORY_WATCHER) |
|
|
|
* M928 - Start SD logging: "M928 filename.gco". Stop with M29. (Requires SDSUPPORT) |
|
|
|
* M999 - Restart after being stopped by error |
|
|
|
* |
|
|
@ -2425,9 +2427,12 @@ static void clean_up_after_endstop_or_probe_move() { |
|
|
|
|
|
|
|
#elif ENABLED(AUTO_BED_LEVELING_UBL) |
|
|
|
|
|
|
|
#if ENABLED(UBL_DELTA) |
|
|
|
if (( ubl.state.active ) && ( ! enable )) { // leveling from on to off
|
|
|
|
planner.unapply_leveling(current_position); |
|
|
|
#if PLANNER_LEVELING |
|
|
|
if (ubl.state.active != enable) { |
|
|
|
if (!enable) // leveling from on to off
|
|
|
|
planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); |
|
|
|
else |
|
|
|
planner.unapply_leveling(current_position); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
@ -3729,7 +3734,7 @@ inline void gcode_G28() { |
|
|
|
// Disable the leveling matrix before homing
|
|
|
|
#if HAS_LEVELING |
|
|
|
#if ENABLED(AUTO_BED_LEVELING_UBL) |
|
|
|
const bool bed_leveling_state_at_entry = ubl.state.active; |
|
|
|
const bool ubl_state_at_entry = ubl.state.active; |
|
|
|
#endif |
|
|
|
set_bed_leveling_enabled(false); |
|
|
|
#endif |
|
|
@ -3872,8 +3877,9 @@ inline void gcode_G28() { |
|
|
|
// move to a height where we can use the full xy-area
|
|
|
|
do_blocking_move_to_z(delta_clip_start_height); |
|
|
|
#endif |
|
|
|
|
|
|
|
#if ENABLED(AUTO_BED_LEVELING_UBL) |
|
|
|
set_bed_leveling_enabled(bed_leveling_state_at_entry); |
|
|
|
set_bed_leveling_enabled(ubl_state_at_entry); |
|
|
|
#endif |
|
|
|
|
|
|
|
clean_up_after_endstop_or_probe_move(); |
|
|
@ -4028,7 +4034,7 @@ void home_all_axes() { gcode_G28(); } |
|
|
|
#endif |
|
|
|
} |
|
|
|
// If there's another point to sample, move there with optional lift.
|
|
|
|
if (mbl_probe_index < (GRID_MAX_POINTS_X) * (GRID_MAX_POINTS_Y)) { |
|
|
|
if (mbl_probe_index < GRID_MAX_POINTS) { |
|
|
|
mbl.zigzag(mbl_probe_index, px, py); |
|
|
|
_manual_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]); |
|
|
|
|
|
|
@ -4247,8 +4253,6 @@ void home_all_axes() { gcode_G28(); } |
|
|
|
ABL_VAR int left_probe_bed_position, right_probe_bed_position, front_probe_bed_position, back_probe_bed_position; |
|
|
|
ABL_VAR float xGridSpacing, yGridSpacing; |
|
|
|
|
|
|
|
#define ABL_GRID_MAX (GRID_MAX_POINTS_X) * (GRID_MAX_POINTS_Y) |
|
|
|
|
|
|
|
#if ABL_PLANAR |
|
|
|
ABL_VAR uint8_t abl_grid_points_x = GRID_MAX_POINTS_X, |
|
|
|
abl_grid_points_y = GRID_MAX_POINTS_Y; |
|
|
@ -4262,7 +4266,7 @@ void home_all_axes() { gcode_G28(); } |
|
|
|
#if ABL_PLANAR |
|
|
|
ABL_VAR int abl2; |
|
|
|
#else // 3-point
|
|
|
|
int constexpr abl2 = ABL_GRID_MAX; |
|
|
|
int constexpr abl2 = GRID_MAX_POINTS; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
@ -4274,8 +4278,8 @@ void home_all_axes() { gcode_G28(); } |
|
|
|
|
|
|
|
ABL_VAR int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; |
|
|
|
|
|
|
|
ABL_VAR float eqnAMatrix[ABL_GRID_MAX * 3], // "A" matrix of the linear system of equations
|
|
|
|
eqnBVector[ABL_GRID_MAX], // "B" vector of Z points
|
|
|
|
ABL_VAR float eqnAMatrix[GRID_MAX_POINTS * 3], // "A" matrix of the linear system of equations
|
|
|
|
eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points
|
|
|
|
mean; |
|
|
|
#endif |
|
|
|
|
|
|
@ -7619,7 +7623,6 @@ inline void gcode_M205() { |
|
|
|
if (code_seen('H')) { |
|
|
|
home_offset[Z_AXIS] = code_value_linear_units() - DELTA_HEIGHT; |
|
|
|
current_position[Z_AXIS] += code_value_linear_units() - DELTA_HEIGHT - home_offset[Z_AXIS]; |
|
|
|
home_offset[Z_AXIS] = code_value_linear_units() - DELTA_HEIGHT; |
|
|
|
update_software_endstops(Z_AXIS); |
|
|
|
} |
|
|
|
if (code_seen('L')) delta_diagonal_rod = code_value_linear_units(); |
|
|
@ -8413,17 +8416,15 @@ void quickstop_stepper() { |
|
|
|
* Use either 'M421 X<linear> Y<linear> Z<linear>' or 'M421 I<xindex> J<yindex> Z<linear>' |
|
|
|
*/ |
|
|
|
inline void gcode_M421() { |
|
|
|
int8_t px = 0, py = 0; |
|
|
|
float z = 0; |
|
|
|
bool hasX, hasY, hasZ, hasI, hasJ; |
|
|
|
if ((hasX = code_seen('X'))) px = mbl.probe_index_x(code_value_linear_units()); |
|
|
|
if ((hasY = code_seen('Y'))) py = mbl.probe_index_y(code_value_linear_units()); |
|
|
|
if ((hasI = code_seen('I'))) px = code_value_linear_units(); |
|
|
|
if ((hasJ = code_seen('J'))) py = code_value_linear_units(); |
|
|
|
if ((hasZ = code_seen('Z'))) z = code_value_linear_units(); |
|
|
|
|
|
|
|
if (hasX && hasY && hasZ) { |
|
|
|
const bool hasX = code_seen('X'), hasI = !hasX && code_seen('I'); |
|
|
|
const int8_t px = hasX || hasI ? mbl.probe_index_x(code_value_linear_units()) : 0; |
|
|
|
const bool hasY = code_seen('Y'), hasJ = !hasY && code_seen('J'); |
|
|
|
const int8_t py = hasY || hasJ ? mbl.probe_index_y(code_value_linear_units()) : 0; |
|
|
|
const bool hasZ = code_seen('Z'); |
|
|
|
const float z = hasZ ? code_value_linear_units() : 0; |
|
|
|
|
|
|
|
if (hasX && hasY && hasZ) { |
|
|
|
if (px >= 0 && py >= 0) |
|
|
|
mbl.set_z(px, py, z); |
|
|
|
else { |
|
|
@ -8450,18 +8451,18 @@ void quickstop_stepper() { |
|
|
|
/**
|
|
|
|
* M421: Set a single Mesh Bed Leveling Z coordinate |
|
|
|
* |
|
|
|
* Usage: |
|
|
|
* M421 I<xindex> J<yindex> Z<linear> |
|
|
|
* or |
|
|
|
* M421 I<xindex> J<yindex> Q<offset> |
|
|
|
*/ |
|
|
|
inline void gcode_M421() { |
|
|
|
int8_t px = 0, py = 0; |
|
|
|
float z = 0; |
|
|
|
bool hasI, hasJ, hasZ, hasQ; |
|
|
|
if ((hasI = code_seen('I'))) px = code_value_int(); |
|
|
|
if ((hasJ = code_seen('J'))) py = code_value_int(); |
|
|
|
if ((hasZ = code_seen('Z'))) z = code_value_linear_units(); |
|
|
|
if ((hasQ = code_seen('Q'))) z = code_value_linear_units(); |
|
|
|
|
|
|
|
const bool hasI = code_seen('I'); |
|
|
|
const int8_t px = hasI ? code_value_int() : 0; |
|
|
|
const bool hasJ = code_seen('J'); |
|
|
|
const int8_t py = hasJ ? code_value_int() : 0; |
|
|
|
const bool hasZ = code_seen('Z'), hasQ = !hasZ && code_seen('Q'); |
|
|
|
const float z = hasZ || hasQ ? code_value_linear_units() : 0; |
|
|
|
|
|
|
|
if (!hasI || !hasJ || (hasQ && hasZ) || (!hasQ && !hasZ)) { |
|
|
|
SERIAL_ERROR_START; |
|
|
@ -8494,35 +8495,33 @@ void quickstop_stepper() { |
|
|
|
/**
|
|
|
|
* M421: Set a single Mesh Bed Leveling Z coordinate |
|
|
|
* |
|
|
|
* Usage: |
|
|
|
* M421 I<xindex> J<yindex> Z<linear> |
|
|
|
* or |
|
|
|
* M421 I<xindex> J<yindex> Q<offset> |
|
|
|
* M421 C Z<linear> |
|
|
|
* M421 C Q<offset> |
|
|
|
*/ |
|
|
|
|
|
|
|
//todo: change multiple points simultaneously?
|
|
|
|
|
|
|
|
inline void gcode_M421() { |
|
|
|
int8_t px = 0, py = 0; |
|
|
|
float z = 0; |
|
|
|
bool hasI, hasJ, hasZ, hasQ, hasC; |
|
|
|
if ((hasI = code_seen('I'))) px = code_value_int(); |
|
|
|
if ((hasJ = code_seen('J'))) py = code_value_int(); |
|
|
|
if ((hasZ = code_seen('Z'))) z = code_value_linear_units(); |
|
|
|
if ((hasQ = code_seen('Q'))) z = code_value_linear_units(); |
|
|
|
hasC = code_seen('C'); |
|
|
|
|
|
|
|
if ( (!(hasI && hasJ) && !hasC) || (hasQ && hasZ) || (!hasQ && !hasZ)) { |
|
|
|
|
|
|
|
// Get the closest position for 'C', if needed
|
|
|
|
const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, current_position[X_AXIS], current_position[Y_AXIS], USE_NOZZLE_AS_REFERENCE, NULL, false); |
|
|
|
|
|
|
|
const bool hasC = code_seen('C'), hasI = code_seen('I'); |
|
|
|
const int8_t px = hasC ? location.x_index : hasI ? code_value_int() : 0; |
|
|
|
|
|
|
|
const bool hasJ = code_seen('J'); |
|
|
|
const int8_t py = hasC ? location.y_index : hasJ ? code_value_int() : 0; |
|
|
|
|
|
|
|
const bool hasZ = code_seen('Z'), hasQ = !hasZ && code_seen('Q'); |
|
|
|
const float z = hasZ || hasQ ? code_value_linear_units() : 0; |
|
|
|
|
|
|
|
if ( ((hasI && hasJ) == hasC) || (hasQ && hasZ) || (!hasQ && !hasZ)) { |
|
|
|
SERIAL_ERROR_START; |
|
|
|
SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (hasC) { // get closest position
|
|
|
|
const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, current_position[X_AXIS], current_position[Y_AXIS], USE_NOZZLE_AS_REFERENCE, NULL, false); |
|
|
|
px = location.x_index; |
|
|
|
py = location.y_index; |
|
|
|
} |
|
|
|
|
|
|
|
if (WITHIN(px, 0, GRID_MAX_POINTS_X - 1) && WITHIN(py, 0, GRID_MAX_POINTS_Y - 1)) { |
|
|
|
if (hasZ) // doing an absolute mesh value
|
|
|
|
ubl.z_values[px][py] = z; |
|
|
@ -8534,7 +8533,8 @@ void quickstop_stepper() { |
|
|
|
SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
#endif // AUTO_BED_LEVELING_UBL
|
|
|
|
|
|
|
|
#if HAS_M206_COMMAND |
|
|
|
|
|
|
@ -11106,7 +11106,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
|
|
|
|
#endif // AUTO_BED_LEVELING_BILINEAR
|
|
|
|
|
|
|
|
#if IS_KINEMATIC && DISABLED(UBL_DELTA) |
|
|
|
#if IS_KINEMATIC && !UBL_DELTA |
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare a linear move in a DELTA or SCARA setup. |
|
|
@ -11117,7 +11117,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
inline bool prepare_kinematic_move_to(float ltarget[XYZE]) { |
|
|
|
|
|
|
|
// Get the top feedrate of the move in the XY plane
|
|
|
|
float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s); |
|
|
|
const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s); |
|
|
|
|
|
|
|
// If the move is only in Z/E don't split up the move
|
|
|
|
if (ltarget[X_AXIS] == current_position[X_AXIS] && ltarget[Y_AXIS] == current_position[Y_AXIS]) { |
|
|
@ -11126,7 +11126,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
} |
|
|
|
|
|
|
|
// Fail if attempting move outside printable radius
|
|
|
|
if ( ! position_is_reachable_xy( ltarget[X_AXIS], ltarget[Y_AXIS] )) return true; |
|
|
|
if (!position_is_reachable_xy(ltarget[X_AXIS], ltarget[Y_AXIS])) return true; |
|
|
|
|
|
|
|
// Get the cartesian distances moved in XYZE
|
|
|
|
float difference[XYZE]; |
|
|
@ -11142,7 +11142,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
if (UNEAR_ZERO(cartesian_mm)) return true; |
|
|
|
|
|
|
|
// Minimum number of seconds to move the given distance
|
|
|
|
float seconds = cartesian_mm / _feedrate_mm_s; |
|
|
|
const float seconds = cartesian_mm / _feedrate_mm_s; |
|
|
|
|
|
|
|
// The number of segments-per-second times the duration
|
|
|
|
// gives the number of segments
|
|
|
@ -11227,7 +11227,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
#else // !IS_KINEMATIC
|
|
|
|
#else // !IS_KINEMATIC || UBL_DELTA
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare a linear move in a Cartesian setup. |
|
|
@ -11265,7 +11265,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
#endif // !IS_KINEMATIC
|
|
|
|
#endif // !IS_KINEMATIC || UBL_DELTA
|
|
|
|
|
|
|
|
#if ENABLED(DUAL_X_CARRIAGE) |
|
|
|
|
|
|
@ -11377,21 +11377,21 @@ void prepare_move_to_destination() { |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
#if IS_KINEMATIC |
|
|
|
#if ENABLED(UBL_DELTA) |
|
|
|
if (ubl_prepare_linear_move_to(destination,feedrate_mm_s)) return; |
|
|
|
#else |
|
|
|
if (prepare_kinematic_move_to(destination)) return; |
|
|
|
#endif |
|
|
|
#else |
|
|
|
#if ENABLED(DUAL_X_CARRIAGE) |
|
|
|
if (prepare_move_to_destination_dualx()) return; |
|
|
|
#elif ENABLED(UBL_DELTA) // will work for CARTESIAN too (smaller segments follow mesh more closely)
|
|
|
|
if (ubl_prepare_linear_move_to(destination,feedrate_mm_s)) return; |
|
|
|
if ( |
|
|
|
#if IS_KINEMATIC |
|
|
|
#if UBL_DELTA |
|
|
|
ubl_prepare_linear_move_to(destination, feedrate_mm_s) |
|
|
|
#else |
|
|
|
prepare_kinematic_move_to(destination) |
|
|
|
#endif |
|
|
|
#elif ENABLED(DUAL_X_CARRIAGE) |
|
|
|
prepare_move_to_destination_dualx() |
|
|
|
#elif UBL_DELTA // will work for CARTESIAN too (smaller segments follow mesh more closely)
|
|
|
|
ubl_prepare_linear_move_to(destination, feedrate_mm_s) |
|
|
|
#else |
|
|
|
if (prepare_move_to_destination_cartesian()) return; |
|
|
|
prepare_move_to_destination_cartesian() |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
) return; |
|
|
|
|
|
|
|
set_current_to_destination(); |
|
|
|
} |
|
|
@ -11432,7 +11432,7 @@ void prepare_move_to_destination() { |
|
|
|
if (angular_travel == 0 && current_position[X_AXIS] == logical[X_AXIS] && current_position[Y_AXIS] == logical[Y_AXIS]) |
|
|
|
angular_travel += RADIANS(360); |
|
|
|
|
|
|
|
float mm_of_travel = HYPOT(angular_travel * radius, fabs(linear_travel)); |
|
|
|
const float mm_of_travel = HYPOT(angular_travel * radius, fabs(linear_travel)); |
|
|
|
if (mm_of_travel < 0.001) return; |
|
|
|
|
|
|
|
uint16_t segments = floor(mm_of_travel / (MM_PER_ARC_SEGMENT)); |
|
|
|