mirror of
https://github.com/grblHAL/core.git
synced 2026-02-05 16:50:16 +08:00
Added support for G5.1 (quadratic spline) and multi turn arc option for G2 and G3 via P-word.
Some additions to data structures used by plugins.
This commit is contained in:
11
README.md
11
README.md
@@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
|
||||
|
||||
---
|
||||
|
||||
Latest build date is 20220710, see the [changelog](changelog.md) for details.
|
||||
Latest build date is 20220718, see the [changelog](changelog.md) for details.
|
||||
__NOTE:__ A settings reset will be performed on an update for versions earlier than 20211122. Backup and restore of settings is recommended.
|
||||
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in version 20211121.
|
||||
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
|
||||
@@ -53,7 +53,7 @@ This is a port/rewrite of [grbl 1.1f](https://github.com/gnea/grbl) and should b
|
||||
List of Supported G-Codes:
|
||||
- Non-Modal Commands: G4, G10L2, G10L20, G28, G30, G28.1, G30.1, G53, G92, G92.1
|
||||
- Additional Non-Modal Commands: G10L1*, G10L10*, G10L11*
|
||||
- Motion Modes: G0, G1, G2, G3, G5, G38.2, G38.3, G38.4, G38.5, G80, G33*
|
||||
- Motion Modes: G0, G1, G2****, G3****, G5, G5.1, G38.2, G38.3, G38.4, G38.5, G80, G33*
|
||||
- Canned cycles: G73, G81, G82, G83, G85, G86, G89, G98, G99
|
||||
- Repetitive cycles: G76*
|
||||
- Feed Rate Modes: G93, G94, G95*, G96*, G97*
|
||||
@@ -72,15 +72,16 @@ List of Supported G-Codes:
|
||||
- Spindle Control: M3, M4, M5
|
||||
- Tool Change: M6* (Two modes possible: manual** - supports jogging, ATC), M61
|
||||
- Switches: M48, M49, M50, M51, M53
|
||||
- Output control***: M62, M63, M64, M65, M66, M67, M68
|
||||
- Input/uutput control***: M62, M63, M64, M65, M66, M67, M68
|
||||
- Valid Non-Command Words: A*, B*, C*, F, H*, I, J, K, L, N, P, Q*, R, S, T, X, Y, Z
|
||||
|
||||
* driver/configuration dependent.
|
||||
** requires compatible GCode sender due to protocol extensions, new state and RT command.
|
||||
*** number of outputs supported dependent on driver implementation.
|
||||
*** number of inputs and outputs supported dependent on driver implementation.
|
||||
**** supports multi turn arcs from build 20220718.
|
||||
```
|
||||
|
||||
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
|
||||
|
||||
---
|
||||
2022-07-10
|
||||
2022-07-18
|
||||
|
||||
22
changelog.md
22
changelog.md
@@ -1,5 +1,25 @@
|
||||
## grblHAL changelog
|
||||
|
||||
20220718:
|
||||
|
||||
Core:
|
||||
|
||||
* Added support for `G5.1` \(quadratic spline\) and multi turn arc option for `G2` and `G3` via P-word.
|
||||
* Some additions to data structures used by plugins.
|
||||
|
||||
Plugins:
|
||||
|
||||
* Networking: added optional function to API for querying current status of connection and running services. Required for the WebUI plugin.
|
||||
Added support for client side ping message used by WebUI v3.
|
||||
* WebUI: added initial support for [WebUI v3](https://github.com/luc-github/ESP3D-WEBUI/discussions/94#discussioncomment-2861616) messaging.
|
||||
* SDCard: added function call for querying current job status.
|
||||
|
||||
Drivers:
|
||||
|
||||
* iMXRT1062, STM32F7xx, ESP32, TM4C1294 and MSP432E401Y: Implemented optional API function for querying current status of connection and running services.
|
||||
|
||||
---
|
||||
|
||||
20220710:
|
||||
|
||||
Core:
|
||||
@@ -8,7 +28,7 @@ Core:
|
||||
|
||||
Drivers:
|
||||
|
||||
* Most: updated for move of stepper enable initial stepper enable call to the core.
|
||||
* Most: Updated for move of stepper enable initial stepper enable call to the core.
|
||||
|
||||
* STM32F4xx: Fix for missing code guard, updated my_machine.h options.
|
||||
|
||||
|
||||
82
gcode.c
82
gcode.c
@@ -148,7 +148,7 @@ inline static float hypot_f (float x, float y)
|
||||
|
||||
inline static bool motion_is_lasercut (motion_mode_t motion)
|
||||
{
|
||||
return motion == MotionMode_Linear || motion == MotionMode_CwArc || motion == MotionMode_CcwArc || motion == MotionMode_CubicSpline;
|
||||
return motion == MotionMode_Linear || motion == MotionMode_CwArc || motion == MotionMode_CcwArc || motion == MotionMode_CubicSpline || motion == MotionMode_QuadraticSpline;
|
||||
}
|
||||
|
||||
parser_state_t *gc_get_state (void)
|
||||
@@ -811,7 +811,14 @@ status_code_t gc_execute_block(char *block)
|
||||
|
||||
case 80:
|
||||
word_bit.modal_group.G1 = On;
|
||||
gc_block.modal.motion = (motion_mode_t)int_value;
|
||||
if(int_value == 5 && mantissa != 0) {
|
||||
if(mantissa == 10) {
|
||||
gc_block.modal.motion = MotionMode_QuadraticSpline;
|
||||
mantissa = 0; // Set to zero to indicate valid non-integer G command.
|
||||
} else
|
||||
FAIL(Status_GcodeUnsupportedCommand);
|
||||
} else
|
||||
gc_block.modal.motion = (motion_mode_t)int_value;
|
||||
gc_block.modal.canned_cycle_active = false;
|
||||
break;
|
||||
|
||||
@@ -2184,7 +2191,7 @@ status_code_t gc_execute_block(char *block)
|
||||
// [G2/3 Radius-Mode Errors]: No axis words in selected plane. Target point is same as current.
|
||||
// [G2/3 Offset-Mode Errors]: No axis words and/or offsets in selected plane. The radius to the current
|
||||
// point and the radius to the target point differs more than 0.002mm (EMC def. 0.5mm OR 0.005mm and 0.1% radius).
|
||||
// [G2/3 Full-Circle-Mode Errors]: NOT SUPPORTED. Axis words exist. No offsets programmed. P must be an integer.
|
||||
// [G2/3 Full-Circle-Mode Errors]: Axis words exist. No offsets programmed. P must be an integer.
|
||||
// NOTE: Both radius and offsets are required for arc tracing and are pre-computed with the error-checking.
|
||||
|
||||
if (!axis_words.mask)
|
||||
@@ -2193,6 +2200,16 @@ status_code_t gc_execute_block(char *block)
|
||||
if (!(axis_words.mask & (bit(plane.axis_0)|bit(plane.axis_1))))
|
||||
FAIL(Status_GcodeNoAxisWordsInPlane); // [No axis words in plane]
|
||||
|
||||
if (gc_block.words.p) { // Number of turns
|
||||
if(!isintf(gc_block.values.p))
|
||||
FAIL(Status_GcodeCommandValueNotInteger); // [P word is not an integer]
|
||||
gc_block.arc_turns = (uint32_t)truncf(gc_block.values.p);
|
||||
if(gc_block.arc_turns == 0)
|
||||
FAIL(Status_GcodeValueOutOfRange); // [P word is 0]
|
||||
gc_block.words.p = Off;
|
||||
} else
|
||||
gc_block.arc_turns = 1;
|
||||
|
||||
// Calculate the change in position along each selected axis
|
||||
float x, y;
|
||||
x = gc_block.values.xyz[plane.axis_0] - gc_state.position[plane.axis_0]; // Delta x between current position and target
|
||||
@@ -2397,6 +2414,37 @@ status_code_t gc_execute_block(char *block)
|
||||
gc_block.words.p = gc_block.words.q = gc_block.words.i = gc_block.words.j = Off;
|
||||
break;
|
||||
|
||||
case MotionMode_QuadraticSpline:
|
||||
// [G5.1 Errors]: Feed rate undefined.
|
||||
// [G5.1 Plane Errors]: The active plane is not G17.
|
||||
// [G5.1 Offset Errors]: Just one of I or J are specified.
|
||||
// [G5.1 Offset Errors]: I or J are unspecified in the first of a series of G5 commands.
|
||||
// [G5.1 Axisword Errors]: An axis other than X or Y is specified.
|
||||
if(gc_block.modal.plane_select != PlaneSelect_XY)
|
||||
FAIL(Status_GcodeIllegalPlane); // [The active plane is not G17]
|
||||
|
||||
if (axis_words.mask & ~(bit(X_AXIS)|bit(Y_AXIS)))
|
||||
FAIL(Status_GcodeAxisCommandConflict); // [An axis other than X or Y is specified]
|
||||
|
||||
if((gc_block.words.mask & ij_words.mask) != ij_words.mask)
|
||||
FAIL(Status_GcodeValueWordMissing); // [I or J are unspecified]
|
||||
|
||||
if(gc_block.values.ijk[I_VALUE] == 0.0f && gc_block.values.ijk[I_VALUE] == 0.0f)
|
||||
FAIL(Status_GcodeValueOutOfRange); // [I or J are zero]
|
||||
|
||||
// Convert I and J values to proper units.
|
||||
if (gc_block.modal.units_imperial) {
|
||||
gc_block.values.ijk[I_VALUE] *= MM_PER_INCH;
|
||||
gc_block.values.ijk[J_VALUE] *= MM_PER_INCH;
|
||||
}
|
||||
// Scale values if scaling active
|
||||
if(gc_state.modal.scaling_active) {
|
||||
gc_block.values.ijk[I_VALUE] *= scale_factor.ijk[X_AXIS];
|
||||
gc_block.values.ijk[J_VALUE] *= scale_factor.ijk[Y_AXIS];
|
||||
}
|
||||
gc_block.words.i = gc_block.words.j = Off;
|
||||
break;
|
||||
|
||||
case MotionMode_ProbeTowardNoError:
|
||||
case MotionMode_ProbeAwayNoError:
|
||||
gc_parser_flags.probe_is_no_error = On;
|
||||
@@ -2861,11 +2909,35 @@ status_code_t gc_execute_block(char *block)
|
||||
case MotionMode_CcwArc:
|
||||
// fail if spindle synchronized motion?
|
||||
mc_arc(gc_block.values.xyz, &plan_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
|
||||
plane, gc_parser_flags.arc_is_clockwise);
|
||||
plane, gc_parser_flags.arc_is_clockwise ? gc_block.arc_turns : - gc_block.arc_turns);
|
||||
break;
|
||||
|
||||
case MotionMode_CubicSpline:
|
||||
mc_cubic_b_spline(gc_block.values.xyz, &plan_data, gc_state.position, gc_block.values.ijk, gc_state.modal.spline_pq);
|
||||
{
|
||||
point_2d cp1 = {
|
||||
.x = gc_state.position[X_AXIS] + gc_block.values.ijk[X_AXIS],
|
||||
.y = gc_state.position[Y_AXIS] + gc_block.values.ijk[Y_AXIS]
|
||||
};
|
||||
point_2d cp2 = {
|
||||
.x = gc_block.values.xyz[X_AXIS] + gc_state.modal.spline_pq[X_AXIS],
|
||||
.y = gc_block.values.xyz[Y_AXIS] + gc_state.modal.spline_pq[Y_AXIS]
|
||||
};
|
||||
mc_cubic_b_spline(gc_block.values.xyz, &plan_data, gc_state.position, cp1.values, cp2.values);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionMode_QuadraticSpline:
|
||||
{
|
||||
point_2d cp1 = {
|
||||
.x = gc_state.position[X_AXIS] + (gc_block.values.ijk[X_AXIS] * 2.0f) / 3.0f,
|
||||
.y = gc_state.position[Y_AXIS] + (gc_block.values.ijk[Y_AXIS] * 2.0f) / 3.0f
|
||||
};
|
||||
point_2d cp2 = {
|
||||
.x = gc_block.values.xyz[X_AXIS] + ((gc_state.position[X_AXIS] + gc_block.values.ijk[X_AXIS] - gc_block.values.xyz[X_AXIS]) * 2.0f) / 3.0f,
|
||||
.y = gc_block.values.xyz[Y_AXIS] + ((gc_state.position[Y_AXIS] + gc_block.values.ijk[Y_AXIS] - gc_block.values.xyz[Y_AXIS]) * 2.0f) / 3.0f
|
||||
};
|
||||
mc_cubic_b_spline(gc_block.values.xyz, &plan_data, gc_state.position, cp1.values, cp2.values);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionMode_SpindleSynchronized:
|
||||
|
||||
2
gcode.h
2
gcode.h
@@ -65,6 +65,7 @@ typedef enum {
|
||||
MotionMode_CwArc = 2, //!< 2 - G2
|
||||
MotionMode_CcwArc = 3, //!< 3 - G3
|
||||
MotionMode_CubicSpline = 5, //!< 5 - G5
|
||||
MotionMode_QuadraticSpline = 51, //!< 51 - G5.1
|
||||
MotionMode_SpindleSynchronized = 33, //!< 33 - G33
|
||||
MotionMode_DrillChipBreak = 73, //!< 73 - G73
|
||||
MotionMode_Threading = 76, //!< 76 - G76
|
||||
@@ -532,6 +533,7 @@ typedef struct {
|
||||
gc_values_t values; //!< Parameter values for block.
|
||||
parameter_words_t words; //!< Bitfield for tracking found parameter values.
|
||||
output_command_t output_command; //!< Details about M62-M68 output command to execute if present in block.
|
||||
uint32_t arc_turns; //
|
||||
} parser_block_t;
|
||||
|
||||
// Initialize the parser
|
||||
|
||||
2
grbl.h
2
grbl.h
@@ -34,7 +34,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20220710
|
||||
#define GRBL_BUILD 20220718
|
||||
|
||||
// The following symbols are set here if not already set by the compiler or in config.h
|
||||
// Do NOT change here!
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hal.h"
|
||||
@@ -223,8 +224,7 @@ bool mc_line (float *target, plan_line_data_t *pl_data)
|
||||
// The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance
|
||||
// of each segment is configured in settings.arc_tolerance, which is defined to be the maximum normal
|
||||
// distance from segment to the circle when the end points both lie on the circle.
|
||||
void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
plane_t plane, bool is_clockwise_arc)
|
||||
void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius, plane_t plane, int32_t turns)
|
||||
{
|
||||
float center_axis0 = position[plane.axis_0] + offset[plane.axis_0];
|
||||
float center_axis1 = position[plane.axis_1] + offset[plane.axis_1];
|
||||
@@ -235,12 +235,49 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2f(r_axis0 * rt_axis1 - r_axis1 * rt_axis0, r_axis0 * rt_axis0 + r_axis1 * rt_axis1);
|
||||
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (turns > 0) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON)
|
||||
angular_travel -= 2.0f * M_PI;
|
||||
} else {
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON)
|
||||
angular_travel += 2.0f * M_PI;
|
||||
} else if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON)
|
||||
angular_travel += 2.0f * M_PI;
|
||||
|
||||
if(labs(turns) > 1) {
|
||||
|
||||
uint32_t n_turns = labs(turns) - 1;
|
||||
float arc_travel = 2.0f * M_PI * n_turns + angular_travel;
|
||||
coord_data_t arc_target;
|
||||
#if N_AXIS > 3
|
||||
uint_fast8_t idx = N_AXIS;
|
||||
float linear_per_turn[N_AXIS];
|
||||
do {
|
||||
idx--;
|
||||
if(!(idx == plane.axis_0 || idx == plane.axis_1))
|
||||
linear_per_turn[idx] = (target[idx] - position[idx]) / arc_travel * 2.0f * M_PI;;
|
||||
} while(idx);
|
||||
#else
|
||||
float linear_per_turn = (target[plane.axis_linear] - position[plane.axis_linear]) / arc_travel * 2.0f * M_PI;
|
||||
#endif
|
||||
|
||||
memcpy(&arc_target, target, sizeof(coord_data_t));
|
||||
|
||||
arc_target.values[plane.axis_0] = position[plane.axis_0];
|
||||
arc_target.values[plane.axis_1] = position[plane.axis_1];
|
||||
arc_target.values[plane.axis_linear] = position[plane.axis_linear];
|
||||
|
||||
while(n_turns--) {
|
||||
#if N_AXIS > 3
|
||||
idx = N_AXIS;
|
||||
do {
|
||||
idx--;
|
||||
if(!(idx == plane.axis_0 || idx == plane.axis_1))
|
||||
arc_target.values[idx] += linear_per_turn[idx];
|
||||
} while(idx);
|
||||
#else
|
||||
arc_target.values[plane.axis_linear] += linear_per_turn;
|
||||
#endif
|
||||
mc_arc(arc_target.values, pl_data, position, offset, radius, plane, turns > 0 ? 1 : -1);
|
||||
memcpy(position, arc_target.values, sizeof(coord_data_t));
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
|
||||
@@ -345,6 +382,7 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure last segment arrives at target location.
|
||||
mc_line(target, pl_data);
|
||||
}
|
||||
@@ -353,7 +391,7 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o
|
||||
// By Giovanni Mascellani - https://github.com/giomasce/Marlin
|
||||
|
||||
// Compute the linear interpolation between two real numbers.
|
||||
static inline float interp(const float a, const float b, const float t)
|
||||
static inline float interp (const float a, const float b, const float t)
|
||||
{
|
||||
return (1.0f - t) * a + t * b;
|
||||
}
|
||||
@@ -364,7 +402,7 @@ static inline float interp(const float a, const float b, const float t)
|
||||
* easy to code and has good numerical stability (very important,
|
||||
* since Arudino works with limited precision real numbers).
|
||||
*/
|
||||
static inline float eval_bezier(const float a, const float b, const float c, const float d, const float t)
|
||||
static inline float eval_bezier (const float a, const float b, const float c, const float d, const float t)
|
||||
{
|
||||
const float iab = interp(a, b, t),
|
||||
ibc = interp(b, c, t),
|
||||
@@ -379,7 +417,7 @@ static inline float eval_bezier(const float a, const float b, const float c, con
|
||||
* We approximate Euclidean distance with the sum of the coordinates
|
||||
* offset (so-called "norm 1"), which is quicker to compute.
|
||||
*/
|
||||
static inline float dist1(const float x1, const float y1, const float x2, const float y2)
|
||||
static inline float dist1 (const float x1, const float y1, const float x2, const float y2)
|
||||
{
|
||||
return fabsf(x1 - x2) + fabsf(y1 - y2);
|
||||
}
|
||||
@@ -424,12 +462,8 @@ static inline float dist1(const float x1, const float y1, const float x2, const
|
||||
* power available on Arduino, I think it is not wise to implement it.
|
||||
*/
|
||||
|
||||
void mc_cubic_b_spline (float *target, plan_line_data_t *pl_data, float *position, float *offset1, float *offset2)
|
||||
void mc_cubic_b_spline (float *target, plan_line_data_t *pl_data, float *position, float *first, float *second)
|
||||
{
|
||||
// Absolute first and second control points are recovered.
|
||||
|
||||
float first[2] = { position[X_AXIS] + offset1[X_AXIS], position[Y_AXIS] + offset1[Y_AXIS] };
|
||||
float second[2] = { target[X_AXIS] + offset2[X_AXIS], target[Y_AXIS] + offset2[Y_AXIS] };
|
||||
float bez_target[N_AXIS];
|
||||
|
||||
memcpy(bez_target, position, sizeof(float) * N_AXIS);
|
||||
|
||||
@@ -43,7 +43,7 @@ bool mc_line(float *target, plan_line_data_t *pl_data);
|
||||
// the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
plane_t plane, bool is_clockwise_arc);
|
||||
plane_t plane, int32_t turns);
|
||||
|
||||
// Execute canned cycle (drill)
|
||||
void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_data, float *position, plane_t plane, uint32_t repeats, gc_canned_t *canned);
|
||||
|
||||
10
nuts_bolts.h
10
nuts_bolts.h
@@ -3,7 +3,7 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2017-2021 Terje Io
|
||||
Copyright (c) 2017-2022 Terje Io
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
@@ -131,6 +131,14 @@ typedef union {
|
||||
};
|
||||
} axes_signals_t;
|
||||
|
||||
typedef union {
|
||||
float values[2];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
} point_2d;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
//! \brief Limit switches struct, consists of four packed axes_signals_t structs.
|
||||
|
||||
Reference in New Issue
Block a user