diff --git a/Marlin/Conditionals_post.h b/Marlin/Conditionals_post.h
index 239780f34676c0bb27a893bf257e362f31ffc329..9861c2b29515c18ef6534a20d8a86d31bf492668 100644
--- a/Marlin/Conditionals_post.h
+++ b/Marlin/Conditionals_post.h
@@ -61,12 +61,16 @@
#define NORMAL_AXIS X_AXIS
#endif
+ #define IS_SCARA (ENABLED(MORGAN_SCARA) || ENABLED(MAKERARM_SCARA))
+ #define IS_KINEMATIC (ENABLED(DELTA) || IS_SCARA)
+ #define IS_CARTESIAN !IS_KINEMATIC
+
/**
- * SCARA
+ * SCARA cannot use SLOWDOWN and requires QUICKHOME
*/
- #if ENABLED(SCARA)
+ #if IS_SCARA
#undef SLOWDOWN
- #define QUICK_HOME //SCARA needs Quickhome
+ #define QUICK_HOME
#endif
/**
@@ -132,12 +136,6 @@
#define HOMING_Z_WITH_PROBE (HAS_BED_PROBE && Z_HOME_DIR < 0 && ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN))
- // Boundaries for probing based on set limits
- #define MIN_PROBE_X (max(X_MIN_POS, X_MIN_POS + X_PROBE_OFFSET_FROM_EXTRUDER))
- #define MAX_PROBE_X (min(X_MAX_POS, X_MAX_POS + X_PROBE_OFFSET_FROM_EXTRUDER))
- #define MIN_PROBE_Y (max(Y_MIN_POS, Y_MIN_POS + Y_PROBE_OFFSET_FROM_EXTRUDER))
- #define MAX_PROBE_Y (min(Y_MAX_POS, Y_MAX_POS + Y_PROBE_OFFSET_FROM_EXTRUDER))
-
#define HAS_Z_SERVO_ENDSTOP (defined(Z_ENDSTOP_SERVO_NR) && Z_ENDSTOP_SERVO_NR >= 0)
/**
@@ -657,18 +655,28 @@
#ifndef DELTA_DIAGONAL_ROD_TRIM_TOWER_3
#define DELTA_DIAGONAL_ROD_TRIM_TOWER_3 0.0
#endif
- #if ENABLED(AUTO_BED_LEVELING_GRID)
- #define DELTA_BED_LEVELING_GRID
- #endif
#endif
/**
- * When not using other bed leveling...
+ * Specify the exact style of auto bed leveling
+ *
+ * 3POINT - 3 Point Probing with the least-squares solution.
+ * LINEAR - Grid Probing with the least-squares solution.
+ * NONLINEAR - Grid Probing with a mesh solution. Best for large beds.
*/
- #if ENABLED(AUTO_BED_LEVELING_FEATURE) && DISABLED(AUTO_BED_LEVELING_GRID) && DISABLED(DELTA_BED_LEVELING_GRID)
- #define AUTO_BED_LEVELING_3POINT
+ #if ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if DISABLED(AUTO_BED_LEVELING_GRID)
+ #define AUTO_BED_LEVELING_LINEAR
+ #define AUTO_BED_LEVELING_3POINT
+ #elif IS_KINEMATIC
+ #define AUTO_BED_LEVELING_NONLINEAR
+ #else
+ #define AUTO_BED_LEVELING_LINEAR
+ #endif
#endif
+ #define PLANNER_LEVELING (ENABLED(MESH_BED_LEVELING) || ENABLED(AUTO_BED_LEVELING_LINEAR))
+
/**
* Buzzer/Speaker
*/
@@ -702,4 +710,18 @@
#define Z_PROBE_TRAVEL_HEIGHT Z_HOMING_HEIGHT
#endif
+ #if IS_KINEMATIC
+ // Check for this in the code instead
+ #define MIN_PROBE_X X_MIN_POS
+ #define MAX_PROBE_X X_MAX_POS
+ #define MIN_PROBE_Y Y_MIN_POS
+ #define MAX_PROBE_Y Y_MAX_POS
+ #else
+ // Boundaries for probing based on set limits
+ #define MIN_PROBE_X (max(X_MIN_POS, X_MIN_POS + X_PROBE_OFFSET_FROM_EXTRUDER))
+ #define MAX_PROBE_X (min(X_MAX_POS, X_MAX_POS + X_PROBE_OFFSET_FROM_EXTRUDER))
+ #define MIN_PROBE_Y (max(Y_MIN_POS, Y_MIN_POS + Y_PROBE_OFFSET_FROM_EXTRUDER))
+ #define MAX_PROBE_Y (min(Y_MAX_POS, Y_MAX_POS + Y_PROBE_OFFSET_FROM_EXTRUDER))
+ #endif
+
#endif // CONDITIONALS_POST_H
diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index f6df89a8509dc2974301db2be50c2dae6cd92be8..cdf223d11d60e602d96bfc26c978a855c75570db 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index da9bc0de90314a65941f023292a57fd13a954353..d34445ac4319f691f7074a3f9807c427dd425aa5 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -220,7 +220,6 @@ void disable_all_steppers();
void FlushSerialRequestResend();
void ok_to_send();
-void reset_bed_level();
void kill(const char*);
void quickstop_stepper();
@@ -266,6 +265,10 @@ extern bool axis_known_position[XYZ]; // axis[n].is_known
extern bool axis_homed[XYZ]; // axis[n].is_homed
extern volatile bool wait_for_heatup;
+#if ENABLED(EMERGENCY_PARSER) && DISABLED(ULTIPANEL)
+ extern volatile bool wait_for_user;
+#endif
+
extern float current_position[NUM_AXIS];
extern float position_shift[XYZ];
extern float home_offset[XYZ];
@@ -298,26 +301,29 @@ int code_value_int();
float code_value_temp_abs();
float code_value_temp_diff();
-#if ENABLED(DELTA)
+#if IS_KINEMATIC
extern float delta[ABC];
- extern float endstop_adj[ABC]; // axis[n].endstop_adj
- extern float delta_radius;
- extern float delta_diagonal_rod;
- extern float delta_segments_per_second;
- extern float delta_diagonal_rod_trim_tower_1;
- extern float delta_diagonal_rod_trim_tower_2;
- extern float delta_diagonal_rod_trim_tower_3;
void inverse_kinematics(const float cartesian[XYZ]);
+#endif
+
+#if ENABLED(DELTA)
+ extern float delta[ABC],
+ endstop_adj[ABC],
+ delta_radius,
+ delta_diagonal_rod,
+ delta_segments_per_second,
+ delta_diagonal_rod_trim_tower_1,
+ delta_diagonal_rod_trim_tower_2,
+ delta_diagonal_rod_trim_tower_3;
void recalc_delta_settings(float radius, float diagonal_rod);
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
- extern int delta_grid_spacing[2];
- void adjust_delta(float cartesian[XYZ]);
- #endif
-#elif ENABLED(SCARA)
- extern float delta[ABC];
+#elif IS_SCARA
extern float axis_scaling[ABC]; // Build size scaling
- void inverse_kinematics(const float cartesian[XYZ]);
- void forward_kinematics_SCARA(float f_scara[ABC]);
+ void forward_kinematics_SCARA(const float &a, const float &b);
+#endif
+
+#if ENABLED(AUTO_BED_LEVELING_NONLINEAR)
+ extern int nonlinear_grid_spacing[2];
+ void adjust_delta(float cartesian[XYZ]);
#endif
#if ENABLED(Z_DUAL_ENDSTOPS)
diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp
index a1b3349fecd26dba7869a23d9b79a60d1530c831..3bb2a822e3d15c33ec70fe042b69a46460b0bd66 100644
--- a/Marlin/MarlinSerial.cpp
+++ b/Marlin/MarlinSerial.cpp
@@ -509,6 +509,9 @@ MarlinSerial customizedSerial;
switch (state) {
case state_M108:
wait_for_heatup = false;
+ #if DISABLED(ULTIPANEL)
+ wait_for_user = false;
+ #endif
break;
case state_M112:
kill(PSTR(MSG_KILLED));
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 4ea114504f0fc7e74deb7b72377865b11e7cb34c..bbc92e9f6a1afe0ca0c613b0007c5b984d530ae9 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -36,12 +36,11 @@
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
#include "vector_3.h"
- #if ENABLED(AUTO_BED_LEVELING_GRID)
- #include "qr_solve.h"
- #endif
-#endif // AUTO_BED_LEVELING_FEATURE
+#endif
-#if ENABLED(MESH_BED_LEVELING)
+#if ENABLED(AUTO_BED_LEVELING_LINEAR)
+ #include "qr_solve.h"
+#elif ENABLED(MESH_BED_LEVELING)
#include "mesh_bed_leveling.h"
#endif
@@ -352,6 +351,10 @@ static bool relative_mode = false;
volatile bool wait_for_heatup = true;
+#if ENABLED(EMERGENCY_PARSER) && DISABLED(ULTIPANEL)
+ wait_for_user = false;
+#endif
+
const char errormagic[] PROGMEM = "Error:";
const char echomagic[] PROGMEM = "echo:";
const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'};
@@ -462,7 +465,6 @@ static uint8_t target_extruder;
#define COS_60 0.5
float delta[ABC],
- cartesian_position[XYZ] = { 0 },
endstop_adj[ABC] = { 0 };
// these are the default values, can be overriden with M665
@@ -483,13 +485,7 @@ static uint8_t target_extruder;
delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND,
delta_clip_start_height = Z_MAX_POS;
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
- int delta_grid_spacing[2] = { 0, 0 };
- float bed_level[AUTO_BED_LEVELING_GRID_POINTS][AUTO_BED_LEVELING_GRID_POINTS];
- #endif
-
float delta_safe_distance_from_top();
- void set_cartesian_from_steppers();
#else
@@ -497,14 +493,24 @@ static uint8_t target_extruder;
#endif
-#if ENABLED(SCARA)
+#if ENABLED(AUTO_BED_LEVELING_NONLINEAR)
+ int nonlinear_grid_spacing[2] = { 0 };
+ float bed_level_grid[AUTO_BED_LEVELING_GRID_POINTS][AUTO_BED_LEVELING_GRID_POINTS];
+#endif
+
+#if IS_SCARA
+ // Float constants for SCARA calculations
+ const float 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));
+
float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND,
delta[ABC],
- axis_scaling[ABC] = { 1, 1, 1 }, // Build size scaling, default to 1
- cartesian_position[XYZ] = { 0 };
- void set_cartesian_from_steppers() { } // to be written later
+ axis_scaling[ABC] = { 1, 1, 1 }; // Build size scaling, default to 1
#endif
+float cartes[XYZ] = { 0 };
+
#if ENABLED(FILAMENT_WIDTH_SENSOR)
bool filament_sensor = false; //M405 turns on filament_sensor control, M406 turns it off
float filament_width_nominal = DEFAULT_NOMINAL_FILAMENT_DIA, // Nominal filament width. Change with M404
@@ -590,6 +596,8 @@ void stop();
void get_available_commands();
void process_next_command();
void prepare_move_to_destination();
+
+void get_cartesian_from_steppers();
void set_current_from_steppers_for_axis(AxisEnum axis);
#if ENABLED(ARC_SUPPORT)
@@ -651,15 +659,15 @@ inline void sync_plan_position() {
}
inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); }
-#if ENABLED(DELTA) || ENABLED(SCARA)
- inline void sync_plan_position_delta() {
+#if IS_KINEMATIC
+ inline void sync_plan_position_kinematic() {
#if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position_delta", current_position);
+ if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position_kinematic", current_position);
#endif
inverse_kinematics(current_position);
planner.set_position_mm(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS]);
}
- #define SYNC_PLAN_POSITION_KINEMATIC() sync_plan_position_delta()
+ #define SYNC_PLAN_POSITION_KINEMATIC() sync_plan_position_kinematic()
#else
#define SYNC_PLAN_POSITION_KINEMATIC() sync_plan_position()
#endif
@@ -756,8 +764,7 @@ void enqueue_and_echo_command_now(const char* cmd) {
bool enqueue_and_echo_command(const char* cmd, bool say_ok/*=false*/) {
if (_enqueuecommand(cmd, say_ok)) {
SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_Enqueueing);
- SERIAL_ECHO(cmd);
+ SERIAL_ECHOPAIR(MSG_Enqueueing, cmd);
SERIAL_ECHOLNPGM("\"");
return true;
}
@@ -846,10 +853,6 @@ void servo_init() {
*/
STOW_Z_SERVO();
#endif
-
- #if HAS_BED_PROBE
- endstops.enable_z_probe(false);
- #endif
}
/**
@@ -875,216 +878,6 @@ void servo_init() {
#endif
-/**
- * Marlin entry-point: Set up before the program loop
- * - Set up the kill pin, filament runout, power hold
- * - Start the serial port
- * - Print startup messages and diagnostics
- * - Get EEPROM or default settings
- * - Initialize managers for:
- * • temperature
- * • planner
- * • watchdog
- * • stepper
- * • photo pin
- * • servos
- * • LCD controller
- * • Digipot I2C
- * • Z probe sled
- * • status LEDs
- */
-void setup() {
-
- #ifdef DISABLE_JTAG
- // Disable JTAG on AT90USB chips to free up pins for IO
- MCUCR = 0x80;
- MCUCR = 0x80;
- #endif
-
- #if ENABLED(FILAMENT_RUNOUT_SENSOR)
- setup_filrunoutpin();
- #endif
-
- setup_killpin();
-
- setup_powerhold();
-
- #if HAS_STEPPER_RESET
- disableStepperDrivers();
- #endif
-
- MYSERIAL.begin(BAUDRATE);
- SERIAL_PROTOCOLLNPGM("start");
- SERIAL_ECHO_START;
-
- // Check startup - does nothing if bootloader sets MCUSR to 0
- byte mcu = MCUSR;
- if (mcu & 1) SERIAL_ECHOLNPGM(MSG_POWERUP);
- if (mcu & 2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
- if (mcu & 4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
- if (mcu & 8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
- if (mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
- MCUSR = 0;
-
- SERIAL_ECHOPGM(MSG_MARLIN);
- SERIAL_ECHOLNPGM(" " SHORT_BUILD_VERSION);
-
- #ifdef STRING_DISTRIBUTION_DATE
- #ifdef STRING_CONFIG_H_AUTHOR
- SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
- SERIAL_ECHOPGM(STRING_DISTRIBUTION_DATE);
- SERIAL_ECHOPGM(MSG_AUTHOR);
- SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
- SERIAL_ECHOPGM("Compiled: ");
- SERIAL_ECHOLNPGM(__DATE__);
- #endif // STRING_CONFIG_H_AUTHOR
- #endif // STRING_DISTRIBUTION_DATE
-
- SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_FREE_MEMORY);
- SERIAL_ECHO(freeMemory());
- SERIAL_ECHOPGM(MSG_PLANNER_BUFFER_BYTES);
- SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
-
- // Send "ok" after commands by default
- for (int8_t i = 0; i < BUFSIZE; i++) send_ok[i] = true;
-
- // Load data from EEPROM if available (or use defaults)
- // This also updates variables in the planner, elsewhere
- Config_RetrieveSettings();
-
- // Initialize current position based on home_offset
- memcpy(current_position, home_offset, sizeof(home_offset));
-
- // Vital to init stepper/planner equivalent for current_position
- SYNC_PLAN_POSITION_KINEMATIC();
-
- thermalManager.init(); // Initialize temperature loop
-
- #if ENABLED(USE_WATCHDOG)
- watchdog_init();
- #endif
-
- stepper.init(); // Initialize stepper, this enables interrupts!
- setup_photpin();
- servo_init();
-
- #if HAS_CONTROLLERFAN
- SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
- #endif
-
- #if HAS_STEPPER_RESET
- enableStepperDrivers();
- #endif
-
- #if ENABLED(DIGIPOT_I2C)
- digipot_i2c_init();
- #endif
-
- #if ENABLED(DAC_STEPPER_CURRENT)
- dac_init();
- #endif
-
- #if ENABLED(Z_PROBE_SLED) && PIN_EXISTS(SLED)
- pinMode(SLED_PIN, OUTPUT);
- digitalWrite(SLED_PIN, LOW); // turn it off
- #endif // Z_PROBE_SLED
-
- setup_homepin();
-
- #ifdef STAT_LED_RED
- pinMode(STAT_LED_RED, OUTPUT);
- digitalWrite(STAT_LED_RED, LOW); // turn it off
- #endif
-
- #ifdef STAT_LED_BLUE
- pinMode(STAT_LED_BLUE, OUTPUT);
- digitalWrite(STAT_LED_BLUE, LOW); // turn it off
- #endif
-
- lcd_init();
- #if ENABLED(SHOW_BOOTSCREEN)
- #if ENABLED(DOGLCD)
- safe_delay(BOOTSCREEN_TIMEOUT);
- #elif ENABLED(ULTRA_LCD)
- bootscreen();
- lcd_init();
- #endif
- #endif
-
- #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
- // Initialize mixing to 100% color 1
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
- mixing_factor[i] = (i == 0) ? 1 : 0;
- for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS; t++)
- for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
- mixing_virtual_tool_mix[t][i] = mixing_factor[i];
- #endif
-
- #if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
- i2c.onReceive(i2c_on_receive);
- i2c.onRequest(i2c_on_request);
- #endif
-}
-
-/**
- * The main Marlin program loop
- *
- * - Save or log commands to SD
- * - Process available commands (if not saving)
- * - Call heater manager
- * - Call inactivity manager
- * - Call endstop manager
- * - Call LCD update
- */
-void loop() {
- if (commands_in_queue < BUFSIZE) get_available_commands();
-
- #if ENABLED(SDSUPPORT)
- card.checkautostart(false);
- #endif
-
- if (commands_in_queue) {
-
- #if ENABLED(SDSUPPORT)
-
- if (card.saving) {
- char* command = command_queue[cmd_queue_index_r];
- if (strstr_P(command, PSTR("M29"))) {
- // M29 closes the file
- card.closefile();
- SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
- ok_to_send();
- }
- else {
- // Write the string from the read buffer to SD
- card.write_command(command);
- if (card.logging)
- process_next_command(); // The card is saving because it's logging
- else
- ok_to_send();
- }
- }
- else
- process_next_command();
-
- #else
-
- process_next_command();
-
- #endif // SDSUPPORT
-
- // The queue may be reset by a command handler or by code invoked by idle() within a handler
- if (commands_in_queue) {
- --commands_in_queue;
- cmd_queue_index_r = (cmd_queue_index_r + 1) % BUFSIZE;
- }
- }
- endstops.report_state();
- idle();
-}
-
void gcode_line_error(const char* err, bool doFlush = true) {
SERIAL_ERROR_START;
serialprintPGM(err);
@@ -1553,34 +1346,34 @@ static void set_axis_is_at_home(AxisEnum axis) {
}
#endif
- #if ENABLED(SCARA)
+ #if ENABLED(MORGAN_SCARA)
if (axis == X_AXIS || axis == Y_AXIS) {
float homeposition[XYZ];
LOOP_XYZ(i) homeposition[i] = LOGICAL_POSITION(base_home_pos(i), i);
- // SERIAL_ECHOPGM("homeposition[x]= "); SERIAL_ECHO(homeposition[0]);
- // SERIAL_ECHOPGM("homeposition[y]= "); SERIAL_ECHOLN(homeposition[1]);
+ // SERIAL_ECHOPAIR("homeposition X:", homeposition[X_AXIS]);
+ // SERIAL_ECHOLNPAIR(" Y:", homeposition[Y_AXIS]);
/**
* Works out real Homeposition angles using inverse kinematics,
* and calculates homing offset using forward kinematics
*/
inverse_kinematics(homeposition);
- forward_kinematics_SCARA(delta);
+ forward_kinematics_SCARA(delta[A_AXIS], delta[B_AXIS]);
- // SERIAL_ECHOPAIR("Delta X=", delta[X_AXIS]);
- // SERIAL_ECHOPGM(" Delta Y="); SERIAL_ECHOLN(delta[Y_AXIS]);
+ // SERIAL_ECHOPAIR("Cartesian X:", cartes[X_AXIS]);
+ // SERIAL_ECHOLNPAIR(" Y:", cartes[Y_AXIS]);
- current_position[axis] = LOGICAL_POSITION(delta[axis], 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); // + (delta[axis] - base_home_pos(axis));
- soft_endstop_max[axis] = base_max_pos(axis); // + (delta[axis] - base_home_pos(axis));
+ 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));
}
else
#endif
@@ -2161,10 +1954,6 @@ static void clean_up_after_endstop_or_probe_move() {
// Prevent stepper_inactive_time from running out and EXTRUDER_RUNOUT_PREVENT from extruding
refresh_cmd_timeout();
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
- planner.bed_level_matrix.set_to_identity();
- #endif
-
#if ENABLED(PROBE_DOUBLE_TOUCH)
// Do a first probe at the fast speed
@@ -2229,17 +2018,11 @@ static void clean_up_after_endstop_or_probe_move() {
feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
do_blocking_move_to_xy(x - (X_PROBE_OFFSET_FROM_EXTRUDER), y - (Y_PROBE_OFFSET_FROM_EXTRUDER));
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
- #endif
if (DEPLOY_PROBE()) return NAN;
float measured_z = run_z_probe();
if (stow) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
- #endif
if (STOW_PROBE()) return NAN;
}
else {
@@ -2272,109 +2055,101 @@ static void clean_up_after_endstop_or_probe_move() {
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
- #if DISABLED(DELTA)
+ /**
+ * Reset calibration results to zero.
+ */
+ void reset_bed_level() {
+ #if ENABLED(DEBUG_LEVELING_FEATURE)
+ if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("reset_bed_level");
+ #endif
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
+ planner.bed_level_matrix.set_to_identity();
+ #elif ENABLED(AUTO_BED_LEVELING_NONLINEAR)
+ memset(bed_level_grid, 0, sizeof(bed_level_grid));
+ nonlinear_grid_spacing[X_AXIS] = nonlinear_grid_spacing[Y_AXIS] = 0;
+ #endif
+ }
+
+#endif // AUTO_BED_LEVELING_FEATURE
- /**
- * Get the stepper positions, apply the rotation matrix
- * using the home XY and Z0 position as the fulcrum.
- */
- vector_3 untilted_stepper_position() {
- vector_3 pos = vector_3(
- RAW_X_POSITION(stepper.get_axis_position_mm(X_AXIS)) - X_TILT_FULCRUM,
- RAW_Y_POSITION(stepper.get_axis_position_mm(Y_AXIS)) - Y_TILT_FULCRUM,
- RAW_Z_POSITION(stepper.get_axis_position_mm(Z_AXIS))
- );
+#if ENABLED(AUTO_BED_LEVELING_LINEAR)
- matrix_3x3 inverse = matrix_3x3::transpose(planner.bed_level_matrix);
+ /**
+ * Get the stepper positions, apply the rotation matrix
+ * using the home XY and Z0 position as the fulcrum.
+ */
+ vector_3 untilted_stepper_position() {
+ get_cartesian_from_steppers();
- //pos.debug("untilted_stepper_position offset");
- //bed_level_matrix.debug("untilted_stepper_position");
- //inverse.debug("in untilted_stepper_position");
+ vector_3 pos = vector_3(
+ cartes[X_AXIS] - X_TILT_FULCRUM,
+ cartes[Y_AXIS] - Y_TILT_FULCRUM,
+ cartes[Z_AXIS]
+ );
- pos.apply_rotation(inverse);
+ matrix_3x3 inverse = matrix_3x3::transpose(planner.bed_level_matrix);
- pos.x = LOGICAL_X_POSITION(pos.x + X_TILT_FULCRUM);
- pos.y = LOGICAL_Y_POSITION(pos.y + Y_TILT_FULCRUM);
- pos.z = LOGICAL_Z_POSITION(pos.z);
+ //pos.debug("untilted_stepper_position offset");
+ //bed_level_matrix.debug("untilted_stepper_position");
+ //inverse.debug("in untilted_stepper_position");
- //pos.debug("after rotation and reorientation");
+ pos.apply_rotation(inverse);
- return pos;
- }
+ pos.x = LOGICAL_X_POSITION(pos.x + X_TILT_FULCRUM);
+ pos.y = LOGICAL_Y_POSITION(pos.y + Y_TILT_FULCRUM);
+ pos.z = LOGICAL_Z_POSITION(pos.z);
- #endif // !DELTA
+ //pos.debug("after rotation and reorientation");
- #if ENABLED(DELTA)
+ return pos;
+ }
- /**
- * All DELTA leveling in the Marlin uses NONLINEAR_BED_LEVELING
- */
- static void extrapolate_one_point(int x, int y, int xdir, int ydir) {
- if (bed_level[x][y] != 0.0) {
- return; // Don't overwrite good values.
- }
- float a = 2 * bed_level[x + xdir][y] - bed_level[x + xdir * 2][y]; // Left to right.
- float b = 2 * bed_level[x][y + ydir] - bed_level[x][y + ydir * 2]; // Front to back.
- float c = 2 * bed_level[x + xdir][y + ydir] - bed_level[x + xdir * 2][y + ydir * 2]; // Diagonal.
- float median = c; // Median is robust (ignores outliers).
- if (a < b) {
- if (b < c) median = b;
- if (c < a) median = a;
- }
- else { // b <= a
- if (c < b) median = b;
- if (a < c) median = a;
- }
- bed_level[x][y] = median;
- }
+#elif ENABLED(AUTO_BED_LEVELING_NONLINEAR)
- /**
- * Fill in the unprobed points (corners of circular print surface)
- * using linear extrapolation, away from the center.
- */
- static void extrapolate_unprobed_bed_level() {
- int half = (AUTO_BED_LEVELING_GRID_POINTS - 1) / 2;
- for (int y = 0; y <= half; y++) {
- for (int x = 0; x <= half; x++) {
- if (x + y < 3) continue;
- extrapolate_one_point(half - x, half - y, x > 1 ? +1 : 0, y > 1 ? +1 : 0);
- extrapolate_one_point(half + x, half - y, x > 1 ? -1 : 0, y > 1 ? +1 : 0);
- extrapolate_one_point(half - x, half + y, x > 1 ? +1 : 0, y > 1 ? -1 : 0);
- extrapolate_one_point(half + x, half + y, x > 1 ? -1 : 0, y > 1 ? -1 : 0);
- }
+ /**
+ * All DELTA leveling in the Marlin uses NONLINEAR_BED_LEVELING
+ */
+ static void extrapolate_one_point(uint8_t x, uint8_t y, int xdir, int ydir) {
+ if (bed_level_grid[x][y]) return; // Don't overwrite good values.
+ float a = 2 * bed_level_grid[x + xdir][y] - bed_level_grid[x + xdir * 2][y], // Left to right.
+ b = 2 * bed_level_grid[x][y + ydir] - bed_level_grid[x][y + ydir * 2], // Front to back.
+ c = 2 * bed_level_grid[x + xdir][y + ydir] - bed_level_grid[x + xdir * 2][y + ydir * 2]; // Diagonal.
+ // Median is robust (ignores outliers).
+ bed_level_grid[x][y] = (a < b) ? ((b < c) ? b : (c < a) ? a : c)
+ : ((c < b) ? b : (a < c) ? a : c);
+ }
+
+ /**
+ * Fill in the unprobed points (corners of circular print surface)
+ * using linear extrapolation, away from the center.
+ */
+ static void extrapolate_unprobed_bed_level() {
+ uint8_t half = (AUTO_BED_LEVELING_GRID_POINTS - 1) / 2;
+ for (uint8_t y = 0; y <= half; y++) {
+ for (uint8_t x = 0; x <= half; x++) {
+ if (x + y < 3) continue;
+ extrapolate_one_point(half - x, half - y, x > 1 ? +1 : 0, y > 1 ? +1 : 0);
+ extrapolate_one_point(half + x, half - y, x > 1 ? -1 : 0, y > 1 ? +1 : 0);
+ extrapolate_one_point(half - x, half + y, x > 1 ? +1 : 0, y > 1 ? -1 : 0);
+ extrapolate_one_point(half + x, half + y, x > 1 ? -1 : 0, y > 1 ? -1 : 0);
}
}
+ }
- /**
- * Print calibration results for plotting or manual frame adjustment.
- */
- static void print_bed_level() {
- for (int y = 0; y < AUTO_BED_LEVELING_GRID_POINTS; y++) {
- for (int x = 0; x < AUTO_BED_LEVELING_GRID_POINTS; x++) {
- SERIAL_PROTOCOL_F(bed_level[x][y], 2);
- SERIAL_PROTOCOLCHAR(' ');
- }
- SERIAL_EOL;
- }
- }
-
- /**
- * Reset calibration results to zero.
- */
- void reset_bed_level() {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("reset_bed_level");
- #endif
- for (int y = 0; y < AUTO_BED_LEVELING_GRID_POINTS; y++) {
- for (int x = 0; x < AUTO_BED_LEVELING_GRID_POINTS; x++) {
- bed_level[x][y] = 0.0;
- }
+ /**
+ * Print calibration results for plotting or manual frame adjustment.
+ */
+ static void print_bed_level() {
+ for (uint8_t y = 0; y < AUTO_BED_LEVELING_GRID_POINTS; y++) {
+ for (uint8_t x = 0; x < AUTO_BED_LEVELING_GRID_POINTS; x++) {
+ SERIAL_PROTOCOL_F(bed_level_grid[x][y], 2);
+ SERIAL_PROTOCOLCHAR(' ');
}
+ SERIAL_EOL;
}
+ }
- #endif // DELTA
-
-#endif // AUTO_BED_LEVELING_FEATURE
+#endif // AUTO_BED_LEVELING_NONLINEAR
/**
* Home an individual axis
@@ -2412,12 +2187,7 @@ static void homeaxis(AxisEnum axis) {
// Homing Z towards the bed? Deploy the Z probe or endstop.
#if HOMING_Z_WITH_PROBE
- if (axis == Z_AXIS) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
- #endif
- if (DEPLOY_PROBE()) return;
- }
+ if (axis == Z_AXIS && DEPLOY_PROBE()) return;
#endif
// Set a flag for Z motor locking
@@ -2495,12 +2265,7 @@ static void homeaxis(AxisEnum axis) {
// Put away the Z probe
#if HOMING_Z_WITH_PROBE
- if (axis == Z_AXIS) {
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
- #endif
- if (STOW_PROBE()) return;
- }
+ if (axis == Z_AXIS && STOW_PROBE()) return;
#endif
#if ENABLED(DEBUG_LEVELING_FEATURE)
@@ -2625,8 +2390,7 @@ void gcode_get_destination() {
void unknown_command_error() {
SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
- SERIAL_ECHO(current_command);
+ SERIAL_ECHOPAIR(MSG_UNKNOWN_COMMAND, current_command);
SERIAL_ECHOLNPGM("\"");
}
@@ -2663,6 +2427,24 @@ void unknown_command_error() {
#endif //HOST_KEEPALIVE_FEATURE
+bool position_is_reachable(float target[XYZ]) {
+ float dx = RAW_X_POSITION(target[X_AXIS]),
+ dy = RAW_Y_POSITION(target[Y_AXIS]);
+
+ #if ENABLED(DELTA)
+ return HYPOT2(dx, dy) <= sq(DELTA_PRINTABLE_RADIUS);
+ #else
+ float dz = RAW_Z_POSITION(target[Z_AXIS]);
+ return dx >= X_MIN_POS - 0.0001 && dx <= X_MAX_POS + 0.0001
+ && dy >= Y_MIN_POS - 0.0001 && dy <= Y_MAX_POS + 0.0001
+ && dz >= Z_MIN_POS - 0.0001 && dz <= Z_MAX_POS + 0.0001;
+ #endif
+}
+
+/**************************************************
+ ***************** GCode Handlers *****************
+ **************************************************/
+
/**
* G0, G1: Coordinated movement of X Y Z E axes
*/
@@ -2811,16 +2593,12 @@ inline void gcode_G4() {
/**
* G20: Set input mode to inches
*/
- inline void gcode_G20() {
- set_input_linear_units(LINEARUNIT_INCH);
- }
+ inline void gcode_G20() { set_input_linear_units(LINEARUNIT_INCH); }
/**
* G21: Set input mode to millimeters
*/
- inline void gcode_G21() {
- set_input_linear_units(LINEARUNIT_MM);
- }
+ inline void gcode_G21() { set_input_linear_units(LINEARUNIT_MM); }
#endif
#if ENABLED(NOZZLE_PARK_FEATURE)
@@ -2870,7 +2648,7 @@ inline void gcode_G4() {
SERIAL_ECHOPGM("Machine Type: ");
#if ENABLED(DELTA)
SERIAL_ECHOLNPGM("Delta");
- #elif ENABLED(SCARA)
+ #elif IS_SCARA
SERIAL_ECHOLNPGM("SCARA");
#elif ENABLED(COREXY) || ENABLED(COREXZ) || ENABLED(COREYZ)
SERIAL_ECHOLNPGM("Core");
@@ -2919,6 +2697,99 @@ inline void gcode_G4() {
#endif // DEBUG_LEVELING_FEATURE
+#if ENABLED(DELTA)
+
+ /**
+ * A delta can only safely home all axes at the same time
+ * This is like quick_home_xy() but for 3 towers.
+ */
+ inline void home_delta() {
+ // Init the current position of all carriages to 0,0,0
+ memset(current_position, 0, sizeof(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] = (Z_MAX_LENGTH + 10);
+ feedrate_mm_s = homing_feedrate_mm_s[X_AXIS];
+ line_to_current_position();
+ stepper.synchronize();
+ endstops.hit_on_purpose(); // clear endstop hit flags
+
+ // Probably not needed. Double-check this line:
+ memset(current_position, 0, sizeof(current_position));
+
+ // At least one carriage has reached the top.
+ // Now back off and 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("(DELTA)", current_position);
+ #endif
+ }
+
+#endif // DELTA
+
+#if ENABLED(Z_SAFE_HOMING)
+
+ inline void home_z_safely() {
+
+ // Disallow Z homing if X or Y are unknown
+ if (!axis_known_position[X_AXIS] || !axis_known_position[Y_AXIS]) {
+ LCD_MESSAGEPGM(MSG_ERR_Z_HOMING);
+ SERIAL_ECHO_START;
+ SERIAL_ECHOLNPGM(MSG_ERR_Z_HOMING);
+ return;
+ }
+
+ #if ENABLED(DEBUG_LEVELING_FEATURE)
+ if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Z_SAFE_HOMING >>>");
+ #endif
+
+ SYNC_PLAN_POSITION_KINEMATIC();
+
+ /**
+ * Move the Z probe (or just the nozzle) to the safe homing point
+ */
+ destination[X_AXIS] = LOGICAL_X_POSITION(Z_SAFE_HOMING_X_POINT);
+ destination[Y_AXIS] = LOGICAL_Y_POSITION(Z_SAFE_HOMING_Y_POINT);
+ destination[Z_AXIS] = current_position[Z_AXIS]; // Z is already at the right height
+
+ #if HAS_BED_PROBE
+ destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
+ destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
+ #endif
+
+ #if ENABLED(DEBUG_LEVELING_FEATURE)
+ if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination);
+ #endif
+
+ if (position_is_reachable(destination)) {
+ do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]);
+ HOMEAXIS(Z);
+ }
+ else {
+ LCD_MESSAGEPGM(MSG_ZPROBE_OUT);
+ SERIAL_ECHO_START;
+ SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT);
+ }
+
+ #if ENABLED(DEBUG_LEVELING_FEATURE)
+ if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING");
+ #endif
+ }
+
+#endif // Z_SAFE_HOMING
+
/**
* G28: Home all axes according to settings
*
@@ -2948,10 +2819,7 @@ inline void gcode_G28() {
// For auto bed leveling, clear the level matrix
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
- planner.bed_level_matrix.set_to_identity();
- #if ENABLED(DELTA)
- reset_bed_level();
- #endif
+ reset_bed_level();
#endif
// Always home with tool 0 active
@@ -2993,44 +2861,9 @@ inline void gcode_G28() {
#endif
endstops.enable(true); // Enable endstops for next homing move
-
#if ENABLED(DELTA)
- /**
- * A delta can only safely home all axes at the same time
- * This is like quick_home_xy() but for 3 towers.
- */
-
- // Init the current position of all carriages to 0,0,0
- memset(current_position, 0, sizeof(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] = (Z_MAX_LENGTH + 10);
- feedrate_mm_s = homing_feedrate_mm_s[X_AXIS];
- line_to_current_position();
- stepper.synchronize();
- endstops.hit_on_purpose(); // clear endstop hit flags
-
- // Probably not needed. Double-check this line:
- memset(current_position, 0, sizeof(current_position));
-
- // At least one carriage has reached the top.
- // Now back off and 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("(DELTA)", current_position);
- #endif
+ home_delta();
#else // NOT DELTA
@@ -3118,81 +2951,16 @@ inline void gcode_G28() {
// Home Z last if homing towards the bed
#if Z_HOME_DIR < 0
-
if (home_all_axis || homeZ) {
-
#if ENABLED(Z_SAFE_HOMING)
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> Z_SAFE_HOMING >>>");
- #endif
-
- if (home_all_axis) {
-
- /**
- * At this point we already have Z at Z_HOMING_HEIGHT height
- * No need to move Z any more as this height should already be safe
- * enough to reach Z_SAFE_HOMING XY positions.
- * Just make sure the planner is in sync.
- */
- SYNC_PLAN_POSITION_KINEMATIC();
-
- /**
- * Move the Z probe (or just the nozzle) to the safe homing point
- */
- destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - (X_PROBE_OFFSET_FROM_EXTRUDER));
- destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - (Y_PROBE_OFFSET_FROM_EXTRUDER));
- destination[Z_AXIS] = current_position[Z_AXIS]; // Z is already at the right height
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) DEBUG_POS("> Z_SAFE_HOMING > home_all_axis", destination);
- #endif
-
- // Move in the XY plane
- do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]);
- }
-
- // Let's see if X and Y are homed
- if (axis_unhomed_error(true, true, false)) return;
-
- /**
- * Make sure the Z probe is within the physical limits
- * NOTE: This doesn't necessarily ensure the Z probe is also
- * within the bed!
- */
- float cpx = RAW_CURRENT_POSITION(X_AXIS), cpy = RAW_CURRENT_POSITION(Y_AXIS);
- if ( cpx >= X_MIN_POS - (X_PROBE_OFFSET_FROM_EXTRUDER)
- && cpx <= X_MAX_POS - (X_PROBE_OFFSET_FROM_EXTRUDER)
- && cpy >= Y_MIN_POS - (Y_PROBE_OFFSET_FROM_EXTRUDER)
- && cpy <= Y_MAX_POS - (Y_PROBE_OFFSET_FROM_EXTRUDER)) {
-
- // Home the Z axis
- HOMEAXIS(Z);
- }
- else {
- LCD_MESSAGEPGM(MSG_ZPROBE_OUT);
- SERIAL_ECHO_START;
- SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT);
- }
-
- #if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING");
- }
- #endif
-
- #else // !Z_SAFE_HOMING
-
+ home_z_safely();
+ #else
HOMEAXIS(Z);
-
- #endif // !Z_SAFE_HOMING
-
+ #endif
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) DEBUG_POS("> (home_all_axis || homeZ) > final", current_position);
#endif
-
} // home_all_axis || homeZ
-
#endif // Z_HOME_DIR < 0
SYNC_PLAN_POSITION_KINEMATIC();
@@ -3533,7 +3301,7 @@ inline void gcode_G28() {
#if ENABLED(AUTO_BED_LEVELING_GRID)
- #if DISABLED(DELTA)
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
bool do_topography_map = verbose_level > 2 || code_seen('T');
#endif
@@ -3544,7 +3312,7 @@ inline void gcode_G28() {
int auto_bed_leveling_grid_points = AUTO_BED_LEVELING_GRID_POINTS;
- #if DISABLED(DELTA)
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
if (code_seen('P')) auto_bed_leveling_grid_points = code_value_int();
if (auto_bed_leveling_grid_points < 2) {
SERIAL_PROTOCOLLNPGM("?Number of probed (P)oints is implausible (2 minimum).");
@@ -3596,22 +3364,18 @@ inline void gcode_G28() {
// Reset the bed_level_matrix because leveling
// needs to be done without leveling enabled.
- planner.bed_level_matrix.set_to_identity();
+ reset_bed_level();
//
// Re-orient the current position without leveling
// based on where the steppers are positioned.
//
- #if ENABLED(DELTA) || ENABLED(SCARA)
-
- #if ENABLED(DELTA)
- reset_bed_level();
- #endif
+ #if IS_KINEMATIC
// For DELTA/SCARA we need to apply forward kinematics.
// This returns raw positions and we remap to the space.
- set_cartesian_from_steppers();
- LOOP_XYZ(i) current_position[i] = LOGICAL_POSITION(cartesian_position[i], i);
+ get_cartesian_from_steppers();
+ LOOP_XYZ(i) current_position[i] = LOGICAL_POSITION(cartes[i], i);
#else
@@ -3639,12 +3403,15 @@ inline void gcode_G28() {
const float xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (auto_bed_leveling_grid_points - 1),
yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (auto_bed_leveling_grid_points - 1);
- #if ENABLED(DELTA)
- delta_grid_spacing[X_AXIS] = xGridSpacing;
- delta_grid_spacing[Y_AXIS] = yGridSpacing;
+ #if ENABLED(AUTO_BED_LEVELING_NONLINEAR)
+
+ nonlinear_grid_spacing[X_AXIS] = xGridSpacing;
+ nonlinear_grid_spacing[Y_AXIS] = yGridSpacing;
float zoffset = zprobe_zoffset;
if (code_seen('Z')) zoffset += code_value_axis_units(Z_AXIS);
- #else // !DELTA
+
+ #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
+
/**
* solve the plane equation ax + by + d = z
* A is the matrix with rows [x y 1] for all the probed points
@@ -3660,15 +3427,16 @@ inline void gcode_G28() {
eqnBVector[abl2], // "B" vector of Z points
mean = 0.0;
int8_t indexIntoAB[auto_bed_leveling_grid_points][auto_bed_leveling_grid_points];
- #endif // !DELTA
+
+ #endif // AUTO_BED_LEVELING_LINEAR
int probePointCounter = 0;
- bool zig = auto_bed_leveling_grid_points & 1; //always end at [RIGHT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION]
+ uint8_t zig = auto_bed_leveling_grid_points & 1; //always end at [RIGHT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION]
- for (int yCount = 0; yCount < auto_bed_leveling_grid_points; yCount++) {
+ for (uint8_t yCount = 0; yCount < auto_bed_leveling_grid_points; yCount++) {
float yBase = front_probe_bed_position + yGridSpacing * yCount,
yProbe = floor(yBase + (yBase < 0 ? 0 : 0.5));
- int xStart, xStop, xInc;
+ int8_t xStart, xStop, xInc;
if (zig) {
xStart = 0;
@@ -3683,7 +3451,7 @@ inline void gcode_G28() {
zig = !zig;
- for (int xCount = xStart; xCount != xStop; xCount += xInc) {
+ for (uint8_t xCount = xStart; xCount != xStop; xCount += xInc) {
float xBase = left_probe_bed_position + xGridSpacing * xCount,
xProbe = floor(xBase + (xBase < 0 ? 0 : 0.5));
@@ -3694,16 +3462,19 @@ inline void gcode_G28() {
float measured_z = probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
- #if DISABLED(DELTA)
- mean += measured_z;
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
+ mean += measured_z;
eqnBVector[probePointCounter] = measured_z;
eqnAMatrix[probePointCounter + 0 * abl2] = xProbe;
eqnAMatrix[probePointCounter + 1 * abl2] = yProbe;
eqnAMatrix[probePointCounter + 2 * abl2] = 1;
indexIntoAB[xCount][yCount] = probePointCounter;
- #else
- bed_level[xCount][yCount] = measured_z + zoffset;
+
+ #elif ENABLED(AUTO_BED_LEVELING_NONLINEAR)
+
+ bed_level_grid[xCount][yCount] = measured_z + zoffset;
+
#endif
probePointCounter++;
@@ -3713,30 +3484,28 @@ inline void gcode_G28() {
} //xProbe
} //yProbe
- #else // !AUTO_BED_LEVELING_GRID
+ #elif ENABLED(AUTO_BED_LEVELING_3POINT)
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
#endif
// Probe at 3 arbitrary points
- float z_at_pt_1 = probe_pt( LOGICAL_X_POSITION(ABL_PROBE_PT_1_X),
- LOGICAL_Y_POSITION(ABL_PROBE_PT_1_Y),
- stow_probe_after_each, verbose_level),
- z_at_pt_2 = probe_pt( LOGICAL_X_POSITION(ABL_PROBE_PT_2_X),
- LOGICAL_Y_POSITION(ABL_PROBE_PT_2_Y),
- stow_probe_after_each, verbose_level),
- z_at_pt_3 = probe_pt( LOGICAL_X_POSITION(ABL_PROBE_PT_3_X),
- LOGICAL_Y_POSITION(ABL_PROBE_PT_3_Y),
- stow_probe_after_each, verbose_level);
-
- if (!dryrun) {
- vector_3 pt1 = vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, z_at_pt_1),
- pt2 = vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, z_at_pt_2),
- pt3 = vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, z_at_pt_3);
+ vector_3 points[3] = {
+ vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, 0),
+ vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, 0),
+ vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, 0)
+ };
- vector_3 planeNormal = vector_3::cross(pt1 - pt2, pt3 - pt2).get_normal();
+ for (uint8_t i = 0; i < 3; ++i)
+ points[i].z = probe_pt(
+ LOGICAL_X_POSITION(points[i].x),
+ LOGICAL_Y_POSITION(points[i].y),
+ stow_probe_after_each, verbose_level
+ );
+ if (!dryrun) {
+ vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
if (planeNormal.z < 0) {
planeNormal.x *= -1;
planeNormal.y *= -1;
@@ -3745,7 +3514,7 @@ inline void gcode_G28() {
planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
}
- #endif // !AUTO_BED_LEVELING_GRID
+ #endif // AUTO_BED_LEVELING_3POINT
// Raise to _Z_PROBE_DEPLOY_HEIGHT. Stow the probe.
if (STOW_PROBE()) return;
@@ -3758,74 +3527,96 @@ inline void gcode_G28() {
#endif
// Calculate leveling, print reports, correct the position
- #if ENABLED(AUTO_BED_LEVELING_GRID)
- #if ENABLED(DELTA)
+ #if ENABLED(AUTO_BED_LEVELING_NONLINEAR)
- if (!dryrun) extrapolate_unprobed_bed_level();
- print_bed_level();
+ if (!dryrun) extrapolate_unprobed_bed_level();
+ print_bed_level();
- #else // !DELTA
+ #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
- // solve lsq problem
- double plane_equation_coefficients[3];
- qr_solve(plane_equation_coefficients, abl2, 3, eqnAMatrix, eqnBVector);
+ // solve lsq problem
+ double plane_equation_coefficients[3];
+ qr_solve(plane_equation_coefficients, abl2, 3, eqnAMatrix, eqnBVector);
- mean /= abl2;
+ mean /= abl2;
- if (verbose_level) {
- SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[0], 8);
- SERIAL_PROTOCOLPGM(" b: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[1], 8);
- SERIAL_PROTOCOLPGM(" d: ");
- SERIAL_PROTOCOL_F(plane_equation_coefficients[2], 8);
+ if (verbose_level) {
+ SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
+ SERIAL_PROTOCOL_F(plane_equation_coefficients[0], 8);
+ SERIAL_PROTOCOLPGM(" b: ");
+ SERIAL_PROTOCOL_F(plane_equation_coefficients[1], 8);
+ SERIAL_PROTOCOLPGM(" d: ");
+ SERIAL_PROTOCOL_F(plane_equation_coefficients[2], 8);
+ SERIAL_EOL;
+ if (verbose_level > 2) {
+ SERIAL_PROTOCOLPGM("Mean of sampled points: ");
+ SERIAL_PROTOCOL_F(mean, 8);
SERIAL_EOL;
- if (verbose_level > 2) {
- SERIAL_PROTOCOLPGM("Mean of sampled points: ");
- SERIAL_PROTOCOL_F(mean, 8);
- SERIAL_EOL;
- }
- }
-
- // Create the matrix but don't correct the position yet
- if (!dryrun) {
- planner.bed_level_matrix = matrix_3x3::create_look_at(
- vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1)
- );
}
+ }
- // Show the Topography map if enabled
- if (do_topography_map) {
+ // Create the matrix but don't correct the position yet
+ if (!dryrun) {
+ planner.bed_level_matrix = matrix_3x3::create_look_at(
+ vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1)
+ );
+ }
- SERIAL_PROTOCOLLNPGM("\nBed Height Topography:\n"
- " +--- BACK --+\n"
- " | |\n"
- " L | (+) | R\n"
- " E | | I\n"
- " F | (-) N (+) | G\n"
- " T | | H\n"
- " | (-) | T\n"
- " | |\n"
- " O-- FRONT --+\n"
- " (0,0)");
+ // Show the Topography map if enabled
+ if (do_topography_map) {
+
+ SERIAL_PROTOCOLLNPGM("\nBed Height Topography:\n"
+ " +--- BACK --+\n"
+ " | |\n"
+ " L | (+) | R\n"
+ " E | | I\n"
+ " F | (-) N (+) | G\n"
+ " T | | H\n"
+ " | (-) | T\n"
+ " | |\n"
+ " O-- FRONT --+\n"
+ " (0,0)");
+
+ float min_diff = 999;
+
+ for (int8_t yy = auto_bed_leveling_grid_points - 1; yy >= 0; yy--) {
+ for (uint8_t xx = 0; xx < auto_bed_leveling_grid_points; xx++) {
+ int ind = indexIntoAB[xx][yy];
+ float diff = eqnBVector[ind] - mean,
+ x_tmp = eqnAMatrix[ind + 0 * abl2],
+ y_tmp = eqnAMatrix[ind + 1 * abl2],
+ z_tmp = 0;
+
+ apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
+
+ NOMORE(min_diff, eqnBVector[ind] - z_tmp);
+
+ if (diff >= 0.0)
+ SERIAL_PROTOCOLPGM(" +"); // Include + for column alignment
+ else
+ SERIAL_PROTOCOLCHAR(' ');
+ SERIAL_PROTOCOL_F(diff, 5);
+ } // xx
+ SERIAL_EOL;
+ } // yy
+ SERIAL_EOL;
- float min_diff = 999;
+ if (verbose_level > 3) {
+ SERIAL_PROTOCOLLNPGM("\nCorrected Bed Height vs. Bed Topology:");
for (int yy = auto_bed_leveling_grid_points - 1; yy >= 0; yy--) {
for (int xx = 0; xx < auto_bed_leveling_grid_points; xx++) {
int ind = indexIntoAB[xx][yy];
- float diff = eqnBVector[ind] - mean;
-
float x_tmp = eqnAMatrix[ind + 0 * abl2],
y_tmp = eqnAMatrix[ind + 1 * abl2],
z_tmp = 0;
apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
- NOMORE(min_diff, eqnBVector[ind] - z_tmp);
-
+ float diff = eqnBVector[ind] - z_tmp - min_diff;
if (diff >= 0.0)
- SERIAL_PROTOCOLPGM(" +"); // Include + for column alignment
+ SERIAL_PROTOCOLPGM(" +");
+ // Include + for column alignment
else
SERIAL_PROTOCOLCHAR(' ');
SERIAL_PROTOCOL_F(diff, 5);
@@ -3833,38 +3624,8 @@ inline void gcode_G28() {
SERIAL_EOL;
} // yy
SERIAL_EOL;
-
- if (verbose_level > 3) {
- SERIAL_PROTOCOLLNPGM("\nCorrected Bed Height vs. Bed Topology:");
-
- for (int yy = auto_bed_leveling_grid_points - 1; yy >= 0; yy--) {
- for (int xx = 0; xx < auto_bed_leveling_grid_points; xx++) {
- int ind = indexIntoAB[xx][yy];
- float x_tmp = eqnAMatrix[ind + 0 * abl2],
- y_tmp = eqnAMatrix[ind + 1 * abl2],
- z_tmp = 0;
-
- apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
-
- float diff = eqnBVector[ind] - z_tmp - min_diff;
- if (diff >= 0.0)
- SERIAL_PROTOCOLPGM(" +");
- // Include + for column alignment
- else
- SERIAL_PROTOCOLCHAR(' ');
- SERIAL_PROTOCOL_F(diff, 5);
- } // xx
- SERIAL_EOL;
- } // yy
- SERIAL_EOL;
- }
- } //do_topography_map
-
- #endif //!DELTA
-
- #endif // AUTO_BED_LEVELING_GRID
-
- #if DISABLED(DELTA)
+ }
+ } //do_topography_map
if (verbose_level > 0)
planner.bed_level_matrix.debug("\n\nBed Level Correction Matrix:");
@@ -3913,14 +3674,11 @@ inline void gcode_G28() {
#endif
}
- #endif // !DELTA
+ #endif // AUTO_BED_LEVELING_LINEAR
#ifdef Z_PROBE_END_SCRIPT
#if ENABLED(DEBUG_LEVELING_FEATURE)
- if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPGM("Z Probe End Script: ");
- SERIAL_ECHOLNPGM(Z_PROBE_END_SCRIPT);
- }
+ if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("Z Probe End Script: ", Z_PROBE_END_SCRIPT);
#endif
enqueue_and_echo_commands_P(PSTR(Z_PROBE_END_SCRIPT));
stepper.synchronize();
@@ -3937,7 +3695,7 @@ inline void gcode_G28() {
KEEPALIVE_STATE(IN_HANDLER);
}
-#endif //AUTO_BED_LEVELING_FEATURE
+#endif // AUTO_BED_LEVELING_FEATURE
#if HAS_BED_PROBE
@@ -3946,6 +3704,10 @@ inline void gcode_G28() {
*/
inline void gcode_G30() {
+ #if ENABLED(AUTO_BED_LEVELING_FEATURE)
+ reset_bed_level();
+ #endif
+
setup_for_endstop_or_probe_move();
// TODO: clear the leveling matrix or the planner will be set incorrectly
@@ -4011,7 +3773,7 @@ inline void gcode_G92() {
sync_plan_position_e();
}
-#if ENABLED(ULTIPANEL)
+#if ENABLED(ULTIPANEL) || ENABLED(EMERGENCY_PARSER)
/**
* M0: Unconditional stop - Wait for user button press on LCD
@@ -4031,38 +3793,68 @@ inline void gcode_G92() {
hasS = codenum > 0;
}
- if (!hasP && !hasS && *args != '\0')
- lcd_setstatus(args, true);
- else {
- LCD_MESSAGEPGM(MSG_USERWAIT);
- #if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
- dontExpireStatus();
- #endif
- }
+ #if ENABLED(ULTIPANEL)
+
+ if (!hasP && !hasS && *args != '\0')
+ lcd_setstatus(args, true);
+ else {
+ LCD_MESSAGEPGM(MSG_USERWAIT);
+ #if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
+ dontExpireStatus();
+ #endif
+ }
+ lcd_ignore_click();
+
+ #else
+
+ if (!hasP && !hasS && *args != '\0') {
+ SERIAL_ECHO_START;
+ SERIAL_ECHOLN(args);
+ }
+
+ #endif
- lcd_ignore_click();
stepper.synchronize();
refresh_cmd_timeout();
- if (codenum > 0) {
- codenum += previous_cmd_ms; // wait until this time for a click
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- while (PENDING(millis(), codenum) && !lcd_clicked()) idle();
- KEEPALIVE_STATE(IN_HANDLER);
- lcd_ignore_click(false);
- }
- else {
- if (!lcd_detected()) return;
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- while (!lcd_clicked()) idle();
- KEEPALIVE_STATE(IN_HANDLER);
- }
- if (IS_SD_PRINTING)
- LCD_MESSAGEPGM(MSG_RESUMING);
- else
- LCD_MESSAGEPGM(WELCOME_MSG);
- }
-#endif // ULTIPANEL
+ #if ENABLED(ULTIPANEL)
+
+ if (codenum > 0) {
+ codenum += previous_cmd_ms; // wait until this time for a click
+ KEEPALIVE_STATE(PAUSED_FOR_USER);
+ while (PENDING(millis(), codenum) && !lcd_clicked()) idle();
+ lcd_ignore_click(false);
+ }
+ else if (lcd_detected()) {
+ KEEPALIVE_STATE(PAUSED_FOR_USER);
+ while (!lcd_clicked()) idle();
+ }
+ else return;
+
+ if (IS_SD_PRINTING)
+ LCD_MESSAGEPGM(MSG_RESUMING);
+ else
+ LCD_MESSAGEPGM(WELCOME_MSG);
+
+ #else
+
+ KEEPALIVE_STATE(PAUSED_FOR_USER);
+ wait_for_user = true;
+
+ if (codenum > 0) {
+ codenum += previous_cmd_ms; // wait until this time for an M108
+ while (PENDING(millis(), codenum) && wait_for_user) idle();
+ }
+ else while (wait_for_user) idle();
+
+ wait_for_user = false;
+
+ #endif
+
+ KEEPALIVE_STATE(IN_HANDLER);
+ }
+
+#endif // ULTIPANEL || EMERGENCY_PARSER
/**
* M17: Enable power on all stepper motors
@@ -4086,23 +3878,17 @@ inline void gcode_M17() {
/**
* M21: Init SD Card
*/
- inline void gcode_M21() {
- card.initsd();
- }
+ inline void gcode_M21() { card.initsd(); }
/**
* M22: Release SD Card
*/
- inline void gcode_M22() {
- card.release();
- }
+ inline void gcode_M22() { card.release(); }
/**
* M23: Open a file
*/
- inline void gcode_M23() {
- card.openFile(current_command_args, true);
- }
+ inline void gcode_M23() { card.openFile(current_command_args, true); }
/**
* M24: Start SD Print
@@ -4115,9 +3901,7 @@ inline void gcode_M17() {
/**
* M25: Pause SD Print
*/
- inline void gcode_M25() {
- card.pauseSDPrint();
- }
+ inline void gcode_M25() { card.pauseSDPrint(); }
/**
* M26: Set SD Card file index
@@ -4130,16 +3914,12 @@ inline void gcode_M17() {
/**
* M27: Get SD Card status
*/
- inline void gcode_M27() {
- card.getStatus();
- }
+ inline void gcode_M27() { card.getStatus(); }
/**
* M28: Start SD Write
*/
- inline void gcode_M28() {
- card.openFile(current_command_args, false);
- }
+ inline void gcode_M28() { card.openFile(current_command_args, false); }
/**
* M29: Stop SD Write
@@ -4159,7 +3939,7 @@ inline void gcode_M17() {
}
}
-#endif //SDSUPPORT
+#endif // SDSUPPORT
/**
* M31: Get the time since the start of SD Print (or last M109)
@@ -4172,8 +3952,7 @@ inline void gcode_M31() {
lcd_setstatus(buffer);
SERIAL_ECHO_START;
- SERIAL_ECHOPGM("Print time: ");
- SERIAL_ECHOLN(buffer);
+ SERIAL_ECHOLNPAIR("Print time: ", buffer);
thermalManager.autotempShutdown();
}
@@ -4358,12 +4137,9 @@ inline void gcode_M42() {
if (verbose_level > 2)
SERIAL_PROTOCOLLNPGM("Positioning the probe...");
- #if ENABLED(DELTA)
- // we don't do bed level correction in M48 because we want the raw data when we probe
+ // we don't do bed level correction in M48 because we want the raw data when we probe
+ #if ENABLED(AUTO_BED_LEVELING_FEATURE)
reset_bed_level();
- #elif ENABLED(AUTO_BED_LEVELING_FEATURE)
- // we don't do bed level correction in M48 because we want the raw data when we probe
- planner.bed_level_matrix.set_to_identity();
#endif
setup_for_endstop_or_probe_move();
@@ -4522,7 +4298,8 @@ inline void gcode_M77() { print_job_timer.stop(); }
// "M78 S78" will reset the statistics
if (code_seen('S') && code_value_int() == 78)
print_job_timer.initStats();
- else print_job_timer.showStats();
+ else
+ print_job_timer.showStats();
}
#endif
@@ -5089,7 +4866,7 @@ inline void gcode_M140() {
}
}
-#endif
+#endif // ULTIPANEL
#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
/**
@@ -5163,7 +4940,6 @@ inline void gcode_M81() {
#endif
}
-
/**
* M82: Set E codes absolute (default)
*/
@@ -5250,7 +5026,7 @@ static void report_current_position() {
stepper.report_positions();
- #if ENABLED(SCARA)
+ #if IS_SCARA
SERIAL_PROTOCOLPGM("SCARA Theta:");
SERIAL_PROTOCOL(delta[X_AXIS]);
SERIAL_PROTOCOLPGM(" Psi+Theta:");
@@ -5488,7 +5264,7 @@ inline void gcode_M206() {
if (code_seen(axis_codes[i]))
set_home_offset((AxisEnum)i, code_value_axis_units(i));
- #if ENABLED(SCARA)
+ #if IS_SCARA
if (code_seen('T')) set_home_offset(X_AXIS, code_value_axis_units(X_AXIS)); // Theta
if (code_seen('P')) set_home_offset(Y_AXIS, code_value_axis_units(Y_AXIS)); // Psi
#endif
@@ -5531,8 +5307,7 @@ inline void gcode_M206() {
endstop_adj[i] = code_value_axis_units(i);
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) {
- SERIAL_ECHOPGM("endstop_adj[");
- SERIAL_ECHO(axis_codes[i]);
+ SERIAL_ECHOPAIR("endstop_adj[", axis_codes[i]);
SERIAL_ECHOLNPAIR("] = ", endstop_adj[i]);
}
#endif
@@ -5615,16 +5390,17 @@ inline void gcode_M211() {
if (code_seen('S')) soft_endstops_enabled = code_value_bool();
#endif
#if ENABLED(min_software_endstops) || ENABLED(max_software_endstops)
- SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS ": ");
+ SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS);
serialprintPGM(soft_endstops_enabled ? PSTR(MSG_ON) : PSTR(MSG_OFF));
#else
- SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS ": " MSG_OFF);
+ SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS);
+ SERIAL_ECHOPGM(MSG_OFF);
#endif
- SERIAL_ECHOPGM(" " MSG_SOFT_MIN ": ");
+ SERIAL_ECHOPGM(MSG_SOFT_MIN);
SERIAL_ECHOPAIR( MSG_X, soft_endstop_min[X_AXIS]);
SERIAL_ECHOPAIR(" " MSG_Y, soft_endstop_min[Y_AXIS]);
SERIAL_ECHOPAIR(" " MSG_Z, soft_endstop_min[Z_AXIS]);
- SERIAL_ECHOPGM(" " MSG_SOFT_MAX ": ");
+ SERIAL_ECHOPGM(MSG_SOFT_MAX);
SERIAL_ECHOPAIR( MSG_X, soft_endstop_max[X_AXIS]);
SERIAL_ECHOPAIR(" " MSG_Y, soft_endstop_max[Y_AXIS]);
SERIAL_ECHOLNPAIR(" " MSG_Z, soft_endstop_max[Z_AXIS]);
@@ -5689,7 +5465,6 @@ inline void gcode_M221() {
inline void gcode_M226() {
if (code_seen('P')) {
int pin_number = code_value_int();
-
int pin_state = code_seen('S') ? code_value_int() : -1; // required pin state - default is inverted
if (pin_state >= -1 && pin_state <= 1) {
@@ -5742,17 +5517,14 @@ inline void gcode_M226() {
MOVE_SERVO(servo_index, code_value_int());
else {
SERIAL_ECHO_START;
- SERIAL_ECHOPGM(" Servo ");
- SERIAL_ECHO(servo_index);
- SERIAL_ECHOPGM(": ");
- SERIAL_ECHOLN(servo[servo_index].read());
+ SERIAL_ECHOPAIR(" Servo ", servo_index);
+ SERIAL_ECHOLNPAIR(": ", servo[servo_index].read());
}
}
else {
SERIAL_ERROR_START;
- SERIAL_ERROR("Servo ");
- SERIAL_ERROR(servo_index);
- SERIAL_ERRORLN(" out of range");
+ SERIAL_ECHOPAIR("Servo ", servo_index);
+ SERIAL_ECHOLNPGM(" out of range");
}
}
@@ -5808,19 +5580,14 @@ inline void gcode_M226() {
thermalManager.updatePID();
SERIAL_ECHO_START;
#if ENABLED(PID_PARAMS_PER_HOTEND)
- SERIAL_ECHOPGM(" e:"); // specify extruder in serial output
- SERIAL_ECHO(e);
+ SERIAL_ECHOPAIR(" e:", e); // specify extruder in serial output
#endif // PID_PARAMS_PER_HOTEND
- SERIAL_ECHOPGM(" p:");
- SERIAL_ECHO(PID_PARAM(Kp, e));
- SERIAL_ECHOPGM(" i:");
- SERIAL_ECHO(unscalePID_i(PID_PARAM(Ki, e)));
- SERIAL_ECHOPGM(" d:");
- SERIAL_ECHO(unscalePID_d(PID_PARAM(Kd, e)));
+ SERIAL_ECHOPAIR(" p:", PID_PARAM(Kp, e));
+ SERIAL_ECHOPAIR(" i:", unscalePID_i(PID_PARAM(Ki, e)));
+ SERIAL_ECHOPAIR(" d:", unscalePID_d(PID_PARAM(Kd, e)));
#if ENABLED(PID_EXTRUSION_SCALING)
- SERIAL_ECHOPGM(" c:");
//Kc does not have scaling applied above, or in resetting defaults
- SERIAL_ECHO(PID_PARAM(Kc, e));
+ SERIAL_ECHOPAIR(" c:", PID_PARAM(Kc, e));
#endif
SERIAL_EOL;
}
@@ -5842,12 +5609,9 @@ inline void gcode_M226() {
thermalManager.updatePID();
SERIAL_ECHO_START;
- SERIAL_ECHOPGM(" p:");
- SERIAL_ECHO(thermalManager.bedKp);
- SERIAL_ECHOPGM(" i:");
- SERIAL_ECHO(unscalePID_i(thermalManager.bedKi));
- SERIAL_ECHOPGM(" d:");
- SERIAL_ECHOLN(unscalePID_d(thermalManager.bedKd));
+ SERIAL_ECHOPAIR(" p:", thermalManager.bedKp);
+ SERIAL_ECHOPAIR(" i:", unscalePID_i(thermalManager.bedKi));
+ SERIAL_ECHOLNPAIR(" d:", unscalePID_d(thermalManager.bedKd));
}
#endif // PIDTEMPBED
@@ -5969,17 +5733,16 @@ inline void gcode_M303() {
#endif
}
-#if ENABLED(SCARA)
- bool SCARA_move_to_cal(uint8_t delta_x, uint8_t delta_y) {
+#if ENABLED(MORGAN_SCARA)
+ bool SCARA_move_to_cal(uint8_t delta_a, uint8_t delta_b) {
//SoftEndsEnabled = false; // Ignore soft endstops during calibration
//SERIAL_ECHOLNPGM(" Soft endstops disabled");
if (IsRunning()) {
//gcode_get_destination(); // For X Y Z E F
- delta[X_AXIS] = delta_x;
- delta[Y_AXIS] = delta_y;
- forward_kinematics_SCARA(delta);
- destination[X_AXIS] = delta[X_AXIS] / axis_scaling[X_AXIS];
- destination[Y_AXIS] = delta[Y_AXIS] / axis_scaling[Y_AXIS];
+ forward_kinematics_SCARA(delta_a, delta_b);
+ destination[X_AXIS] = cartes[X_AXIS] / axis_scaling[X_AXIS];
+ destination[Y_AXIS] = cartes[Y_AXIS] / axis_scaling[Y_AXIS];
+ destination[Z_AXIS] = current_position[Z_AXIS];
prepare_move_to_destination();
//ok_to_send();
return true;
@@ -6312,11 +6075,9 @@ inline void gcode_M503() {
SERIAL_ECHO(zprobe_zoffset);
}
else {
- SERIAL_ECHOPGM(MSG_Z_MIN);
- SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MIN);
+ SERIAL_ECHOPAIR(MSG_Z_MIN, Z_PROBE_OFFSET_RANGE_MIN);
SERIAL_CHAR(' ');
- SERIAL_ECHOPGM(MSG_Z_MAX);
- SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MAX);
+ SERIAL_ECHOPAIR(MSG_Z_MAX, Z_PROBE_OFFSET_RANGE_MAX);
}
}
else {
@@ -6361,7 +6122,7 @@ inline void gcode_M503() {
lastpos[i] = destination[i] = current_position[i];
// Define runplan for move axes
- #if ENABLED(DELTA)
+ #if IS_KINEMATIC
#define RUNPLAN(RATE_MM_S) inverse_kinematics(destination); \
planner.buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], RATE_MM_S, active_extruder);
#else
@@ -6482,7 +6243,7 @@ inline void gcode_M503() {
destination[E_AXIS] = lastpos[E_AXIS];
planner.set_e_position_mm(current_position[E_AXIS]);
- #if ENABLED(DELTA)
+ #if IS_KINEMATIC
// Move XYZ to starting position, then E
inverse_kinematics(lastpos);
planner.buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], FILAMENT_CHANGE_XY_FEEDRATE, active_extruder);
@@ -6754,6 +6515,10 @@ inline void invalid_extruder_error(const uint8_t &e) {
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
}
+/**
+ * Perform a tool-change, which may result in moving the
+ * previous tool out of the way and the new tool into place.
+ */
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
#if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
@@ -6925,7 +6690,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
* Z software endstop. But this is technically correct (and
* there is no viable alternative).
*/
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
// Offset extruder, make sure to apply the bed level rotation matrix
vector_3 tmp_offset_vec = vector_3(hotend_offset[X_AXIS][tmp_extruder],
hotend_offset[Y_AXIS][tmp_extruder],
@@ -7037,8 +6802,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
#endif // HOTENDS <= 1
SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER);
- SERIAL_PROTOCOLLN((int)active_extruder);
+ SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, (int)active_extruder);
#endif //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
}
@@ -7617,7 +7381,7 @@ void process_next_command() {
gcode_M303();
break;
- #if ENABLED(SCARA)
+ #if ENABLED(MORGAN_SCARA)
case 360: // M360 SCARA Theta pos1
if (gcode_M360()) return;
break;
@@ -7781,6 +7545,10 @@ ExitUnknownCommand:
ok_to_send();
}
+/**
+ * Send a "Resend: nnn" message to the host to
+ * indicate that a command needs to be re-sent.
+ */
void FlushSerialRequestResend() {
//char command_queue[cmd_queue_index_r][100]="Resend:";
MYSERIAL.flush();
@@ -7789,6 +7557,15 @@ void FlushSerialRequestResend() {
ok_to_send();
}
+/**
+ * Send an "ok" message to the host, indicating
+ * that a command was successfully processed.
+ *
+ * If ADVANCED_OK is enabled also include:
+ * N<int> Line number of the command, if any
+ * P<int> Planner space remaining
+ * B<int> Block queue space remaining
+ */
void ok_to_send() {
refresh_cmd_timeout();
if (!send_ok[cmd_queue_index_r]) return;
@@ -7809,6 +7586,9 @@ void ok_to_send() {
#if ENABLED(min_software_endstops) || ENABLED(max_software_endstops)
+ /**
+ * Constrain the given coordinates to the software endstops.
+ */
void clamp_to_software_endstops(float target[XYZ]) {
#if ENABLED(min_software_endstops)
NOLESS(target[X_AXIS], soft_endstop_min[X_AXIS]);
@@ -7826,6 +7606,10 @@ void ok_to_send() {
#if ENABLED(DELTA)
+ /**
+ * 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_tower1_x = -SIN_60 * (radius + DELTA_RADIUS_TRIM_TOWER_1); // front left tower
delta_tower1_y = -COS_60 * (radius + DELTA_RADIUS_TRIM_TOWER_1);
@@ -7838,37 +7622,85 @@ void ok_to_send() {
delta_diagonal_rod_2_tower_3 = sq(diagonal_rod + delta_diagonal_rod_trim_tower_3);
}
- void inverse_kinematics(const float in_cartesian[XYZ]) {
+ #if ENABLED(DELTA_FAST_SQRT)
+ /**
+ * 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;
+ }
+
+ #define _SQRT(n) (1.0f / Q_rsqrt(n))
+
+ #else
+
+ #define _SQRT(n) sqrt(n)
+
+ #endif
+
+ /**
+ * 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)
+ */
+ void inverse_kinematics(const float logical[XYZ]) {
const float cartesian[XYZ] = {
- RAW_X_POSITION(in_cartesian[X_AXIS]),
- RAW_Y_POSITION(in_cartesian[Y_AXIS]),
- RAW_Z_POSITION(in_cartesian[Z_AXIS])
+ RAW_X_POSITION(logical[X_AXIS]),
+ RAW_Y_POSITION(logical[Y_AXIS]),
+ RAW_Z_POSITION(logical[Z_AXIS])
};
- delta[A_AXIS] = sqrt(delta_diagonal_rod_2_tower_1
- - sq(delta_tower1_x - cartesian[X_AXIS])
- - sq(delta_tower1_y - cartesian[Y_AXIS])
- ) + cartesian[Z_AXIS];
- delta[B_AXIS] = sqrt(delta_diagonal_rod_2_tower_2
- - sq(delta_tower2_x - cartesian[X_AXIS])
- - sq(delta_tower2_y - cartesian[Y_AXIS])
- ) + cartesian[Z_AXIS];
- delta[C_AXIS] = sqrt(delta_diagonal_rod_2_tower_3
- - sq(delta_tower3_x - cartesian[X_AXIS])
- - sq(delta_tower3_y - cartesian[Y_AXIS])
- ) + cartesian[Z_AXIS];
- /**
- SERIAL_ECHOPGM("cartesian x="); SERIAL_ECHO(cartesian[X_AXIS]);
- SERIAL_ECHOPGM(" y="); SERIAL_ECHO(cartesian[Y_AXIS]);
- SERIAL_ECHOPGM(" z="); SERIAL_ECHOLN(cartesian[Z_AXIS]);
+ // Macro to obtain the Z position of an individual tower
+ #define DELTA_Z(T) cartesian[Z_AXIS] + _SQRT( \
+ delta_diagonal_rod_2_tower_##T - HYPOT2( \
+ delta_tower##T##_x - cartesian[X_AXIS], \
+ delta_tower##T##_y - cartesian[Y_AXIS] \
+ ) \
+ )
- SERIAL_ECHOPGM("delta a="); SERIAL_ECHO(delta[A_AXIS]);
- SERIAL_ECHOPGM(" b="); SERIAL_ECHO(delta[B_AXIS]);
- SERIAL_ECHOPGM(" c="); SERIAL_ECHOLN(delta[C_AXIS]);
- */
+ delta[A_AXIS] = DELTA_Z(1);
+ delta[B_AXIS] = DELTA_Z(2);
+ delta[C_AXIS] = DELTA_Z(3);
+
+ /*
+ SERIAL_ECHOPAIR("cartesian X:", cartesian[X_AXIS]);
+ SERIAL_ECHOPAIR(" Y:", cartesian[Y_AXIS]);
+ SERIAL_ECHOLNPAIR(" Z:", cartesian[Z_AXIS]);
+ SERIAL_ECHOPAIR("delta A:", delta[A_AXIS]);
+ SERIAL_ECHOPAIR(" B:", delta[B_AXIS]);
+ SERIAL_ECHOLNPAIR(" C:", delta[C_AXIS]);
+ //*/
}
+ /**
+ * 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),
@@ -7882,101 +7714,102 @@ void ok_to_send() {
return abs(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) {
- //As discussed in Wikipedia "Trilateration"
- //we are establishing a new coordinate
- //system in the plane of the three carriage points.
- //This system will have the origin at tower1 and
- //tower2 is 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.
- // https://en.wikipedia.org/wiki/Trilateration
-
- // Variable names matched to Marlin, c-version
- // and avoiding a vector library
- // by Andreas Hardtung 2016-06-7
- // based on a Java function from
- // "Delta Robot Kinematics by Steve Graves" V3
-
- // Result is in cartesian_position[].
-
- //Create a vector in old coordinates along x axis of new coordinate
+ // Create a vector in old coordinates along x axis of new coordinate
float p12[3] = { delta_tower2_x - delta_tower1_x, delta_tower2_y - delta_tower1_y, z2 - z1 };
- //Get the Magnitude of vector.
- float d = sqrt( p12[0]*p12[0] + p12[1]*p12[1] + p12[2]*p12[2] );
+ // 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 };
+ // Create unit vector by dividing by magnitude.
+ float ex[3] = { p12[0] / d, p12[1] / d, p12[2] / d };
- //Now find vector from the origin of the new system to the third point.
+ // Get the vector from the origin of the new system to the third point.
float p13[3] = { delta_tower3_x - delta_tower1_x, delta_tower3_y - delta_tower1_y, z3 - z1 };
- //Now use 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];
+ // 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];
- //Now 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 };
+ // 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 };
- //Now subtract the X component away from the original vector leaving only the Y component. 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]};
+ // 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]));
+ // The magnitude of Y component
+ float j = sqrt( sq(ey[0]) + sq(ey[1]) + sq(ey[2]) );
- //Now make vector a unit vector
+ // 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] };
-
- //Now we have the d, i and j values defined in Wikipedia.
- //We can plug them into the equations defined in
- //Wikipedia for Xnew, Ynew and Znew
- float Xnew = (delta_diagonal_rod_2_tower_1 - delta_diagonal_rod_2_tower_2 + d*d)/(d*2);
- float Ynew = ((delta_diagonal_rod_2_tower_1 - delta_diagonal_rod_2_tower_3 + i*i + j*j)/2 - i*Xnew) /j;
- float Znew = sqrt(delta_diagonal_rod_2_tower_1 - Xnew*Xnew - Ynew*Ynew);
-
- //Now we can start from the origin in the old coords and
- //add vectors in the old coords that represent the
- //Xnew, Ynew and Znew to find the point in the old system
- cartesian_position[X_AXIS] = delta_tower1_x + ex[0]*Xnew + ey[0]*Ynew - ez[0]*Znew;
- cartesian_position[Y_AXIS] = delta_tower1_y + ex[1]*Xnew + ey[1]*Ynew - ez[1]*Znew;
- cartesian_position[Z_AXIS] = z1 + ex[2]*Xnew + ey[2]*Ynew - ez[2]*Znew;
+ // 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_1 - delta_diagonal_rod_2_tower_2 + sq(d)) / (d * 2),
+ Ynew = ((delta_diagonal_rod_2_tower_1 - delta_diagonal_rod_2_tower_3 + HYPOT2(i, j)) / 2 - i * Xnew) / j,
+ Znew = sqrt(delta_diagonal_rod_2_tower_1 - 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_tower1_x + ex[0] * Xnew + ey[0] * Ynew - ez[0] * Znew;
+ cartes[Y_AXIS] = delta_tower1_y + ex[1] * Xnew + ey[1] * Ynew - ez[1] * Znew;
+ cartes[Z_AXIS] = z1 + ex[2] * Xnew + ey[2] * Ynew - ez[2] * Znew;
};
void forward_kinematics_DELTA(float point[ABC]) {
forward_kinematics_DELTA(point[A_AXIS], point[B_AXIS], point[C_AXIS]);
}
- void set_cartesian_from_steppers() {
- forward_kinematics_DELTA(stepper.get_axis_position_mm(A_AXIS),
- stepper.get_axis_position_mm(B_AXIS),
- stepper.get_axis_position_mm(C_AXIS));
- }
-
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(AUTO_BED_LEVELING_NONLINEAR)
// Adjust print surface height by linear interpolation over the bed_level array.
void adjust_delta(float cartesian[XYZ]) {
- if (delta_grid_spacing[X_AXIS] == 0 || delta_grid_spacing[Y_AXIS] == 0) return; // G29 not done!
+ if (nonlinear_grid_spacing[X_AXIS] == 0 || nonlinear_grid_spacing[Y_AXIS] == 0) return; // G29 not done!
int half = (AUTO_BED_LEVELING_GRID_POINTS - 1) / 2;
float h1 = 0.001 - half, h2 = half - 0.001,
- grid_x = max(h1, min(h2, RAW_X_POSITION(cartesian[X_AXIS]) / delta_grid_spacing[X_AXIS])),
- grid_y = max(h1, min(h2, RAW_Y_POSITION(cartesian[Y_AXIS]) / delta_grid_spacing[Y_AXIS]));
+ grid_x = max(h1, min(h2, RAW_X_POSITION(cartesian[X_AXIS]) / nonlinear_grid_spacing[X_AXIS])),
+ grid_y = max(h1, min(h2, RAW_Y_POSITION(cartesian[Y_AXIS]) / nonlinear_grid_spacing[Y_AXIS]));
int floor_x = floor(grid_x), floor_y = floor(grid_y);
float ratio_x = grid_x - floor_x, ratio_y = grid_y - floor_y,
- z1 = bed_level[floor_x + half][floor_y + half],
- z2 = bed_level[floor_x + half][floor_y + half + 1],
- z3 = bed_level[floor_x + half + 1][floor_y + half],
- z4 = bed_level[floor_x + half + 1][floor_y + half + 1],
+ z1 = bed_level_grid[floor_x + half][floor_y + half],
+ z2 = bed_level_grid[floor_x + half][floor_y + half + 1],
+ z3 = bed_level_grid[floor_x + half + 1][floor_y + half],
+ z4 = bed_level_grid[floor_x + half + 1][floor_y + half + 1],
left = (1 - ratio_y) * z1 + ratio_y * z2,
right = (1 - ratio_y) * z3 + ratio_y * z4,
offset = (1 - ratio_x) * left + ratio_x * right;
@@ -7986,32 +7819,68 @@ void ok_to_send() {
delta[Z_AXIS] += offset;
/**
- SERIAL_ECHOPGM("grid_x="); SERIAL_ECHO(grid_x);
- SERIAL_ECHOPGM(" grid_y="); SERIAL_ECHO(grid_y);
- SERIAL_ECHOPGM(" floor_x="); SERIAL_ECHO(floor_x);
- SERIAL_ECHOPGM(" floor_y="); SERIAL_ECHO(floor_y);
- SERIAL_ECHOPGM(" ratio_x="); SERIAL_ECHO(ratio_x);
- SERIAL_ECHOPGM(" ratio_y="); SERIAL_ECHO(ratio_y);
- SERIAL_ECHOPGM(" z1="); SERIAL_ECHO(z1);
- SERIAL_ECHOPGM(" z2="); SERIAL_ECHO(z2);
- SERIAL_ECHOPGM(" z3="); SERIAL_ECHO(z3);
- SERIAL_ECHOPGM(" z4="); SERIAL_ECHO(z4);
- SERIAL_ECHOPGM(" left="); SERIAL_ECHO(left);
- SERIAL_ECHOPGM(" right="); SERIAL_ECHO(right);
- SERIAL_ECHOPGM(" offset="); SERIAL_ECHOLN(offset);
+ SERIAL_ECHOPAIR("grid_x=", grid_x);
+ SERIAL_ECHOPAIR(" grid_y=", grid_y);
+ SERIAL_ECHOPAIR(" floor_x=", floor_x);
+ SERIAL_ECHOPAIR(" floor_y=", floor_y);
+ SERIAL_ECHOPAIR(" ratio_x=", ratio_x);
+ SERIAL_ECHOPAIR(" ratio_y=", ratio_y);
+ SERIAL_ECHOPAIR(" z1=", z1);
+ SERIAL_ECHOPAIR(" z2=", z2);
+ SERIAL_ECHOPAIR(" z3=", z3);
+ SERIAL_ECHOPAIR(" z4=", z4);
+ SERIAL_ECHOPAIR(" left=", left);
+ SERIAL_ECHOPAIR(" right=", right);
+ SERIAL_ECHOLNPAIR(" offset=", offset);
*/
}
- #endif // AUTO_BED_LEVELING_FEATURE
+ #endif // AUTO_BED_LEVELING_NONLINEAR
#endif // DELTA
-void set_current_from_steppers_for_axis(AxisEnum 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)
- set_cartesian_from_steppers();
- current_position[axis] = LOGICAL_POSITION(cartesian_position[axis], axis);
- #elif ENABLED(AUTO_BED_LEVELING_FEATURE)
+ forward_kinematics_DELTA(
+ stepper.get_axis_position_mm(A_AXIS),
+ stepper.get_axis_position_mm(B_AXIS),
+ stepper.get_axis_position_mm(C_AXIS)
+ );
+ #elif IS_SCARA
+ forward_kinematics_SCARA(
+ stepper.get_axis_position_degrees(A_AXIS),
+ stepper.get_axis_position_degrees(B_AXIS)
+ );
+ 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.
+ *
+ * << INCOMPLETE! Still needs to unapply leveling! >>
+ */
+void set_current_from_steppers_for_axis(AxisEnum axis) {
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
vector_3 pos = untilted_stepper_position();
current_position[axis] = axis == X_AXIS ? pos.x : axis == Y_AXIS ? pos.y : pos.z;
+ #elif IS_KINEMATIC
+ get_cartesian_from_steppers();
+ current_position[axis] = LOGICAL_POSITION(cartes[axis], axis);
#else
current_position[axis] = stepper.get_axis_position_mm(axis); // CORE handled transparently
#endif
@@ -8019,65 +7888,75 @@ void set_current_from_steppers_for_axis(AxisEnum axis) {
#if ENABLED(MESH_BED_LEVELING)
-// This function is used to split lines on mesh borders so each segment is only part of one mesh area
-void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_splits = 0xff) {
- int cx1 = mbl.cell_index_x(RAW_CURRENT_POSITION(X_AXIS)),
- cy1 = mbl.cell_index_y(RAW_CURRENT_POSITION(Y_AXIS)),
- cx2 = mbl.cell_index_x(RAW_X_POSITION(destination[X_AXIS])),
- cy2 = mbl.cell_index_y(RAW_Y_POSITION(destination[Y_AXIS]));
- NOMORE(cx1, MESH_NUM_X_POINTS - 2);
- NOMORE(cy1, MESH_NUM_Y_POINTS - 2);
- NOMORE(cx2, MESH_NUM_X_POINTS - 2);
- NOMORE(cy2, MESH_NUM_Y_POINTS - 2);
-
- if (cx1 == cx2 && cy1 == cy2) {
- // Start and end on same mesh square
- line_to_destination(fr_mm_s);
- set_current_to_destination();
- return;
- }
+ /**
+ * Prepare a mesh-leveled linear move in a Cartesian setup,
+ * splitting the move where it crosses mesh borders.
+ */
+ void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_splits = 0xff) {
+ int cx1 = mbl.cell_index_x(RAW_CURRENT_POSITION(X_AXIS)),
+ cy1 = mbl.cell_index_y(RAW_CURRENT_POSITION(Y_AXIS)),
+ cx2 = mbl.cell_index_x(RAW_X_POSITION(destination[X_AXIS])),
+ cy2 = mbl.cell_index_y(RAW_Y_POSITION(destination[Y_AXIS]));
+ NOMORE(cx1, MESH_NUM_X_POINTS - 2);
+ NOMORE(cy1, MESH_NUM_Y_POINTS - 2);
+ NOMORE(cx2, MESH_NUM_X_POINTS - 2);
+ NOMORE(cy2, MESH_NUM_Y_POINTS - 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 MBL_SEGMENT_END(A) (current_position[A ##_AXIS] + (destination[A ##_AXIS] - current_position[A ##_AXIS]) * normalized_dist)
+ #define MBL_SEGMENT_END(A) (current_position[A ##_AXIS] + (destination[A ##_AXIS] - current_position[A ##_AXIS]) * normalized_dist)
- float normalized_dist, end[NUM_AXIS];
+ float normalized_dist, end[NUM_AXIS];
- // Split at the left/front border of the right/top square
- int8_t gcx = max(cx1, cx2), gcy = max(cy1, cy2);
- if (cx2 != cx1 && TEST(x_splits, gcx)) {
- memcpy(end, destination, sizeof(end));
- destination[X_AXIS] = LOGICAL_X_POSITION(mbl.get_probe_x(gcx));
- normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
- destination[Y_AXIS] = MBL_SEGMENT_END(Y);
- CBI(x_splits, gcx);
- }
- else if (cy2 != cy1 && TEST(y_splits, gcy)) {
- memcpy(end, destination, sizeof(end));
- destination[Y_AXIS] = LOGICAL_Y_POSITION(mbl.get_probe_y(gcy));
- normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
- destination[X_AXIS] = MBL_SEGMENT_END(X);
- CBI(y_splits, gcy);
- }
- else {
- // Already split on a border
- line_to_destination(fr_mm_s);
- set_current_to_destination();
- return;
- }
+ // Split at the left/front border of the right/top square
+ int8_t gcx = max(cx1, cx2), gcy = max(cy1, cy2);
+ if (cx2 != cx1 && TEST(x_splits, gcx)) {
+ memcpy(end, destination, sizeof(end));
+ destination[X_AXIS] = LOGICAL_X_POSITION(mbl.get_probe_x(gcx));
+ normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
+ destination[Y_AXIS] = MBL_SEGMENT_END(Y);
+ CBI(x_splits, gcx);
+ }
+ else if (cy2 != cy1 && TEST(y_splits, gcy)) {
+ memcpy(end, destination, sizeof(end));
+ destination[Y_AXIS] = LOGICAL_Y_POSITION(mbl.get_probe_y(gcy));
+ normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
+ destination[X_AXIS] = MBL_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] = MBL_SEGMENT_END(Z);
- destination[E_AXIS] = MBL_SEGMENT_END(E);
+ destination[Z_AXIS] = MBL_SEGMENT_END(Z);
+ destination[E_AXIS] = MBL_SEGMENT_END(E);
- // Do the split and look for more borders
- mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
+ // Do the split and look for more borders
+ mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
+
+ // Restore destination from stack
+ memcpy(destination, end, sizeof(end));
+ mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
+ }
- // Restore destination from stack
- memcpy(destination, end, sizeof(end));
- mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
-}
#endif // MESH_BED_LEVELING
-#if ENABLED(DELTA) || ENABLED(SCARA)
+#if IS_KINEMATIC
+ /**
+ * Prepare a linear move in a DELTA or SCARA setup.
+ *
+ * This calls planner.buffer_line several times, adding
+ * small incremental moves for DELTA or SCARA.
+ */
inline bool prepare_kinematic_move_to(float target[NUM_AXIS]) {
float difference[NUM_AXIS];
LOOP_XYZE(i) difference[i] = target[i] - current_position[i];
@@ -8090,9 +7969,9 @@ void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_
int steps = max(1, int(delta_segments_per_second * seconds));
float inv_steps = 1.0/steps;
- // SERIAL_ECHOPGM("mm="); SERIAL_ECHO(cartesian_mm);
- // SERIAL_ECHOPGM(" seconds="); SERIAL_ECHO(seconds);
- // SERIAL_ECHOPGM(" steps="); SERIAL_ECHOLN(steps);
+ // SERIAL_ECHOPAIR("mm=", cartesian_mm);
+ // SERIAL_ECHOPAIR(" seconds=", seconds);
+ // SERIAL_ECHOLNPAIR(" steps=", steps);
for (int s = 1; s <= steps; s++) {
@@ -8103,7 +7982,7 @@ void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_
inverse_kinematics(target);
- #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_NONLINEAR)
if (!bed_leveling_in_progress) adjust_delta(target);
#endif
@@ -8115,10 +7994,37 @@ void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_
return true;
}
-#endif // DELTA || SCARA
+#else
+
+ /**
+ * Prepare a linear move in a Cartesian setup.
+ * If Mesh Bed Leveling is enabled, perform a mesh move.
+ */
+ inline bool prepare_move_to_destination_cartesian() {
+ // Do not use feedrate_percentage for E or Z only moves
+ if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS]) {
+ line_to_destination();
+ }
+ else {
+ #if ENABLED(MESH_BED_LEVELING)
+ if (mbl.active()) {
+ mesh_line_to_destination(MMS_SCALED(feedrate_mm_s));
+ return false;
+ }
+ else
+ #endif
+ line_to_destination(MMS_SCALED(feedrate_mm_s));
+ }
+ return true;
+ }
+
+#endif // !IS_KINEMATIC
#if ENABLED(DUAL_X_CARRIAGE)
+ /**
+ * Prepare a linear move in a dual X axis setup
+ */
inline bool prepare_move_to_destination_dualx() {
if (active_extruder_parked) {
if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) {
@@ -8161,66 +8067,38 @@ void mesh_line_to_destination(float fr_mm_s, uint8_t x_splits = 0xff, uint8_t y_
#endif // DUAL_X_CARRIAGE
-#if DISABLED(DELTA) && DISABLED(SCARA)
-
- inline bool prepare_move_to_destination_cartesian() {
- // Do not use feedrate_percentage for E or Z only moves
- if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS]) {
- line_to_destination();
- }
- else {
- #if ENABLED(MESH_BED_LEVELING)
- if (mbl.active()) {
- mesh_line_to_destination(MMS_SCALED(feedrate_mm_s));
- return false;
- }
- else
- #endif
- line_to_destination(MMS_SCALED(feedrate_mm_s));
- }
- return true;
- }
-
-#endif // !DELTA && !SCARA
-
-#if ENABLED(PREVENT_COLD_EXTRUSION)
-
- inline void prevent_dangerous_extrude(float& curr_e, float& dest_e) {
- if (DEBUGGING(DRYRUN)) return;
- float de = dest_e - curr_e;
- if (de) {
- if (thermalManager.tooColdToExtrude(active_extruder)) {
- curr_e = dest_e; // Behave as if the move really took place, but ignore E part
- SERIAL_ECHO_START;
- SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
- }
- #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
- if (labs(de) > EXTRUDE_MAXLENGTH) {
- curr_e = dest_e; // Behave as if the move really took place, but ignore E part
- SERIAL_ECHO_START;
- SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
- }
- #endif
- }
- }
-
-#endif // PREVENT_COLD_EXTRUSION
-
/**
* Prepare a single move and get ready for the next one
*
- * (This may call planner.buffer_line several times to put
- * smaller moves into the planner for DELTA or SCARA.)
+ * This may result in several calls to planner.buffer_line to
+ * do smaller moves for DELTA, SCARA, mesh moves, etc.
*/
void prepare_move_to_destination() {
clamp_to_software_endstops(destination);
refresh_cmd_timeout();
#if ENABLED(PREVENT_COLD_EXTRUSION)
- prevent_dangerous_extrude(current_position[E_AXIS], destination[E_AXIS]);
+
+ if (!DEBUGGING(DRYRUN)) {
+ if (destination[E_AXIS] != current_position[E_AXIS]) {
+ if (thermalManager.tooColdToExtrude(active_extruder)) {
+ current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part
+ SERIAL_ECHO_START;
+ SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
+ }
+ #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
+ if (labs(destination[E_AXIS] - current_position[E_AXIS]) > EXTRUDE_MAXLENGTH) {
+ current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part
+ SERIAL_ECHO_START;
+ SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
+ }
+ #endif
+ }
+ }
+
#endif
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
if (!prepare_kinematic_move_to(destination)) return;
#else
#if ENABLED(DUAL_X_CARRIAGE)
@@ -8356,9 +8234,9 @@ void prepare_move_to_destination() {
clamp_to_software_endstops(arc_target);
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
inverse_kinematics(arc_target);
- #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_NONLINEAR)
adjust_delta(arc_target);
#endif
planner.buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], arc_target[E_AXIS], fr_mm_s, active_extruder);
@@ -8368,9 +8246,9 @@ void prepare_move_to_destination() {
}
// Ensure last segment arrives at target location.
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
inverse_kinematics(target);
- #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_NONLINEAR)
adjust_delta(target);
#endif
planner.buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], target[E_AXIS], fr_mm_s, active_extruder);
@@ -8435,32 +8313,32 @@ void prepare_move_to_destination() {
#endif // HAS_CONTROLLERFAN
-#if ENABLED(SCARA)
+#if IS_SCARA
- void forward_kinematics_SCARA(float f_scara[ABC]) {
- // Perform forward kinematics, and place results in delta[]
+ void forward_kinematics_SCARA(const float &a, const float &b) {
+ // Perform forward kinematics, and place results in cartes[]
// The maths and first version has been done by QHARLEY . Integrated into masterbranch 06/2014 and slightly restructured by Joachim Cerny in June 2014
- float x_sin, x_cos, y_sin, y_cos;
-
- //SERIAL_ECHOPGM("f_delta x="); SERIAL_ECHO(f_scara[X_AXIS]);
- //SERIAL_ECHOPGM(" y="); SERIAL_ECHO(f_scara[Y_AXIS]);
+ float a_sin, a_cos, b_sin, b_cos;
- x_sin = sin(f_scara[X_AXIS] / SCARA_RAD2DEG) * Linkage_1;
- x_cos = cos(f_scara[X_AXIS] / SCARA_RAD2DEG) * Linkage_1;
- y_sin = sin(f_scara[Y_AXIS] / SCARA_RAD2DEG) * Linkage_2;
- y_cos = cos(f_scara[Y_AXIS] / SCARA_RAD2DEG) * Linkage_2;
+ a_sin = sin(RADIANS(a)) * L1;
+ a_cos = cos(RADIANS(a)) * L1;
+ b_sin = sin(RADIANS(b)) * L2;
+ b_cos = cos(RADIANS(b)) * L2;
- //SERIAL_ECHOPGM(" x_sin="); SERIAL_ECHO(x_sin);
- //SERIAL_ECHOPGM(" x_cos="); SERIAL_ECHO(x_cos);
- //SERIAL_ECHOPGM(" y_sin="); SERIAL_ECHO(y_sin);
- //SERIAL_ECHOPGM(" y_cos="); SERIAL_ECHOLN(y_cos);
+ cartes[X_AXIS] = a_cos + b_cos + SCARA_OFFSET_X; //theta
+ cartes[Y_AXIS] = a_sin + b_sin + SCARA_OFFSET_Y; //theta+phi
- delta[X_AXIS] = x_cos + y_cos + SCARA_offset_x; //theta
- delta[Y_AXIS] = x_sin + y_sin + SCARA_offset_y; //theta+phi
-
- //SERIAL_ECHOPGM(" delta[X_AXIS]="); SERIAL_ECHO(delta[X_AXIS]);
- //SERIAL_ECHOPGM(" delta[Y_AXIS]="); SERIAL_ECHOLN(delta[Y_AXIS]);
+ /*
+ SERIAL_ECHOPAIR("f_delta x=", a);
+ SERIAL_ECHOPAIR(" y=", 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]);
+ //*/
}
void inverse_kinematics(const float cartesian[XYZ]) {
@@ -8469,51 +8347,42 @@ void prepare_move_to_destination() {
// The maths and first version were done by QHARLEY.
// Integrated, tweaked by Joachim Cerny in June 2014.
- float SCARA_pos[2];
- static float SCARA_C2, SCARA_S2, SCARA_K1, SCARA_K2, SCARA_theta, SCARA_psi;
+ static float C2, S2, SK1, SK2, THETA, PSI;
- SCARA_pos[X_AXIS] = RAW_X_POSITION(cartesian[X_AXIS]) * axis_scaling[X_AXIS] - SCARA_offset_x; //Translate SCARA to standard X Y
- SCARA_pos[Y_AXIS] = RAW_Y_POSITION(cartesian[Y_AXIS]) * axis_scaling[Y_AXIS] - SCARA_offset_y; // With scaling factor.
+ float sx = RAW_X_POSITION(cartesian[X_AXIS]) * axis_scaling[X_AXIS] - SCARA_OFFSET_X, //Translate SCARA to standard X Y
+ sy = RAW_Y_POSITION(cartesian[Y_AXIS]) * axis_scaling[Y_AXIS] - SCARA_OFFSET_Y; // With scaling factor.
- #if (Linkage_1 == Linkage_2)
- SCARA_C2 = ((sq(SCARA_pos[X_AXIS]) + sq(SCARA_pos[Y_AXIS])) / (2 * (float)L1_2)) - 1;
+ #if (L1 == L2)
+ C2 = HYPOT2(sx, sy) / (2 * L1_2) - 1;
#else
- SCARA_C2 = (sq(SCARA_pos[X_AXIS]) + sq(SCARA_pos[Y_AXIS]) - (float)L1_2 - (float)L2_2) / 45000;
+ C2 = (HYPOT2(sx, sy) - L1_2 - L2_2) / 45000;
#endif
- SCARA_S2 = sqrt(1 - sq(SCARA_C2));
+ S2 = sqrt(1 - sq(C2));
- SCARA_K1 = Linkage_1 + Linkage_2 * SCARA_C2;
- SCARA_K2 = Linkage_2 * SCARA_S2;
+ SK1 = L1 + L2 * C2;
+ SK2 = L2 * S2;
- SCARA_theta = (atan2(SCARA_pos[X_AXIS], SCARA_pos[Y_AXIS]) - atan2(SCARA_K1, SCARA_K2)) * -1;
- SCARA_psi = atan2(SCARA_S2, SCARA_C2);
+ THETA = (atan2(sx, sy) - atan2(SK1, SK2)) * -1;
+ PSI = atan2(S2, C2);
- delta[X_AXIS] = SCARA_theta * SCARA_RAD2DEG; // Multiply by 180/Pi - theta is support arm angle
- delta[Y_AXIS] = (SCARA_theta + SCARA_psi) * SCARA_RAD2DEG; // - equal to sub arm angle (inverted motor)
- delta[Z_AXIS] = RAW_Z_POSITION(cartesian[Z_AXIS]);
+ delta[A_AXIS] = DEGREES(THETA); // theta is support arm angle
+ delta[B_AXIS] = DEGREES(THETA + PSI); // equal to sub arm angle (inverted motor)
+ delta[Z_AXIS] = cartesian[Z_AXIS];
/**
- SERIAL_ECHOPGM("cartesian x="); SERIAL_ECHO(cartesian[X_AXIS]);
- SERIAL_ECHOPGM(" y="); SERIAL_ECHO(cartesian[Y_AXIS]);
- SERIAL_ECHOPGM(" z="); SERIAL_ECHOLN(cartesian[Z_AXIS]);
-
- SERIAL_ECHOPGM("scara x="); SERIAL_ECHO(SCARA_pos[X_AXIS]);
- SERIAL_ECHOPGM(" y="); SERIAL_ECHOLN(SCARA_pos[Y_AXIS]);
-
- SERIAL_ECHOPGM("delta x="); SERIAL_ECHO(delta[X_AXIS]);
- SERIAL_ECHOPGM(" y="); SERIAL_ECHO(delta[Y_AXIS]);
- SERIAL_ECHOPGM(" z="); SERIAL_ECHOLN(delta[Z_AXIS]);
-
- SERIAL_ECHOPGM("C2="); SERIAL_ECHO(SCARA_C2);
- SERIAL_ECHOPGM(" S2="); SERIAL_ECHO(SCARA_S2);
- SERIAL_ECHOPGM(" Theta="); SERIAL_ECHO(SCARA_theta);
- SERIAL_ECHOPGM(" Psi="); SERIAL_ECHOLN(SCARA_psi);
- SERIAL_EOL;
- */
+ DEBUG_POS("SCARA IK", cartesian);
+ 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);
+ //*/
}
-#endif // SCARA
+#endif // IS_SCARA
#if ENABLED(TEMP_STAT_LEDS)
@@ -8541,64 +8410,122 @@ void prepare_move_to_destination() {
#endif
-void enable_all_steppers() {
- enable_x();
- enable_y();
- enable_z();
- enable_e0();
- enable_e1();
- enable_e2();
- enable_e3();
-}
-
-void disable_all_steppers() {
- disable_x();
- disable_y();
- disable_z();
- disable_e0();
- disable_e1();
- disable_e2();
- disable_e3();
-}
-
-/**
- * Standard idle routine keeps the machine alive
- */
-void idle(
- #if ENABLED(FILAMENT_CHANGE_FEATURE)
- bool no_stepper_sleep/*=false*/
- #endif
-) {
- lcd_update();
- host_keepalive();
- manage_inactivity(
- #if ENABLED(FILAMENT_CHANGE_FEATURE)
- no_stepper_sleep
- #endif
- );
+#if ENABLED(FILAMENT_RUNOUT_SENSOR)
- thermalManager.manage_heater();
+ void handle_filament_runout() {
+ if (!filament_ran_out) {
+ filament_ran_out = true;
+ enqueue_and_echo_commands_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
+ stepper.synchronize();
+ }
+ }
- #if ENABLED(PRINTCOUNTER)
- print_job_timer.tick();
- #endif
+#endif // FILAMENT_RUNOUT_SENSOR
- #if HAS_BUZZER && PIN_EXISTS(BEEPER)
- buzzer.tick();
- #endif
-}
+#if ENABLED(FAST_PWM_FAN)
-/**
- * Manage several activities:
- * - Check for Filament Runout
- * - Keep the command buffer full
- * - Check for maximum inactive time between commands
- * - Check for maximum inactive time between stepper commands
- * - Check if pin CHDK needs to go LOW
- * - Check for KILL button held down
- * - Check for HOME button held down
- * - Check if cooling fan needs to be switched on
- * - Check if an idle but hot extruder needs filament extruded (EXTRUDER_RUNOUT_PREVENT)
+ void setPwmFrequency(uint8_t pin, int val) {
+ val &= 0x07;
+ switch (digitalPinToTimer(pin)) {
+ #if defined(TCCR0A)
+ case TIMER0A:
+ case TIMER0B:
+ // TCCR0B &= ~(_BV(CS00) | _BV(CS01) | _BV(CS02));
+ // TCCR0B |= val;
+ break;
+ #endif
+ #if defined(TCCR1A)
+ case TIMER1A:
+ case TIMER1B:
+ // TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
+ // TCCR1B |= val;
+ break;
+ #endif
+ #if defined(TCCR2)
+ case TIMER2:
+ case TIMER2:
+ TCCR2 &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
+ TCCR2 |= val;
+ break;
+ #endif
+ #if defined(TCCR2A)
+ case TIMER2A:
+ case TIMER2B:
+ TCCR2B &= ~(_BV(CS20) | _BV(CS21) | _BV(CS22));
+ TCCR2B |= val;
+ break;
+ #endif
+ #if defined(TCCR3A)
+ case TIMER3A:
+ case TIMER3B:
+ case TIMER3C:
+ TCCR3B &= ~(_BV(CS30) | _BV(CS31) | _BV(CS32));
+ TCCR3B |= val;
+ break;
+ #endif
+ #if defined(TCCR4A)
+ case TIMER4A:
+ case TIMER4B:
+ case TIMER4C:
+ TCCR4B &= ~(_BV(CS40) | _BV(CS41) | _BV(CS42));
+ TCCR4B |= val;
+ break;
+ #endif
+ #if defined(TCCR5A)
+ case TIMER5A:
+ case TIMER5B:
+ case TIMER5C:
+ TCCR5B &= ~(_BV(CS50) | _BV(CS51) | _BV(CS52));
+ TCCR5B |= val;
+ break;
+ #endif
+ }
+ }
+
+#endif // FAST_PWM_FAN
+
+float calculate_volumetric_multiplier(float diameter) {
+ if (!volumetric_enabled || diameter == 0) return 1.0;
+ float d2 = diameter * 0.5;
+ return 1.0 / (M_PI * d2 * d2);
+}
+
+void calculate_volumetric_multipliers() {
+ for (uint8_t i = 0; i < COUNT(filament_size); i++)
+ volumetric_multiplier[i] = calculate_volumetric_multiplier(filament_size[i]);
+}
+
+void enable_all_steppers() {
+ enable_x();
+ enable_y();
+ enable_z();
+ enable_e0();
+ enable_e1();
+ enable_e2();
+ enable_e3();
+}
+
+void disable_all_steppers() {
+ disable_x();
+ disable_y();
+ disable_z();
+ disable_e0();
+ disable_e1();
+ disable_e2();
+ disable_e3();
+}
+
+/**
+ * Manage several activities:
+ * - Check for Filament Runout
+ * - Keep the command buffer full
+ * - Check for maximum inactive time between commands
+ * - Check for maximum inactive time between stepper commands
+ * - Check if pin CHDK needs to go LOW
+ * - Check for KILL button held down
+ * - Check for HOME button held down
+ * - Check if cooling fan needs to be switched on
+ * - Check if an idle but hot extruder needs filament extruded (EXTRUDER_RUNOUT_PREVENT)
*/
void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
@@ -8681,11 +8608,11 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
if (ELAPSED(ms, previous_cmd_ms + (EXTRUDER_RUNOUT_SECONDS) * 1000UL)
&& thermalManager.degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP) {
+ bool oldstatus;
#if ENABLED(SWITCHING_EXTRUDER)
- bool oldstatus = E0_ENABLE_READ;
+ oldstatus = E0_ENABLE_READ;
enable_e0();
#else // !SWITCHING_EXTRUDER
- bool oldstatus;
switch (active_extruder) {
case 0:
oldstatus = E0_ENABLE_READ;
@@ -8712,15 +8639,14 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
}
#endif // !SWITCHING_EXTRUDER
- float oldepos = current_position[E_AXIS], oldedes = destination[E_AXIS];
- planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS],
- destination[E_AXIS] + (EXTRUDER_RUNOUT_EXTRUDE) * (EXTRUDER_RUNOUT_ESTEPS) * planner.steps_to_mm[E_AXIS],
- MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED) * (EXTRUDER_RUNOUT_ESTEPS) * planner.steps_to_mm[E_AXIS], active_extruder);
- current_position[E_AXIS] = oldepos;
- destination[E_AXIS] = oldedes;
- planner.set_e_position_mm(oldepos);
previous_cmd_ms = ms; // refresh_cmd_timeout()
+ planner.buffer_line(
+ current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
+ current_position[E_AXIS] + EXTRUDER_RUNOUT_EXTRUDE,
+ MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED), active_extruder
+ );
stepper.synchronize();
+ planner.set_e_position_mm(current_position[E_AXIS]);
#if ENABLED(SWITCHING_EXTRUDER)
E0_ENABLE_WRITE(oldstatus);
#else
@@ -8765,6 +8691,37 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
planner.check_axes_activity();
}
+/**
+ * Standard idle routine keeps the machine alive
+ */
+void idle(
+ #if ENABLED(FILAMENT_CHANGE_FEATURE)
+ bool no_stepper_sleep/*=false*/
+ #endif
+) {
+ lcd_update();
+ host_keepalive();
+ manage_inactivity(
+ #if ENABLED(FILAMENT_CHANGE_FEATURE)
+ no_stepper_sleep
+ #endif
+ );
+
+ thermalManager.manage_heater();
+
+ #if ENABLED(PRINTCOUNTER)
+ print_job_timer.tick();
+ #endif
+
+ #if HAS_BUZZER && PIN_EXISTS(BEEPER)
+ buzzer.tick();
+ #endif
+}
+
+/**
+ * Kill all activity and lock the machine.
+ * After this the machine will need to be reset.
+ */
void kill(const char* lcd_msg) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
@@ -8793,79 +8750,10 @@ void kill(const char* lcd_msg) {
} // Wait for reset
}
-#if ENABLED(FILAMENT_RUNOUT_SENSOR)
-
- void handle_filament_runout() {
- if (!filament_ran_out) {
- filament_ran_out = true;
- enqueue_and_echo_commands_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
- stepper.synchronize();
- }
- }
-
-#endif // FILAMENT_RUNOUT_SENSOR
-
-#if ENABLED(FAST_PWM_FAN)
-
- void setPwmFrequency(uint8_t pin, int val) {
- val &= 0x07;
- switch (digitalPinToTimer(pin)) {
- #if defined(TCCR0A)
- case TIMER0A:
- case TIMER0B:
- // TCCR0B &= ~(_BV(CS00) | _BV(CS01) | _BV(CS02));
- // TCCR0B |= val;
- break;
- #endif
- #if defined(TCCR1A)
- case TIMER1A:
- case TIMER1B:
- // TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
- // TCCR1B |= val;
- break;
- #endif
- #if defined(TCCR2)
- case TIMER2:
- case TIMER2:
- TCCR2 &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
- TCCR2 |= val;
- break;
- #endif
- #if defined(TCCR2A)
- case TIMER2A:
- case TIMER2B:
- TCCR2B &= ~(_BV(CS20) | _BV(CS21) | _BV(CS22));
- TCCR2B |= val;
- break;
- #endif
- #if defined(TCCR3A)
- case TIMER3A:
- case TIMER3B:
- case TIMER3C:
- TCCR3B &= ~(_BV(CS30) | _BV(CS31) | _BV(CS32));
- TCCR3B |= val;
- break;
- #endif
- #if defined(TCCR4A)
- case TIMER4A:
- case TIMER4B:
- case TIMER4C:
- TCCR4B &= ~(_BV(CS40) | _BV(CS41) | _BV(CS42));
- TCCR4B |= val;
- break;
- #endif
- #if defined(TCCR5A)
- case TIMER5A:
- case TIMER5B:
- case TIMER5C:
- TCCR5B &= ~(_BV(CS50) | _BV(CS51) | _BV(CS52));
- TCCR5B |= val;
- break;
- #endif
- }
- }
-#endif // FAST_PWM_FAN
-
+/**
+ * Turn off heaters and stop the print in progress
+ * After a stop the machine may be resumed with M999
+ */
void stop() {
thermalManager.disable_all_heaters();
if (IsRunning()) {
@@ -8877,13 +8765,212 @@ void stop() {
}
}
-float calculate_volumetric_multiplier(float diameter) {
- if (!volumetric_enabled || diameter == 0) return 1.0;
- float d2 = diameter * 0.5;
- return 1.0 / (M_PI * d2 * d2);
+/**
+ * Marlin entry-point: Set up before the program loop
+ * - Set up the kill pin, filament runout, power hold
+ * - Start the serial port
+ * - Print startup messages and diagnostics
+ * - Get EEPROM or default settings
+ * - Initialize managers for:
+ * • temperature
+ * • planner
+ * • watchdog
+ * • stepper
+ * • photo pin
+ * • servos
+ * • LCD controller
+ * • Digipot I2C
+ * • Z probe sled
+ * • status LEDs
+ */
+void setup() {
+
+ #ifdef DISABLE_JTAG
+ // Disable JTAG on AT90USB chips to free up pins for IO
+ MCUCR = 0x80;
+ MCUCR = 0x80;
+ #endif
+
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ setup_filrunoutpin();
+ #endif
+
+ setup_killpin();
+
+ setup_powerhold();
+
+ #if HAS_STEPPER_RESET
+ disableStepperDrivers();
+ #endif
+
+ MYSERIAL.begin(BAUDRATE);
+ SERIAL_PROTOCOLLNPGM("start");
+ SERIAL_ECHO_START;
+
+ // Check startup - does nothing if bootloader sets MCUSR to 0
+ byte mcu = MCUSR;
+ if (mcu & 1) SERIAL_ECHOLNPGM(MSG_POWERUP);
+ if (mcu & 2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
+ if (mcu & 4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
+ if (mcu & 8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
+ if (mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
+ MCUSR = 0;
+
+ SERIAL_ECHOPGM(MSG_MARLIN);
+ SERIAL_CHAR(' ');
+ SERIAL_ECHOLNPGM(SHORT_BUILD_VERSION);
+ SERIAL_EOL;
+
+ #if defined(STRING_DISTRIBUTION_DATE) && defined(STRING_CONFIG_H_AUTHOR)
+ SERIAL_ECHO_START;
+ SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
+ SERIAL_ECHOPGM(STRING_DISTRIBUTION_DATE);
+ SERIAL_ECHOLNPGM(MSG_AUTHOR STRING_CONFIG_H_AUTHOR);
+ SERIAL_ECHOLNPGM("Compiled: " __DATE__);
+ #endif
+
+ SERIAL_ECHO_START;
+ SERIAL_ECHOPAIR(MSG_FREE_MEMORY, freeMemory());
+ SERIAL_ECHOLNPAIR(MSG_PLANNER_BUFFER_BYTES, (int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
+
+ // Send "ok" after commands by default
+ for (int8_t i = 0; i < BUFSIZE; i++) send_ok[i] = true;
+
+ // Load data from EEPROM if available (or use defaults)
+ // This also updates variables in the planner, elsewhere
+ Config_RetrieveSettings();
+
+ // Initialize current position based on home_offset
+ memcpy(current_position, home_offset, sizeof(home_offset));
+
+ // Vital to init stepper/planner equivalent for current_position
+ SYNC_PLAN_POSITION_KINEMATIC();
+
+ thermalManager.init(); // Initialize temperature loop
+
+ #if ENABLED(USE_WATCHDOG)
+ watchdog_init();
+ #endif
+
+ stepper.init(); // Initialize stepper, this enables interrupts!
+ setup_photpin();
+ servo_init();
+
+ #if HAS_BED_PROBE
+ endstops.enable_z_probe(false);
+ #endif
+
+ #if HAS_CONTROLLERFAN
+ SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
+ #endif
+
+ #if HAS_STEPPER_RESET
+ enableStepperDrivers();
+ #endif
+
+ #if ENABLED(DIGIPOT_I2C)
+ digipot_i2c_init();
+ #endif
+
+ #if ENABLED(DAC_STEPPER_CURRENT)
+ dac_init();
+ #endif
+
+ #if ENABLED(Z_PROBE_SLED) && PIN_EXISTS(SLED)
+ pinMode(SLED_PIN, OUTPUT);
+ digitalWrite(SLED_PIN, LOW); // turn it off
+ #endif // Z_PROBE_SLED
+
+ setup_homepin();
+
+ #ifdef STAT_LED_RED
+ pinMode(STAT_LED_RED, OUTPUT);
+ digitalWrite(STAT_LED_RED, LOW); // turn it off
+ #endif
+
+ #ifdef STAT_LED_BLUE
+ pinMode(STAT_LED_BLUE, OUTPUT);
+ digitalWrite(STAT_LED_BLUE, LOW); // turn it off
+ #endif
+
+ lcd_init();
+ #if ENABLED(SHOW_BOOTSCREEN)
+ #if ENABLED(DOGLCD)
+ safe_delay(BOOTSCREEN_TIMEOUT);
+ #elif ENABLED(ULTRA_LCD)
+ bootscreen();
+ lcd_init();
+ #endif
+ #endif
+
+ #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
+ // Initialize mixing to 100% color 1
+ for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
+ mixing_factor[i] = (i == 0) ? 1 : 0;
+ for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS; t++)
+ for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
+ mixing_virtual_tool_mix[t][i] = mixing_factor[i];
+ #endif
+
+ #if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
+ i2c.onReceive(i2c_on_receive);
+ i2c.onRequest(i2c_on_request);
+ #endif
}
-void calculate_volumetric_multipliers() {
- for (uint8_t i = 0; i < COUNT(filament_size); i++)
- volumetric_multiplier[i] = calculate_volumetric_multiplier(filament_size[i]);
+/**
+ * The main Marlin program loop
+ *
+ * - Save or log commands to SD
+ * - Process available commands (if not saving)
+ * - Call heater manager
+ * - Call inactivity manager
+ * - Call endstop manager
+ * - Call LCD update
+ */
+void loop() {
+ if (commands_in_queue < BUFSIZE) get_available_commands();
+
+ #if ENABLED(SDSUPPORT)
+ card.checkautostart(false);
+ #endif
+
+ if (commands_in_queue) {
+
+ #if ENABLED(SDSUPPORT)
+
+ if (card.saving) {
+ char* command = command_queue[cmd_queue_index_r];
+ if (strstr_P(command, PSTR("M29"))) {
+ // M29 closes the file
+ card.closefile();
+ SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
+ ok_to_send();
+ }
+ else {
+ // Write the string from the read buffer to SD
+ card.write_command(command);
+ if (card.logging)
+ process_next_command(); // The card is saving because it's logging
+ else
+ ok_to_send();
+ }
+ }
+ else
+ process_next_command();
+
+ #else
+
+ process_next_command();
+
+ #endif // SDSUPPORT
+
+ // The queue may be reset by a command handler or by code invoked by idle() within a handler
+ if (commands_in_queue) {
+ --commands_in_queue;
+ cmd_queue_index_r = (cmd_queue_index_r + 1) % BUFSIZE;
+ }
+ }
+ endstops.report_state();
+ idle();
}
diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h
index 0234baee1cc78dd71d7fab0219fadedb6f31045f..6a3433e387944f2974b2aafe079f8b399d1fa2ee 100644
--- a/Marlin/SanityCheck.h
+++ b/Marlin/SanityCheck.h
@@ -137,6 +137,8 @@
#error Please replace "const int dropsegments" with "#define MIN_STEPS_PER_SEGMENT" (and increase by 1) in Configuration_adv.h.
#elif defined(PREVENT_DANGEROUS_EXTRUDE)
#error "PREVENT_DANGEROUS_EXTRUDE is now PREVENT_COLD_EXTRUSION. Please update your configuration."
+#elif defined(SCARA)
+ #error "SCARA is now MORGAN_SCARA. Please update your configuration."
#endif
/**
@@ -179,11 +181,9 @@
#if ENABLED(LCD_PROGRESS_BAR)
#if DISABLED(SDSUPPORT)
#error "LCD_PROGRESS_BAR requires SDSUPPORT."
- #endif
- #if ENABLED(DOGLCD)
+ #elif ENABLED(DOGLCD)
#error "LCD_PROGRESS_BAR does not apply to graphical displays."
- #endif
- #if ENABLED(FILAMENT_LCD_DISPLAY)
+ #elif ENABLED(FILAMENT_LCD_DISPLAY)
#error "LCD_PROGRESS_BAR and FILAMENT_LCD_DISPLAY are not fully compatible. Comment out this line to use both."
#endif
#endif
@@ -573,11 +573,39 @@
/**
* Don't set more than one kinematic type
*/
-#if (ENABLED(DELTA) && (ENABLED(SCARA) || ENABLED(COREXY) || ENABLED(COREXZ) || ENABLED(COREYZ))) \
- || (ENABLED(SCARA) && (ENABLED(COREXY) || ENABLED(COREXZ) || ENABLED(COREYZ))) \
- || (ENABLED(COREXY) && (ENABLED(COREXZ) || ENABLED(COREYZ))) \
- || (ENABLED(COREXZ) && ENABLED(COREYZ))
- #error "Please enable only one of DELTA, SCARA, COREXY, COREXZ, or COREYZ."
+#define COUNT_KIN_1 0
+#if ENABLED(DELTA)
+ #define COUNT_KIN_2 INCREMENT(COUNT_KIN_1)
+#else
+ #define COUNT_KIN_2 COUNT_KIN_1
+#endif
+#if ENABLED(MORGAN_SCARA)
+ #define COUNT_KIN_3 INCREMENT(COUNT_KIN_2)
+#else
+ #define COUNT_KIN_3 COUNT_KIN_2
+#endif
+#if ENABLED(MAKERARM_SCARA)
+ #define COUNT_KIN_4 INCREMENT(COUNT_KIN_3)
+#else
+ #define COUNT_KIN_4 COUNT_KIN_3
+#endif
+#if ENABLED(COREXY)
+ #define COUNT_KIN_5 INCREMENT(COUNT_KIN_4)
+#else
+ #define COUNT_KIN_5 COUNT_KIN_4
+#endif
+#if ENABLED(COREXZ)
+ #define COUNT_KIN_6 INCREMENT(COUNT_KIN_5)
+#else
+ #define COUNT_KIN_6 COUNT_KIN_5
+#endif
+#if ENABLED(COREYZ)
+ #define COUNT_KIN_7 INCREMENT(COUNT_KIN_6)
+#else
+ #define COUNT_KIN_7 COUNT_KIN_6
+#endif
+#if COUNT_KIN_7 > 1
+ #error "Please enable only one of DELTA, MORGAN_SCARA, MAKERARM_SCARA, COREXY, COREXZ, or COREYZ."
#endif
/**
@@ -750,7 +778,7 @@
#elif ENABLED(DELTA)
#error "Z_DUAL_ENDSTOPS is not compatible with DELTA."
#endif
-#elif DISABLED(SCARA)
+#elif !IS_SCARA
#if X_HOME_DIR < 0 && DISABLED(USE_XMIN_PLUG)
#error "Enable USE_XMIN_PLUG when homing X to MIN."
#elif X_HOME_DIR > 0 && DISABLED(USE_XMAX_PLUG)
@@ -783,3 +811,136 @@
#error "I2C_SLAVE_ADDRESS can't be over 127. (Only 7 bits allowed.)"
#endif
#endif
+
+/**
+ * Make sure only one display is enabled
+ *
+ * Note: BQ_LCD_SMART_CONTROLLER => REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
+ * REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER => REPRAP_DISCOUNT_SMART_CONTROLLER
+ * SAV_3DGLCD => U8GLIB_SH1106 => ULTIMAKERCONTROLLER
+ * miniVIKI => ULTIMAKERCONTROLLER
+ * VIKI2 => ULTIMAKERCONTROLLER
+ * ELB_FULL_GRAPHIC_CONTROLLER => ULTIMAKERCONTROLLER
+ * PANEL_ONE => ULTIMAKERCONTROLLER
+ */
+#define COUNT_LCD_1 0
+#if ENABLED(ULTIMAKERCONTROLLER) \
+ && DISABLED(SAV_3DGLCD) && DISABLED(miniVIKI) && DISABLED(VIKI2) \
+ && DISABLED(ELB_FULL_GRAPHIC_CONTROLLER) && DISABLED(PANEL_ONE)
+ #define COUNT_LCD_2 INCREMENT(COUNT_LCD_1)
+#else
+ #define COUNT_LCD_2 COUNT_LCD_1
+#endif
+#if ENABLED(REPRAP_DISCOUNT_SMART_CONTROLLER) && DISABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER)
+ #define COUNT_LCD_3 INCREMENT(COUNT_LCD_2)
+#else
+ #define COUNT_LCD_3 COUNT_LCD_2
+#endif
+#if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) && DISABLED(BQ_LCD_SMART_CONTROLLER)
+ #define COUNT_LCD_4 INCREMENT(COUNT_LCD_3)
+#else
+ #define COUNT_LCD_4 COUNT_LCD_3
+#endif
+#if ENABLED(CARTESIO_UI)
+ #define COUNT_LCD_5 INCREMENT(COUNT_LCD_4)
+#else
+ #define COUNT_LCD_5 COUNT_LCD_4
+#endif
+#if ENABLED(PANEL_ONE)
+ #define COUNT_LCD_6 INCREMENT(COUNT_LCD_5)
+#else
+ #define COUNT_LCD_6 COUNT_LCD_5
+#endif
+#if ENABLED(MAKRPANEL)
+ #define COUNT_LCD_7 INCREMENT(COUNT_LCD_6)
+#else
+ #define COUNT_LCD_7 COUNT_LCD_6
+#endif
+#if ENABLED(REPRAPWORLD_GRAPHICAL_LCD)
+ #define COUNT_LCD_8 INCREMENT(COUNT_LCD_7)
+#else
+ #define COUNT_LCD_8 COUNT_LCD_7
+#endif
+#if ENABLED(VIKI2)
+ #define COUNT_LCD_9 INCREMENT(COUNT_LCD_8)
+#else
+ #define COUNT_LCD_9 COUNT_LCD_8
+#endif
+#if ENABLED(miniVIKI)
+ #define COUNT_LCD_10 INCREMENT(COUNT_LCD_9)
+#else
+ #define COUNT_LCD_10 COUNT_LCD_9
+#endif
+#if ENABLED(ELB_FULL_GRAPHIC_CONTROLLER)
+ #define COUNT_LCD_11 INCREMENT(COUNT_LCD_10)
+#else
+ #define COUNT_LCD_11 COUNT_LCD_10
+#endif
+#if ENABLED(G3D_PANEL)
+ #define COUNT_LCD_12 INCREMENT(COUNT_LCD_11)
+#else
+ #define COUNT_LCD_12 COUNT_LCD_11
+#endif
+#if ENABLED(MINIPANEL)
+ #define COUNT_LCD_13 INCREMENT(COUNT_LCD_12)
+#else
+ #define COUNT_LCD_13 COUNT_LCD_12
+#endif
+#if ENABLED(REPRAPWORLD_KEYPAD)
+ #define COUNT_LCD_14 INCREMENT(COUNT_LCD_13)
+#else
+ #define COUNT_LCD_14 COUNT_LCD_13
+#endif
+#if ENABLED(RIGIDBOT_PANEL)
+ #define COUNT_LCD_15 INCREMENT(COUNT_LCD_14)
+#else
+ #define COUNT_LCD_15 COUNT_LCD_14
+#endif
+#if ENABLED(RA_CONTROL_PANEL)
+ #define COUNT_LCD_16 INCREMENT(COUNT_LCD_15)
+#else
+ #define COUNT_LCD_16 COUNT_LCD_15
+#endif
+#if ENABLED(LCD_I2C_SAINSMART_YWROBOT)
+ #define COUNT_LCD_17 INCREMENT(COUNT_LCD_16)
+#else
+ #define COUNT_LCD_17 COUNT_LCD_16
+#endif
+#if ENABLED(LCM1602)
+ #define COUNT_LCD_18 INCREMENT(COUNT_LCD_17)
+#else
+ #define COUNT_LCD_18 COUNT_LCD_17
+#endif
+#if ENABLED(LCD_I2C_PANELOLU2)
+ #define COUNT_LCD_19 INCREMENT(COUNT_LCD_18)
+#else
+ #define COUNT_LCD_19 COUNT_LCD_18
+#endif
+#if ENABLED(LCD_I2C_VIKI)
+ #define COUNT_LCD_20 INCREMENT(COUNT_LCD_19)
+#else
+ #define COUNT_LCD_20 COUNT_LCD_19
+#endif
+#if ENABLED(U8GLIB_SSD1306)
+ #define COUNT_LCD_21 INCREMENT(COUNT_LCD_20)
+#else
+ #define COUNT_LCD_21 COUNT_LCD_20
+#endif
+#if ENABLED(SAV_3DLCD)
+ #define COUNT_LCD_22 INCREMENT(COUNT_LCD_21)
+#else
+ #define COUNT_LCD_22 COUNT_LCD_21
+#endif
+#if ENABLED(BQ_LCD_SMART_CONTROLLER)
+ #define COUNT_LCD_23 INCREMENT(COUNT_LCD_22)
+#else
+ #define COUNT_LCD_23 COUNT_LCD_22
+#endif
+#if ENABLED(SAV_3DGLCD)
+ #define COUNT_LCD_24 INCREMENT(COUNT_LCD_23)
+#else
+ #define COUNT_LCD_24 COUNT_LCD_23
+#endif
+#if COUNT_LCD_24 > 1
+ #error "Please select no more than one LCD controller option."
+#endif
diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp
index f54cd88a2f8d0a027b6385d4c1c29f4a7f8fa590..0dd1ce6da40286fe18ad5169847f5493d06b525a 100644
--- a/Marlin/configuration_store.cpp
+++ b/Marlin/configuration_store.cpp
@@ -330,7 +330,7 @@ void Config_StoreSettings() {
#endif
EEPROM_WRITE(lcd_contrast);
- #if ENABLED(SCARA)
+ #if IS_SCARA
EEPROM_WRITE(axis_scaling); // 3 floats
#else
dummy = 1.0f;
@@ -520,7 +520,7 @@ void Config_RetrieveSettings() {
#endif
EEPROM_READ(lcd_contrast);
- #if ENABLED(SCARA)
+ #if IS_SCARA
EEPROM_READ(axis_scaling); // 3 floats
#else
EEPROM_READ(dummy);
@@ -584,7 +584,7 @@ void Config_ResetDefault() {
planner.axis_steps_per_mm[i] = tmp1[i];
planner.max_feedrate_mm_s[i] = tmp2[i];
planner.max_acceleration_mm_per_s2[i] = tmp3[i];
- #if ENABLED(SCARA)
+ #if IS_SCARA
if (i < COUNT(axis_scaling))
axis_scaling[i] = 1;
#endif
@@ -716,7 +716,7 @@ void Config_PrintSettings(bool forReplay) {
CONFIG_ECHO_START;
- #if ENABLED(SCARA)
+ #if IS_SCARA
if (!forReplay) {
SERIAL_ECHOLNPGM("Scaling factors:");
CONFIG_ECHO_START;
diff --git a/Marlin/enum.h b/Marlin/enum.h
index ded1be6ec7c4a7583095de54780e2eea602cfca9..18db5a6f5f31434bb9eeff092f55b6a7ac724710 100644
--- a/Marlin/enum.h
+++ b/Marlin/enum.h
@@ -42,7 +42,8 @@ enum AxisEnum {
E_AXIS = 3,
X_HEAD = 4,
Y_HEAD = 5,
- Z_HEAD = 6
+ Z_HEAD = 6,
+ ALL_AXES = 100
};
#define LOOP_XYZ(VAR) for (uint8_t VAR=X_AXIS; VAR<=Z_AXIS; VAR++)
diff --git a/Marlin/example_configurations/Cartesio/Configuration_adv.h b/Marlin/example_configurations/Cartesio/Configuration_adv.h
index 0763b33823d4716c888f8df83b115dfc6013bc71..fb5a2ebca18626b832c7fcad97beaeee71af1134 100644
--- a/Marlin/example_configurations/Cartesio/Configuration_adv.h
+++ b/Marlin/example_configurations/Cartesio/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/Felix/Configuration_adv.h b/Marlin/example_configurations/Felix/Configuration_adv.h
index a24bca1a2666451223ccdcea10ac7515a95c2346..6ebe50e926c4041e6eb78507eae66397e03a6c4c 100644
--- a/Marlin/example_configurations/Felix/Configuration_adv.h
+++ b/Marlin/example_configurations/Felix/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/Hephestos/Configuration_adv.h b/Marlin/example_configurations/Hephestos/Configuration_adv.h
index 7b826b5277bb9b4fac91589d75e2037095ee7d60..71139893fc8bf982b5a77fef8dcfb882173d49b2 100644
--- a/Marlin/example_configurations/Hephestos/Configuration_adv.h
+++ b/Marlin/example_configurations/Hephestos/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h
index deb6262928a8febb81a0aecef02ff660f075f470..4a426c6ac7a328df3f7a53389511b933080f1c20 100644
--- a/Marlin/example_configurations/Hephestos_2/Configuration_adv.h
+++ b/Marlin/example_configurations/Hephestos_2/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/K8200/Configuration_adv.h b/Marlin/example_configurations/K8200/Configuration_adv.h
index d57fcea93dd2876e824cf8535b2cd63117668197..34d12ec22984dc75a94e171580050ac14e338028 100644
--- a/Marlin/example_configurations/K8200/Configuration_adv.h
+++ b/Marlin/example_configurations/K8200/Configuration_adv.h
@@ -174,14 +174,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/K8400/Configuration_adv.h b/Marlin/example_configurations/K8400/Configuration_adv.h
index 7a8426981809176e4a28ce774529f4e2bb2c715c..463f17382f66819e2f03b0a282ccb0b1a7a2f10e 100644
--- a/Marlin/example_configurations/K8400/Configuration_adv.h
+++ b/Marlin/example_configurations/K8400/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/RigidBot/Configuration_adv.h b/Marlin/example_configurations/RigidBot/Configuration_adv.h
index faebf06ffa86153e08f6180a629aaa67d625b854..191f1b824610dfea578f6b349258e3c27e8cca19 100644
--- a/Marlin/example_configurations/RigidBot/Configuration_adv.h
+++ b/Marlin/example_configurations/RigidBot/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/SCARA/Configuration.h b/Marlin/example_configurations/SCARA/Configuration.h
index 085880e210e6e2b36f022118195fba145a47d59d..3c2e96a696958b48a7202351d9f6c3416733a567 100644
--- a/Marlin/example_configurations/SCARA/Configuration.h
+++ b/Marlin/example_configurations/SCARA/Configuration.h
@@ -75,35 +75,37 @@
//
//===========================================================================
-//========================= SCARA Settings ==================================
+//============================= SCARA Printer ===============================
//===========================================================================
-// SCARA-mode for Marlin has been developed by QHARLEY in ZA in 2012/2013. Implemented
+// MORGAN_SCARA for Marlin was developed by QHARLEY in ZA in 2012/2013. Implemented
// and slightly reworked by JCERNY in 06/2014 with the goal to bring it into Master-Branch
// QHARLEYS Autobedlevelling has not been ported, because Marlin has now Bed-levelling
// You might need Z-Min endstop on SCARA-Printer to use this feature. Actually untested!
-// Uncomment to use Morgan scara mode
-#define SCARA
-#define SCARA_SEGMENTS_PER_SECOND 200 // If movement is choppy try lowering this value
-// Length of inner support arm
-#define Linkage_1 150 //mm Preprocessor cannot handle decimal point...
-// Length of outer support arm Measure arm lengths precisely and enter
-#define Linkage_2 150 //mm
-
-// SCARA tower offset (position of Tower relative to bed zero position)
-// This needs to be reasonably accurate as it defines the printbed position in the SCARA space.
-#define SCARA_offset_x 100 //mm
-#define SCARA_offset_y -56 //mm
-#define SCARA_RAD2DEG 57.2957795 // to convert RAD to degrees
-
-#define THETA_HOMING_OFFSET 0 //calculatated from Calibration Guide and command M360 / M114 see picture in http://reprap.harleystudio.co.za/?page_id=1073
-#define PSI_HOMING_OFFSET 0 //calculatated from Calibration Guide and command M364 / M114 see picture in http://reprap.harleystudio.co.za/?page_id=1073
-
-//some helper variables to make kinematics faster
-#define L1_2 sq(Linkage_1) // do not change
-#define L2_2 sq(Linkage_2) // do not change
+
+// Specify the specific SCARA model
+#define MORGAN_SCARA
+//#define MAKERARM_SCARA
+
+#if ENABLED(MORGAN_SCARA) || ENABLED(MAKERARM_SCARA)
+ //#define DEBUG_SCARA_KINEMATICS
+
+ #define SCARA_SEGMENTS_PER_SECOND 200 // If movement is choppy try lowering this value
+ // Length of inner support arm
+ #define SCARA_LINKAGE_1 150 //mm Preprocessor cannot handle decimal point...
+ // Length of outer support arm Measure arm lengths precisely and enter
+ #define SCARA_LINKAGE_2 150 //mm
+
+ // SCARA tower offset (position of Tower relative to bed zero position)
+ // This needs to be reasonably accurate as it defines the printbed position in the SCARA space.
+ #define SCARA_OFFSET_X 100 //mm
+ #define SCARA_OFFSET_Y -56 //mm
+
+ #define THETA_HOMING_OFFSET 0 //calculatated from Calibration Guide and command M360 / M114 see picture in http://reprap.harleystudio.co.za/?page_id=1073
+ #define PSI_HOMING_OFFSET 0 //calculatated from Calibration Guide and command M364 / M114 see picture in http://reprap.harleystudio.co.za/?page_id=1073
+#endif
//===========================================================================
-//========================= SCARA Settings end ==============================
+//==================== END ==== SCARA Printer ==== END ======================
//===========================================================================
// @section info
diff --git a/Marlin/example_configurations/SCARA/Configuration_adv.h b/Marlin/example_configurations/SCARA/Configuration_adv.h
index a6d33e8aa80fe7829cf0546b1474d30752f021c1..7bc8880251d4a6d07ae14054c0a358735ccfc6bf 100644
--- a/Marlin/example_configurations/SCARA/Configuration_adv.h
+++ b/Marlin/example_configurations/SCARA/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 180
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 180 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 180 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/TAZ4/Configuration_adv.h b/Marlin/example_configurations/TAZ4/Configuration_adv.h
index 6252c27964a027e2655164c0010aba112438dd2c..7d420646a112db46ff0c91f7d423bbea7f35f276 100644
--- a/Marlin/example_configurations/TAZ4/Configuration_adv.h
+++ b/Marlin/example_configurations/TAZ4/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/WITBOX/Configuration_adv.h b/Marlin/example_configurations/WITBOX/Configuration_adv.h
index 7b826b5277bb9b4fac91589d75e2037095ee7d60..71139893fc8bf982b5a77fef8dcfb882173d49b2 100644
--- a/Marlin/example_configurations/WITBOX/Configuration_adv.h
+++ b/Marlin/example_configurations/WITBOX/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h
index bbafe89f6ecd7e2fa22404e9778f64878daefcae..b4efc0016d8007ef7fda0671dc6e4b5647002c6c 100644
--- a/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h
+++ b/Marlin/example_configurations/delta/biv2.5/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/delta/generic/Configuration_adv.h b/Marlin/example_configurations/delta/generic/Configuration_adv.h
index 3345f32ec4e1231cf9e6994f2e260010544bd393..2960f84138eed1da494a5011893b0e7fdba6ed42 100644
--- a/Marlin/example_configurations/delta/generic/Configuration_adv.h
+++ b/Marlin/example_configurations/delta/generic/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h
index 97a1712c8a72d6f7a663cf573efa1cac1cc836ce..9936c54e52167e8b230624842caea435e356ebf7 100644
--- a/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h
+++ b/Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h
index 2203ee7942febef8515afc2ce4f2d82bcbd47951..9c82b1fb00385e87aa0a89d51285ac8fe5a02bd1 100644
--- a/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h
+++ b/Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h
@@ -173,14 +173,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h
index 4532819852dbc4552bc40271250bd589c327eb7d..fc68cbcefc85533455807086844058aebeb0cd03 100644
--- a/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h
+++ b/Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h
index addfc7acdff986eccaf9f43276182a9100cad12a..7e9d002f87523fcca4ac7d39720662f00212fe28 100644
--- a/Marlin/example_configurations/makibox/Configuration_adv.h
+++ b/Marlin/example_configurations/makibox/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h
index 1e8e626cc0a1d7f75150b1157aee03b8af7f1695..e6f1a7f25b1e18769233cfc706bcc2770755534a 100644
--- a/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h
+++ b/Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h
@@ -168,14 +168,16 @@
// @section extruder
-// extruder run-out prevention.
-//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
+// Extruder runout prevention.
+// If the machine is idle and the temperature over MINTEMP
+// then extrude some filament every couple of SECONDS.
//#define EXTRUDER_RUNOUT_PREVENT
-#define EXTRUDER_RUNOUT_MINTEMP 190
-#define EXTRUDER_RUNOUT_SECONDS 30
-#define EXTRUDER_RUNOUT_ESTEPS 14 // mm filament
-#define EXTRUDER_RUNOUT_SPEED 1500 // extrusion speed
-#define EXTRUDER_RUNOUT_EXTRUDE 100
+#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
+ #define EXTRUDER_RUNOUT_MINTEMP 190
+ #define EXTRUDER_RUNOUT_SECONDS 30
+ #define EXTRUDER_RUNOUT_SPEED 1500 // mm/m
+ #define EXTRUDER_RUNOUT_EXTRUDE 5 // mm
+#endif
// @section temperature
diff --git a/Marlin/language.h b/Marlin/language.h
index e6c1b8efd5e9115fee9f2efa9e44de3b8baf6660..6311e6c600e0c1ce2589b5413446ad1a4184b8a8 100644
--- a/Marlin/language.h
+++ b/Marlin/language.h
@@ -157,9 +157,9 @@
#define MSG_ENDSTOP_OPEN "open"
#define MSG_HOTEND_OFFSET "Hotend offsets:"
#define MSG_DUPLICATION_MODE "Duplication mode: "
-#define MSG_SOFT_ENDSTOPS "Soft endstops"
-#define MSG_SOFT_MIN "Min"
-#define MSG_SOFT_MAX "Max"
+#define MSG_SOFT_ENDSTOPS "Soft endstops: "
+#define MSG_SOFT_MIN " Min: "
+#define MSG_SOFT_MAX " Max: "
#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir "
#define MSG_SD_INIT_FAIL "SD init fail"
diff --git a/Marlin/language_en.h b/Marlin/language_en.h
index a0443f4d586890c868945275848120ed8c05df77..b1b8e0af751af08946f203c0443e8877be15e62e 100644
--- a/Marlin/language_en.h
+++ b/Marlin/language_en.h
@@ -408,6 +408,9 @@
#ifndef MSG_ERR_MINTEMP_BED
#define MSG_ERR_MINTEMP_BED "Err: MINTEMP BED"
#endif
+#ifndef MSG_ERR_Z_HOMING
+ #define MSG_ERR_Z_HOMING "G28 Z Forbidden"
+#endif
#ifndef MSG_HALTED
#define MSG_HALTED "PRINTER HALTED"
#endif
diff --git a/Marlin/macros.h b/Marlin/macros.h
index 351272804d70446851607184b4a0b371e0c392d2..b098597c52536ad218c6ecfe5c672b8ab905eac6 100644
--- a/Marlin/macros.h
+++ b/Marlin/macros.h
@@ -55,7 +55,8 @@
#endif
#define RADIANS(d) ((d)*M_PI/180.0)
#define DEGREES(r) ((r)*180.0/M_PI)
-#define HYPOT(x,y) sqrt(sq(x)+sq(y))
+#define HYPOT2(x,y) (sq(x)+sq(y))
+#define HYPOT(x,y) sqrt(HYPOT2(x,y))
// Macros to contrain values
#define NOLESS(v,n) do{ if (v < n) v = n; }while(0)
@@ -124,4 +125,8 @@
#define MAX3(a, b, c) max(max(a, b), c)
#define MAX4(a, b, c, d) max(max(max(a, b), c), d)
+#define UNEAR_ZERO(x) ((x) < 0.000001)
+#define NEAR_ZERO(x) ((x) > -0.000001 && (x) < 0.000001)
+#define NEAR(x,y) NEAR_ZERO((x)-(y))
+
#endif //__MACROS_H
diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp
index bcad2c9069abec93eea8004308771ca579e70522..93084792f17456a7c920bdeba18ad35b1884c7fe 100644
--- a/Marlin/planner.cpp
+++ b/Marlin/planner.cpp
@@ -98,7 +98,7 @@ float Planner::min_feedrate_mm_s,
Planner::max_e_jerk,
Planner::min_travel_feedrate_mm_s;
-#if ENABLED(AUTO_BED_LEVELING_FEATURE)
+#if ENABLED(AUTO_BED_LEVELING_LINEAR)
matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
#endif
@@ -138,7 +138,7 @@ void Planner::init() {
memset(position, 0, sizeof(position)); // clear position
LOOP_XYZE(i) previous_speed[i] = 0.0;
previous_nominal_speed = 0.0;
- #if ENABLED(AUTO_BED_LEVELING_FEATURE)
+ #if ENABLED(AUTO_BED_LEVELING_LINEAR)
bed_level_matrix.set_to_identity();
#endif
}
@@ -521,37 +521,51 @@ void Planner::check_axes_activity() {
#endif
}
-#if ENABLED(AUTO_BED_LEVELING_FEATURE) || ENABLED(MESH_BED_LEVELING)
+#if PLANNER_LEVELING
- void Planner::apply_leveling(
+ void Planner::apply_leveling(float &lx, float &ly, float &lz) {
#if ENABLED(MESH_BED_LEVELING)
- const float &x, const float &y
- #else
- float &x, float &y
+
+ if (mbl.active())
+ lz += mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly));
+
+ #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
+
+ float dx = RAW_X_POSITION(lx) - (X_TILT_FULCRUM),
+ dy = RAW_Y_POSITION(ly) - (Y_TILT_FULCRUM),
+ dz = RAW_Z_POSITION(lz);
+
+ apply_rotation_xyz(bed_level_matrix, dx, dy, dz);
+
+ lx = LOGICAL_X_POSITION(dx + X_TILT_FULCRUM);
+ ly = LOGICAL_Y_POSITION(dy + Y_TILT_FULCRUM);
+ lz = LOGICAL_Z_POSITION(dz);
+
#endif
- , float &z
- ) {
+ }
+
+ void Planner::unapply_leveling(float &lx, float &ly, float &lz) {
#if ENABLED(MESH_BED_LEVELING)
if (mbl.active())
- z += mbl.get_z(RAW_X_POSITION(x), RAW_Y_POSITION(y));
+ lz -= mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly));
+
+ #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
- #elif ENABLED(AUTO_BED_LEVELING_FEATURE)
+ matrix_3x3 inverse = matrix_3x3::transpose(bed_level_matrix);
- float tx = RAW_X_POSITION(x) - (X_TILT_FULCRUM),
- ty = RAW_Y_POSITION(y) - (Y_TILT_FULCRUM),
- tz = RAW_Z_POSITION(z);
+ float dx = lx - (X_TILT_FULCRUM), dy = ly - (Y_TILT_FULCRUM), dz = lz;
- apply_rotation_xyz(bed_level_matrix, tx, ty, tz);
+ apply_rotation_xyz(inverse, dx, dy, dz);
- x = LOGICAL_X_POSITION(tx + X_TILT_FULCRUM);
- y = LOGICAL_Y_POSITION(ty + Y_TILT_FULCRUM);
- z = LOGICAL_Z_POSITION(tz);
+ lx = LOGICAL_X_POSITION(dx + X_TILT_FULCRUM);
+ ly = LOGICAL_Y_POSITION(dy + Y_TILT_FULCRUM);
+ lz = LOGICAL_Z_POSITION(dz);
#endif
}
-#endif
+#endif // PLANNER_LEVELING
/**
* Planner::buffer_line
@@ -562,15 +576,7 @@ void Planner::check_axes_activity() {
* fr_mm_s - (target) speed of the move
* extruder - target extruder
*/
-
-void Planner::buffer_line(
- #if ENABLED(AUTO_BED_LEVELING_FEATURE) || ENABLED(MESH_BED_LEVELING)
- float x, float y, float z
- #else
- const float& x, const float& y, const float& z
- #endif
- , const float& e, float fr_mm_s, const uint8_t extruder
-) {
+void Planner::buffer_line(ARG_X, ARG_Y, ARG_Z, const float &e, float fr_mm_s, const uint8_t extruder) {
// Calculate the buffer head after we push this byte
int next_buffer_head = next_block_index(block_buffer_head);
@@ -578,17 +584,17 @@ void Planner::buffer_line(
// Rest here until there is room in the buffer.
while (block_buffer_tail == next_buffer_head) idle();
- #if ENABLED(MESH_BED_LEVELING) || ENABLED(AUTO_BED_LEVELING_FEATURE)
- apply_leveling(x, y, z);
+ #if PLANNER_LEVELING
+ apply_leveling(lx, ly, lz);
#endif
// The target position of the tool in absolute steps
// Calculate target position in absolute steps
//this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
long target[NUM_AXIS] = {
- lround(x * axis_steps_per_mm[X_AXIS]),
- lround(y * axis_steps_per_mm[Y_AXIS]),
- lround(z * axis_steps_per_mm[Z_AXIS]),
+ lround(lx * axis_steps_per_mm[X_AXIS]),
+ lround(ly * axis_steps_per_mm[Y_AXIS]),
+ lround(lz * axis_steps_per_mm[Z_AXIS]),
lround(e * axis_steps_per_mm[E_AXIS])
};
@@ -598,11 +604,22 @@ void Planner::buffer_line(
/*
SERIAL_ECHO_START;
- SERIAL_ECHOPAIR("Planner X:", x);
- SERIAL_ECHOPAIR(" (", dx);
- SERIAL_ECHOPAIR(") Y:", y);
+ SERIAL_ECHOPGM("Planner ", x);
+ #if IS_KINEMATIC
+ SERIAL_ECHOPAIR("A:", x);
+ SERIAL_ECHOPAIR(" (", dx);
+ SERIAL_ECHOPAIR(") B:", y);
+ #else
+ SERIAL_ECHOPAIR("X:", x);
+ SERIAL_ECHOPAIR(" (", dx);
+ SERIAL_ECHOPAIR(") Y:", y);
+ #endif
SERIAL_ECHOPAIR(" (", dy);
- SERIAL_ECHOPAIR(") Z:", z);
+ #elif ENABLED(DELTA)
+ SERIAL_ECHOPAIR(") C:", z);
+ #else
+ SERIAL_ECHOPAIR(") Z:", z);
+ #endif
SERIAL_ECHOPAIR(" (", dz);
SERIAL_ECHOLNPGM(")");
//*/
@@ -671,7 +688,7 @@ void Planner::buffer_line(
// For a mixing extruder, get a magnified step_event_count for each
#if ENABLED(MIXING_EXTRUDER)
for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
- block->mix_event_count[i] = (mixing_factor[i] < 0.0001) ? 0 : block->step_event_count / mixing_factor[i];
+ block->mix_event_count[i] = UNEAR_ZERO(mixing_factor[i]) ? 0 : block->step_event_count / mixing_factor[i];
#endif
#if FAN_COUNT > 0
@@ -1124,7 +1141,7 @@ void Planner::buffer_line(
block->advance_rate = acc_dist ? advance / (float)acc_dist : 0;
}
/**
- SERIAL_ECHO_START;
+ SERIAL_ECHO_START;
SERIAL_ECHOPGM("advance :");
SERIAL_ECHO(block->advance/256.0);
SERIAL_ECHOPGM("advance rate :");
@@ -1152,22 +1169,15 @@ void Planner::buffer_line(
*
* On CORE machines stepper ABC will be translated from the given XYZ.
*/
-void Planner::set_position_mm(
- #if ENABLED(AUTO_BED_LEVELING_FEATURE) || ENABLED(MESH_BED_LEVELING)
- float x, float y, float z
- #else
- const float& x, const float& y, const float& z
- #endif
- , const float& e
-) {
+void Planner::set_position_mm(ARG_X, ARG_Y, ARG_Z, const float &e) {
- #if ENABLED(MESH_BED_LEVELING) || ENABLED(AUTO_BED_LEVELING_FEATURE)
- apply_leveling(x, y, z);
+ #if PLANNER_LEVELING
+ apply_leveling(lx, ly, lz);
#endif
- long nx = position[X_AXIS] = lround(x * axis_steps_per_mm[X_AXIS]),
- ny = position[Y_AXIS] = lround(y * axis_steps_per_mm[Y_AXIS]),
- nz = position[Z_AXIS] = lround(z * axis_steps_per_mm[Z_AXIS]),
+ long nx = position[X_AXIS] = lround(lx * axis_steps_per_mm[X_AXIS]),
+ ny = position[Y_AXIS] = lround(ly * axis_steps_per_mm[Y_AXIS]),
+ nz = position[Z_AXIS] = lround(lz * axis_steps_per_mm[Z_AXIS]),
ne = position[E_AXIS] = lround(e * axis_steps_per_mm[E_AXIS]);
stepper.set_position(nx, ny, nz, ne);
previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
@@ -1193,7 +1203,7 @@ void Planner::reset_acceleration_rates() {
// Recalculate position, steps_to_mm if axis_steps_per_mm changes!
void Planner::refresh_positioning() {
LOOP_XYZE(i) steps_to_mm[i] = 1.0 / axis_steps_per_mm[i];
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
inverse_kinematics(current_position);
set_position_mm(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS]);
#else
diff --git a/Marlin/planner.h b/Marlin/planner.h
index ecca0fd3fc62750d0e83b34ae6fee98165f379be..e38e9e5f03200c2318aceee2b3311eecf78a1999 100644
--- a/Marlin/planner.h
+++ b/Marlin/planner.h
@@ -202,39 +202,45 @@ class Planner {
static bool is_full() { return (block_buffer_tail == BLOCK_MOD(block_buffer_head + 1)); }
#if ENABLED(AUTO_BED_LEVELING_FEATURE) || ENABLED(MESH_BED_LEVELING)
+ #define ARG_X float lx
+ #define ARG_Y float ly
+ #define ARG_Z float lz
+ #else
+ #define ARG_X const float &lx
+ #define ARG_Y const float &ly
+ #define ARG_Z const float &lz
+ #endif
- #if ENABLED(MESH_BED_LEVELING)
- static void apply_leveling(const float &x, const float &y, float &z);
- #else
- static void apply_leveling(float &x, float &y, float &z);
- #endif
+ #if PLANNER_LEVELING
/**
- * Add a new linear movement to the buffer.
- *
- * x,y,z,e - target position in mm
- * fr_mm_s - (target) speed of the move (mm/s)
- * extruder - target extruder
+ * Apply leveling to transform a cartesian position
+ * as it will be given to the planner and steppers.
*/
- static void buffer_line(float x, float y, float z, const float& e, float fr_mm_s, const uint8_t extruder);
+ static void apply_leveling(float &lx, float &ly, float &lz);
+ static void unapply_leveling(float &lx, float &ly, float &lz);
- /**
- * Set the planner.position and individual stepper positions.
- * Used by G92, G28, G29, and other procedures.
- *
- * Multiplies by axis_steps_per_mm[] and does necessary conversion
- * for COREXY / COREXZ / COREYZ to set the corresponding stepper positions.
- *
- * Clears previous speed values.
- */
- static void set_position_mm(float x, float y, float z, const float& e);
-
- #else
+ #endif
- static void buffer_line(const float& x, const float& y, const float& z, const float& e, float fr_mm_s, const uint8_t extruder);
- static void set_position_mm(const float& x, const float& y, const float& z, const float& e);
+ /**
+ * Add a new linear movement to the buffer.
+ *
+ * x,y,z,e - target position in mm
+ * fr_mm_s - (target) speed of the move (mm/s)
+ * extruder - target extruder
+ */
+ static void buffer_line(ARG_X, ARG_Y, ARG_Z, const float& e, float fr_mm_s, const uint8_t extruder);
- #endif // AUTO_BED_LEVELING_FEATURE || MESH_BED_LEVELING
+ /**
+ * Set the planner.position and individual stepper positions.
+ * Used by G92, G28, G29, and other procedures.
+ *
+ * Multiplies by axis_steps_per_mm[] and does necessary conversion
+ * for COREXY / COREXZ / COREYZ to set the corresponding stepper positions.
+ *
+ * Clears previous speed values.
+ */
+ static void set_position_mm(ARG_X, ARG_Y, ARG_Z, const float& e);
/**
* Set the E position (mm) of the planner (and the E stepper)
diff --git a/Marlin/planner_bezier.cpp b/Marlin/planner_bezier.cpp
index 6ca7afd1d6b6f27f7dc3b966d409df9ffcd5aa7c..15c80916351a992e8b2bca3090f6047775cce918 100644
--- a/Marlin/planner_bezier.cpp
+++ b/Marlin/planner_bezier.cpp
@@ -188,7 +188,7 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
bez_target[E_AXIS] = interp(position[E_AXIS], target[E_AXIS], t);
clamp_to_software_endstops(bez_target);
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
inverse_kinematics(bez_target);
#if ENABLED(DELTA) && ENABLED(AUTO_BED_LEVELING_FEATURE)
adjust_delta(bez_target);
diff --git a/Marlin/qr_solve.cpp b/Marlin/qr_solve.cpp
index ddafb005eaddeff95617c02845e2f42e38fc4825..e60b1d3274bf9d090d7b37badb0453103c8b3d45 100644
--- a/Marlin/qr_solve.cpp
+++ b/Marlin/qr_solve.cpp
@@ -22,7 +22,7 @@
#include "qr_solve.h"
-#if ENABLED(AUTO_BED_LEVELING_GRID)
+#if ENABLED(AUTO_BED_LEVELING_LINEAR)
#include <stdlib.h>
#include <math.h>
diff --git a/Marlin/stepper.h b/Marlin/stepper.h
index 4a2287c7d7207c1d3cea6f5d18469931cf1ea788..d7507aff2c9204301dd1c27311b917e3ebfcf4ef 100644
--- a/Marlin/stepper.h
+++ b/Marlin/stepper.h
@@ -91,6 +91,11 @@ class Stepper {
static bool performing_homing;
#endif
+ //
+ // Positions of stepper motors, in step units
+ //
+ static volatile long count_position[NUM_AXIS];
+
private:
static unsigned char last_direction_bits; // The next stepping-bits to be output
@@ -138,11 +143,6 @@ class Stepper {
static constexpr int motor_current_setting[3] = PWM_MOTOR_CURRENT;
#endif
- //
- // Positions of stepper motors, in step units
- //
- static volatile long count_position[NUM_AXIS];
-
//
// Current direction of stepper motors (+1 or -1)
//
@@ -211,6 +211,13 @@ class Stepper {
//
static float get_axis_position_mm(AxisEnum axis);
+ //
+ // SCARA AB axes are in degrees, not mm
+ //
+ #if IS_SCARA
+ static FORCE_INLINE float get_axis_position_degrees(AxisEnum axis) { return get_axis_position_mm(axis); }
+ #endif
+
//
// The stepper subsystem goes to sleep when it runs out of things to execute. Call this
// to notify the subsystem that it is time to go to work.
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index f5459757dbb614eac7c25fb846843fd9ee3a34a3..55247c15d56fbec7a157d4d722265e392a9be73a 100755
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -1418,7 +1418,7 @@ void kill_screen(const char* lcd_msg) {
*
*/
- #if ENABLED(DELTA) || ENABLED(SCARA)
+ #if IS_KINEMATIC
#define _MOVE_XYZ_ALLOWED (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
#else
#define _MOVE_XYZ_ALLOWED true
@@ -1823,7 +1823,7 @@ void kill_screen(const char* lcd_msg) {
#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &stepper.abort_on_endstop_hit);
#endif
- #if ENABLED(SCARA)
+ #if IS_SCARA
MENU_ITEM_EDIT(float74, MSG_XSCALE, &axis_scaling[X_AXIS], 0.5, 2);
MENU_ITEM_EDIT(float74, MSG_YSCALE, &axis_scaling[Y_AXIS], 0.5, 2);
#endif