Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposed fix for #20382 (Unreliable circle detection) #20440

Merged
merged 8 commits into from Dec 23, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions Marlin/src/gcode/motion/G2_G3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,12 @@
#endif

/**
* Plan an arc in 2 dimensions
* Plan an arc in 2 dimensions, with optional linear motion in a 3rd dimension
*
* The arc is approximated by generating many small linear segments.
* The length of each segment is configured in MM_PER_ARC_SEGMENT (Default 1mm)
* Arcs should only be made relatively large (over 5mm), as larger arcs with
* larger segments will tend to be more efficient. Your slicer should have
* options for G2/G3 arc generation. In future these options may be GCode tunable.
* The arc is traced by generating many small linear segments, as configured by
* MM_PER_ARC_SEGMENT (Default 1mm). In the future we hope more slicers will include
* an option to generate G2/G3 arcs for curved surfaces, as this will allow faster
* boards to produce much smoother curved surfaces.
*/
void plan_arc(
const xyze_pos_t &cart, // Destination position
Expand Down Expand Up @@ -77,26 +76,33 @@ void plan_arc(
rt_Y = cart[q_axis] - center_Q,
start_L = current_position[l_axis];

// Angle of rotation between position and target from the circle center.
float angular_travel = ATAN2(rvec.a * rt_Y - rvec.b * rt_X, rvec.a * rt_X + rvec.b * rt_Y);

#ifdef MIN_ARC_SEGMENTS
uint16_t min_segments = MIN_ARC_SEGMENTS;
#else
constexpr uint16_t min_segments = 1;
#endif

// Do a full circle if angular rotation is near 0 and the target is current position
if (!angular_travel || (NEAR_ZERO(angular_travel) && NEAR(current_position[p_axis], cart[p_axis]) && NEAR(current_position[q_axis], cart[q_axis]))) {
// Angle of rotation between position and target from the circle center.
float angular_travel;

// Do a full circle if starting and ending positions are "identical"
if (NEAR(current_position[p_axis], cart[p_axis]) && NEAR(current_position[q_axis], cart[q_axis])) {
// Preserve direction for circles
angular_travel = clockwise ? -RADIANS(360) : RADIANS(360);
}
else {
// Calculate the angle
angular_travel = ATAN2(rvec.a * rt_Y - rvec.b * rt_X, rvec.a * rt_X + rvec.b * rt_Y);

// Angular travel too small to detect? Just return.
if (!angular_travel) return;

// Make sure angular travel over 180 degrees goes the other way around.
switch (((angular_travel < 0) << 1) | clockwise) {
case 1: angular_travel -= RADIANS(360); break; // Positive but CW? Reverse direction.
case 2: angular_travel += RADIANS(360); break; // Negative but CCW? Reverse direction.
}

#ifdef MIN_ARC_SEGMENTS
min_segments = CEIL(min_segments * ABS(angular_travel) / RADIANS(360));
NOLESS(min_segments, 1U);
Expand Down