diff --git a/Marlin/Conditionals_post.h b/Marlin/Conditionals_post.h index 239780f34..9861c2b29 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 f6df89a85..cdf223d11 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 da9bc0de9..d34445ac4 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 a1b3349fe..3bb2a822e 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 4ea114504..bbc92e9f6 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 Line number of the command, if any + * P Planner space remaining + * B 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 0234baee1..6a3433e38 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 f54cd88a2..0dd1ce6da 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 ded1be6ec..18db5a6f5 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 0763b3382..fb5a2ebca 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 a24bca1a2..6ebe50e92 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 7b826b527..71139893f 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 deb626292..4a426c6ac 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 d57fcea93..34d12ec22 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 7a8426981..463f17382 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 faebf06ff..191f1b824 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 085880e21..3c2e96a69 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 a6d33e8aa..7bc888025 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 6252c2796..7d420646a 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 7b826b527..71139893f 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 bbafe89f6..b4efc0016 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 3345f32ec..2960f8413 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 97a1712c8..9936c54e5 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 2203ee794..9c82b1fb0 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 453281985..fc68cbcef 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 addfc7acd..7e9d002f8 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 1e8e626cc..e6f1a7f25 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 e6c1b8efd..6311e6c60 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 a0443f4d5..b1b8e0af7 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 351272804..b098597c5 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 bcad2c906..93084792f 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 ecca0fd3f..e38e9e5f0 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 6ca7afd1d..15c809163 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 ddafb005e..e60b1d327 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 #include diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 4a2287c7d..d7507aff2 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 f5459757d..55247c15d 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