From 4aa5a7530109e24ac7b85c0351a75f4131bfc940 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Thu, 7 May 2020 11:03:08 -0500 Subject: [PATCH 01/10] Enhance arc interpolation and add M214 for controlling arc interpolation settings. --- Firmware/ConfigurationStore.cpp | 15 +- Firmware/ConfigurationStore.h | 5 + Firmware/Configuration_adv.h | 4 +- Firmware/Marlin_main.cpp | 102 +++++++- Firmware/motion_control.cpp | 242 ++++++++++-------- Firmware/motion_control.h | 4 +- .../variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h | 8 + .../variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h | 8 + .../1_75mm_MK25S-RAMBo10a-E3Dv6full.h | 8 + .../1_75mm_MK25S-RAMBo13a-E3Dv6full.h | 8 + .../variants/1_75mm_MK3-EINSy10a-E3Dv6full.h | 8 + .../variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h | 8 + .../obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h | 8 + .../obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h | 8 + 14 files changed, 306 insertions(+), 130 deletions(-) mode change 100755 => 100644 Firmware/Marlin_main.cpp diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 92ee6429..ea2dcc47 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -169,6 +169,10 @@ void Config_PrintSettings(uint8_t level) echomagic, echomagic, extruder_advance_K); #endif //LIN_ADVANCE } + // Arc Interpolation Settings + printf_P(PSTR( + "%SArc Settings: N=Arc segment length max (mm) S=Arc segment length Min (mm), R=Min arc segments, F=Arc segments per second.\n%S M214 N%.2f S%.2f R%d F%d\n"), + echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.min_arc_segments, cs.arc_segments_per_sec); } #endif @@ -184,7 +188,7 @@ static_assert (false, "zprobe_zoffset was not initialized in printers in field t "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf"); #endif -static_assert (sizeof(M500_conf) == 196, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, " +static_assert (sizeof(M500_conf) == 208, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, " "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized." "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM," "leave as it is to keep fast code, or reorder struct members to pack more tightly."); @@ -233,6 +237,10 @@ static const M500_conf default_conf PROGMEM = {16,16,16,16}, #endif DEFAULT_TRAVEL_ACCELERATION, + DEFAULT_MM_PER_ARC_SEGMENT, + DEFAULT_MIN_MM_PER_ARC_SEGMENT, + DEFAULT_MIN_ARC_SEGMENTS, + DEFAULT_ARC_SEGMENTS_PER_SEC }; @@ -273,6 +281,11 @@ bool Config_RetrieveSettings() memcpy_P(&cs.max_acceleration_units_per_sq_second_silent[i],&default_conf.max_acceleration_units_per_sq_second_silent[i],sizeof(cs.max_acceleration_units_per_sq_second_silent[i])); } } + // Initialize arc interpolation settings if they are not already (Not sure about this bit, please review) + if (0xff == cs.mm_per_arc_segment) cs.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; + if (0xff == cs.min_mm_per_arc_segment) cs.min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; + if (0xff == cs.min_arc_segments) cs.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; + if (0xff == cs.arc_segments_per_sec) cs.arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; #ifdef TMC2130 for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index 3e3caf72..26a835a2 100644 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -39,6 +39,11 @@ typedef struct unsigned long max_acceleration_units_per_sq_second_silent[4]; unsigned char axis_ustep_resolution[4]; float travel_acceleration; //!< travel acceleration mm/s^2 + // Arc Interpolation Settings, configurable via M214 + float mm_per_arc_segment; + float min_mm_per_arc_segment; + int min_arc_segments; // If less than or equal to zero, this is disabled + int arc_segments_per_sec; // If less than or equal to zero, this is disabled } M500_conf; extern M500_conf cs; diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 8b846752..769a28c7 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -289,9 +289,7 @@ //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging #endif -// Arc interpretation settings: -#define MM_PER_ARC_SEGMENT 1 -#define N_ARC_CORRECTION 25 +// Arc interpretation settings : Moded to printer default settings (Configuration_prusa.h) const unsigned int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp old mode 100755 new mode 100644 index db1d0b53..eedcf3fa --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7502,9 +7502,88 @@ Sigma_Exit: } }break; -#endif // FWRETRACT + #endif // FWRETRACT + /*! + ### M214 - Set Arc configuration values (Use M500 to store in eeprom) + #### Usage + M214 [N] [S] [R] [F] + + #### Parameters + - `N` - A float representing the max and default millimeters per arc segment. Must be greater than 0. + - `S` - A float representing the minimum allowable millimeters per arc segment. Set to 0 to disable + - `R` - An int representing the minimum number of segments per arcs of any radius, + except when the results in segment lengths greater than or less than the minimum + and maximum segment length. Set to 0 to disable. + - 'F' - An int representing the number of segments per second, unless this results in segment lengths + greater than or less than the minimum and maximum segment length. Set to 0 to disable. + */ + case 214: //!@n M214 - Set Arc Parameters (Use M500 to store in eeprom) N S R F + { + // Extract N + float n = cs.mm_per_arc_segment; + float s = cs.min_mm_per_arc_segment; + int r = cs.min_arc_segments; + int f = cs.arc_segments_per_sec; + // Extract N + if (code_seen('N')) + { + n = code_value(); + if (n <= 0 || (s != 0 && n <= s)) + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(1)"); + break; + } + } + // Extract S + if (code_seen('S')) + { + s = code_value(); + if (s < 0 || s >= n) + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(1)"); + break; + } + } + // Extract R + if (code_seen('R')) + { + + r = code_value(); + if (r < 0) + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(1)"); + break; + } + } + // Extract F + if (code_seen('F')) + { + f = code_value(); + if (f < 0) + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(1)"); + break; + } + } + cs.mm_per_arc_segment = n; + cs.min_mm_per_arc_segment = s; + cs.min_arc_segments = r; + cs.arc_segments_per_sec = f; + }break; #if EXTRUDERS > 1 /*! @@ -9641,18 +9720,15 @@ void prepare_move() set_current_to_destination(); } -void prepare_arc_move(bool isclockwise) { - float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc - - // Trace the arc - mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder); - - // As far as the parser is concerned, the position is now == target. In reality the - // motion control system might still be processing the action and the real tool position - // in any intermediate location. - set_current_to_destination(); - - previous_millis_cmd.start(); +void prepare_arc_move(char isclockwise) { + float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc + // Trace the arc + mc_arc(current_position, destination, offset, feedrate * feedmultiply / 60 / 100.0, r, isclockwise, active_extruder); + // As far as the parser is concerned, the position is now == target. In reality the + // motion control system might still be processing the action and the real tool position + // in any intermediate location. + set_current_to_destination(); + previous_millis_cmd.start(); } #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 91d0bc64..3b52b4d5 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -4,7 +4,8 @@ Copyright (c) 2009-2011 Simen Svale Skogsrud Copyright (c) 2011 Sungeun K. Jeon - + Copyright (c) 2020 Brad Hochgesang + Grbl is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -25,121 +26,140 @@ // The arc is approximated by generating a huge number of tiny, linear segments. The length of each // segment is configured in settings.mm_per_arc_segment. -void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1, - uint8_t axis_linear, float feed_rate, float radius, bool isclockwise, uint8_t extruder) -{ - // int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled(); - // plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc - float center_axis0 = position[axis_0] + offset[axis_0]; - float center_axis1 = position[axis_1] + offset[axis_1]; - float linear_travel = target[axis_linear] - position[axis_linear]; - float extruder_travel = target[E_AXIS] - position[E_AXIS]; - float r_axis0 = -offset[axis_0]; // Radius vector from center to current location - float r_axis1 = -offset[axis_1]; - float rt_axis0 = target[axis_0] - center_axis0; - float rt_axis1 = target[axis_1] - center_axis1; - - // CCW angle between position and target from circle center. Only one atan2() trig computation required. - float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1); - if (angular_travel < 0) { angular_travel += 2*M_PI; } - if (isclockwise) { angular_travel -= 2*M_PI; } - - //20141002:full circle for G03 did not work, e.g. G03 X80 Y80 I20 J0 F2000 is giving an Angle of zero so head is not moving - //to compensate when start pos = target pos && angle is zero -> angle = 2Pi - if (position[axis_0] == target[axis_0] && position[axis_1] == target[axis_1] && angular_travel == 0) - { - angular_travel += 2*M_PI; - } - //end fix G03 - - float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel)); - if (millimeters_of_travel < 0.001) { return; } - uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT); - if(segments == 0) segments = 1; - - /* - // Multiply inverse feed_rate to compensate for the fact that this movement is approximated - // by a number of discrete segments. The inverse feed_rate should be correct for the sum of - // all segments. - if (invert_feed_rate) { feed_rate *= segments; } - */ - float theta_per_segment = angular_travel/segments; - float linear_per_segment = linear_travel/segments; - float extruder_per_segment = extruder_travel/segments; - - /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, - and phi is the angle of rotation. Based on the solution approach by Jens Geisler. - r_T = [cos(phi) -sin(phi); - sin(phi) cos(phi] * r ; - - For arc generation, the center of the circle is the axis of rotation and the radius vector is - defined from the circle center to the initial position. Each line segment is formed by successive - vector rotations. This requires only two cos() and sin() computations to form the rotation - matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since - all double numbers are single precision on the Arduino. (True double precision will not have - round off issues for CNC applications.) Single precision error can accumulate to be greater than - tool precision in some cases. Therefore, arc path correction is implemented. +void mc_arc(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder) +{ + // Extract the position to reduce indexing at the cost of a few bytes of mem + float p_x = position[X_AXIS]; + float p_y = position[Y_AXIS]; + float p_z = position[Z_AXIS]; + float p_e = position[E_AXIS]; - Small angle approximation may be used to reduce computation overhead further. This approximation - holds for everything, but very small circles and large mm_per_arc_segment values. In other words, - theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large - to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for - numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an - issue for CNC machines with the single precision Arduino calculations. - - This approximation also allows mc_arc to immediately insert a line segment into the planner - without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied - a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead. - This is important when there are successive arc motions. - */ - // Vector rotation matrix values - float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation - float sin_T = theta_per_segment; - - float arc_target[4]; - float sin_Ti; - float cos_Ti; - float r_axisi; - uint16_t i; - int8_t count = 0; + float t_x = target[X_AXIS]; + float t_y = target[Y_AXIS]; + float t_z = target[Z_AXIS]; + float t_e = target[E_AXIS]; - // Initialize the linear axis - arc_target[axis_linear] = position[axis_linear]; - - // Initialize the extruder axis - arc_target[E_AXIS] = position[E_AXIS]; + float r_axis_x = -offset[X_AXIS]; // Radius vector from center to current location + float r_axis_y = -offset[Y_AXIS]; + float center_axis_x = p_x - r_axis_x; + float center_axis_y = p_y - r_axis_y; + float travel_z = t_z - p_z; + float extruder_travel_total = t_e - p_e; - for (i = 1; i 0) + { + // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation + // Do this before converting the angular travel for clockwise rotation + mm_per_arc_segment = radius * ((2.0f * M_PI) / cs.min_arc_segments); + check_mm_per_arc_segment_max = true; } - // Update arc_target location - arc_target[axis_0] = center_axis0 + r_axis0; - arc_target[axis_1] = center_axis1 + r_axis1; - arc_target[axis_linear] += linear_per_segment; - arc_target[E_AXIS] += extruder_per_segment; + if (cs.arc_segments_per_sec > 0) + { + // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation + float mm_per_arc_segment_sec = (feed_rate / 60.0f) * (1.0f / cs.arc_segments_per_sec); + if (mm_per_arc_segment_sec < mm_per_arc_segment) + mm_per_arc_segment = mm_per_arc_segment_sec; + check_mm_per_arc_segment_max = true; + } - clamp_to_software_endstops(arc_target); - plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, extruder); - - } - // Ensure last segment arrives at target location. - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder); + if (cs.min_mm_per_arc_segment > 0) + { + check_mm_per_arc_segment_max = true; + // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined + // This prevents a very high number of segments from being generated for curves of a short radius + if (mm_per_arc_segment < cs.min_mm_per_arc_segment) mm_per_arc_segment = cs.min_mm_per_arc_segment; + } - // plan_set_acceleration_manager_enabled(acceleration_manager_was_enabled); + if (check_mm_per_arc_segment_max && mm_per_arc_segment > cs.mm_per_arc_segment) mm_per_arc_segment = cs.mm_per_arc_segment; + + + + // Adjust the angular travel if the direction is clockwise + if (isclockwise) { angular_travel_total -= 2 * M_PI; } + + //20141002:full circle for G03 did not work, e.g. G03 X80 Y80 I20 J0 F2000 is giving an Angle of zero so head is not moving + //to compensate when start pos = target pos && angle is zero -> angle = 2Pi + if (p_x == t_x && p_y == t_y && angular_travel_total == 0) + { + angular_travel_total += 2 * M_PI; + } + //end fix G03 + + // 20200417 - FormerLurker - rename millimeters_of_travel to millimeters_of_travel_arc to better describe what we are + // calculating here + float millimeters_of_travel_arc = hypot(angular_travel_total * radius, fabs(travel_z)); + if (millimeters_of_travel_arc < 0.001) { return; } + // Calculate the total travel per segment + // Calculate the number of arc segments + uint16_t segments = static_cast(ceil(millimeters_of_travel_arc / mm_per_arc_segment)); + + + // Calculate theta per segments and linear (z) travel per segment + float theta_per_segment = angular_travel_total / segments; + float linear_per_segment = travel_z / (segments); + // Calculate the extrusion amount per segment + float segment_extruder_travel = extruder_travel_total / (segments); + /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, + and phi is the angle of rotation. Based on the solution approach by Jens Geisler. + r_T = [cos(phi) -sin(phi); + sin(phi) cos(phi] * r ; + + For arc generation, the center of the circle is the axis of rotation and the radius vector is + defined from the circle center to the initial position. Each line segment is formed by successive + vector rotations. This requires only two cos() and sin() computations to form the rotation + matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since + all double numbers are single precision on the Arduino. (True double precision will not have + round off issues for CNC applications.) Single precision error can accumulate to be greater than + tool precision in some cases. Therefore, arc path correction is implemented. + + The small angle approximation was removed because of excessive errors for small circles (perhaps unique to + 3d printing applications, causing significant path deviation and extrusion issues). + Now there will be no corrections applied, but an accurate initial sin and cos will be calculated. + This seems to work with a very high degree of accuracy and results in much simpler code. + + Finding a faster way to approximate sin, knowing that there can be substantial deviations from the true + arc when using the previous approximation, would be beneficial. + */ + + // Don't bother calculating cot_T or sin_T if there is only 1 segment. + if (segments > 1) + { + // Initialize the extruder axis + + float cos_T = cos(theta_per_segment); + float sin_T = sin(theta_per_segment); + float r_axisi; + uint16_t i; + + for (i = 1; i < segments; i++) { // Increment (segments-1) + r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; + r_axis_x = r_axis_x * cos_T - r_axis_y * sin_T; + r_axis_y = r_axisi; + + // Update arc_target location + p_x = center_axis_x + r_axis_x; + p_y = center_axis_y + r_axis_y; + p_z += linear_per_segment; + p_e += segment_extruder_travel; + // We can't clamp to the target because we are interpolating! We would need to update a position, clamp to it + // after updating from calculated values. + //clamp_to_software_endstops(position); + plan_buffer_line(p_x, p_y, p_z, p_e, feed_rate, extruder); + } + } + // Ensure last segment arrives at target location. + // Here we could clamp, but why bother. We would need to update our current position, clamp to it + //clamp_to_software_endstops(target); + plan_buffer_line(t_x, t_y, t_z, t_e, feed_rate, extruder); } - diff --git a/Firmware/motion_control.h b/Firmware/motion_control.h index 8f5f6fff..95186cba 100644 --- a/Firmware/motion_control.h +++ b/Firmware/motion_control.h @@ -26,7 +26,7 @@ // offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is // the direction of helical travel, radius == circle radius, isclockwise boolean. Used // for vector transformation direction. -void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1, - uint8_t axis_linear, float feed_rate, float radius, bool isclockwise, uint8_t extruder); +void mc_arc(float *position, float *target, float *offset, float feed_rate, float radius, + unsigned char isclockwise, uint8_t extruder); #endif diff --git a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h index e26f5ea6..741ba725 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h @@ -525,4 +525,12 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h index 00c937db..0ea0d37f 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h @@ -529,4 +529,12 @@ //#define HEATBED_ANALYSIS //for meash bed leveling and heatbed analysis D-codes D80 and D81 //#define MICROMETER_LOGGING //related to D-codes D80 and D81, currently works on MK2.5 only (MK3 board pin definitions missing) +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h index 7b7149ba..e88f9834 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h @@ -532,4 +532,12 @@ //#define MMU_ALWAYS_CUT #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h index 51644aaf..bd4b8904 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h @@ -533,4 +533,12 @@ //#define MMU_ALWAYS_CUT #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h index dd4f1ffd..da35f7af 100644 --- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h @@ -671,4 +671,12 @@ #define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h index dbc92ac0..f1e5cea8 100644 --- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h @@ -683,4 +683,12 @@ //#define MMU_ALWAYS_CUT #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h index c3aa75d7..266a9523 100644 --- a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h @@ -449,4 +449,12 @@ THERMISTORS SETTINGS #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h index 0158d600..1122939e 100644 --- a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h @@ -438,4 +438,12 @@ THERMISTORS SETTINGS #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning +// Default Arc Interpolation Settings (Now configurable via M214) +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than + MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. +#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. + #endif //__CONFIGURATION_PRUSA_H From 58d9916d548ed6aa63c0abee488e97c885a4af1b Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Thu, 7 May 2020 15:49:44 -0500 Subject: [PATCH 02/10] Make suggested corrections. --- Firmware/ConfigurationStore.cpp | 12 ++++++---- Firmware/ConfigurationStore.h | 5 ++-- Firmware/Marlin_main.cpp | 42 +++++++++++---------------------- Firmware/motion_control.cpp | 41 ++++++++++++-------------------- 4 files changed, 38 insertions(+), 62 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index ea2dcc47..1ad9d1e0 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -171,7 +171,7 @@ void Config_PrintSettings(uint8_t level) } // Arc Interpolation Settings printf_P(PSTR( - "%SArc Settings: N=Arc segment length max (mm) S=Arc segment length Min (mm), R=Min arc segments, F=Arc segments per second.\n%S M214 N%.2f S%.2f R%d F%d\n"), + "%SArc Settings: P=Arc segment length max (mm) S=Arc segment length Min (mm), R=Min arc segments, F=Arc segments per second.\n%S M214 P%.2f S%.2f R%d F%d\n"), echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.min_arc_segments, cs.arc_segments_per_sec); } #endif @@ -282,10 +282,11 @@ bool Config_RetrieveSettings() } } // Initialize arc interpolation settings if they are not already (Not sure about this bit, please review) - if (0xff == cs.mm_per_arc_segment) cs.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; - if (0xff == cs.min_mm_per_arc_segment) cs.min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; - if (0xff == cs.min_arc_segments) cs.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; - if (0xff == cs.arc_segments_per_sec) cs.arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; + if (is_uninitialized(cs.mm_per_arc_segment, sizeof(float))) cs.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; + if (is_uninitialized(cs.min_mm_per_arc_segment, sizeof(float))) cs.min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; + if (is_uninitialized(cs.min_arc_segments, sizeof(uint16_t))) cs.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; + if (is_uninitialized(cs.arc_segments_per_sec, sizeof(uint16_t))) cs.arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; + #ifdef TMC2130 for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) @@ -357,3 +358,4 @@ SERIAL_ECHO_START; SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded"); } + diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index 26a835a2..bf768db3 100644 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -42,8 +42,8 @@ typedef struct // Arc Interpolation Settings, configurable via M214 float mm_per_arc_segment; float min_mm_per_arc_segment; - int min_arc_segments; // If less than or equal to zero, this is disabled - int arc_segments_per_sec; // If less than or equal to zero, this is disabled + uint16_t min_arc_segments; // If less than or equal to zero, this is disabled + uint16_t arc_segments_per_sec; // If less than or equal to zero, this is disabled } M500_conf; extern M500_conf cs; @@ -67,5 +67,4 @@ FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_Prin inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); } inline void calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); } inline bool calibration_status_pinda() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); } - #endif//CONFIG_STORE_H diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index eedcf3fa..7de7fe61 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -4162,6 +4162,7 @@ extern uint8_t st_backlash_y; //!@n M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting //!@n M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] //!@n M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. +//!@n M214 - Set Arc Parameters (Use M500 to store in eeprom) P S R F //!@n M218 - set hotend offset (in mm): T X Y //!@n M220 S- set speed factor override percentage //!@n M221 S- set extrude factor override percentage @@ -7508,10 +7509,10 @@ Sigma_Exit: #### Usage - M214 [N] [S] [R] [F] + M214 [P] [S] [R] [F] #### Parameters - - `N` - A float representing the max and default millimeters per arc segment. Must be greater than 0. + - `P` - A float representing the max and default millimeters per arc segment. Must be greater than 0. - `S` - A float representing the minimum allowable millimeters per arc segment. Set to 0 to disable - `R` - An int representing the minimum number of segments per arcs of any radius, except when the results in segment lengths greater than or less than the minimum @@ -7519,36 +7520,29 @@ Sigma_Exit: - 'F' - An int representing the number of segments per second, unless this results in segment lengths greater than or less than the minimum and maximum segment length. Set to 0 to disable. */ - case 214: //!@n M214 - Set Arc Parameters (Use M500 to store in eeprom) N S R F + case 214: //!@n M214 - Set Arc Parameters (Use M500 to store in eeprom) P S R F { // Extract N - float n = cs.mm_per_arc_segment; + float p = cs.mm_per_arc_segment; float s = cs.min_mm_per_arc_segment; - int r = cs.min_arc_segments; - int f = cs.arc_segments_per_sec; + uint16_t r = cs.min_arc_segments; + uint16_t f = cs.arc_segments_per_sec; + // Extract N - if (code_seen('N')) + if (code_seen('P')) { - n = code_value(); - if (n <= 0 || (s != 0 && n <= s)) + p = code_value_float(); + if (p <= 0 || (s != 0 && p <= s)) { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(1)"); break; } } // Extract S if (code_seen('S')) { - s = code_value(); - if (s < 0 || s >= n) + s = code_value_float(); + if (s < 0 || s >= p) { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(1)"); break; } } @@ -7559,10 +7553,6 @@ Sigma_Exit: r = code_value(); if (r < 0) { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(1)"); break; } } @@ -7572,14 +7562,10 @@ Sigma_Exit: f = code_value(); if (f < 0) { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(1)"); break; } } - cs.mm_per_arc_segment = n; + cs.mm_per_arc_segment = p; cs.min_mm_per_arc_segment = s; cs.min_arc_segments = r; cs.arc_segments_per_sec = f; diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 3b52b4d5..8524e2fc 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -28,26 +28,15 @@ // segment is configured in settings.mm_per_arc_segment. void mc_arc(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder) { - // Extract the position to reduce indexing at the cost of a few bytes of mem - float p_x = position[X_AXIS]; - float p_y = position[Y_AXIS]; - float p_z = position[Z_AXIS]; - float p_e = position[E_AXIS]; - - float t_x = target[X_AXIS]; - float t_y = target[Y_AXIS]; - float t_z = target[Z_AXIS]; - float t_e = target[E_AXIS]; - float r_axis_x = -offset[X_AXIS]; // Radius vector from center to current location float r_axis_y = -offset[Y_AXIS]; - float center_axis_x = p_x - r_axis_x; - float center_axis_y = p_y - r_axis_y; - float travel_z = t_z - p_z; - float extruder_travel_total = t_e - p_e; + float center_axis_x = position[X_AXIS] - r_axis_x; + float center_axis_y = position[Y_AXIS] - r_axis_y; + float travel_z = target[Z_AXIS] - position[Z_AXIS]; + float extruder_travel_total = target[E_AXIS] - position[E_AXIS]; - float rt_x = t_x - center_axis_x; - float rt_y = t_y - center_axis_y; + float rt_x = target[X_AXIS] - center_axis_x; + float rt_y = target[Y_AXIS] - center_axis_y; // 20200419 - Add a variable that will be used to hold the arc segment length float mm_per_arc_segment = cs.mm_per_arc_segment; @@ -90,7 +79,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa //20141002:full circle for G03 did not work, e.g. G03 X80 Y80 I20 J0 F2000 is giving an Angle of zero so head is not moving //to compensate when start pos = target pos && angle is zero -> angle = 2Pi - if (p_x == t_x && p_y == t_y && angular_travel_total == 0) + if (position[X_AXIS] == target[X_AXIS] && position[Y_AXIS] == target[Y_AXIS] && angular_travel_total == 0) { angular_travel_total += 2 * M_PI; } @@ -148,18 +137,18 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa r_axis_y = r_axisi; // Update arc_target location - p_x = center_axis_x + r_axis_x; - p_y = center_axis_y + r_axis_y; - p_z += linear_per_segment; - p_e += segment_extruder_travel; + position[X_AXIS] = center_axis_x + r_axis_x; + position[Y_AXIS] = center_axis_y + r_axis_y; + position[Z_AXIS] += linear_per_segment; + position[E_AXIS] += segment_extruder_travel; // We can't clamp to the target because we are interpolating! We would need to update a position, clamp to it // after updating from calculated values. - //clamp_to_software_endstops(position); - plan_buffer_line(p_x, p_y, p_z, p_e, feed_rate, extruder); + clamp_to_software_endstops(position); + plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder); } } // Ensure last segment arrives at target location. // Here we could clamp, but why bother. We would need to update our current position, clamp to it - //clamp_to_software_endstops(target); - plan_buffer_line(t_x, t_y, t_z, t_e, feed_rate, extruder); + clamp_to_software_endstops(target); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder); } From 6fc8155cbe8cedcf42af76bd287491eca21633f3 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Tue, 12 Jan 2021 15:44:39 -0600 Subject: [PATCH 03/10] Add n_arc_correction and enhanced small angle sin/cos approximation. --- Firmware/ConfigurationStore.cpp | 141 +++++++++--------- Firmware/ConfigurationStore.h | 5 +- Firmware/Marlin_main.cpp | 15 +- Firmware/motion_control.cpp | 37 ++++- .../variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h | 16 +- .../variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h | 16 +- .../1_75mm_MK25S-RAMBo10a-E3Dv6full.h | 16 +- .../1_75mm_MK25S-RAMBo13a-E3Dv6full.h | 16 +- .../variants/1_75mm_MK3-EINSy10a-E3Dv6full.h | 16 +- .../variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h | 16 +- .../obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h | 16 +- .../obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h | 16 +- 12 files changed, 199 insertions(+), 127 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 1ad9d1e0..65bca1dc 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -34,8 +34,8 @@ static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const c #ifdef DEBUG_EEPROM_WRITE printf_P(PSTR("EEPROM_WRITE_VAR addr=0x%04x size=0x%02x name=%s\n"), pos, size, name); #endif //DEBUG_EEPROM_WRITE - while (size--) - { + while (size--) + { eeprom_update_byte(pos, *value); if (eeprom_read_byte(pos) != *value) { @@ -43,9 +43,9 @@ static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const c return false; } - pos++; - value++; - } + pos++; + value++; + } return true; } @@ -89,8 +89,8 @@ void Config_StoreSettings() void Config_PrintSettings(uint8_t level) { // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown #ifdef TMC2130 - printf_P(PSTR( - "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" + printf_P(PSTR( + "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" "%SUStep resolution: \n%S M350 X%d Y%d Z%d E%d\n" "%SMaximum feedrates - normal (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" "%SMaximum feedrates - stealth (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" @@ -125,54 +125,54 @@ void Config_PrintSettings(uint8_t level) echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS], echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS] #endif //TMC2130 - ); + ); #ifdef PIDTEMP - printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"), - echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd)); + printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"), + echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd)); #endif #ifdef PIDTEMPBED - printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"), - echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd)); + printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"), + echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd)); #endif #ifdef FWRETRACT - printf_P(PSTR( - "%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n" - "%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n" - "%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n" - ), - echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift, - echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60, - echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0) - ); + printf_P(PSTR( + "%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n" + "%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n" + "%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n" + ), + echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift, + echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60, + echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0) + ); #if EXTRUDERS > 1 - printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"), - echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap); + printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"), + echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap); #endif - if (cs.volumetric_enabled) { - printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"), - echomagic, echomagic, cs.filament_size[0]); + if (cs.volumetric_enabled) { + printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"), + echomagic, echomagic, cs.filament_size[0]); #if EXTRUDERS > 1 - printf_P(PSTR("%S M200 T1 D%.2f\n"), - echomagic, echomagic, cs.filament_size[1]); + printf_P(PSTR("%S M200 T1 D%.2f\n"), + echomagic, echomagic, cs.filament_size[1]); #if EXTRUDERS > 2 - printf_P(PSTR("%S M200 T1 D%.2f\n"), - echomagic, echomagic, cs.filament_size[2]); + printf_P(PSTR("%S M200 T1 D%.2f\n"), + echomagic, echomagic, cs.filament_size[2]); #endif #endif } else { printf_P(PSTR("%SFilament settings: Disabled\n"), echomagic); } #endif - if (level >= 10) { + if (level >= 10) { #ifdef LIN_ADVANCE - printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"), + printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"), echomagic, echomagic, extruder_advance_K); #endif //LIN_ADVANCE - } + } // Arc Interpolation Settings printf_P(PSTR( - "%SArc Settings: P=Arc segment length max (mm) S=Arc segment length Min (mm), R=Min arc segments, F=Arc segments per second.\n%S M214 P%.2f S%.2f R%d F%d\n"), - echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.min_arc_segments, cs.arc_segments_per_sec); + "%SArc Settings: P=Arc segment length max (mm) S=Arc segment length Min (mm), N=Num Segments Per Correction, R=Min arc segments, F=Arc segments per second.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"), + echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.n_arc_correction, cs.min_arc_segments, cs.arc_segments_per_sec); } #endif @@ -188,7 +188,7 @@ static_assert (false, "zprobe_zoffset was not initialized in printers in field t "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf"); #endif -static_assert (sizeof(M500_conf) == 208, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, " +static_assert (sizeof(M500_conf) == 209, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, " "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized." "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM," "leave as it is to keep fast code, or reorder struct members to pack more tightly."); @@ -260,7 +260,7 @@ static bool is_uninitialized(void* addr, uint8_t len) //! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data. bool Config_RetrieveSettings() { - bool previous_settings_retrieved = true; + bool previous_settings_retrieved = true; char ver[4]=EEPROM_VERSION; EEPROM_readData(reinterpret_cast(EEPROM_M500_base->version), reinterpret_cast(cs.version), sizeof(cs.version), "cs.version"); //read stored version // SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << cs.version << "]"); @@ -270,7 +270,7 @@ bool Config_RetrieveSettings() EEPROM_readData(reinterpret_cast(EEPROM_M500_base), reinterpret_cast(&cs), sizeof(cs), "cs"); calculate_extruder_multipliers(); - //if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values: + //if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values: for (uint8_t i = 0; i < (sizeof(cs.max_feedrate_silent)/sizeof(cs.max_feedrate_silent[0])); ++i) { const uint32_t erased = 0xffffffff; @@ -284,32 +284,33 @@ bool Config_RetrieveSettings() // Initialize arc interpolation settings if they are not already (Not sure about this bit, please review) if (is_uninitialized(cs.mm_per_arc_segment, sizeof(float))) cs.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; if (is_uninitialized(cs.min_mm_per_arc_segment, sizeof(float))) cs.min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; + if (is_uninitialized(cs.n_arc_correction), sizeof(uint8_t)) cs.n_arc_correction = DEFAULT_N_ARC_CORRECTION; if (is_uninitialized(cs.min_arc_segments, sizeof(uint16_t))) cs.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; if (is_uninitialized(cs.arc_segments_per_sec, sizeof(uint16_t))) cs.arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; #ifdef TMC2130 - for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) - { - if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY) - cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY; - if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY) - cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY; - if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY) - cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY; - if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY) - cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY; - } + for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) + { + if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY) + cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY; + if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY) + cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY; + if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY) + cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY; + if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY) + cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY; + } - if(cs.axis_ustep_resolution[X_AXIS] == 0xff){ cs.axis_ustep_resolution[X_AXIS] = TMC2130_USTEPS_XY; } - if(cs.axis_ustep_resolution[Y_AXIS] == 0xff){ cs.axis_ustep_resolution[Y_AXIS] = TMC2130_USTEPS_XY; } - if(cs.axis_ustep_resolution[Z_AXIS] == 0xff){ cs.axis_ustep_resolution[Z_AXIS] = TMC2130_USTEPS_Z; } - if(cs.axis_ustep_resolution[E_AXIS] == 0xff){ cs.axis_ustep_resolution[E_AXIS] = TMC2130_USTEPS_E; } + if(cs.axis_ustep_resolution[X_AXIS] == 0xff){ cs.axis_ustep_resolution[X_AXIS] = TMC2130_USTEPS_XY; } + if(cs.axis_ustep_resolution[Y_AXIS] == 0xff){ cs.axis_ustep_resolution[Y_AXIS] = TMC2130_USTEPS_XY; } + if(cs.axis_ustep_resolution[Z_AXIS] == 0xff){ cs.axis_ustep_resolution[Z_AXIS] = TMC2130_USTEPS_Z; } + if(cs.axis_ustep_resolution[E_AXIS] == 0xff){ cs.axis_ustep_resolution[E_AXIS] = TMC2130_USTEPS_E; } - tmc2130_set_res(X_AXIS, cs.axis_ustep_resolution[X_AXIS]); - tmc2130_set_res(Y_AXIS, cs.axis_ustep_resolution[Y_AXIS]); - tmc2130_set_res(Z_AXIS, cs.axis_ustep_resolution[Z_AXIS]); - tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]); + tmc2130_set_res(X_AXIS, cs.axis_ustep_resolution[X_AXIS]); + tmc2130_set_res(Y_AXIS, cs.axis_ustep_resolution[Y_AXIS]); + tmc2130_set_res(Z_AXIS, cs.axis_ustep_resolution[Z_AXIS]); + tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]); #endif //TMC2130 if(is_uninitialized(&cs.travel_acceleration, sizeof(cs.travel_acceleration))) @@ -317,27 +318,27 @@ bool Config_RetrieveSettings() reset_acceleration_rates(); - // Call updatePID (similar to when we have processed M301) - updatePID(); + // Call updatePID (similar to when we have processed M301) + updatePID(); SERIAL_ECHO_START; SERIAL_ECHOLNPGM("Stored settings retrieved"); } else { Config_ResetDefault(); - //Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now. - //In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used. - if (eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[0]))) != 0xFF || - eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[1]))) != 0xFF || - eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[2]))) != 0xFF) - { - previous_settings_retrieved = false; - } + //Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now. + //In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used. + if (eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[0]))) != 0xFF || + eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[1]))) != 0xFF || + eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[2]))) != 0xFF) + { + previous_settings_retrieved = false; + } } #ifdef EEPROM_CHITCHAT Config_PrintSettings(); #endif - return previous_settings_retrieved; + return previous_settings_retrieved; } #endif @@ -345,14 +346,14 @@ void Config_ResetDefault() { memcpy_P(&cs,&default_conf, sizeof(cs)); - // steps per sq second need to be updated to agree with the units per sq second + // steps per sq second need to be updated to agree with the units per sq second reset_acceleration_rates(); #ifdef PIDTEMP updatePID(); #endif//PIDTEMP - calculate_extruder_multipliers(); + calculate_extruder_multipliers(); SERIAL_ECHO_START; SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded"); diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index bf768db3..a5b7b762 100644 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -42,8 +42,9 @@ typedef struct // Arc Interpolation Settings, configurable via M214 float mm_per_arc_segment; float min_mm_per_arc_segment; - uint16_t min_arc_segments; // If less than or equal to zero, this is disabled - uint16_t arc_segments_per_sec; // If less than or equal to zero, this is disabled + uint8_t n_arc_correction; // If equal to zero, this is disabled + uint16_t min_arc_segments; // If equal to zero, this is disabled + uint16_t arc_segments_per_sec; // If equal to zero, this is disabled } M500_conf; extern M500_conf cs; diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 7de7fe61..0bc9c6bc 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7509,11 +7509,12 @@ Sigma_Exit: #### Usage - M214 [P] [S] [R] [F] + M214 [P] [S] [N] [R] [F] #### Parameters - `P` - A float representing the max and default millimeters per arc segment. Must be greater than 0. - `S` - A float representing the minimum allowable millimeters per arc segment. Set to 0 to disable + - `N` - An int representing the number of arcs to draw before correcting the small angle approximation. Set to 1 or 0 to disable. - `R` - An int representing the minimum number of segments per arcs of any radius, except when the results in segment lengths greater than or less than the minimum and maximum segment length. Set to 0 to disable. @@ -7525,6 +7526,7 @@ Sigma_Exit: // Extract N float p = cs.mm_per_arc_segment; float s = cs.min_mm_per_arc_segment; + uint8_t n = cs.n_arc_correction; uint16_t r = cs.min_arc_segments; uint16_t f = cs.arc_segments_per_sec; @@ -7546,6 +7548,16 @@ Sigma_Exit: break; } } + // Extract N + if (code_seen('N')) + { + + n = code_value(); + if (n < 0) + { + break; + } + } // Extract R if (code_seen('R')) { @@ -7567,6 +7579,7 @@ Sigma_Exit: } cs.mm_per_arc_segment = p; cs.min_mm_per_arc_segment = s; + cs.n_arc_correction = n; cs.min_arc_segments = r; cs.arc_segments_per_sec = f; }break; diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 8524e2fc..28e803a2 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -39,6 +39,9 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa float rt_y = target[Y_AXIS] - center_axis_y; // 20200419 - Add a variable that will be used to hold the arc segment length float mm_per_arc_segment = cs.mm_per_arc_segment; + // 20210109 - Add a variable to hold the n_arc_correction value + bool correction_enabled = cs.n_arc_correction > 1; + uint8_t n_arc_correction = cs.n_arc_correction; // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel_total = atan2(r_axis_x * rt_y - r_axis_y * rt_x, r_axis_x * rt_x + r_axis_y * rt_y); @@ -126,16 +129,38 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa { // Initialize the extruder axis - float cos_T = cos(theta_per_segment); - float sin_T = sin(theta_per_segment); + float cos_T; + float sin_T; + + if (correction_enabled > 1){ + float sq_theta_per_segment = theta_per_segment * theta_per_segment; + // Small angle approximation + sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, + cos_T = 1 - 0.5f * sq_theta_per_segment; + } + else { + cos_T = cos(theta_per_segment); + sin_T = sin(theta_per_segment); + } + float r_axisi; uint16_t i; for (i = 1; i < segments; i++) { // Increment (segments-1) - r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; - r_axis_x = r_axis_x * cos_T - r_axis_y * sin_T; - r_axis_y = r_axisi; - + if (correction_enabled && --n_arc_correction == 0) { + // Calculate the actual position for r_axis_x and r_axis_y + const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); + r_axis_x = -offset[X_AXIS] * cos_Ti + offset[Y_AXIS] * sin_Ti; + r_axis_y = -offset[X_AXIS] * sin_Ti - offset[Y_AXIS] * cos_Ti; + // reset n_arc_correction + n_arc_correction = cs.n_arc_correction; + } + else { + r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; + r_axis_x = r_axis_x * cos_T - r_axis_y * sin_T; + r_axis_y = r_axisi; + } + // Update arc_target location position[X_AXIS] = center_axis_x + r_axis_x; position[Y_AXIS] = center_axis_y + r_axis_y; diff --git a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h index 741ba725..e431e1e3 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h @@ -526,11 +526,15 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment +/* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h index 0ea0d37f..0cdd80e4 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h @@ -530,11 +530,15 @@ //#define MICROMETER_LOGGING //related to D-codes D80 and D81, currently works on MK2.5 only (MK3 board pin definitions missing) // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h index e88f9834..99103020 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h @@ -533,11 +533,15 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h index bd4b8904..8592ff8f 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h @@ -534,11 +534,15 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h index da35f7af..0b24f2e2 100644 --- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h @@ -672,11 +672,15 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h index f1e5cea8..5acb23f2 100644 --- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h @@ -684,11 +684,15 @@ #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h index 266a9523..4fc5fd8c 100644 --- a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo10a-E3Dv6full.h @@ -450,11 +450,15 @@ THERMISTORS SETTINGS #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h index 1122939e..674f3c36 100644 --- a/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/obsolete/1_75mm_MK2-RAMBo13a-E3Dv6full.h @@ -439,11 +439,15 @@ THERMISTORS SETTINGS #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning // Default Arc Interpolation Settings (Now configurable via M214) -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than - MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 20 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_N_ARC_CORRECTION 25 // Number of interpolated segments between corrections. +/* A value of 1 or less for N_ARC_CORRECTION will trigger the use of Sin and Cos for every arc, which will improve accuracy at the + cost of performance*/ +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0f // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.5f //the enforced minimum length of an interpolated segment + /* MIN_MM_PER_ARC_SEGMENT Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 + or ARC_SEGMENTS_PER_SEC > 0 . If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum + calculated segment length is used. */ +#define DEFAULT_MIN_ARC_SEGMENTS 20 // The enforced minimum segments in a full circle of the same radius. Set to 0 to disable +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // Use feedrate to choose segment length. Set to 0 to disable #endif //__CONFIGURATION_PRUSA_H From 388077769177aeed37cf7fd78fbba23a7a921543 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Tue, 12 Jan 2021 16:41:23 -0600 Subject: [PATCH 04/10] Fix invalid bool compare. --- Firmware/motion_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 28e803a2..cc2cabd5 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -132,7 +132,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa float cos_T; float sin_T; - if (correction_enabled > 1){ + if (correction_enabled){ float sq_theta_per_segment = theta_per_segment * theta_per_segment; // Small angle approximation sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, From acc234b0c5f90e0e6ffb70aa4656642954f43b52 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Tue, 12 Jan 2021 17:15:37 -0600 Subject: [PATCH 05/10] Fix config store load (was missing n_arc_correction). --- Firmware/ConfigurationStore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 65bca1dc..fec4a0c5 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -239,6 +239,7 @@ static const M500_conf default_conf PROGMEM = DEFAULT_TRAVEL_ACCELERATION, DEFAULT_MM_PER_ARC_SEGMENT, DEFAULT_MIN_MM_PER_ARC_SEGMENT, + DEFAULT_N_ARC_CORRECTION, DEFAULT_MIN_ARC_SEGMENTS, DEFAULT_ARC_SEGMENTS_PER_SEC }; From 623c029bfac88b53acb08071124602e1ed058be9 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Wed, 13 Jan 2021 18:37:15 -0600 Subject: [PATCH 06/10] Code cleanup to reduce program storage --- Firmware/ConfigurationStore.cpp | 2 +- Firmware/Marlin_main.cpp | 62 ++++++------------------------- Firmware/motion_control.cpp | 66 +++++++++++---------------------- 3 files changed, 34 insertions(+), 96 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index fec4a0c5..a24bae15 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -171,7 +171,7 @@ void Config_PrintSettings(uint8_t level) } // Arc Interpolation Settings printf_P(PSTR( - "%SArc Settings: P=Arc segment length max (mm) S=Arc segment length Min (mm), N=Num Segments Per Correction, R=Min arc segments, F=Arc segments per second.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"), + "%SArc Settings: P:Max length(mm) S:Min length (mm) N:Corrections R:Min segments F:Segments/sec.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"), echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.n_arc_correction, cs.min_arc_segments, cs.arc_segments_per_sec); } #endif diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 0bc9c6bc..b600a1b2 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -4901,6 +4901,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) #### Parameters - `X` - The position to move to on the X axis - `Y` - The position to move to on the Y axis + - 'Z' - The position to move to on the Z axis - `I` - The point in X space from the current X position to maintain a constant distance from - `J` - The point in Y space from the current Y position to maintain a constant distance from - `E` - The amount to extrude between the starting point and ending point @@ -7514,7 +7515,7 @@ Sigma_Exit: #### Parameters - `P` - A float representing the max and default millimeters per arc segment. Must be greater than 0. - `S` - A float representing the minimum allowable millimeters per arc segment. Set to 0 to disable - - `N` - An int representing the number of arcs to draw before correcting the small angle approximation. Set to 1 or 0 to disable. + - `N` - An int representing the number of arcs to draw before correcting the small angle approximation. Set to 0 to disable. - `R` - An int representing the minimum number of segments per arcs of any radius, except when the results in segment lengths greater than or less than the minimum and maximum segment length. Set to 0 to disable. @@ -7523,60 +7524,19 @@ Sigma_Exit: */ case 214: //!@n M214 - Set Arc Parameters (Use M500 to store in eeprom) P S R F { - // Extract N - float p = cs.mm_per_arc_segment; - float s = cs.min_mm_per_arc_segment; - uint8_t n = cs.n_arc_correction; - uint16_t r = cs.min_arc_segments; - uint16_t f = cs.arc_segments_per_sec; + // Extract all possible parameters if they appear + float p = code_seen('P') ? code_value_float() : cs.mm_per_arc_segment; + float s = code_seen('S') ? code_value_float() : cs.min_mm_per_arc_segment; + uint8_t n = code_seen('N') ? code_value() : cs.n_arc_correction; + uint16_t r = code_seen('R') ? code_value() : cs.min_arc_segments; + uint16_t f = code_seen('F') ? code_value() : cs.arc_segments_per_sec; - // Extract N - if (code_seen('P')) + // Ensure mm_per_arc_segment is greater than 0, and that min_mm_per_arc_segment is sero or greater than or equal to mm_per_arc_segment + if (p <=0 || s < 0 || p < s) { - p = code_value_float(); - if (p <= 0 || (s != 0 && p <= s)) - { - break; - } + break; } - // Extract S - if (code_seen('S')) - { - s = code_value_float(); - if (s < 0 || s >= p) - { - break; - } - } - // Extract N - if (code_seen('N')) - { - n = code_value(); - if (n < 0) - { - break; - } - } - // Extract R - if (code_seen('R')) - { - - r = code_value(); - if (r < 0) - { - break; - } - } - // Extract F - if (code_seen('F')) - { - f = code_value(); - if (f < 0) - { - break; - } - } cs.mm_per_arc_segment = p; cs.min_mm_per_arc_segment = s; cs.n_arc_correction = n; diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index cc2cabd5..44876f6c 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -33,49 +33,43 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa float center_axis_x = position[X_AXIS] - r_axis_x; float center_axis_y = position[Y_AXIS] - r_axis_y; float travel_z = target[Z_AXIS] - position[Z_AXIS]; - float extruder_travel_total = target[E_AXIS] - position[E_AXIS]; - float rt_x = target[X_AXIS] - center_axis_x; float rt_y = target[Y_AXIS] - center_axis_y; // 20200419 - Add a variable that will be used to hold the arc segment length float mm_per_arc_segment = cs.mm_per_arc_segment; // 20210109 - Add a variable to hold the n_arc_correction value - bool correction_enabled = cs.n_arc_correction > 1; uint8_t n_arc_correction = cs.n_arc_correction; // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel_total = atan2(r_axis_x * rt_y - r_axis_y * rt_x, r_axis_x * rt_x + r_axis_y * rt_y); if (angular_travel_total < 0) { angular_travel_total += 2 * M_PI; } - bool check_mm_per_arc_segment_max = false; if (cs.min_arc_segments > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation // Do this before converting the angular travel for clockwise rotation mm_per_arc_segment = radius * ((2.0f * M_PI) / cs.min_arc_segments); - check_mm_per_arc_segment_max = true; } - if (cs.arc_segments_per_sec > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation float mm_per_arc_segment_sec = (feed_rate / 60.0f) * (1.0f / cs.arc_segments_per_sec); if (mm_per_arc_segment_sec < mm_per_arc_segment) mm_per_arc_segment = mm_per_arc_segment_sec; - check_mm_per_arc_segment_max = true; } - if (cs.min_mm_per_arc_segment > 0) + // Note: no need to check to see if min_mm_per_arc_segment is enabled or not (i.e. = 0), since mm_per_arc_segment can never be below 0. + if (mm_per_arc_segment < cs.min_mm_per_arc_segment) { - check_mm_per_arc_segment_max = true; // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined // This prevents a very high number of segments from being generated for curves of a short radius - if (mm_per_arc_segment < cs.min_mm_per_arc_segment) mm_per_arc_segment = cs.min_mm_per_arc_segment; + mm_per_arc_segment = cs.min_mm_per_arc_segment; + } + else if (mm_per_arc_segment > cs.mm_per_arc_segment){ + // 20210113 - This can be implemented in an else if since we can't be below the min AND above the max at the same time. + // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined + mm_per_arc_segment = cs.mm_per_arc_segment; } - - if (check_mm_per_arc_segment_max && mm_per_arc_segment > cs.mm_per_arc_segment) mm_per_arc_segment = cs.mm_per_arc_segment; - - // Adjust the angular travel if the direction is clockwise if (isclockwise) { angular_travel_total -= 2 * M_PI; } @@ -90,18 +84,12 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa // 20200417 - FormerLurker - rename millimeters_of_travel to millimeters_of_travel_arc to better describe what we are // calculating here - float millimeters_of_travel_arc = hypot(angular_travel_total * radius, fabs(travel_z)); + const float millimeters_of_travel_arc = hypot(angular_travel_total * radius, fabs(travel_z)); if (millimeters_of_travel_arc < 0.001) { return; } // Calculate the total travel per segment // Calculate the number of arc segments uint16_t segments = static_cast(ceil(millimeters_of_travel_arc / mm_per_arc_segment)); - - // Calculate theta per segments and linear (z) travel per segment - float theta_per_segment = angular_travel_total / segments; - float linear_per_segment = travel_z / (segments); - // Calculate the extrusion amount per segment - float segment_extruder_travel = extruder_travel_total / (segments); /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, and phi is the angle of rotation. Based on the solution approach by Jens Geisler. r_T = [cos(phi) -sin(phi); @@ -124,30 +112,20 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa arc when using the previous approximation, would be beneficial. */ - // Don't bother calculating cot_T or sin_T if there is only 1 segment. + // If there is only one segment, no need to do a bunch of work since this is a straight line! if (segments > 1) { - // Initialize the extruder axis - - float cos_T; - float sin_T; - - if (correction_enabled){ - float sq_theta_per_segment = theta_per_segment * theta_per_segment; - // Small angle approximation - sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, - cos_T = 1 - 0.5f * sq_theta_per_segment; - } - else { - cos_T = cos(theta_per_segment); - sin_T = sin(theta_per_segment); - } - - float r_axisi; - uint16_t i; - - for (i = 1; i < segments; i++) { // Increment (segments-1) - if (correction_enabled && --n_arc_correction == 0) { + + // Calculate theta per segments and linear (z) travel per segment + const float theta_per_segment = angular_travel_total / segments, + linear_per_segment = travel_z / (segments), + segment_extruder_travel = (target[E_AXIS] - position[E_AXIS]) / (segments), + sq_theta_per_segment = theta_per_segment * theta_per_segment, + sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, + cos_T = 1 - 0.5f * sq_theta_per_segment; + + for (uint16_t i = 1; i < segments; i++) { // Increment (segments-1) + if (n_arc_correction--<1) { // Calculate the actual position for r_axis_x and r_axis_y const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); r_axis_x = -offset[X_AXIS] * cos_Ti + offset[Y_AXIS] * sin_Ti; @@ -156,7 +134,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa n_arc_correction = cs.n_arc_correction; } else { - r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; + const float r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; r_axis_x = r_axis_x * cos_T - r_axis_y * sin_T; r_axis_y = r_axisi; } From 02b0307307606641ed526ad62ef28bda562fb31e Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Mon, 18 Jan 2021 13:51:08 -0600 Subject: [PATCH 07/10] Code Cleanup --- Firmware/motion_control.cpp | 44 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 44876f6c..68784300 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -63,9 +63,9 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa { // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined // This prevents a very high number of segments from being generated for curves of a short radius - mm_per_arc_segment = cs.min_mm_per_arc_segment; + mm_per_arc_segment = cs.min_mm_per_arc_segment; } - else if (mm_per_arc_segment > cs.mm_per_arc_segment){ + else if (mm_per_arc_segment > cs.mm_per_arc_segment) { // 20210113 - This can be implemented in an else if since we can't be below the min AND above the max at the same time. // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined mm_per_arc_segment = cs.mm_per_arc_segment; @@ -86,7 +86,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa // calculating here const float millimeters_of_travel_arc = hypot(angular_travel_total * radius, fabs(travel_z)); if (millimeters_of_travel_arc < 0.001) { return; } - // Calculate the total travel per segment + // Calculate the number of arc segments uint16_t segments = static_cast(ceil(millimeters_of_travel_arc / mm_per_arc_segment)); @@ -115,17 +115,18 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa // If there is only one segment, no need to do a bunch of work since this is a straight line! if (segments > 1) { - - // Calculate theta per segments and linear (z) travel per segment + // Calculate theta per segments, and linear (z) travel per segment, e travel per segment + // as well as the small angle approximation for sin and cos. const float theta_per_segment = angular_travel_total / segments, - linear_per_segment = travel_z / (segments), - segment_extruder_travel = (target[E_AXIS] - position[E_AXIS]) / (segments), - sq_theta_per_segment = theta_per_segment * theta_per_segment, - sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, - cos_T = 1 - 0.5f * sq_theta_per_segment; - - for (uint16_t i = 1; i < segments; i++) { // Increment (segments-1) - if (n_arc_correction--<1) { + linear_per_segment = travel_z / (segments), + segment_extruder_travel = (target[E_AXIS] - position[E_AXIS]) / (segments), + sq_theta_per_segment = theta_per_segment * theta_per_segment, + sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, + cos_T = 1 - 0.5f * sq_theta_per_segment; + // Loop through all but one of the segments. The last one can be done simply + // by moving to the target. + for (uint16_t i = 1; i < segments; i++) { + if (n_arc_correction-- == 0) { // Calculate the actual position for r_axis_x and r_axis_y const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); r_axis_x = -offset[X_AXIS] * cos_Ti + offset[Y_AXIS] * sin_Ti; @@ -134,24 +135,25 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa n_arc_correction = cs.n_arc_correction; } else { + // Calculate X and Y using the small angle approximation const float r_axisi = r_axis_x * sin_T + r_axis_y * cos_T; r_axis_x = r_axis_x * cos_T - r_axis_y * sin_T; r_axis_y = r_axisi; } - - // Update arc_target location + + // Update Position position[X_AXIS] = center_axis_x + r_axis_x; position[Y_AXIS] = center_axis_y + r_axis_y; position[Z_AXIS] += linear_per_segment; position[E_AXIS] += segment_extruder_travel; - // We can't clamp to the target because we are interpolating! We would need to update a position, clamp to it - // after updating from calculated values. + // Clamp to the calculated position. clamp_to_software_endstops(position); - plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder); + // Insert the segment into the buffer + plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder, position); } } - // Ensure last segment arrives at target location. - // Here we could clamp, but why bother. We would need to update our current position, clamp to it + // Clamp to the target position. clamp_to_software_endstops(target); - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder); + // Ensure last segment arrives at target location. + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder, target); } From bb33c76d2b42be87d621d6e7517d449b504905a8 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Mon, 25 Apr 2022 09:41:35 -0500 Subject: [PATCH 08/10] Fix and simplify M214 data types and default config initialization. --- Firmware/ConfigurationStore.cpp | 10 +++++----- Firmware/ConfigurationStore.h | 6 +++--- Firmware/Marlin_main.cpp | 9 +++++---- Firmware/motion_control.cpp | 6 +++--- Firmware/motion_control.h | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index a24bae15..4fdf2bcf 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -283,11 +283,11 @@ bool Config_RetrieveSettings() } } // Initialize arc interpolation settings if they are not already (Not sure about this bit, please review) - if (is_uninitialized(cs.mm_per_arc_segment, sizeof(float))) cs.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; - if (is_uninitialized(cs.min_mm_per_arc_segment, sizeof(float))) cs.min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; - if (is_uninitialized(cs.n_arc_correction), sizeof(uint8_t)) cs.n_arc_correction = DEFAULT_N_ARC_CORRECTION; - if (is_uninitialized(cs.min_arc_segments, sizeof(uint16_t))) cs.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; - if (is_uninitialized(cs.arc_segments_per_sec, sizeof(uint16_t))) cs.arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; + if (is_uninitialized(&cs.mm_per_arc_segment, sizeof(cs.mm_per_arc_segment))) cs.mm_per_arc_segment = default_conf.mm_per_arc_segment; + if (is_uninitialized(&cs.min_mm_per_arc_segment, sizeof(cs.min_mm_per_arc_segment))) cs.min_mm_per_arc_segment = default_conf.min_mm_per_arc_segment; + if (is_uninitialized(&cs.n_arc_correction, sizeof(cs.n_arc_correction))) cs.n_arc_correction = default_conf.n_arc_correction; + if (is_uninitialized(&cs.min_arc_segments, sizeof(cs.min_arc_segments))) cs.min_arc_segments = default_conf.min_arc_segments; + if (is_uninitialized(&cs.arc_segments_per_sec, sizeof(cs.arc_segments_per_sec))) cs.arc_segments_per_sec = default_conf.arc_segments_per_sec; #ifdef TMC2130 diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index a5b7b762..ec40ebc0 100644 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -42,9 +42,9 @@ typedef struct // Arc Interpolation Settings, configurable via M214 float mm_per_arc_segment; float min_mm_per_arc_segment; - uint8_t n_arc_correction; // If equal to zero, this is disabled - uint16_t min_arc_segments; // If equal to zero, this is disabled - uint16_t arc_segments_per_sec; // If equal to zero, this is disabled + unsigned char n_arc_correction; // If equal to zero, this is disabled + unsigned short min_arc_segments; // If equal to zero, this is disabled + unsigned short arc_segments_per_sec; // If equal to zero, this is disabled } M500_conf; extern M500_conf cs; diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index b600a1b2..f6a6731e 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7527,13 +7527,14 @@ Sigma_Exit: // Extract all possible parameters if they appear float p = code_seen('P') ? code_value_float() : cs.mm_per_arc_segment; float s = code_seen('S') ? code_value_float() : cs.min_mm_per_arc_segment; - uint8_t n = code_seen('N') ? code_value() : cs.n_arc_correction; - uint16_t r = code_seen('R') ? code_value() : cs.min_arc_segments; - uint16_t f = code_seen('F') ? code_value() : cs.arc_segments_per_sec; + unsigned char n = code_seen('N') ? code_value() : cs.n_arc_correction; + unsigned short r = code_seen('R') ? code_value() : cs.min_arc_segments; + unsigned short f = code_seen('F') ? code_value() : cs.arc_segments_per_sec; // Ensure mm_per_arc_segment is greater than 0, and that min_mm_per_arc_segment is sero or greater than or equal to mm_per_arc_segment if (p <=0 || s < 0 || p < s) { + // Should we display some error here? break; } @@ -9679,7 +9680,7 @@ void prepare_move() set_current_to_destination(); } -void prepare_arc_move(char isclockwise) { +void prepare_arc_move(bool isclockwise) { float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc // Trace the arc mc_arc(current_position, destination, offset, feedrate * feedmultiply / 60 / 100.0, r, isclockwise, active_extruder); diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index 68784300..af7e69a8 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -26,7 +26,7 @@ // The arc is approximated by generating a huge number of tiny, linear segments. The length of each // segment is configured in settings.mm_per_arc_segment. -void mc_arc(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder) +void mc_arc(float* position, float* target, float* offset, float feed_rate, float radius, bool isclockwise, uint8_t extruder) { float r_axis_x = -offset[X_AXIS]; // Radius vector from center to current location float r_axis_y = -offset[Y_AXIS]; @@ -38,7 +38,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa // 20200419 - Add a variable that will be used to hold the arc segment length float mm_per_arc_segment = cs.mm_per_arc_segment; // 20210109 - Add a variable to hold the n_arc_correction value - uint8_t n_arc_correction = cs.n_arc_correction; + unsigned char n_arc_correction = cs.n_arc_correction; // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel_total = atan2(r_axis_x * rt_y - r_axis_y * rt_x, r_axis_x * rt_x + r_axis_y * rt_y); @@ -88,7 +88,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa if (millimeters_of_travel_arc < 0.001) { return; } // Calculate the number of arc segments - uint16_t segments = static_cast(ceil(millimeters_of_travel_arc / mm_per_arc_segment)); + unsigned short segments = static_cast(ceil(millimeters_of_travel_arc / mm_per_arc_segment)); /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, and phi is the angle of rotation. Based on the solution approach by Jens Geisler. diff --git a/Firmware/motion_control.h b/Firmware/motion_control.h index 95186cba..4cc16ffa 100644 --- a/Firmware/motion_control.h +++ b/Firmware/motion_control.h @@ -27,6 +27,6 @@ // the direction of helical travel, radius == circle radius, isclockwise boolean. Used // for vector transformation direction. void mc_arc(float *position, float *target, float *offset, float feed_rate, float radius, - unsigned char isclockwise, uint8_t extruder); + bool isclockwise, uint8_t extruder); #endif From 0b23ccdee9ff811f871d1fee450172e61d3f053e Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Fri, 29 Apr 2022 20:38:48 +0200 Subject: [PATCH 09/10] Abort arc on planner hard stop --- Firmware/motion_control.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index af7e69a8..e2442894 100644 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -150,6 +150,9 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa clamp_to_software_endstops(position); // Insert the segment into the buffer plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder, position); + // Handle the situation where the planner is aborted hard. + if (waiting_inside_plan_buffer_line_print_aborted) + return; } } // Clamp to the target position. From 7515db1ef0ce3b18862383b28187fee4b9e50848 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Mon, 2 May 2022 10:02:00 +0200 Subject: [PATCH 10/10] Adjust comments --- Firmware/ConfigurationStore.cpp | 2 +- Firmware/Configuration_adv.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 4fdf2bcf..77ef6df6 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -282,7 +282,7 @@ bool Config_RetrieveSettings() memcpy_P(&cs.max_acceleration_units_per_sq_second_silent[i],&default_conf.max_acceleration_units_per_sq_second_silent[i],sizeof(cs.max_acceleration_units_per_sq_second_silent[i])); } } - // Initialize arc interpolation settings if they are not already (Not sure about this bit, please review) + // Initialize arc interpolation settings if they are not already if (is_uninitialized(&cs.mm_per_arc_segment, sizeof(cs.mm_per_arc_segment))) cs.mm_per_arc_segment = default_conf.mm_per_arc_segment; if (is_uninitialized(&cs.min_mm_per_arc_segment, sizeof(cs.min_mm_per_arc_segment))) cs.min_mm_per_arc_segment = default_conf.min_mm_per_arc_segment; if (is_uninitialized(&cs.n_arc_correction, sizeof(cs.n_arc_correction))) cs.n_arc_correction = default_conf.n_arc_correction; diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 769a28c7..997aafd1 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -289,7 +289,7 @@ //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging #endif -// Arc interpretation settings : Moded to printer default settings (Configuration_prusa.h) +// Arc interpretation settings : Moved to the variant files. const unsigned int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement