Consolidate "bedlevel" code
This commit is contained in:
@ -93,7 +93,7 @@
|
||||
* 329 G29 S ubl.state.storage_slot (int8_t)
|
||||
*
|
||||
* DELTA: 48 bytes
|
||||
* 348 M666 XYZ endstop_adj (float x3)
|
||||
* 348 M666 XYZ delta_endstop_adj (float x3)
|
||||
* 360 M665 R delta_radius (float)
|
||||
* 364 M665 L delta_diagonal_rod (float)
|
||||
* 368 M665 S delta_segments_per_second (float)
|
||||
@ -187,6 +187,10 @@ MarlinSettings settings;
|
||||
|
||||
#include "../gcode/parser.h"
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
#include "../module/probe.h"
|
||||
#endif
|
||||
@ -199,14 +203,6 @@ MarlinSettings settings;
|
||||
#include "../feature/fwretract.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
extern void refresh_bed_level();
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
#include "../gcode/feature/fwretract/fwretract.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Post-process after Retrieve or Reset
|
||||
*/
|
||||
@ -421,7 +417,7 @@ void MarlinSettings::postprocess() {
|
||||
|
||||
// 9 floats for DELTA / Z_DUAL_ENDSTOPS
|
||||
#if ENABLED(DELTA)
|
||||
EEPROM_WRITE(endstop_adj); // 3 floats
|
||||
EEPROM_WRITE(delta_endstop_adj); // 3 floats
|
||||
EEPROM_WRITE(delta_radius); // 1 float
|
||||
EEPROM_WRITE(delta_diagonal_rod); // 1 float
|
||||
EEPROM_WRITE(delta_segments_per_second); // 1 float
|
||||
@ -806,7 +802,7 @@ void MarlinSettings::postprocess() {
|
||||
#endif // AUTO_BED_LEVELING_UBL
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
EEPROM_READ(endstop_adj); // 3 floats
|
||||
EEPROM_READ(delta_endstop_adj); // 3 floats
|
||||
EEPROM_READ(delta_radius); // 1 float
|
||||
EEPROM_READ(delta_diagonal_rod); // 1 float
|
||||
EEPROM_READ(delta_segments_per_second); // 1 float
|
||||
@ -1196,7 +1192,7 @@ void MarlinSettings::reset() {
|
||||
#if ENABLED(DELTA)
|
||||
const float adj[ABC] = DELTA_ENDSTOP_ADJ,
|
||||
dta[ABC] = DELTA_TOWER_ANGLE_TRIM;
|
||||
COPY(endstop_adj, adj);
|
||||
COPY(delta_endstop_adj, adj);
|
||||
delta_radius = DELTA_RADIUS;
|
||||
delta_diagonal_rod = DELTA_DIAGONAL_ROD;
|
||||
delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;
|
||||
@ -1602,9 +1598,9 @@ void MarlinSettings::reset() {
|
||||
SERIAL_ECHOLNPGM("Endstop adjustment:");
|
||||
}
|
||||
CONFIG_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M666 X", LINEAR_UNIT(endstop_adj[X_AXIS]));
|
||||
SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(endstop_adj[Y_AXIS]));
|
||||
SERIAL_ECHOLNPAIR(" Z", LINEAR_UNIT(endstop_adj[Z_AXIS]));
|
||||
SERIAL_ECHOPAIR(" M666 X", LINEAR_UNIT(delta_endstop_adj[X_AXIS]));
|
||||
SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(delta_endstop_adj[Y_AXIS]));
|
||||
SERIAL_ECHOLNPAIR(" Z", LINEAR_UNIT(delta_endstop_adj[Z_AXIS]));
|
||||
if (!forReplay) {
|
||||
CONFIG_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Delta settings: L<diagonal_rod> R<radius> H<height> S<segments_per_s> B<calibration radius> XYZ<tower angle corrections>");
|
||||
|
269
Marlin/src/module/delta.cpp
Normal file
269
Marlin/src/module/delta.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* delta.cpp
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
|
||||
#include "delta.h"
|
||||
#include "motion.h"
|
||||
|
||||
// For homing:
|
||||
#include "stepper.h"
|
||||
#include "endstops.h"
|
||||
#include "../lcd/ultralcd.h"
|
||||
#include "../Marlin.h"
|
||||
|
||||
// Initialized by settings.load()
|
||||
float delta_endstop_adj[ABC] = { 0 },
|
||||
delta_radius,
|
||||
delta_diagonal_rod,
|
||||
delta_segments_per_second,
|
||||
delta_calibration_radius,
|
||||
delta_tower_angle_trim[2];
|
||||
|
||||
float delta_tower[ABC][2],
|
||||
delta_diagonal_rod_2_tower[ABC],
|
||||
delta_clip_start_height = Z_MAX_POS;
|
||||
|
||||
float delta_safe_distance_from_top();
|
||||
|
||||
/**
|
||||
* Recalculate factors used for delta kinematics whenever
|
||||
* settings have been changed (e.g., by M665).
|
||||
*/
|
||||
void recalc_delta_settings(float radius, float diagonal_rod) {
|
||||
const float trt[ABC] = DELTA_RADIUS_TRIM_TOWER,
|
||||
drt[ABC] = DELTA_DIAGONAL_ROD_TRIM_TOWER;
|
||||
delta_tower[A_AXIS][X_AXIS] = cos(RADIANS(210 + delta_tower_angle_trim[A_AXIS])) * (radius + trt[A_AXIS]); // front left tower
|
||||
delta_tower[A_AXIS][Y_AXIS] = sin(RADIANS(210 + delta_tower_angle_trim[A_AXIS])) * (radius + trt[A_AXIS]);
|
||||
delta_tower[B_AXIS][X_AXIS] = cos(RADIANS(330 + delta_tower_angle_trim[B_AXIS])) * (radius + trt[B_AXIS]); // front right tower
|
||||
delta_tower[B_AXIS][Y_AXIS] = sin(RADIANS(330 + delta_tower_angle_trim[B_AXIS])) * (radius + trt[B_AXIS]);
|
||||
delta_tower[C_AXIS][X_AXIS] = 0.0; // back middle tower
|
||||
delta_tower[C_AXIS][Y_AXIS] = (radius + trt[C_AXIS]);
|
||||
delta_diagonal_rod_2_tower[A_AXIS] = sq(diagonal_rod + drt[A_AXIS]);
|
||||
delta_diagonal_rod_2_tower[B_AXIS] = sq(diagonal_rod + drt[B_AXIS]);
|
||||
delta_diagonal_rod_2_tower[C_AXIS] = sq(diagonal_rod + drt[C_AXIS]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delta Inverse Kinematics
|
||||
*
|
||||
* Calculate the tower positions for a given logical
|
||||
* position, storing the result in the delta[] array.
|
||||
*
|
||||
* This is an expensive calculation, requiring 3 square
|
||||
* roots per segmented linear move, and strains the limits
|
||||
* of a Mega2560 with a Graphical Display.
|
||||
*
|
||||
* Suggested optimizations include:
|
||||
*
|
||||
* - Disable the home_offset (M206) and/or position_shift (G92)
|
||||
* features to remove up to 12 float additions.
|
||||
*
|
||||
* - Use a fast-inverse-sqrt function and add the reciprocal.
|
||||
* (see above)
|
||||
*/
|
||||
|
||||
#if ENABLED(DELTA_FAST_SQRT) && defined(ARDUINO_ARCH_AVR)
|
||||
/**
|
||||
* Fast inverse sqrt from Quake III Arena
|
||||
* See: https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
*/
|
||||
float Q_rsqrt(float number) {
|
||||
long i;
|
||||
float x2, y;
|
||||
const float threehalfs = 1.5f;
|
||||
x2 = number * 0.5f;
|
||||
y = number;
|
||||
i = * ( long * ) &y; // evil floating point bit level hacking
|
||||
i = 0x5F3759DF - ( i >> 1 ); // what the f***?
|
||||
y = * ( float * ) &i;
|
||||
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
|
||||
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DELTA_DEBUG() do { \
|
||||
SERIAL_ECHOPAIR("cartesian X:", raw[X_AXIS]); \
|
||||
SERIAL_ECHOPAIR(" Y:", raw[Y_AXIS]); \
|
||||
SERIAL_ECHOLNPAIR(" Z:", raw[Z_AXIS]); \
|
||||
SERIAL_ECHOPAIR("delta A:", delta[A_AXIS]); \
|
||||
SERIAL_ECHOPAIR(" B:", delta[B_AXIS]); \
|
||||
SERIAL_ECHOLNPAIR(" C:", delta[C_AXIS]); \
|
||||
}while(0)
|
||||
|
||||
void inverse_kinematics(const float logical[XYZ]) {
|
||||
DELTA_LOGICAL_IK();
|
||||
// DELTA_DEBUG();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the highest Z position where the
|
||||
* effector has the full range of XY motion.
|
||||
*/
|
||||
float delta_safe_distance_from_top() {
|
||||
float cartesian[XYZ] = {
|
||||
LOGICAL_X_POSITION(0),
|
||||
LOGICAL_Y_POSITION(0),
|
||||
LOGICAL_Z_POSITION(0)
|
||||
};
|
||||
inverse_kinematics(cartesian);
|
||||
float distance = delta[A_AXIS];
|
||||
cartesian[Y_AXIS] = LOGICAL_Y_POSITION(DELTA_PRINTABLE_RADIUS);
|
||||
inverse_kinematics(cartesian);
|
||||
return FABS(distance - delta[A_AXIS]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delta Forward Kinematics
|
||||
*
|
||||
* See the Wikipedia article "Trilateration"
|
||||
* https://en.wikipedia.org/wiki/Trilateration
|
||||
*
|
||||
* Establish a new coordinate system in the plane of the
|
||||
* three carriage points. This system has its origin at
|
||||
* tower1, with tower2 on the X axis. Tower3 is in the X-Y
|
||||
* plane with a Z component of zero.
|
||||
* We will define unit vectors in this coordinate system
|
||||
* in our original coordinate system. Then when we calculate
|
||||
* the Xnew, Ynew and Znew values, we can translate back into
|
||||
* the original system by moving along those unit vectors
|
||||
* by the corresponding values.
|
||||
*
|
||||
* Variable names matched to Marlin, c-version, and avoid the
|
||||
* use of any vector library.
|
||||
*
|
||||
* by Andreas Hardtung 2016-06-07
|
||||
* based on a Java function from "Delta Robot Kinematics V3"
|
||||
* by Steve Graves
|
||||
*
|
||||
* The result is stored in the cartes[] array.
|
||||
*/
|
||||
void forward_kinematics_DELTA(float z1, float z2, float z3) {
|
||||
// Create a vector in old coordinates along x axis of new coordinate
|
||||
float p12[3] = { delta_tower[B_AXIS][X_AXIS] - delta_tower[A_AXIS][X_AXIS], delta_tower[B_AXIS][Y_AXIS] - delta_tower[A_AXIS][Y_AXIS], z2 - z1 };
|
||||
|
||||
// Get the Magnitude of vector.
|
||||
float d = SQRT( sq(p12[0]) + sq(p12[1]) + sq(p12[2]) );
|
||||
|
||||
// Create unit vector by dividing by magnitude.
|
||||
float ex[3] = { p12[0] / d, p12[1] / d, p12[2] / d };
|
||||
|
||||
// Get the vector from the origin of the new system to the third point.
|
||||
float p13[3] = { delta_tower[C_AXIS][X_AXIS] - delta_tower[A_AXIS][X_AXIS], delta_tower[C_AXIS][Y_AXIS] - delta_tower[A_AXIS][Y_AXIS], z3 - z1 };
|
||||
|
||||
// Use the dot product to find the component of this vector on the X axis.
|
||||
float i = ex[0] * p13[0] + ex[1] * p13[1] + ex[2] * p13[2];
|
||||
|
||||
// Create a vector along the x axis that represents the x component of p13.
|
||||
float iex[3] = { ex[0] * i, ex[1] * i, ex[2] * i };
|
||||
|
||||
// Subtract the X component from the original vector leaving only Y. We use the
|
||||
// variable that will be the unit vector after we scale it.
|
||||
float ey[3] = { p13[0] - iex[0], p13[1] - iex[1], p13[2] - iex[2] };
|
||||
|
||||
// The magnitude of Y component
|
||||
float j = SQRT( sq(ey[0]) + sq(ey[1]) + sq(ey[2]) );
|
||||
|
||||
// Convert to a unit vector
|
||||
ey[0] /= j; ey[1] /= j; ey[2] /= j;
|
||||
|
||||
// The cross product of the unit x and y is the unit z
|
||||
// float[] ez = vectorCrossProd(ex, ey);
|
||||
float ez[3] = {
|
||||
ex[1] * ey[2] - ex[2] * ey[1],
|
||||
ex[2] * ey[0] - ex[0] * ey[2],
|
||||
ex[0] * ey[1] - ex[1] * ey[0]
|
||||
};
|
||||
|
||||
// We now have the d, i and j values defined in Wikipedia.
|
||||
// Plug them into the equations defined in Wikipedia for Xnew, Ynew and Znew
|
||||
float Xnew = (delta_diagonal_rod_2_tower[A_AXIS] - delta_diagonal_rod_2_tower[B_AXIS] + sq(d)) / (d * 2),
|
||||
Ynew = ((delta_diagonal_rod_2_tower[A_AXIS] - delta_diagonal_rod_2_tower[C_AXIS] + HYPOT2(i, j)) / 2 - i * Xnew) / j,
|
||||
Znew = SQRT(delta_diagonal_rod_2_tower[A_AXIS] - HYPOT2(Xnew, Ynew));
|
||||
|
||||
// Start from the origin of the old coordinates and add vectors in the
|
||||
// old coords that represent the Xnew, Ynew and Znew to find the point
|
||||
// in the old system.
|
||||
cartes[X_AXIS] = delta_tower[A_AXIS][X_AXIS] + ex[0] * Xnew + ey[0] * Ynew - ez[0] * Znew;
|
||||
cartes[Y_AXIS] = delta_tower[A_AXIS][Y_AXIS] + ex[1] * Xnew + ey[1] * Ynew - ez[1] * Znew;
|
||||
cartes[Z_AXIS] = z1 + ex[2] * Xnew + ey[2] * Ynew - ez[2] * Znew;
|
||||
}
|
||||
|
||||
/**
|
||||
* A delta can only safely home all axes at the same time
|
||||
* This is like quick_home_xy() but for 3 towers.
|
||||
*/
|
||||
bool home_delta() {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
|
||||
#endif
|
||||
// Init the current position of all carriages to 0,0,0
|
||||
ZERO(current_position);
|
||||
sync_plan_position();
|
||||
|
||||
// Move all carriages together linearly until an endstop is hit.
|
||||
current_position[X_AXIS] = current_position[Y_AXIS] = current_position[Z_AXIS] = (DELTA_HEIGHT + home_offset[Z_AXIS] + 10);
|
||||
feedrate_mm_s = homing_feedrate(X_AXIS);
|
||||
line_to_current_position();
|
||||
stepper.synchronize();
|
||||
|
||||
// If an endstop was not hit, then damage can occur if homing is continued.
|
||||
// This can occur if the delta height (DELTA_HEIGHT + home_offset[Z_AXIS]) is
|
||||
// not set correctly.
|
||||
if (!(Endstops::endstop_hit_bits & (_BV(X_MAX) | _BV(Y_MAX) | _BV(Z_MAX)))) {
|
||||
LCD_MESSAGEPGM(MSG_ERR_HOMING_FAILED);
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_HOMING_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
endstops.hit_on_purpose(); // clear endstop hit flags
|
||||
|
||||
// At least one carriage has reached the top.
|
||||
// Now re-home each carriage separately.
|
||||
HOMEAXIS(A);
|
||||
HOMEAXIS(B);
|
||||
HOMEAXIS(C);
|
||||
|
||||
// Set all carriages to their home positions
|
||||
// Do this here all at once for Delta, because
|
||||
// XYZ isn't ABC. Applying this per-tower would
|
||||
// give the impression that they are the same.
|
||||
LOOP_XYZ(i) set_axis_is_at_home((AxisEnum)i);
|
||||
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< home_delta", current_position);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // DELTA
|
141
Marlin/src/module/delta.h
Normal file
141
Marlin/src/module/delta.h
Normal file
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* delta.h - Delta-specific functions
|
||||
*/
|
||||
|
||||
#ifndef __DELTA_H__
|
||||
#define __DELTA_H__
|
||||
|
||||
extern float delta_endstop_adj[ABC],
|
||||
delta_radius,
|
||||
delta_diagonal_rod,
|
||||
delta_segments_per_second,
|
||||
delta_calibration_radius,
|
||||
delta_tower_angle_trim[2];
|
||||
|
||||
extern float delta_tower[ABC][2],
|
||||
delta_diagonal_rod_2_tower[ABC],
|
||||
delta_clip_start_height;
|
||||
|
||||
/**
|
||||
* Recalculate factors used for delta kinematics whenever
|
||||
* settings have been changed (e.g., by M665).
|
||||
*/
|
||||
void recalc_delta_settings(float radius, float diagonal_rod);
|
||||
|
||||
/**
|
||||
* Delta Inverse Kinematics
|
||||
*
|
||||
* Calculate the tower positions for a given logical
|
||||
* position, storing the result in the delta[] array.
|
||||
*
|
||||
* This is an expensive calculation, requiring 3 square
|
||||
* roots per segmented linear move, and strains the limits
|
||||
* of a Mega2560 with a Graphical Display.
|
||||
*
|
||||
* Suggested optimizations include:
|
||||
*
|
||||
* - Disable the home_offset (M206) and/or position_shift (G92)
|
||||
* features to remove up to 12 float additions.
|
||||
*
|
||||
* - Use a fast-inverse-sqrt function and add the reciprocal.
|
||||
* (see above)
|
||||
*/
|
||||
|
||||
#if ENABLED(DELTA_FAST_SQRT) && defined(ARDUINO_ARCH_AVR)
|
||||
/**
|
||||
* Fast inverse sqrt from Quake III Arena
|
||||
* See: https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
*/
|
||||
float Q_rsqrt(float number);
|
||||
#define _SQRT(n) (1.0f / Q_rsqrt(n))
|
||||
#else
|
||||
#define _SQRT(n) SQRT(n)
|
||||
#endif
|
||||
|
||||
// Macro to obtain the Z position of an individual tower
|
||||
#define DELTA_Z(T) raw[Z_AXIS] + _SQRT( \
|
||||
delta_diagonal_rod_2_tower[T] - HYPOT2( \
|
||||
delta_tower[T][X_AXIS] - raw[X_AXIS], \
|
||||
delta_tower[T][Y_AXIS] - raw[Y_AXIS] \
|
||||
) \
|
||||
)
|
||||
|
||||
#define DELTA_RAW_IK() do { \
|
||||
delta[A_AXIS] = DELTA_Z(A_AXIS); \
|
||||
delta[B_AXIS] = DELTA_Z(B_AXIS); \
|
||||
delta[C_AXIS] = DELTA_Z(C_AXIS); \
|
||||
}while(0)
|
||||
|
||||
#define DELTA_LOGICAL_IK() do { \
|
||||
const float raw[XYZ] = { \
|
||||
RAW_X_POSITION(logical[X_AXIS]), \
|
||||
RAW_Y_POSITION(logical[Y_AXIS]), \
|
||||
RAW_Z_POSITION(logical[Z_AXIS]) \
|
||||
}; \
|
||||
DELTA_RAW_IK(); \
|
||||
}while(0)
|
||||
|
||||
void inverse_kinematics(const float logical[XYZ]);
|
||||
|
||||
/**
|
||||
* Calculate the highest Z position where the
|
||||
* effector has the full range of XY motion.
|
||||
*/
|
||||
float delta_safe_distance_from_top();
|
||||
|
||||
/**
|
||||
* Delta Forward Kinematics
|
||||
*
|
||||
* See the Wikipedia article "Trilateration"
|
||||
* https://en.wikipedia.org/wiki/Trilateration
|
||||
*
|
||||
* Establish a new coordinate system in the plane of the
|
||||
* three carriage points. This system has its origin at
|
||||
* tower1, with tower2 on the X axis. Tower3 is in the X-Y
|
||||
* plane with a Z component of zero.
|
||||
* We will define unit vectors in this coordinate system
|
||||
* in our original coordinate system. Then when we calculate
|
||||
* the Xnew, Ynew and Znew values, we can translate back into
|
||||
* the original system by moving along those unit vectors
|
||||
* by the corresponding values.
|
||||
*
|
||||
* Variable names matched to Marlin, c-version, and avoid the
|
||||
* use of any vector library.
|
||||
*
|
||||
* by Andreas Hardtung 2016-06-07
|
||||
* based on a Java function from "Delta Robot Kinematics V3"
|
||||
* by Steve Graves
|
||||
*
|
||||
* The result is stored in the cartes[] array.
|
||||
*/
|
||||
void forward_kinematics_DELTA(float z1, float z2, float z3);
|
||||
|
||||
FORCE_INLINE void forward_kinematics_DELTA(float point[ABC]) {
|
||||
forward_kinematics_DELTA(point[A_AXIS], point[B_AXIS], point[C_AXIS]);
|
||||
}
|
||||
|
||||
bool home_delta();
|
||||
|
||||
#endif // __DELTA_H__
|
@ -25,23 +25,38 @@
|
||||
*/
|
||||
|
||||
#include "motion.h"
|
||||
#include "endstops.h"
|
||||
#include "stepper.h"
|
||||
#include "planner.h"
|
||||
#include "temperature.h"
|
||||
|
||||
#include "../gcode/gcode.h"
|
||||
// #include "../module/planner.h"
|
||||
// #include "../Marlin.h"
|
||||
// #include "../inc/MarlinConfig.h"
|
||||
|
||||
#include "../core/serial.h"
|
||||
#include "../module/stepper.h"
|
||||
#include "../module/temperature.h"
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if IS_SCARA
|
||||
#include "../libs/buzzer.h"
|
||||
#include "../lcd/ultralcd.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#include "../feature/ubl/ubl.h"
|
||||
// #if ENABLED(DUAL_X_CARRIAGE)
|
||||
// #include "tool_change.h"
|
||||
// #endif
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
#include "probe.h"
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
#if NEED_UNHOMED_ERR && ENABLED(ULTRA_LCD)
|
||||
#include "../lcd/ultralcd.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
#include "../feature/tmc2130.h"
|
||||
#endif
|
||||
|
||||
#define XYZ_CONSTS(type, array, CONFIG) const PROGMEM type array##_P[XYZ] = { X_##CONFIG, Y_##CONFIG, Z_##CONFIG }
|
||||
@ -72,15 +87,85 @@ float current_position[XYZE] = { 0.0 };
|
||||
*/
|
||||
float destination[XYZE] = { 0.0 };
|
||||
|
||||
|
||||
// The active extruder (tool). Set with T<extruder> command.
|
||||
uint8_t active_extruder = 0;
|
||||
|
||||
// Extruder offsets
|
||||
#if HOTENDS > 1
|
||||
float hotend_offset[XYZ][HOTENDS]; // Initialized by settings.load()
|
||||
#endif
|
||||
|
||||
// The feedrate for the current move, often used as the default if
|
||||
// no other feedrate is specified. Overridden for special moves.
|
||||
// Set by the last G0 through G5 command's "F" parameter.
|
||||
// Functions that override this for custom moves *must always* restore it!
|
||||
float feedrate_mm_s = MMM_TO_MMS(1500.0);
|
||||
|
||||
int16_t feedrate_percentage = 100;
|
||||
|
||||
// Homing feedrate is const progmem - compare to constexpr in the header
|
||||
const float homing_feedrate_mm_s[4] PROGMEM = {
|
||||
#if ENABLED(DELTA)
|
||||
MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z),
|
||||
#else
|
||||
MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY),
|
||||
#endif
|
||||
MMM_TO_MMS(HOMING_FEEDRATE_Z), 0
|
||||
};
|
||||
|
||||
// Cartesian conversion result goes here:
|
||||
float cartes[XYZ];
|
||||
|
||||
// Until kinematics.cpp is created, create this here
|
||||
#if IS_KINEMATIC
|
||||
float delta[ABC];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The workspace can be offset by some commands, or
|
||||
* these offsets may be omitted to save on computation.
|
||||
*/
|
||||
#if HAS_WORKSPACE_OFFSET
|
||||
#if HAS_POSITION_SHIFT
|
||||
// The distance that XYZ has been offset by G92. Reset by G28.
|
||||
float position_shift[XYZ] = { 0 };
|
||||
#endif
|
||||
#if HAS_HOME_OFFSET
|
||||
// This offset is added to the configured home position.
|
||||
// Set by M206, M428, or menu item. Saved to EEPROM.
|
||||
float home_offset[XYZ] = { 0 };
|
||||
#endif
|
||||
#if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
|
||||
// The above two are combined to save on computes
|
||||
float workspace_offset[XYZ] = { 0 };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if OLDSCHOOL_ABL
|
||||
float xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_SPEED);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Output the current position to serial
|
||||
*/
|
||||
void report_current_position() {
|
||||
SERIAL_PROTOCOLPGM("X:");
|
||||
SERIAL_PROTOCOL(current_position[X_AXIS]);
|
||||
SERIAL_PROTOCOLPGM(" Y:");
|
||||
SERIAL_PROTOCOL(current_position[Y_AXIS]);
|
||||
SERIAL_PROTOCOLPGM(" Z:");
|
||||
SERIAL_PROTOCOL(current_position[Z_AXIS]);
|
||||
SERIAL_PROTOCOLPGM(" E:");
|
||||
SERIAL_PROTOCOL(current_position[E_AXIS]);
|
||||
|
||||
stepper.report_positions();
|
||||
|
||||
#if IS_SCARA
|
||||
scara_report_positions();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* sync_plan_position
|
||||
*
|
||||
@ -96,6 +181,56 @@ void sync_plan_position() {
|
||||
|
||||
void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); }
|
||||
|
||||
/**
|
||||
* Get the stepper positions in the cartes[] array.
|
||||
* Forward kinematics are applied for DELTA and SCARA.
|
||||
*
|
||||
* The result is in the current coordinate space with
|
||||
* leveling applied. The coordinates need to be run through
|
||||
* unapply_leveling to obtain the "ideal" coordinates
|
||||
* suitable for current_position, etc.
|
||||
*/
|
||||
void get_cartesian_from_steppers() {
|
||||
#if ENABLED(DELTA)
|
||||
forward_kinematics_DELTA(
|
||||
stepper.get_axis_position_mm(A_AXIS),
|
||||
stepper.get_axis_position_mm(B_AXIS),
|
||||
stepper.get_axis_position_mm(C_AXIS)
|
||||
);
|
||||
cartes[X_AXIS] += LOGICAL_X_POSITION(0);
|
||||
cartes[Y_AXIS] += LOGICAL_Y_POSITION(0);
|
||||
cartes[Z_AXIS] += LOGICAL_Z_POSITION(0);
|
||||
#elif IS_SCARA
|
||||
forward_kinematics_SCARA(
|
||||
stepper.get_axis_position_degrees(A_AXIS),
|
||||
stepper.get_axis_position_degrees(B_AXIS)
|
||||
);
|
||||
cartes[X_AXIS] += LOGICAL_X_POSITION(0);
|
||||
cartes[Y_AXIS] += LOGICAL_Y_POSITION(0);
|
||||
cartes[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS);
|
||||
#else
|
||||
cartes[X_AXIS] = stepper.get_axis_position_mm(X_AXIS);
|
||||
cartes[Y_AXIS] = stepper.get_axis_position_mm(Y_AXIS);
|
||||
cartes[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current_position for an axis based on
|
||||
* the stepper positions, removing any leveling that
|
||||
* may have been applied.
|
||||
*/
|
||||
void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||
get_cartesian_from_steppers();
|
||||
#if PLANNER_LEVELING
|
||||
planner.unapply_leveling(cartes);
|
||||
#endif
|
||||
if (axis == ALL_AXES)
|
||||
COPY(current_position, cartes);
|
||||
else
|
||||
current_position[axis] = cartes[axis];
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the planner to the current position from wherever it last moved
|
||||
* (or from wherever it has been told it is located).
|
||||
@ -149,6 +284,167 @@ void line_to_destination(const float fr_mm_s) {
|
||||
|
||||
#endif // IS_KINEMATIC
|
||||
|
||||
/**
|
||||
* Plan a move to (X, Y, Z) and set the current_position
|
||||
* The final current_position may not be the one that was requested
|
||||
*/
|
||||
void do_blocking_move_to(const float &lx, const float &ly, const float &lz, const float &fr_mm_s/*=0.0*/) {
|
||||
const float old_feedrate_mm_s = feedrate_mm_s;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) print_xyz(PSTR(">>> do_blocking_move_to"), NULL, lx, ly, lz);
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
|
||||
if (!position_is_reachable_xy(lx, ly)) return;
|
||||
|
||||
feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
|
||||
|
||||
set_destination_to_current(); // sync destination at the start
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("set_destination_to_current", destination);
|
||||
#endif
|
||||
|
||||
// when in the danger zone
|
||||
if (current_position[Z_AXIS] > delta_clip_start_height) {
|
||||
if (lz > delta_clip_start_height) { // staying in the danger zone
|
||||
destination[X_AXIS] = lx; // move directly (uninterpolated)
|
||||
destination[Y_AXIS] = ly;
|
||||
destination[Z_AXIS] = lz;
|
||||
prepare_uninterpolated_move_to_destination(); // set_current_to_destination
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("danger zone move", current_position);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else {
|
||||
destination[Z_AXIS] = delta_clip_start_height;
|
||||
prepare_uninterpolated_move_to_destination(); // set_current_to_destination
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("zone border move", current_position);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (lz > current_position[Z_AXIS]) { // raising?
|
||||
destination[Z_AXIS] = lz;
|
||||
prepare_uninterpolated_move_to_destination(); // set_current_to_destination
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("z raise move", current_position);
|
||||
#endif
|
||||
}
|
||||
|
||||
destination[X_AXIS] = lx;
|
||||
destination[Y_AXIS] = ly;
|
||||
prepare_move_to_destination(); // set_current_to_destination
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("xy move", current_position);
|
||||
#endif
|
||||
|
||||
if (lz < current_position[Z_AXIS]) { // lowering?
|
||||
destination[Z_AXIS] = lz;
|
||||
prepare_uninterpolated_move_to_destination(); // set_current_to_destination
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("z lower move", current_position);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif IS_SCARA
|
||||
|
||||
if (!position_is_reachable_xy(lx, ly)) return;
|
||||
|
||||
set_destination_to_current();
|
||||
|
||||
// If Z needs to raise, do it before moving XY
|
||||
if (destination[Z_AXIS] < lz) {
|
||||
destination[Z_AXIS] = lz;
|
||||
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS));
|
||||
}
|
||||
|
||||
destination[X_AXIS] = lx;
|
||||
destination[Y_AXIS] = ly;
|
||||
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S);
|
||||
|
||||
// If Z needs to lower, do it after moving XY
|
||||
if (destination[Z_AXIS] > lz) {
|
||||
destination[Z_AXIS] = lz;
|
||||
prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// If Z needs to raise, do it before moving XY
|
||||
if (current_position[Z_AXIS] < lz) {
|
||||
feedrate_mm_s = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS);
|
||||
current_position[Z_AXIS] = lz;
|
||||
line_to_current_position();
|
||||
}
|
||||
|
||||
feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
|
||||
current_position[X_AXIS] = lx;
|
||||
current_position[Y_AXIS] = ly;
|
||||
line_to_current_position();
|
||||
|
||||
// If Z needs to lower, do it after moving XY
|
||||
if (current_position[Z_AXIS] > lz) {
|
||||
feedrate_mm_s = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS);
|
||||
current_position[Z_AXIS] = lz;
|
||||
line_to_current_position();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
stepper.synchronize();
|
||||
|
||||
feedrate_mm_s = old_feedrate_mm_s;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< do_blocking_move_to");
|
||||
#endif
|
||||
}
|
||||
void do_blocking_move_to_x(const float &lx, const float &fr_mm_s/*=0.0*/) {
|
||||
do_blocking_move_to(lx, current_position[Y_AXIS], current_position[Z_AXIS], fr_mm_s);
|
||||
}
|
||||
void do_blocking_move_to_z(const float &lz, const float &fr_mm_s/*=0.0*/) {
|
||||
do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], lz, fr_mm_s);
|
||||
}
|
||||
void do_blocking_move_to_xy(const float &lx, const float &ly, const float &fr_mm_s/*=0.0*/) {
|
||||
do_blocking_move_to(lx, ly, current_position[Z_AXIS], fr_mm_s);
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare to do endstop or probe moves
|
||||
// with custom feedrates.
|
||||
//
|
||||
// - Save current feedrates
|
||||
// - Reset the rate multiplier
|
||||
// - Reset the command timeout
|
||||
// - Enable the endstops (for endstop moves)
|
||||
//
|
||||
void bracket_probe_move(const bool before) {
|
||||
static float saved_feedrate_mm_s;
|
||||
static int16_t saved_feedrate_percentage;
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("bracket_probe_move", current_position);
|
||||
#endif
|
||||
if (before) {
|
||||
saved_feedrate_mm_s = feedrate_mm_s;
|
||||
saved_feedrate_percentage = feedrate_percentage;
|
||||
feedrate_percentage = 100;
|
||||
gcode.refresh_cmd_timeout();
|
||||
}
|
||||
else {
|
||||
feedrate_mm_s = saved_feedrate_mm_s;
|
||||
feedrate_percentage = saved_feedrate_percentage;
|
||||
gcode.refresh_cmd_timeout();
|
||||
}
|
||||
}
|
||||
|
||||
void setup_for_endstop_or_probe_move() { bracket_probe_move(true); }
|
||||
void clean_up_after_endstop_or_probe_move() { bracket_probe_move(false); }
|
||||
|
||||
// Software Endstops are based on the configured limits.
|
||||
float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
||||
soft_endstop_max[XYZ] = { X_MAX_BED, Y_MAX_BED, Z_MAX_POS };
|
||||
@ -189,73 +485,24 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
|
||||
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) && !IS_KINEMATIC
|
||||
|
||||
#define CELL_INDEX(A,V) ((RAW_##A##_POSITION(V) - bilinear_start[A##_AXIS]) * ABL_BG_FACTOR(A##_AXIS))
|
||||
|
||||
/**
|
||||
* Prepare a bilinear-leveled linear move on Cartesian,
|
||||
* splitting the move where it crosses grid borders.
|
||||
*/
|
||||
void bilinear_line_to_destination(const float fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF);
|
||||
int cx1 = CELL_INDEX(X, current_position[X_AXIS]),
|
||||
cy1 = CELL_INDEX(Y, current_position[Y_AXIS]),
|
||||
cx2 = CELL_INDEX(X, destination[X_AXIS]),
|
||||
cy2 = CELL_INDEX(Y, destination[Y_AXIS]);
|
||||
cx1 = constrain(cx1, 0, ABL_BG_POINTS_X - 2);
|
||||
cy1 = constrain(cy1, 0, ABL_BG_POINTS_Y - 2);
|
||||
cx2 = constrain(cx2, 0, ABL_BG_POINTS_X - 2);
|
||||
cy2 = constrain(cy2, 0, ABL_BG_POINTS_Y - 2);
|
||||
|
||||
if (cx1 == cx2 && cy1 == cy2) {
|
||||
// Start and end on same mesh square
|
||||
line_to_destination(fr_mm_s);
|
||||
set_current_to_destination();
|
||||
return;
|
||||
}
|
||||
|
||||
#define LINE_SEGMENT_END(A) (current_position[A ##_AXIS] + (destination[A ##_AXIS] - current_position[A ##_AXIS]) * normalized_dist)
|
||||
|
||||
float normalized_dist, end[XYZE];
|
||||
|
||||
// Split at the left/front border of the right/top square
|
||||
const int8_t gcx = max(cx1, cx2), gcy = max(cy1, cy2);
|
||||
if (cx2 != cx1 && TEST(x_splits, gcx)) {
|
||||
COPY(end, destination);
|
||||
destination[X_AXIS] = LOGICAL_X_POSITION(bilinear_start[X_AXIS] + ABL_BG_SPACING(X_AXIS) * gcx);
|
||||
normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
|
||||
destination[Y_AXIS] = LINE_SEGMENT_END(Y);
|
||||
CBI(x_splits, gcx);
|
||||
}
|
||||
else if (cy2 != cy1 && TEST(y_splits, gcy)) {
|
||||
COPY(end, destination);
|
||||
destination[Y_AXIS] = LOGICAL_Y_POSITION(bilinear_start[Y_AXIS] + ABL_BG_SPACING(Y_AXIS) * gcy);
|
||||
normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
|
||||
destination[X_AXIS] = LINE_SEGMENT_END(X);
|
||||
CBI(y_splits, gcy);
|
||||
}
|
||||
else {
|
||||
// Already split on a border
|
||||
line_to_destination(fr_mm_s);
|
||||
set_current_to_destination();
|
||||
return;
|
||||
}
|
||||
|
||||
destination[Z_AXIS] = LINE_SEGMENT_END(Z);
|
||||
destination[E_AXIS] = LINE_SEGMENT_END(E);
|
||||
|
||||
// Do the split and look for more borders
|
||||
bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
|
||||
|
||||
// Restore destination from stack
|
||||
COPY(destination, end);
|
||||
bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_BILINEAR
|
||||
|
||||
#if IS_KINEMATIC && !UBL_DELTA
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
#if ENABLED(DELTA)
|
||||
#define ADJUST_DELTA(V) \
|
||||
if (planner.abl_enabled) { \
|
||||
const float zadj = bilinear_z_offset(V); \
|
||||
delta[A_AXIS] += zadj; \
|
||||
delta[B_AXIS] += zadj; \
|
||||
delta[C_AXIS] += zadj; \
|
||||
}
|
||||
#else
|
||||
#define ADJUST_DELTA(V) if (planner.abl_enabled) { delta[Z_AXIS] += bilinear_z_offset(V); }
|
||||
#endif
|
||||
#else
|
||||
#define ADJUST_DELTA(V) NOOP
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prepare a linear move in a DELTA or SCARA setup.
|
||||
*
|
||||
@ -572,3 +819,453 @@ void prepare_move_to_destination() {
|
||||
|
||||
set_current_to_destination();
|
||||
}
|
||||
|
||||
#if NEED_UNHOMED_ERR
|
||||
|
||||
bool axis_unhomed_error(const bool x/*=true*/, const bool y/*=true*/, const bool z/*=true*/) {
|
||||
#if ENABLED(HOME_AFTER_DEACTIVATE)
|
||||
const bool xx = x && !axis_known_position[X_AXIS],
|
||||
yy = y && !axis_known_position[Y_AXIS],
|
||||
zz = z && !axis_known_position[Z_AXIS];
|
||||
#else
|
||||
const bool xx = x && !axis_homed[X_AXIS],
|
||||
yy = y && !axis_homed[Y_AXIS],
|
||||
zz = z && !axis_homed[Z_AXIS];
|
||||
#endif
|
||||
if (xx || yy || zz) {
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM(MSG_HOME " ");
|
||||
if (xx) SERIAL_ECHOPGM(MSG_X);
|
||||
if (yy) SERIAL_ECHOPGM(MSG_Y);
|
||||
if (zz) SERIAL_ECHOPGM(MSG_Z);
|
||||
SERIAL_ECHOLNPGM(" " MSG_FIRST);
|
||||
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : "");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The homing feedrate may vary
|
||||
*/
|
||||
inline float get_homing_bump_feedrate(const AxisEnum axis) {
|
||||
static const uint8_t homing_bump_divisor[] PROGMEM = HOMING_BUMP_DIVISOR;
|
||||
uint8_t hbd = pgm_read_byte(&homing_bump_divisor[axis]);
|
||||
if (hbd < 1) {
|
||||
hbd = 10;
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOLNPGM("Warning: Homing Bump Divisor < 1");
|
||||
}
|
||||
return homing_feedrate(axis) / hbd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home an individual linear axis
|
||||
*/
|
||||
static void do_homing_move(const AxisEnum axis, const float distance, const float fr_mm_s=0.0) {
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR(">>> do_homing_move(", axis_codes[axis]);
|
||||
SERIAL_ECHOPAIR(", ", distance);
|
||||
SERIAL_ECHOPAIR(", ", fr_mm_s);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
|
||||
const bool deploy_bltouch = (axis == Z_AXIS && distance < 0);
|
||||
if (deploy_bltouch) set_bltouch_deployed(true);
|
||||
#endif
|
||||
|
||||
#if QUIET_PROBING
|
||||
if (axis == Z_AXIS) probing_pause(true);
|
||||
#endif
|
||||
|
||||
// Tell the planner we're at Z=0
|
||||
current_position[axis] = 0;
|
||||
|
||||
#if IS_SCARA
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
current_position[axis] = distance;
|
||||
inverse_kinematics(current_position);
|
||||
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], current_position[E_AXIS], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
|
||||
#else
|
||||
sync_plan_position();
|
||||
current_position[axis] = distance;
|
||||
planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
|
||||
#endif
|
||||
|
||||
stepper.synchronize();
|
||||
|
||||
#if QUIET_PROBING
|
||||
if (axis == Z_AXIS) probing_pause(false);
|
||||
#endif
|
||||
|
||||
#if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
|
||||
if (deploy_bltouch) set_bltouch_deployed(false);
|
||||
#endif
|
||||
|
||||
endstops.hit_on_purpose();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("<<< do_homing_move(", axis_codes[axis]);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an axis' current position to its home position (after homing).
|
||||
*
|
||||
* For Core and Cartesian robots this applies one-to-one when an
|
||||
* individual axis has been homed.
|
||||
*
|
||||
* DELTA should wait until all homing is done before setting the XYZ
|
||||
* current_position to home, because homing is a single operation.
|
||||
* In the case where the axis positions are already known and previously
|
||||
* homed, DELTA could home to X or Y individually by moving either one
|
||||
* to the center. However, homing Z always homes XY and Z.
|
||||
*
|
||||
* SCARA should wait until all XY homing is done before setting the XY
|
||||
* current_position to home, because neither X nor Y is at home until
|
||||
* both are at home. Z can however be homed individually.
|
||||
*
|
||||
* Callers must sync the planner position after calling this!
|
||||
*/
|
||||
void set_axis_is_at_home(const AxisEnum axis) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR(">>> set_axis_is_at_home(", axis_codes[axis]);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
axis_known_position[axis] = axis_homed[axis] = true;
|
||||
|
||||
#if HAS_POSITION_SHIFT
|
||||
position_shift[axis] = 0;
|
||||
update_software_endstops(axis);
|
||||
#endif
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
|
||||
current_position[X_AXIS] = x_home_pos(active_extruder);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(MORGAN_SCARA)
|
||||
scara_set_axis_is_at_home(axis);
|
||||
#else
|
||||
current_position[axis] = LOGICAL_POSITION(base_home_pos(axis), axis);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Z Probe Z Homing? Account for the probe's Z offset.
|
||||
*/
|
||||
#if HAS_BED_PROBE && Z_HOME_DIR < 0
|
||||
if (axis == Z_AXIS) {
|
||||
#if HOMING_Z_WITH_PROBE
|
||||
|
||||
current_position[Z_AXIS] -= zprobe_zoffset;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOLNPGM("*** Z HOMED WITH PROBE (Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) ***");
|
||||
SERIAL_ECHOLNPAIR("> zprobe_zoffset = ", zprobe_zoffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("*** Z HOMED TO ENDSTOP (Z_MIN_PROBE_ENDSTOP) ***");
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
#if HAS_HOME_OFFSET
|
||||
SERIAL_ECHOPAIR("> home_offset[", axis_codes[axis]);
|
||||
SERIAL_ECHOLNPAIR("] = ", home_offset[axis]);
|
||||
#endif
|
||||
DEBUG_POS("", current_position);
|
||||
SERIAL_ECHOPAIR("<<< set_axis_is_at_home(", axis_codes[axis]);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_POSITION_ENCODERS)
|
||||
I2CPEM.homed(axis);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Home an individual "raw axis" to its endstop.
|
||||
* This applies to XYZ on Cartesian and Core robots, and
|
||||
* to the individual ABC steppers on DELTA and SCARA.
|
||||
*
|
||||
* At the end of the procedure the axis is marked as
|
||||
* homed and the current position of that axis is updated.
|
||||
* Kinematic robots should wait till all axes are homed
|
||||
* before updating the current position.
|
||||
*/
|
||||
|
||||
void homeaxis(const AxisEnum axis) {
|
||||
|
||||
#if IS_SCARA
|
||||
// Only Z homing (with probe) is permitted
|
||||
if (axis != Z_AXIS) { BUZZ(100, 880); return; }
|
||||
#else
|
||||
#define CAN_HOME(A) \
|
||||
(axis == A##_AXIS && ((A##_MIN_PIN > -1 && A##_HOME_DIR < 0) || (A##_MAX_PIN > -1 && A##_HOME_DIR > 0)))
|
||||
if (!CAN_HOME(X) && !CAN_HOME(Y) && !CAN_HOME(Z)) return;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR(">>> homeaxis(", axis_codes[axis]);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
const int axis_home_dir =
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
(axis == X_AXIS) ? x_home_dir(active_extruder) :
|
||||
#endif
|
||||
home_dir(axis);
|
||||
|
||||
// Homing Z towards the bed? Deploy the Z probe or endstop.
|
||||
#if HOMING_Z_WITH_PROBE
|
||||
if (axis == Z_AXIS && DEPLOY_PROBE()) return;
|
||||
#endif
|
||||
|
||||
// Set a flag for Z motor locking
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
if (axis == Z_AXIS) stepper.set_homing_flag(true);
|
||||
#endif
|
||||
|
||||
// Disable stealthChop if used. Enable diag1 pin on driver.
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
#if ENABLED(X_IS_TMC2130)
|
||||
if (axis == X_AXIS) tmc2130_sensorless_homing(stepperX);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC2130)
|
||||
if (axis == Y_AXIS) tmc2130_sensorless_homing(stepperY);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Fast move towards endstop until triggered
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 1 Fast:");
|
||||
#endif
|
||||
do_homing_move(axis, 1.5 * max_length(axis) * axis_home_dir);
|
||||
|
||||
// When homing Z with probe respect probe clearance
|
||||
const float bump = axis_home_dir * (
|
||||
#if HOMING_Z_WITH_PROBE
|
||||
(axis == Z_AXIS) ? max(Z_CLEARANCE_BETWEEN_PROBES, home_bump_mm(Z_AXIS)) :
|
||||
#endif
|
||||
home_bump_mm(axis)
|
||||
);
|
||||
|
||||
// If a second homing move is configured...
|
||||
if (bump) {
|
||||
// Move away from the endstop by the axis HOME_BUMP_MM
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Move Away:");
|
||||
#endif
|
||||
do_homing_move(axis, -bump);
|
||||
|
||||
// Slow move towards endstop until triggered
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 2 Slow:");
|
||||
#endif
|
||||
do_homing_move(axis, 2 * bump, get_homing_bump_feedrate(axis));
|
||||
}
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
if (axis == Z_AXIS) {
|
||||
float adj = FABS(z_endstop_adj);
|
||||
bool lockZ1;
|
||||
if (axis_home_dir > 0) {
|
||||
adj = -adj;
|
||||
lockZ1 = (z_endstop_adj > 0);
|
||||
}
|
||||
else
|
||||
lockZ1 = (z_endstop_adj < 0);
|
||||
|
||||
if (lockZ1) stepper.set_z_lock(true); else stepper.set_z2_lock(true);
|
||||
|
||||
// Move to the adjusted endstop height
|
||||
do_homing_move(axis, adj);
|
||||
|
||||
if (lockZ1) stepper.set_z_lock(false); else stepper.set_z2_lock(false);
|
||||
stepper.set_homing_flag(false);
|
||||
} // Z_AXIS
|
||||
#endif
|
||||
|
||||
#if IS_SCARA
|
||||
|
||||
set_axis_is_at_home(axis);
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#elif ENABLED(DELTA)
|
||||
|
||||
// Delta has already moved all three towers up in G28
|
||||
// so here it re-homes each tower in turn.
|
||||
// Delta homing treats the axes as normal linear axes.
|
||||
|
||||
// retrace by the amount specified in delta_endstop_adj + additional 0.1mm in order to have minimum steps
|
||||
if (delta_endstop_adj[axis] * Z_HOME_DIR <= 0) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("delta_endstop_adj:");
|
||||
#endif
|
||||
do_homing_move(axis, delta_endstop_adj[axis] - 0.1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// For cartesian/core machines,
|
||||
// set the axis to its home position
|
||||
set_axis_is_at_home(axis);
|
||||
sync_plan_position();
|
||||
|
||||
destination[axis] = current_position[axis];
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("> AFTER set_axis_is_at_home", current_position);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Re-enable stealthChop if used. Disable diag1 pin on driver.
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
#if ENABLED(X_IS_TMC2130)
|
||||
if (axis == X_AXIS) tmc2130_sensorless_homing(stepperX, false);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC2130)
|
||||
if (axis == Y_AXIS) tmc2130_sensorless_homing(stepperY, false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Put away the Z probe
|
||||
#if HOMING_Z_WITH_PROBE
|
||||
if (axis == Z_AXIS && STOW_PROBE()) return;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("<<< homeaxis(", axis_codes[axis]);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
} // homeaxis()
|
||||
|
||||
#if HAS_WORKSPACE_OFFSET || ENABLED(DUAL_X_CARRIAGE)
|
||||
|
||||
/**
|
||||
* Software endstops can be used to monitor the open end of
|
||||
* an axis that has a hardware endstop on the other end. Or
|
||||
* they can prevent axes from moving past endstops and grinding.
|
||||
*
|
||||
* To keep doing their job as the coordinate system changes,
|
||||
* the software endstop positions must be refreshed to remain
|
||||
* at the same positions relative to the machine.
|
||||
*/
|
||||
void update_software_endstops(const AxisEnum axis) {
|
||||
const float offs = 0.0
|
||||
#if HAS_HOME_OFFSET
|
||||
+ home_offset[axis]
|
||||
#endif
|
||||
#if HAS_POSITION_SHIFT
|
||||
+ position_shift[axis]
|
||||
#endif
|
||||
;
|
||||
|
||||
#if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
|
||||
workspace_offset[axis] = offs;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
if (axis == X_AXIS) {
|
||||
|
||||
// In Dual X mode hotend_offset[X] is T1's home position
|
||||
float dual_max_x = max(hotend_offset[X_AXIS][1], X2_MAX_POS);
|
||||
|
||||
if (active_extruder != 0) {
|
||||
// T1 can move from X2_MIN_POS to X2_MAX_POS or X2 home position (whichever is larger)
|
||||
soft_endstop_min[X_AXIS] = X2_MIN_POS + offs;
|
||||
soft_endstop_max[X_AXIS] = dual_max_x + offs;
|
||||
}
|
||||
else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
|
||||
// In Duplication Mode, T0 can move as far left as X_MIN_POS
|
||||
// but not so far to the right that T1 would move past the end
|
||||
soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS) + offs;
|
||||
soft_endstop_max[X_AXIS] = min(base_max_pos(X_AXIS), dual_max_x - duplicate_extruder_x_offset) + offs;
|
||||
}
|
||||
else {
|
||||
// In other modes, T0 can move from X_MIN_POS to X_MAX_POS
|
||||
soft_endstop_min[axis] = base_min_pos(axis) + offs;
|
||||
soft_endstop_max[axis] = base_max_pos(axis) + offs;
|
||||
}
|
||||
}
|
||||
#elif ENABLED(DELTA)
|
||||
soft_endstop_min[axis] = base_min_pos(axis) + (axis == Z_AXIS ? 0 : offs);
|
||||
soft_endstop_max[axis] = base_max_pos(axis) + offs;
|
||||
#else
|
||||
soft_endstop_min[axis] = base_min_pos(axis) + offs;
|
||||
soft_endstop_max[axis] = base_max_pos(axis) + offs;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("For ", axis_codes[axis]);
|
||||
#if HAS_HOME_OFFSET
|
||||
SERIAL_ECHOPAIR(" axis:\n home_offset = ", home_offset[axis]);
|
||||
#endif
|
||||
#if HAS_POSITION_SHIFT
|
||||
SERIAL_ECHOPAIR("\n position_shift = ", position_shift[axis]);
|
||||
#endif
|
||||
SERIAL_ECHOPAIR("\n soft_endstop_min = ", soft_endstop_min[axis]);
|
||||
SERIAL_ECHOLNPAIR("\n soft_endstop_max = ", soft_endstop_max[axis]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
if (axis == Z_AXIS)
|
||||
delta_clip_start_height = soft_endstop_max[axis] - delta_safe_distance_from_top();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // HAS_WORKSPACE_OFFSET || DUAL_X_CARRIAGE
|
||||
|
||||
#if HAS_M206_COMMAND
|
||||
/**
|
||||
* Change the home offset for an axis, update the current
|
||||
* position and the software endstops to retain the same
|
||||
* relative distance to the new home.
|
||||
*
|
||||
* Since this changes the current_position, code should
|
||||
* call sync_plan_position soon after this.
|
||||
*/
|
||||
void set_home_offset(const AxisEnum axis, const float v) {
|
||||
current_position[axis] += v - home_offset[axis];
|
||||
home_offset[axis] = v;
|
||||
update_software_endstops(axis);
|
||||
}
|
||||
#endif // HAS_M206_COMMAND
|
||||
|
@ -32,20 +32,53 @@
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
//#include "../HAL/HAL.h"
|
||||
|
||||
// #if ENABLED(DELTA)
|
||||
// #include "../module/delta.h"
|
||||
// #endif
|
||||
#if IS_SCARA
|
||||
#include "../module/scara.h"
|
||||
#endif
|
||||
|
||||
extern bool relative_mode;
|
||||
|
||||
extern float current_position[XYZE], destination[XYZE];
|
||||
extern float current_position[XYZE], // High-level current tool position
|
||||
destination[XYZE]; // Destination for a move
|
||||
|
||||
// Scratch space for a cartesian result
|
||||
extern float cartes[XYZ];
|
||||
|
||||
// Until kinematics.cpp is created, declare this here
|
||||
#if IS_KINEMATIC
|
||||
extern float delta[ABC];
|
||||
#endif
|
||||
|
||||
#if OLDSCHOOL_ABL
|
||||
extern float 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
|
||||
|
||||
/**
|
||||
* Feed rates are often configured with mm/m
|
||||
* but the planner and stepper like mm/s units.
|
||||
*/
|
||||
extern const float homing_feedrate_mm_s[4];
|
||||
FORCE_INLINE float homing_feedrate(const AxisEnum a) { return pgm_read_float(&homing_feedrate_mm_s[a]); }
|
||||
|
||||
extern float feedrate_mm_s;
|
||||
|
||||
/**
|
||||
* Feedrate scaling and conversion
|
||||
*/
|
||||
extern int16_t feedrate_percentage;
|
||||
#define MMS_SCALED(MM_S) ((MM_S)*feedrate_percentage*0.01)
|
||||
|
||||
extern uint8_t active_extruder;
|
||||
|
||||
#if HOTENDS > 1
|
||||
extern float hotend_offset[XYZ][HOTENDS];
|
||||
#endif
|
||||
|
||||
extern float soft_endstop_min[XYZ], soft_endstop_max[XYZ];
|
||||
|
||||
FORCE_INLINE float pgm_read_any(const float *p) { return pgm_read_float_near(p); }
|
||||
@ -71,9 +104,14 @@ XYZ_DEFS(signed char, home_dir, HOME_DIR);
|
||||
#define clamp_to_software_endstops(x) NOOP
|
||||
#endif
|
||||
|
||||
void report_current_position();
|
||||
|
||||
inline void set_current_to_destination() { COPY(current_position, destination); }
|
||||
inline void set_destination_to_current() { COPY(destination, current_position); }
|
||||
|
||||
void get_cartesian_from_steppers();
|
||||
void set_current_from_steppers_for_axis(const AxisEnum axis);
|
||||
|
||||
/**
|
||||
* sync_plan_position
|
||||
*
|
||||
@ -110,7 +148,35 @@ inline void line_to_destination() { line_to_destination(feedrate_mm_s); }
|
||||
|
||||
void prepare_move_to_destination();
|
||||
|
||||
void clamp_to_software_endstops(float target[XYZ]);
|
||||
/**
|
||||
* Blocking movement and shorthand functions
|
||||
*/
|
||||
void do_blocking_move_to(const float &x, const float &y, const float &z, const float &fr_mm_s=0.0);
|
||||
void do_blocking_move_to_x(const float &x, const float &fr_mm_s=0.0);
|
||||
void do_blocking_move_to_z(const float &z, const float &fr_mm_s=0.0);
|
||||
void do_blocking_move_to_xy(const float &x, const float &y, const float &fr_mm_s=0.0);
|
||||
|
||||
void setup_for_endstop_or_probe_move();
|
||||
void clean_up_after_endstop_or_probe_move();
|
||||
|
||||
void bracket_probe_move(const bool before);
|
||||
void setup_for_endstop_or_probe_move();
|
||||
void clean_up_after_endstop_or_probe_move();
|
||||
|
||||
//
|
||||
// Homing
|
||||
//
|
||||
|
||||
#define NEED_UNHOMED_ERR (HAS_PROBING_PROCEDURE || HOTENDS > 1 || ENABLED(Z_PROBE_ALLEN_KEY) || ENABLED(Z_PROBE_SLED) || ENABLED(NOZZLE_CLEAN_FEATURE) || ENABLED(NOZZLE_PARK_FEATURE) || ENABLED(DELTA_AUTO_CALIBRATION))
|
||||
|
||||
#if NEED_UNHOMED_ERR
|
||||
bool axis_unhomed_error(const bool x=true, const bool y=true, const bool z=true);
|
||||
#endif
|
||||
|
||||
void set_axis_is_at_home(const AxisEnum axis);
|
||||
|
||||
void homeaxis(const AxisEnum axis);
|
||||
#define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS)
|
||||
|
||||
//
|
||||
// Macros
|
||||
@ -162,10 +228,6 @@ void clamp_to_software_endstops(float target[XYZ]);
|
||||
|
||||
#if IS_KINEMATIC // (DELTA or SCARA)
|
||||
|
||||
#if IS_SCARA
|
||||
extern const float L1, L2;
|
||||
#endif
|
||||
|
||||
inline bool position_is_reachable_raw_xy(const float &rx, const float &ry) {
|
||||
#if ENABLED(DELTA)
|
||||
return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS);
|
||||
@ -214,10 +276,16 @@ FORCE_INLINE bool position_is_reachable_xy(const float &lx, const float &ly) {
|
||||
return position_is_reachable_raw_xy(RAW_X_POSITION(lx), RAW_Y_POSITION(ly));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dual X Carriage / Dual Nozzle
|
||||
*/
|
||||
#if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
|
||||
extern bool extruder_duplication_enabled; // Used in Dual X mode 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Dual X Carriage
|
||||
*/
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
|
||||
extern DualXMode dual_x_carriage_mode;
|
||||
@ -234,4 +302,12 @@ FORCE_INLINE bool position_is_reachable_xy(const float &lx, const float &ly) {
|
||||
|
||||
#endif // DUAL_X_CARRIAGE
|
||||
|
||||
#if HAS_WORKSPACE_OFFSET || ENABLED(DUAL_X_CARRIAGE)
|
||||
void update_software_endstops(const AxisEnum axis);
|
||||
#endif
|
||||
|
||||
#if HAS_M206_COMMAND
|
||||
void set_home_offset(const AxisEnum axis, const float v);
|
||||
#endif
|
||||
|
||||
#endif // MOTION_H
|
||||
|
@ -64,13 +64,12 @@
|
||||
#include "../module/temperature.h"
|
||||
#include "../lcd/ultralcd.h"
|
||||
#include "../core/language.h"
|
||||
#include "../feature/ubl/ubl.h"
|
||||
#include "../gcode/parser.h"
|
||||
|
||||
#include "../Marlin.h"
|
||||
|
||||
#if ENABLED(MESH_BED_LEVELING)
|
||||
#include "../feature/mbl/mesh_bed_leveling.h"
|
||||
#if HAS_LEVELING
|
||||
#include "../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
Planner planner;
|
||||
@ -107,12 +106,11 @@ float Planner::min_feedrate_mm_s,
|
||||
Planner::max_jerk[XYZE], // The largest speed change requiring no acceleration
|
||||
Planner::min_travel_feedrate_mm_s;
|
||||
|
||||
#if HAS_ABL
|
||||
#if OLDSCHOOL_ABL
|
||||
bool Planner::abl_enabled = false; // Flag that auto bed leveling is enabled
|
||||
#endif
|
||||
|
||||
#if ABL_PLANAR
|
||||
matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
|
||||
#if ABL_PLANAR
|
||||
matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
@ -546,7 +544,7 @@ void Planner::check_axes_activity() {
|
||||
#endif // FADE
|
||||
#endif // UBL
|
||||
|
||||
#if HAS_ABL
|
||||
#if OLDSCHOOL_ABL
|
||||
if (!abl_enabled) return;
|
||||
#endif
|
||||
|
||||
@ -634,7 +632,7 @@ void Planner::check_axes_activity() {
|
||||
|
||||
#endif
|
||||
|
||||
#if HAS_ABL
|
||||
#if OLDSCHOOL_ABL
|
||||
if (!abl_enabled) return;
|
||||
#endif
|
||||
|
||||
|
@ -34,6 +34,12 @@
|
||||
|
||||
#include "../Marlin.h"
|
||||
|
||||
#include "motion.h"
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
#include "delta.h"
|
||||
#endif
|
||||
|
||||
#if HAS_ABL
|
||||
#include "../libs/vector_3.h"
|
||||
#endif
|
||||
@ -159,7 +165,7 @@ class Planner {
|
||||
max_jerk[XYZE], // The largest speed change requiring no acceleration
|
||||
min_travel_feedrate_mm_s;
|
||||
|
||||
#if HAS_ABL
|
||||
#if OLDSCHOOL_ABL
|
||||
static bool abl_enabled; // Flag that bed leveling is enabled
|
||||
#if ABL_PLANAR
|
||||
static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
|
||||
|
709
Marlin/src/module/probe.cpp
Normal file
709
Marlin/src/module/probe.cpp
Normal file
@ -0,0 +1,709 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* probe.cpp
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
|
||||
#include "probe.h"
|
||||
#include "motion.h"
|
||||
#include "temperature.h"
|
||||
#include "endstops.h"
|
||||
|
||||
#include "../gcode/gcode.h"
|
||||
#include "../lcd/ultralcd.h"
|
||||
|
||||
#include "../Marlin.h"
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
#include "../module/delta.h"
|
||||
#endif
|
||||
|
||||
float zprobe_zoffset; // Initialized by settings.load()
|
||||
|
||||
#if HAS_Z_SERVO_ENDSTOP
|
||||
const int z_servo_angle[2] = Z_SERVO_ANGLES;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Raise Z to a minimum height to make room for a probe to move
|
||||
*/
|
||||
inline void do_probe_raise(const float z_raise) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("do_probe_raise(", z_raise);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
float z_dest = z_raise;
|
||||
if (zprobe_zoffset < 0) z_dest -= zprobe_zoffset;
|
||||
|
||||
if (z_dest > current_position[Z_AXIS])
|
||||
do_blocking_move_to_z(z_dest);
|
||||
}
|
||||
|
||||
#if ENABLED(Z_PROBE_SLED)
|
||||
|
||||
#ifndef SLED_DOCKING_OFFSET
|
||||
#define SLED_DOCKING_OFFSET 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Method to dock/undock a sled designed by Charles Bell.
|
||||
*
|
||||
* stow[in] If false, move to MAX_X and engage the solenoid
|
||||
* If true, move to MAX_X and release the solenoid
|
||||
*/
|
||||
static void dock_sled(bool stow) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("dock_sled(", stow);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Dock sled a bit closer to ensure proper capturing
|
||||
do_blocking_move_to_x(X_MAX_POS + SLED_DOCKING_OFFSET - ((stow) ? 1 : 0));
|
||||
|
||||
#if HAS_SOLENOID_1 && DISABLED(EXT_SOLENOID)
|
||||
WRITE(SOL1_PIN, !stow); // switch solenoid
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif ENABLED(Z_PROBE_ALLEN_KEY)
|
||||
|
||||
FORCE_INLINE void do_blocking_move_to(const float logical[XYZ], const float &fr_mm_s) {
|
||||
do_blocking_move_to(logical[X_AXIS], logical[Y_AXIS], logical[Z_AXIS], fr_mm_s);
|
||||
}
|
||||
|
||||
void run_deploy_moves_script() {
|
||||
#if defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_X
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Y
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Z
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE 0.0
|
||||
#endif
|
||||
const float deploy_1[] = { Z_PROBE_ALLEN_KEY_DEPLOY_1_X, Z_PROBE_ALLEN_KEY_DEPLOY_1_Y, Z_PROBE_ALLEN_KEY_DEPLOY_1_Z };
|
||||
do_blocking_move_to(deploy_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_X
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Y
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Z
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE 0.0
|
||||
#endif
|
||||
const float deploy_2[] = { Z_PROBE_ALLEN_KEY_DEPLOY_2_X, Z_PROBE_ALLEN_KEY_DEPLOY_2_Y, Z_PROBE_ALLEN_KEY_DEPLOY_2_Z };
|
||||
do_blocking_move_to(deploy_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_X
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Y
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Z
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE 0.0
|
||||
#endif
|
||||
const float deploy_3[] = { Z_PROBE_ALLEN_KEY_DEPLOY_3_X, Z_PROBE_ALLEN_KEY_DEPLOY_3_Y, Z_PROBE_ALLEN_KEY_DEPLOY_3_Z };
|
||||
do_blocking_move_to(deploy_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_X
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_4_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Y
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_4_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Z
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_4_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE 0.0
|
||||
#endif
|
||||
const float deploy_4[] = { Z_PROBE_ALLEN_KEY_DEPLOY_4_X, Z_PROBE_ALLEN_KEY_DEPLOY_4_Y, Z_PROBE_ALLEN_KEY_DEPLOY_4_Z };
|
||||
do_blocking_move_to(deploy_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_X
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_5_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Y
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_5_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Z
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_5_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE 0.0
|
||||
#endif
|
||||
const float deploy_5[] = { Z_PROBE_ALLEN_KEY_DEPLOY_5_X, Z_PROBE_ALLEN_KEY_DEPLOY_5_Y, Z_PROBE_ALLEN_KEY_DEPLOY_5_Z };
|
||||
do_blocking_move_to(deploy_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE));
|
||||
#endif
|
||||
}
|
||||
|
||||
void run_stow_moves_script() {
|
||||
#if defined(Z_PROBE_ALLEN_KEY_STOW_1_X) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_1_X
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_1_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_1_Y
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_1_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_1_Z
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_1_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE 0.0
|
||||
#endif
|
||||
const float stow_1[] = { Z_PROBE_ALLEN_KEY_STOW_1_X, Z_PROBE_ALLEN_KEY_STOW_1_Y, Z_PROBE_ALLEN_KEY_STOW_1_Z };
|
||||
do_blocking_move_to(stow_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_STOW_2_X) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_2_X
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_2_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_2_Y
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_2_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_2_Z
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_2_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE 0.0
|
||||
#endif
|
||||
const float stow_2[] = { Z_PROBE_ALLEN_KEY_STOW_2_X, Z_PROBE_ALLEN_KEY_STOW_2_Y, Z_PROBE_ALLEN_KEY_STOW_2_Z };
|
||||
do_blocking_move_to(stow_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_STOW_3_X) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_3_X
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_3_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_3_Y
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_3_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_3_Z
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_3_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE 0.0
|
||||
#endif
|
||||
const float stow_3[] = { Z_PROBE_ALLEN_KEY_STOW_3_X, Z_PROBE_ALLEN_KEY_STOW_3_Y, Z_PROBE_ALLEN_KEY_STOW_3_Z };
|
||||
do_blocking_move_to(stow_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_STOW_4_X) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_4_X
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_4_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_4_Y
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_4_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_4_Z
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_4_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE 0.0
|
||||
#endif
|
||||
const float stow_4[] = { Z_PROBE_ALLEN_KEY_STOW_4_X, Z_PROBE_ALLEN_KEY_STOW_4_Y, Z_PROBE_ALLEN_KEY_STOW_4_Z };
|
||||
do_blocking_move_to(stow_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE));
|
||||
#endif
|
||||
#if defined(Z_PROBE_ALLEN_KEY_STOW_5_X) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Z)
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_5_X
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_5_X current_position[X_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_5_Y
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_5_Y current_position[Y_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_5_Z
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_5_Z current_position[Z_AXIS]
|
||||
#endif
|
||||
#ifndef Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE
|
||||
#define Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE 0.0
|
||||
#endif
|
||||
const float stow_5[] = { Z_PROBE_ALLEN_KEY_STOW_5_X, Z_PROBE_ALLEN_KEY_STOW_5_Y, Z_PROBE_ALLEN_KEY_STOW_5_Z };
|
||||
do_blocking_move_to(stow_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBING_FANS_OFF)
|
||||
|
||||
void fans_pause(const bool p) {
|
||||
if (p != fans_paused) {
|
||||
fans_paused = p;
|
||||
if (p)
|
||||
for (uint8_t x = 0; x < FAN_COUNT; x++) {
|
||||
paused_fanSpeeds[x] = fanSpeeds[x];
|
||||
fanSpeeds[x] = 0;
|
||||
}
|
||||
else
|
||||
for (uint8_t x = 0; x < FAN_COUNT; x++)
|
||||
fanSpeeds[x] = paused_fanSpeeds[x];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PROBING_FANS_OFF
|
||||
|
||||
#if QUIET_PROBING
|
||||
void probing_pause(const bool p) {
|
||||
#if ENABLED(PROBING_HEATERS_OFF)
|
||||
thermalManager.pause(p);
|
||||
#endif
|
||||
#if ENABLED(PROBING_FANS_OFF)
|
||||
fans_pause(p);
|
||||
#endif
|
||||
if (p) safe_delay(
|
||||
#if DELAY_BEFORE_PROBING > 25
|
||||
DELAY_BEFORE_PROBING
|
||||
#else
|
||||
25
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif // QUIET_PROBING
|
||||
|
||||
#if ENABLED(BLTOUCH)
|
||||
|
||||
void bltouch_command(const int angle) {
|
||||
MOVE_SERVO(Z_ENDSTOP_SERVO_NR, angle); // Give the BL-Touch the command and wait
|
||||
safe_delay(BLTOUCH_DELAY);
|
||||
}
|
||||
|
||||
bool set_bltouch_deployed(const bool deploy) {
|
||||
if (deploy && TEST_BLTOUCH()) { // If BL-Touch says it's triggered
|
||||
bltouch_command(BLTOUCH_RESET); // try to reset it.
|
||||
bltouch_command(BLTOUCH_DEPLOY); // Also needs to deploy and stow to
|
||||
bltouch_command(BLTOUCH_STOW); // clear the triggered condition.
|
||||
safe_delay(1500); // Wait for internal self-test to complete.
|
||||
// (Measured completion time was 0.65 seconds
|
||||
// after reset, deploy, and stow sequence)
|
||||
if (TEST_BLTOUCH()) { // If it still claims to be triggered...
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_STOP_BLTOUCH);
|
||||
stop(); // punt!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bltouch_command(deploy ? BLTOUCH_DEPLOY : BLTOUCH_STOW);
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("set_bltouch_deployed(", deploy);
|
||||
SERIAL_CHAR(')');
|
||||
SERIAL_EOL();
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // BLTOUCH
|
||||
|
||||
// returns false for ok and true for failure
|
||||
bool set_probe_deployed(const bool deploy) {
|
||||
|
||||
// Can be extended to servo probes, if needed.
|
||||
#if ENABLED(PROBE_IS_TRIGGERED_WHEN_STOWED_TEST)
|
||||
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
|
||||
#define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
|
||||
#else
|
||||
#define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
DEBUG_POS("set_probe_deployed", current_position);
|
||||
SERIAL_ECHOLNPAIR("deploy: ", deploy);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (endstops.z_probe_enabled == deploy) return false;
|
||||
|
||||
// Make room for probe
|
||||
do_probe_raise(_Z_CLEARANCE_DEPLOY_PROBE);
|
||||
|
||||
#if ENABLED(Z_PROBE_SLED) || ENABLED(Z_PROBE_ALLEN_KEY)
|
||||
#if ENABLED(Z_PROBE_SLED)
|
||||
#define _AUE_ARGS true, false, false
|
||||
#else
|
||||
#define _AUE_ARGS
|
||||
#endif
|
||||
if (axis_unhomed_error(_AUE_ARGS)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_STOP_UNHOMED);
|
||||
stop();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const float oldXpos = current_position[X_AXIS],
|
||||
oldYpos = current_position[Y_AXIS];
|
||||
|
||||
#ifdef _TRIGGERED_WHEN_STOWED_TEST
|
||||
|
||||
// If endstop is already false, the Z probe is deployed
|
||||
if (_TRIGGERED_WHEN_STOWED_TEST == deploy) { // closed after the probe specific actions.
|
||||
// Would a goto be less ugly?
|
||||
//while (!_TRIGGERED_WHEN_STOWED_TEST) idle(); // would offer the opportunity
|
||||
// for a triggered when stowed manual probe.
|
||||
|
||||
if (!deploy) endstops.enable_z_probe(false); // Switch off triggered when stowed probes early
|
||||
// otherwise an Allen-Key probe can't be stowed.
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOLENOID_PROBE)
|
||||
|
||||
#if HAS_SOLENOID_1
|
||||
WRITE(SOL1_PIN, deploy);
|
||||
#endif
|
||||
|
||||
#elif ENABLED(Z_PROBE_SLED)
|
||||
|
||||
dock_sled(!deploy);
|
||||
|
||||
#elif HAS_Z_SERVO_ENDSTOP && DISABLED(BLTOUCH)
|
||||
|
||||
MOVE_SERVO(Z_ENDSTOP_SERVO_NR, z_servo_angle[deploy ? 0 : 1]);
|
||||
|
||||
#elif ENABLED(Z_PROBE_ALLEN_KEY)
|
||||
|
||||
deploy ? run_deploy_moves_script() : run_stow_moves_script();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _TRIGGERED_WHEN_STOWED_TEST
|
||||
} // _TRIGGERED_WHEN_STOWED_TEST == deploy
|
||||
|
||||
if (_TRIGGERED_WHEN_STOWED_TEST == deploy) { // State hasn't changed?
|
||||
|
||||
if (IsRunning()) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM("Z-Probe failed");
|
||||
LCD_ALERTMESSAGEPGM("Err: ZPROBE");
|
||||
}
|
||||
stop();
|
||||
return true;
|
||||
|
||||
} // _TRIGGERED_WHEN_STOWED_TEST == deploy
|
||||
|
||||
#endif
|
||||
|
||||
do_blocking_move_to(oldXpos, oldYpos, current_position[Z_AXIS]); // return to position before deploy
|
||||
endstops.enable_z_probe(deploy);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Used by run_z_probe to do a single Z probe move.
|
||||
*
|
||||
* @param z Z destination
|
||||
* @param fr_mm_s Feedrate in mm/s
|
||||
* @return true to indicate an error
|
||||
*/
|
||||
static bool do_probe_move(const float z, const float fr_mm_m) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> do_probe_move", current_position);
|
||||
#endif
|
||||
|
||||
// Deploy BLTouch at the start of any probe
|
||||
#if ENABLED(BLTOUCH)
|
||||
if (set_bltouch_deployed(true)) return true;
|
||||
#endif
|
||||
|
||||
#if QUIET_PROBING
|
||||
probing_pause(true);
|
||||
#endif
|
||||
|
||||
// Move down until probe triggered
|
||||
do_blocking_move_to_z(z, MMM_TO_MMS(fr_mm_m));
|
||||
|
||||
// Check to see if the probe was triggered
|
||||
const bool probe_triggered = TEST(Endstops::endstop_hit_bits,
|
||||
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
|
||||
Z_MIN
|
||||
#else
|
||||
Z_MIN_PROBE
|
||||
#endif
|
||||
);
|
||||
|
||||
#if QUIET_PROBING
|
||||
probing_pause(false);
|
||||
#endif
|
||||
|
||||
// Retract BLTouch immediately after a probe if it was triggered
|
||||
#if ENABLED(BLTOUCH)
|
||||
if (probe_triggered && set_bltouch_deployed(false)) return true;
|
||||
#endif
|
||||
|
||||
// Clear endstop flags
|
||||
endstops.hit_on_purpose();
|
||||
|
||||
// Get Z where the steppers were interrupted
|
||||
set_current_from_steppers_for_axis(Z_AXIS);
|
||||
|
||||
// Tell the planner where we actually are
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< do_probe_move", current_position);
|
||||
#endif
|
||||
|
||||
return !probe_triggered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @details Used by probe_pt to do a single Z probe.
|
||||
* Leaves current_position[Z_AXIS] at the height where the probe triggered.
|
||||
*
|
||||
* @param short_move Flag for a shorter probe move towards the bed
|
||||
* @return The raw Z position where the probe was triggered
|
||||
*/
|
||||
static float run_z_probe(const bool short_move=true) {
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> run_z_probe", current_position);
|
||||
#endif
|
||||
|
||||
// Prevent stepper_inactive_time from running out and EXTRUDER_RUNOUT_PREVENT from extruding
|
||||
gcode.refresh_cmd_timeout();
|
||||
|
||||
#if ENABLED(PROBE_DOUBLE_TOUCH)
|
||||
|
||||
// Do a first probe at the fast speed
|
||||
if (do_probe_move(-10, Z_PROBE_SPEED_FAST)) return NAN;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
float first_probe_z = current_position[Z_AXIS];
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("1st Probe Z:", first_probe_z);
|
||||
#endif
|
||||
|
||||
// move up to make clearance for the probe
|
||||
do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
|
||||
|
||||
#else
|
||||
|
||||
// If the nozzle is above the travel height then
|
||||
// move down quickly before doing the slow probe
|
||||
float z = Z_CLEARANCE_DEPLOY_PROBE;
|
||||
if (zprobe_zoffset < 0) z -= zprobe_zoffset;
|
||||
|
||||
if (z < current_position[Z_AXIS]) {
|
||||
|
||||
// If we don't make it to the z position (i.e. the probe triggered), move up to make clearance for the probe
|
||||
if (!do_probe_move(z, Z_PROBE_SPEED_FAST))
|
||||
do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
|
||||
}
|
||||
#endif
|
||||
|
||||
// move down slowly to find bed
|
||||
if (do_probe_move(-10 + (short_move ? 0 : -(Z_MAX_LENGTH)), Z_PROBE_SPEED_SLOW)) return NAN;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< run_z_probe", current_position);
|
||||
#endif
|
||||
|
||||
// Debug: compare probe heights
|
||||
#if ENABLED(PROBE_DOUBLE_TOUCH) && ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("2nd Probe Z:", current_position[Z_AXIS]);
|
||||
SERIAL_ECHOLNPAIR(" Discrepancy:", first_probe_z - current_position[Z_AXIS]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RAW_CURRENT_POSITION(Z) + zprobe_zoffset
|
||||
#if ENABLED(DELTA)
|
||||
+ home_offset[Z_AXIS] // Account for delta height adjustment
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* - Move to the given XY
|
||||
* - Deploy the probe, if not already deployed
|
||||
* - Probe the bed, get the Z position
|
||||
* - Depending on the 'stow' flag
|
||||
* - Stow the probe, or
|
||||
* - Raise to the BETWEEN height
|
||||
* - Return the probed Z position
|
||||
*/
|
||||
float probe_pt(const float &lx, const float &ly, const bool stow, const uint8_t verbose_level, const bool printable/*=true*/) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR(">>> probe_pt(", lx);
|
||||
SERIAL_ECHOPAIR(", ", ly);
|
||||
SERIAL_ECHOPAIR(", ", stow ? "" : "no ");
|
||||
SERIAL_ECHOLNPGM("stow)");
|
||||
DEBUG_POS("", current_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
const float nx = lx - (X_PROBE_OFFSET_FROM_EXTRUDER), ny = ly - (Y_PROBE_OFFSET_FROM_EXTRUDER);
|
||||
|
||||
if (printable
|
||||
? !position_is_reachable_xy(nx, ny)
|
||||
: !position_is_reachable_by_probe_xy(lx, ly)
|
||||
) return NAN;
|
||||
|
||||
|
||||
const float old_feedrate_mm_s = feedrate_mm_s;
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
if (current_position[Z_AXIS] > delta_clip_start_height)
|
||||
do_blocking_move_to_z(delta_clip_start_height);
|
||||
#endif
|
||||
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// Store the status of the soft endstops and disable if we're probing a non-printable location
|
||||
static bool enable_soft_endstops = soft_endstops_enabled;
|
||||
if (!printable) soft_endstops_enabled = false;
|
||||
#endif
|
||||
|
||||
feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
|
||||
|
||||
// Move the probe to the given XY
|
||||
do_blocking_move_to_xy(nx, ny);
|
||||
|
||||
float measured_z = NAN;
|
||||
if (!DEPLOY_PROBE()) {
|
||||
measured_z = run_z_probe(printable);
|
||||
|
||||
if (!stow)
|
||||
do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
|
||||
else
|
||||
if (STOW_PROBE()) measured_z = NAN;
|
||||
}
|
||||
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// Restore the soft endstop status
|
||||
soft_endstops_enabled = enable_soft_endstops;
|
||||
#endif
|
||||
|
||||
if (verbose_level > 2) {
|
||||
SERIAL_PROTOCOLPGM("Bed X: ");
|
||||
SERIAL_PROTOCOL_F(lx, 3);
|
||||
SERIAL_PROTOCOLPGM(" Y: ");
|
||||
SERIAL_PROTOCOL_F(ly, 3);
|
||||
SERIAL_PROTOCOLPGM(" Z: ");
|
||||
SERIAL_PROTOCOL_F(measured_z, 3);
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< probe_pt");
|
||||
#endif
|
||||
|
||||
feedrate_mm_s = old_feedrate_mm_s;
|
||||
|
||||
if (isnan(measured_z)) {
|
||||
LCD_MESSAGEPGM(MSG_ERR_PROBING_FAILED);
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_PROBING_FAILED);
|
||||
}
|
||||
|
||||
return measured_z;
|
||||
}
|
||||
|
||||
void refresh_zprobe_zoffset(const bool no_babystep/*=false*/) {
|
||||
static float last_zoffset = NAN;
|
||||
|
||||
if (!isnan(last_zoffset)) {
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(BABYSTEP_ZPROBE_OFFSET) || ENABLED(DELTA)
|
||||
const float diff = zprobe_zoffset - last_zoffset;
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
// Correct bilinear grid for new probe offset
|
||||
if (diff) {
|
||||
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
|
||||
for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
|
||||
z_values[x][y] -= diff;
|
||||
}
|
||||
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
|
||||
bed_level_virt_interpolate();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
|
||||
if (!no_babystep && leveling_is_active())
|
||||
thermalManager.babystep_axis(Z_AXIS, -LROUND(diff * planner.axis_steps_per_mm[Z_AXIS]));
|
||||
#else
|
||||
UNUSED(no_babystep);
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA) // correct the delta_height
|
||||
home_offset[Z_AXIS] -= diff;
|
||||
#endif
|
||||
}
|
||||
|
||||
last_zoffset = zprobe_zoffset;
|
||||
}
|
||||
|
||||
#if HAS_Z_SERVO_ENDSTOP
|
||||
|
||||
void servo_probe_init() {
|
||||
/**
|
||||
* Set position of Z Servo Endstop
|
||||
*
|
||||
* The servo might be deployed and positioned too low to stow
|
||||
* when starting up the machine or rebooting the board.
|
||||
* There's no way to know where the nozzle is positioned until
|
||||
* homing has been done - no homing with z-probe without init!
|
||||
*
|
||||
*/
|
||||
STOW_Z_SERVO();
|
||||
}
|
||||
|
||||
#endif // HAS_Z_SERVO_ENDSTOP
|
||||
|
||||
#endif // HAS_BED_PROBE
|
69
Marlin/src/module/probe.h
Normal file
69
Marlin/src/module/probe.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* probe.h - Move, deploy, enable, etc.
|
||||
*/
|
||||
|
||||
#ifndef PROBE_H
|
||||
#define PROBE_H
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
bool set_probe_deployed(const bool deploy);
|
||||
float probe_pt(const float &lx, const float &ly, const bool, const uint8_t, const bool printable=true);
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
extern float zprobe_zoffset;
|
||||
void refresh_zprobe_zoffset(const bool no_babystep=false);
|
||||
#define DEPLOY_PROBE() set_probe_deployed(true)
|
||||
#define STOW_PROBE() set_probe_deployed(false)
|
||||
#else
|
||||
#define DEPLOY_PROBE()
|
||||
#define STOW_PROBE()
|
||||
#endif
|
||||
|
||||
#if HAS_Z_SERVO_ENDSTOP
|
||||
extern const int z_servo_angle[2];
|
||||
void servo_probe_init();
|
||||
#endif
|
||||
|
||||
#if QUIET_PROBING
|
||||
void probing_pause(const bool p);
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBING_FANS_OFF)
|
||||
void fans_pause(const bool p);
|
||||
#endif
|
||||
|
||||
#if ENABLED(BLTOUCH)
|
||||
void bltouch_command(int angle);
|
||||
bool set_bltouch_deployed(const bool deploy);
|
||||
FORCE_INLINE void bltouch_init() {
|
||||
// Make sure any BLTouch error condition is cleared
|
||||
bltouch_command(BLTOUCH_RESET);
|
||||
set_bltouch_deployed(true);
|
||||
set_bltouch_deployed(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PROBE_H
|
155
Marlin/src/module/scara.cpp
Normal file
155
Marlin/src/module/scara.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* scara.cpp
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if IS_SCARA
|
||||
|
||||
#include "scara.h"
|
||||
#include "motion.h"
|
||||
#include "stepper.h"
|
||||
|
||||
float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND;
|
||||
|
||||
void scara_set_axis_is_at_home(const AxisEnum axis) {
|
||||
if (axis == Z_AXIS)
|
||||
current_position[Z_AXIS] = LOGICAL_POSITION(Z_HOME_POS, Z_AXIS);
|
||||
else {
|
||||
|
||||
/**
|
||||
* SCARA homes XY at the same time
|
||||
*/
|
||||
float homeposition[XYZ];
|
||||
LOOP_XYZ(i) homeposition[i] = LOGICAL_POSITION(base_home_pos((AxisEnum)i), i);
|
||||
|
||||
// SERIAL_ECHOPAIR("homeposition X:", homeposition[X_AXIS]);
|
||||
// SERIAL_ECHOLNPAIR(" Y:", homeposition[Y_AXIS]);
|
||||
|
||||
/**
|
||||
* Get Home position SCARA arm angles using inverse kinematics,
|
||||
* and calculate homing offset using forward kinematics
|
||||
*/
|
||||
inverse_kinematics(homeposition);
|
||||
forward_kinematics_SCARA(delta[A_AXIS], delta[B_AXIS]);
|
||||
|
||||
// SERIAL_ECHOPAIR("Cartesian X:", cartes[X_AXIS]);
|
||||
// SERIAL_ECHOLNPAIR(" Y:", cartes[Y_AXIS]);
|
||||
|
||||
current_position[axis] = LOGICAL_POSITION(cartes[axis], axis);
|
||||
|
||||
/**
|
||||
* SCARA home positions are based on configuration since the actual
|
||||
* limits are determined by the inverse kinematic transform.
|
||||
*/
|
||||
soft_endstop_min[axis] = base_min_pos(axis); // + (cartes[axis] - base_home_pos(axis));
|
||||
soft_endstop_max[axis] = base_max_pos(axis); // + (cartes[axis] - base_home_pos(axis));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Morgan SCARA Forward Kinematics. Results in cartes[].
|
||||
* Maths and first version by QHARLEY.
|
||||
* Integrated into Marlin and slightly restructured by Joachim Cerny.
|
||||
*/
|
||||
void forward_kinematics_SCARA(const float &a, const float &b) {
|
||||
|
||||
const float a_sin = sin(RADIANS(a)) * L1,
|
||||
a_cos = cos(RADIANS(a)) * L1,
|
||||
b_sin = sin(RADIANS(b)) * L2,
|
||||
b_cos = cos(RADIANS(b)) * L2;
|
||||
|
||||
cartes[X_AXIS] = a_cos + b_cos + SCARA_OFFSET_X; //theta
|
||||
cartes[Y_AXIS] = a_sin + b_sin + SCARA_OFFSET_Y; //theta+phi
|
||||
|
||||
/*
|
||||
SERIAL_ECHOPAIR("SCARA FK Angle a=", a);
|
||||
SERIAL_ECHOPAIR(" b=", b);
|
||||
SERIAL_ECHOPAIR(" a_sin=", a_sin);
|
||||
SERIAL_ECHOPAIR(" a_cos=", a_cos);
|
||||
SERIAL_ECHOPAIR(" b_sin=", b_sin);
|
||||
SERIAL_ECHOLNPAIR(" b_cos=", b_cos);
|
||||
SERIAL_ECHOPAIR(" cartes[X_AXIS]=", cartes[X_AXIS]);
|
||||
SERIAL_ECHOLNPAIR(" cartes[Y_AXIS]=", cartes[Y_AXIS]);
|
||||
//*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Morgan SCARA Inverse Kinematics. Results in delta[].
|
||||
*
|
||||
* See http://forums.reprap.org/read.php?185,283327
|
||||
*
|
||||
* Maths and first version by QHARLEY.
|
||||
* Integrated into Marlin and slightly restructured by Joachim Cerny.
|
||||
*/
|
||||
void inverse_kinematics(const float logical[XYZ]) {
|
||||
|
||||
static float C2, S2, SK1, SK2, THETA, PSI;
|
||||
|
||||
float sx = RAW_X_POSITION(logical[X_AXIS]) - SCARA_OFFSET_X, // Translate SCARA to standard X Y
|
||||
sy = RAW_Y_POSITION(logical[Y_AXIS]) - SCARA_OFFSET_Y; // With scaling factor.
|
||||
|
||||
if (L1 == L2)
|
||||
C2 = HYPOT2(sx, sy) / L1_2_2 - 1;
|
||||
else
|
||||
C2 = (HYPOT2(sx, sy) - (L1_2 + L2_2)) / (2.0 * L1 * L2);
|
||||
|
||||
S2 = SQRT(1 - sq(C2));
|
||||
|
||||
// Unrotated Arm1 plus rotated Arm2 gives the distance from Center to End
|
||||
SK1 = L1 + L2 * C2;
|
||||
|
||||
// Rotated Arm2 gives the distance from Arm1 to Arm2
|
||||
SK2 = L2 * S2;
|
||||
|
||||
// Angle of Arm1 is the difference between Center-to-End angle and the Center-to-Elbow
|
||||
THETA = ATAN2(SK1, SK2) - ATAN2(sx, sy);
|
||||
|
||||
// Angle of Arm2
|
||||
PSI = ATAN2(S2, C2);
|
||||
|
||||
delta[A_AXIS] = DEGREES(THETA); // theta is support arm angle
|
||||
delta[B_AXIS] = DEGREES(THETA + PSI); // equal to sub arm angle (inverted motor)
|
||||
delta[C_AXIS] = logical[Z_AXIS];
|
||||
|
||||
/*
|
||||
DEBUG_POS("SCARA IK", logical);
|
||||
DEBUG_POS("SCARA IK", delta);
|
||||
SERIAL_ECHOPAIR(" SCARA (x,y) ", sx);
|
||||
SERIAL_ECHOPAIR(",", sy);
|
||||
SERIAL_ECHOPAIR(" C2=", C2);
|
||||
SERIAL_ECHOPAIR(" S2=", S2);
|
||||
SERIAL_ECHOPAIR(" Theta=", THETA);
|
||||
SERIAL_ECHOLNPAIR(" Phi=", PHI);
|
||||
//*/
|
||||
}
|
||||
|
||||
void scara_report_positions() {
|
||||
SERIAL_PROTOCOLPAIR("SCARA Theta:", stepper.get_axis_position_degrees(A_AXIS));
|
||||
SERIAL_PROTOCOLLNPAIR(" Psi+Theta:", stepper.get_axis_position_degrees(B_AXIS));
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
#endif // IS_SCARA
|
46
Marlin/src/module/scara.h
Normal file
46
Marlin/src/module/scara.h
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* scara.h - SCARA-specific functions
|
||||
*/
|
||||
|
||||
#ifndef __SCARA_H__
|
||||
#define __SCARA_H__
|
||||
|
||||
#include "../core/macros.h"
|
||||
|
||||
extern float delta_segments_per_second;
|
||||
|
||||
// Float constants for SCARA calculations
|
||||
float constexpr L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2,
|
||||
L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
|
||||
L2_2 = sq(float(L2));
|
||||
|
||||
void scara_set_axis_is_at_home(const AxisEnum axis);
|
||||
|
||||
void inverse_kinematics(const float logical[XYZ]);
|
||||
void forward_kinematics_SCARA(const float &a, const float &b);
|
||||
|
||||
void scara_report_positions();
|
||||
|
||||
#endif // __SCARA_H__
|
@ -52,6 +52,7 @@
|
||||
|
||||
#include "endstops.h"
|
||||
#include "planner.h"
|
||||
#include "motion.h"
|
||||
|
||||
#include "../Marlin.h"
|
||||
#include "../module/temperature.h"
|
||||
|
Reference in New Issue
Block a user