Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Replace some constants with N_AXIS. #156

Closed
wants to merge 1 commit into from

2 participants

@daapp

Replace some constants with N_AXIS macro for future axis addition.

There was some white space cleanup by Emacs, sorry :)

Signed-off-by: Alexander Danilov alexander.a.danilov@gmail.com

@daapp daapp Replace some constants with N_AXIS.
Signed-off-by: Alexander Danilov <alexander.a.danilov@gmail.com>
aea3079
@chamnit
Owner

Thanks @daapp! For some reason, github won't let me automatically merge this pull request. I still haven't figured out why it likes certain pulls vs not others. It may have to do with all of the spaces involved or something else. I'm out of town right now and don't have time to fix the pull, but there are two options: I can manually add the changes and push them (unfortunately your pull won't get credited into the grbl commit history) or you can try get it play nicer with automatic merging (it's very tedious to fix a non-automatic merge on my side, especially with the 400+ lines there are in the pull). Let me know what you'd like to do!

@daapp

It is the second time github don't want to merge my pull request... I am ready to fix my commit, but is it possible to know what github told you, why it don't want to merge?

@chamnit
Owner

I had a chance to look at it last night. I think the conflicts have to do with versions. If you checkout a version and make changes to it, then I push one later and you push one after. The merger no longer knows which changes are the correct ones. So it has to be done manually. I checked the current edge version against your push, and it seems that I have already updated some of the N_AXIS variables, but your pull request diff doesn't have these. It should be ignoring them.

I guess you'll have to make sure that you're working on the most recent version and then issue a pull request, before I have a pushed something. Try to limit any changes to a minimum so if there are merging conflicts, it'll be easy for me to fix. Fixing 406 changes manually it a bit too much, so I'll close this for now. Sorry!

@chamnit chamnit closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 30, 2012
  1. @daapp

    Replace some constants with N_AXIS.

    daapp authored
    Signed-off-by: Alexander Danilov <alexander.a.danilov@gmail.com>
This page is out of date. Refresh to see the latest.
View
240 gcode.c
@@ -4,7 +4,7 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011-2012 Sungeun K. Jeon
-
+
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
@@ -41,39 +41,39 @@ parser_state_t gc;
static int next_statement(char *letter, float *float_ptr, char *line, uint8_t *char_counter);
-static void select_plane(uint8_t axis_0, uint8_t axis_1, uint8_t axis_2)
+static void select_plane(uint8_t axis_0, uint8_t axis_1, uint8_t axis_2)
{
gc.plane_axis_0 = axis_0;
gc.plane_axis_1 = axis_1;
gc.plane_axis_2 = axis_2;
}
-void gc_init()
+void gc_init()
{
memset(&gc, 0, sizeof(gc));
gc.feed_rate = settings.default_feed_rate; // Should be zero at initialization.
// gc.seek_rate = settings.default_seek_rate;
select_plane(X_AXIS, Y_AXIS, Z_AXIS);
gc.absolute_mode = true;
-
+
// Load default G54 coordinate system.
- if (!(settings_read_coord_data(gc.coord_select,gc.coord_system))) {
- report_status_message(STATUS_SETTING_READ_FAIL);
- }
-
+ if (!(settings_read_coord_data(gc.coord_select,gc.coord_system))) {
+ report_status_message(STATUS_SETTING_READ_FAIL);
+ }
+
// protocol_status_message(settings_execute_startup());
}
// Sets g-code parser position in mm. Input in steps. Called by the system abort and hard
// limit pull-off routines.
-void gc_set_current_position(int32_t x, int32_t y, int32_t z)
+void gc_set_current_position(int32_t x, int32_t y, int32_t z)
{
gc.position[X_AXIS] = x/settings.steps_per_mm[X_AXIS];
gc.position[Y_AXIS] = y/settings.steps_per_mm[Y_AXIS];
- gc.position[Z_AXIS] = z/settings.steps_per_mm[Z_AXIS];
+ gc.position[Z_AXIS] = z/settings.steps_per_mm[Z_AXIS];
}
-static float to_millimeters(float value)
+static float to_millimeters(float value)
{
return(gc.inches_mode ? (value * MM_PER_INCH) : value);
}
@@ -82,26 +82,26 @@ static float to_millimeters(float value)
// characters and signed floating point values (no whitespace). Comments and block delete
// characters have been removed. All units and positions are converted and exported to grbl's
// internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively.
-uint8_t gc_execute_line(char *line)
+uint8_t gc_execute_line(char *line)
{
- uint8_t char_counter = 0;
+ uint8_t char_counter = 0;
char letter;
float value;
int int_value;
-
+
uint16_t modal_group_words = 0; // Bitflag variable to track and check modal group words in block
uint8_t axis_words = 0; // Bitflag to track which XYZ(ABC) parameters exist in block
float inverse_feed_rate = -1; // negative inverse_feed_rate means no inverse_feed_rate specified
uint8_t absolute_override = false; // true(1) = absolute motion for this block only {G53}
uint8_t non_modal_action = NON_MODAL_NONE; // Tracks the actions of modal group 0 (non-modal)
-
- float target[3], offset[3];
+
+ float target[N_AXIS], offset[N_AXIS];
clear_vector(target); // XYZ(ABC) axes parameters.
clear_vector(offset); // IJK Arc offsets are incremental. Value of zero indicates no change.
-
+
gc.status_code = STATUS_OK;
-
+
/* Pass 1: Commands and set all modes. Check for modal group violations.
NOTE: Modal group numbers are defined in Table 4 of NIST RS274-NGC v3, pg.20 */
uint8_t group_number = MODAL_GROUP_NONE;
@@ -118,7 +118,7 @@ uint8_t gc_execute_line(char *line)
case 93: case 94: group_number = MODAL_GROUP_5; break;
case 20: case 21: group_number = MODAL_GROUP_6; break;
case 54: case 55: case 56: case 57: case 58: case 59: group_number = MODAL_GROUP_12; break;
- }
+ }
// Set 'G' commands
switch(int_value) {
case 0: gc.motion_mode = MOTION_MODE_SEEK; break;
@@ -132,7 +132,7 @@ uint8_t gc_execute_line(char *line)
case 19: select_plane(Y_AXIS, Z_AXIS, X_AXIS); break;
case 20: gc.inches_mode = true; break;
case 21: gc.inches_mode = false; break;
- case 28: case 30:
+ case 28: case 30:
int_value = trunc(10*value); // Multiply by 10 to pick up Gxx.1
switch(int_value) {
case 280: non_modal_action = NON_MODAL_GO_HOME_0; break;
@@ -149,10 +149,10 @@ uint8_t gc_execute_line(char *line)
case 80: gc.motion_mode = MOTION_MODE_CANCEL; break;
case 90: gc.absolute_mode = true; break;
case 91: gc.absolute_mode = false; break;
- case 92:
+ case 92:
int_value = trunc(10*value); // Multiply by 10 to pick up G92.1
switch(int_value) {
- case 920: non_modal_action = NON_MODAL_SET_COORDINATE_OFFSET; break;
+ case 920: non_modal_action = NON_MODAL_SET_COORDINATE_OFFSET; break;
case 921: non_modal_action = NON_MODAL_RESET_COORDINATE_OFFSET; break;
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
@@ -161,22 +161,22 @@ uint8_t gc_execute_line(char *line)
case 94: gc.inverse_feed_rate_mode = false; break;
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
- break;
+ break;
case 'M':
// Set modal group values
switch(int_value) {
case 0: case 1: case 2: case 30: group_number = MODAL_GROUP_4; break;
case 3: case 4: case 5: group_number = MODAL_GROUP_7; break;
- }
+ }
// Set 'M' commands
switch(int_value) {
case 0: gc.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause
case 1: // Program pause with optional stop on, otherwise do nothing.
if (bit_istrue(gc.switches,BITFLAG_OPT_STOP)) {
- gc.program_flow = PROGRAM_FLOW_PAUSED;
+ gc.program_flow = PROGRAM_FLOW_PAUSED;
}
- break;
- case 2: case 30: gc.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset
+ break;
+ case 2: case 30: gc.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset
case 3: gc.spindle_direction = 1; break;
case 4: gc.spindle_direction = -1; break;
case 5: gc.spindle_direction = 0; break;
@@ -186,9 +186,9 @@ uint8_t gc_execute_line(char *line)
case 8: gc.coolant_mode = COOLANT_FLOOD_ENABLE; break;
case 9: gc.coolant_mode = COOLANT_DISABLE; break;
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
- }
+ }
break;
- }
+ }
// Check for modal group multiple command violations in the current block
if (group_number) {
if ( bit_istrue(modal_group_words,bit(group_number)) ) {
@@ -198,12 +198,12 @@ uint8_t gc_execute_line(char *line)
}
group_number = MODAL_GROUP_NONE; // Reset for next command.
}
- }
+ }
// If there were any errors parsing this line, we will return right away with the bad news
if (gc.status_code) { return(gc.status_code); }
-
- /* Pass 2: Parameters. All units converted according to current block commands. Position
+
+ /* Pass 2: Parameters. All units converted according to current block commands. Position
parameters are converted and flagged to indicate a change. These can have multiple connotations
for different commands. Each will be converted to their proper value upon execution. */
float p = 0, r = 0;
@@ -212,26 +212,26 @@ uint8_t gc_execute_line(char *line)
while(next_statement(&letter, &value, line, &char_counter)) {
switch(letter) {
case 'G': case 'M': case 'N': break; // Ignore command statements and line numbers
- case 'F':
+ case 'F':
if (value <= 0) { FAIL(STATUS_INVALID_STATEMENT); } // Must be greater than zero
if (gc.inverse_feed_rate_mode) {
inverse_feed_rate = to_millimeters(value); // seconds per motion for this motion only
- } else {
+ } else {
gc.feed_rate = to_millimeters(value); // millimeters per minute
}
break;
case 'I': case 'J': case 'K': offset[letter-'I'] = to_millimeters(value); break;
case 'L': l = trunc(value); break;
- case 'P': p = value; break;
+ case 'P': p = value; break;
case 'R': r = to_millimeters(value); break;
- case 'S':
+ case 'S':
if (value < 0) { FAIL(STATUS_INVALID_STATEMENT); } // Cannot be negative
// TBD: Spindle speed not supported due to PWM issues, but may come back once resolved.
// gc.spindle_speed = value;
break;
- case 'T':
+ case 'T':
if (value < 0) { FAIL(STATUS_INVALID_STATEMENT); } // Cannot be negative
- gc.tool = trunc(value);
+ gc.tool = trunc(value);
break;
case 'X': target[X_AXIS] = to_millimeters(value); bit_true(axis_words,bit(X_AXIS)); break;
case 'Y': target[Y_AXIS] = to_millimeters(value); bit_true(axis_words,bit(Y_AXIS)); break;
@@ -239,41 +239,41 @@ uint8_t gc_execute_line(char *line)
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
}
-
+
// If there were any errors parsing this line, we will return right away with the bad news
if (gc.status_code) { return(gc.status_code); }
-
-
+
+
/* Execute Commands: Perform by order of execution defined in NIST RS274-NGC.v3, Table 8, pg.41.
- NOTE: Independent non-motion/settings parameters are set out of this order for code efficiency
+ NOTE: Independent non-motion/settings parameters are set out of this order for code efficiency
and simplicity purposes, but this should not affect proper g-code execution. */
-
+
// ([F]: Set feed and seek rates.)
// TODO: Seek rates can change depending on the direction and maximum speeds of each axes. When
// max axis speed is installed, the calculation can be performed here, or maybe in the planner.
-
+
// ([M6]: Tool change should be executed here.)
-
+
// [M3,M4,M5]: Update spindle state
if (!(gc.switches & BITFLAG_CHECK_GCODE)) { spindle_run(gc.spindle_direction); }
-
+
// [*M7,M8,M9]: Update coolant state
if (!(gc.switches & BITFLAG_CHECK_GCODE)) { coolant_run(gc.coolant_mode); }
-
+
// [G54,G55,...,G59]: Coordinate system selection
if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_12)) ) { // Check if called in block
float coord_data[N_AXIS];
- if (!(settings_read_coord_data(gc.coord_select,coord_data))) { return(STATUS_SETTING_READ_FAIL); }
+ if (!(settings_read_coord_data(gc.coord_select,coord_data))) { return(STATUS_SETTING_READ_FAIL); }
memcpy(gc.coord_system,coord_data,sizeof(coord_data));
}
-
+
// [G4,G10,G28,G30,G92,G92.1]: Perform dwell, set coordinate system data, homing, or set axis offsets.
// NOTE: These commands are in the same modal group, hence are mutually exclusive. G53 is in this
// modal group and do not effect these actions.
switch (non_modal_action) {
case NON_MODAL_DWELL:
if (p < 0) { // Time cannot be negative.
- FAIL(STATUS_INVALID_STATEMENT);
+ FAIL(STATUS_INVALID_STATEMENT);
} else {
// Ignore dwell in check gcode modes
if (!(gc.switches & BITFLAG_CHECK_GCODE)) { mc_dwell(p); }
@@ -281,8 +281,8 @@ uint8_t gc_execute_line(char *line)
break;
case NON_MODAL_SET_COORDINATE_DATA:
int_value = trunc(p); // Convert p value to int.
- if ((l != 2 && l != 20) || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 and L20. P1=G54, P2=G55, ...
- FAIL(STATUS_UNSUPPORTED_STATEMENT);
+ if ((l != 2 && l != 20) || (int_value < 1 || int_value > N_COORDINATE_SYSTEM)) { // L2 and L20. P1=G54, P2=G55, ...
+ FAIL(STATUS_UNSUPPORTED_STATEMENT);
} else if (!axis_words && l==2) { // No axis words.
FAIL(STATUS_INVALID_STATEMENT);
} else {
@@ -306,8 +306,8 @@ uint8_t gc_execute_line(char *line)
}
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
- case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
- // Move to intermediate position before going home. Obeys current coordinate system and offsets
+ case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
+ // Move to intermediate position before going home. Obeys current coordinate system and offsets
// and absolute and incremental modes.
if (axis_words) {
// Apply absolute mode coordinate offsets or incremental mode offsets.
@@ -330,7 +330,7 @@ uint8_t gc_execute_line(char *line)
uint8_t home_select = SETTING_INDEX_G28;
if (non_modal_action == NON_MODAL_GO_HOME_1) { home_select = SETTING_INDEX_G30; }
if (!settings_read_coord_data(home_select,coord_data)) { return(STATUS_SETTING_READ_FAIL); }
- mc_line(coord_data[X_AXIS], coord_data[Y_AXIS], coord_data[Z_AXIS], settings.default_seek_rate, false);
+ mc_line(coord_data[X_AXIS], coord_data[Y_AXIS], coord_data[Z_AXIS], settings.default_seek_rate, false);
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
case NON_MODAL_SET_HOME_0: case NON_MODAL_SET_HOME_1:
@@ -343,9 +343,9 @@ uint8_t gc_execute_line(char *line)
FAIL(STATUS_INVALID_STATEMENT);
} else {
// Update axes defined only in block. Offsets current system to defined value. Does not update when
- // active coordinate system is selected, but is still active unless G92.1 disables it.
+ // active coordinate system is selected, but is still active unless G92.1 disables it.
uint8_t i;
- for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used.
+ for (i=0; i<N_AXIS; i++) { // Axes indices are consistent, so loop may be used.
if (bit_istrue(axis_words,bit(i)) ) {
gc.coord_offset[i] = gc.position[i]-gc.coord_system[i]-target[i];
}
@@ -353,18 +353,18 @@ uint8_t gc_execute_line(char *line)
}
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
- case NON_MODAL_RESET_COORDINATE_OFFSET:
+ case NON_MODAL_RESET_COORDINATE_OFFSET:
clear_vector(gc.coord_offset); // Disable G92 offsets by zeroing offset vector.
break;
}
- // [G0,G1,G2,G3,G80]: Perform motion modes.
- // NOTE: Commands G10,G28,G30,G92 lock out and prevent axis words from use in motion modes.
+ // [G0,G1,G2,G3,G80]: Perform motion modes.
+ // NOTE: Commands G10,G28,G30,G92 lock out and prevent axis words from use in motion modes.
// Enter motion modes only if there are axis words or a motion mode command word in the block.
if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_1)) || axis_words ) {
- // G1,G2,G3 require F word in inverse time mode.
- if ( gc.inverse_feed_rate_mode ) {
+ // G1,G2,G3 require F word in inverse time mode.
+ if ( gc.inverse_feed_rate_mode ) {
if (inverse_feed_rate < 0 && gc.motion_mode != MOTION_MODE_CANCEL) {
FAIL(STATUS_INVALID_STATEMENT);
}
@@ -373,14 +373,14 @@ uint8_t gc_execute_line(char *line)
if ( absolute_override && !(gc.motion_mode == MOTION_MODE_SEEK || gc.motion_mode == MOTION_MODE_LINEAR)) {
FAIL(STATUS_INVALID_STATEMENT);
}
- // Report any errors.
+ // Report any errors.
if (gc.status_code) { return(gc.status_code); }
// Convert all target position data to machine coordinates for executing motion. Apply
// absolute mode coordinate offsets or incremental mode offsets.
// NOTE: Tool offsets may be appended to these conversions when/if this feature is added.
uint8_t i;
- for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used to save flash space.
+ for (i=0; i<N_AXIS; i++) { // Axes indices are consistent, so loop may be used to save flash space.
if ( bit_istrue(axis_words,bit(i)) ) {
if (!absolute_override) { // Do not update target in absolute override mode
if (gc.absolute_mode) {
@@ -393,13 +393,13 @@ uint8_t gc_execute_line(char *line)
target[i] = gc.position[i]; // No axis word in block. Keep same axis position.
}
}
-
+
switch (gc.motion_mode) {
- case MOTION_MODE_CANCEL:
+ case MOTION_MODE_CANCEL:
if (axis_words) { FAIL(STATUS_INVALID_STATEMENT); } // No axis words allowed while active.
break;
case MOTION_MODE_SEEK:
- if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);}
+ if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);}
else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], settings.default_seek_rate, false); }
break;
case MOTION_MODE_LINEAR:
@@ -407,32 +407,32 @@ uint8_t gc_execute_line(char *line)
// to check for initial F-word upon startup. Maybe just set to zero upon initialization
// and after an inverse time move and then check for non-zero feed rate each time. This
// should be efficient and effective.
- if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);}
- else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
+ if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);}
+ else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
(gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode); }
break;
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
- // Check if at least one of the axes of the selected plane has been specified. If in center
+ // Check if at least one of the axes of the selected plane has been specified. If in center
// format arc mode, also check for at least one of the IJK axes of the selected plane was sent.
- if ( !( bit_false(axis_words,bit(gc.plane_axis_2)) ) ||
- ( !r && !offset[gc.plane_axis_0] && !offset[gc.plane_axis_1] ) ) {
+ if ( !( bit_false(axis_words,bit(gc.plane_axis_2)) ) ||
+ ( !r && !offset[gc.plane_axis_0] && !offset[gc.plane_axis_1] ) ) {
FAIL(STATUS_INVALID_STATEMENT);
} else {
if (r != 0) { // Arc Radius Mode
- /*
+ /*
We need to calculate the center of the circle that has the designated radius and passes
through both the current position and the target position. This method calculates the following
- set of equations where [x,y] is the vector from current to target position, d == magnitude of
+ set of equations where [x,y] is the vector from current to target position, d == magnitude of
that vector, h == hypotenuse of the triangle formed by the radius of the circle, the distance to
- the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the
- length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point
+ the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the
+ length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point
[i,j] at [x/2-y/d*h, y/2+x/d*h] which will be the center of our arc.
-
+
d^2 == x^2 + y^2
h^2 == r^2 - (d/2)^2
i == x/2 - y/d*h
j == y/2 + x/d*h
-
+
O <- [i,j]
- |
r - |
@@ -441,38 +441,38 @@ uint8_t gc_execute_line(char *line)
- |
[0,0] -> C -----------------+--------------- T <- [x,y]
| <------ d/2 ---->|
-
+
C - Current position
T - Target position
O - center of circle that pass through both C and T
d - distance from C to T
r - designated radius
h - distance from center of CT to O
-
+
Expanding the equations:
-
+
d -> sqrt(x^2 + y^2)
h -> sqrt(4 * r^2 - x^2 - y^2)/2
- i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
+ i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
-
+
Which can be written:
-
+
i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
-
+
Which we for size and speed reasons optimize to:
-
+
h_x2_div_d = sqrt(4 * r^2 - x^2 - y^2)/sqrt(x^2 + y^2)
i = (x - (y * h_x2_div_d))/2
j = (y + (x * h_x2_div_d))/2
-
+
*/
-
+
// Calculate the change in position along each selected axis
float x = target[gc.plane_axis_0]-gc.position[gc.plane_axis_0];
float y = target[gc.plane_axis_1]-gc.position[gc.plane_axis_1];
-
+
clear_vector(offset);
// First, use h_x2_div_d to compute 4*h^2 to check if it is negative or r is smaller
// than d. If so, the sqrt of a negative number is complex and error out.
@@ -482,85 +482,85 @@ uint8_t gc_execute_line(char *line)
h_x2_div_d = -sqrt(h_x2_div_d)/hypot(x,y); // == -(h * 2 / d)
// Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below)
if (gc.motion_mode == MOTION_MODE_CCW_ARC) { h_x2_div_d = -h_x2_div_d; }
-
+
/* The counter clockwise circle lies to the left of the target direction. When offset is positive,
the left hand circle will be generated - when it is negative the right hand circle is generated.
-
-
+
+
T <-- Target position
-
- ^
+
+ ^
Clockwise circles with this center | Clockwise circles with this center will have
will have > 180 deg of angular travel | < 180 deg of angular travel, which is a good thing!
- \ | /
+ \ | /
center of arc when h_x2_div_d is positive -> x <----- | -----> x <- center of arc when h_x2_div_d is negative
|
|
-
+
C <-- Current position */
-
-
- // Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!),
- // even though it is advised against ever generating such circles in a single line of g-code. By
+
+
+ // Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!),
+ // even though it is advised against ever generating such circles in a single line of g-code. By
// inverting the sign of h_x2_div_d the center of the circles is placed on the opposite side of the line of
// travel and thus we get the unadvisably long arcs as prescribed.
- if (r < 0) {
- h_x2_div_d = -h_x2_div_d;
+ if (r < 0) {
+ h_x2_div_d = -h_x2_div_d;
r = -r; // Finished with r. Set to positive for mc_arc
- }
+ }
// Complete the operation by calculating the actual center of the arc
offset[gc.plane_axis_0] = 0.5*(x-(y*h_x2_div_d));
offset[gc.plane_axis_1] = 0.5*(y+(x*h_x2_div_d));
- } else { // Arc Center Format Offset Mode
+ } else { // Arc Center Format Offset Mode
r = hypot(offset[gc.plane_axis_0], offset[gc.plane_axis_1]); // Compute arc radius for mc_arc
}
-
+
// Set clockwise/counter-clockwise sign for mc_arc computations
uint8_t isclockwise = false;
if (gc.motion_mode == MOTION_MODE_CW_ARC) { isclockwise = true; }
-
+
// Trace the arc
mc_arc(gc.position, target, offset, gc.plane_axis_0, gc.plane_axis_1, gc.plane_axis_2,
(gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode,
r, isclockwise);
- }
+ }
break;
}
-
+
// Report any errors.
- if (gc.status_code) { return(gc.status_code); }
-
+ if (gc.status_code) { return(gc.status_code); }
+
// 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.
memcpy(gc.position, target, sizeof(target)); // gc.position[] = target[];
}
-
- // M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may
+
+ // M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may
// refill and can only be resumed by the cycle start run-time command.
if (gc.program_flow || bit_istrue(gc.switches,BITFLAG_SINGLE_BLOCK)) {
plan_synchronize(); // Finish all remaining buffered motions. Program paused when complete.
sys.auto_start = false; // Disable auto cycle start. Forces pause until cycle start issued.
-
+
// If complete, reset to reload defaults (G92.2,G54,G17,G90,G94,M48,G40,M5,M9). Otherwise,
// re-enable program flow after pause complete, where cycle start will resume the program.
if (gc.program_flow == PROGRAM_FLOW_COMPLETED) { sys.execute |= EXEC_RESET; }
else { gc.program_flow = PROGRAM_FLOW_RUNNING; }
- }
-
+ }
+
return(gc.status_code);
}
// Parses the next statement and leaves the counter on the first character following
// the statement. Returns 1 if there was a statements, 0 if end of string was reached
// or there was an error (check state.status_code).
-static int next_statement(char *letter, float *float_ptr, char *line, uint8_t *char_counter)
+static int next_statement(char *letter, float *float_ptr, char *line, uint8_t *char_counter)
{
if (line[*char_counter] == 0) {
return(0); // No more statements
}
-
+
*letter = line[*char_counter];
if((*letter < 'A') || (*letter > 'Z')) {
FAIL(STATUS_EXPECTED_COMMAND_LETTER);
@@ -568,13 +568,13 @@ static int next_statement(char *letter, float *float_ptr, char *line, uint8_t *c
}
(*char_counter)++;
if (!read_float(line, char_counter, float_ptr)) {
- FAIL(STATUS_BAD_NUMBER_FORMAT);
+ FAIL(STATUS_BAD_NUMBER_FORMAT);
return(0);
};
return(1);
}
-/*
+/*
Not supported:
- Canned cycles
@@ -585,7 +585,7 @@ static int next_statement(char *letter, float *float_ptr, char *line, uint8_t *c
- Probing
- Override control
- Tool changes
-
+
(*) Indicates optional parameter, enabled through config.h and re-compile
group 0 = {G92.2, G92.3} (Non modal: Cancel and re-enable G92 offsets)
group 1 = {G38.2, G81 - G89} (Motion modes: straight probe, canned cycles)
View
20 gcode.h
@@ -4,7 +4,7 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011-2012 Sungeun K. Jeon
-
+
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
@@ -24,10 +24,10 @@
#include <avr/io.h>
#include "nuts_bolts.h"
-// Define modal group internal numbers for checking multiple command violations and tracking the
+// Define modal group internal numbers for checking multiple command violations and tracking the
// type of command that is called in the block. A modal group is a group of g-code commands that are
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
-// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
+// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
#define MODAL_GROUP_NONE 0
#define MODAL_GROUP_0 1 // [G4,G10,G28,G30,G53,G92,G92.1] Non-modal
@@ -42,7 +42,7 @@
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
-#define MOTION_MODE_SEEK 0 // G0
+#define MOTION_MODE_SEEK 0 // G0
#define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3
@@ -84,17 +84,17 @@ typedef struct {
uint8_t coolant_mode; // 0 = Disable, 1 = Flood Enable {M8, M9}
float feed_rate; // Millimeters/min
// float seek_rate; // Millimeters/min. Will be used in v0.9 when axis independence is installed
- float position[3]; // Where the interpreter considers the tool to be at this point in the code
+ float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
uint8_t tool;
// uint16_t spindle_speed; // RPM/100
- uint8_t plane_axis_0,
- plane_axis_1,
- plane_axis_2; // The axes of the selected plane
+ uint8_t plane_axis_0,
+ plane_axis_1,
+ plane_axis_2; // The axes of the selected plane
uint8_t coord_select; // Active work coordinate system number. Default: 0=G54.
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
// position in mm. Loaded from EEPROM when called.
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
- // machine zero in mm. Non-persistent. Cleared upon reset and boot.
+ // machine zero in mm. Non-persistent. Cleared upon reset and boot.
} parser_state_t;
extern parser_state_t gc;
@@ -105,6 +105,6 @@ void gc_init();
uint8_t gc_execute_line(char *line);
// Set g-code parser position. Input in steps.
-void gc_set_current_position(int32_t x, int32_t y, int32_t z);
+void gc_set_current_position(int32_t x, int32_t y, int32_t z);
#endif
View
72 limits.c
@@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
@@ -35,7 +35,7 @@
#define MICROSECONDS_PER_ACCELERATION_TICK (1000000/ACCELERATION_TICKS_PER_SECOND)
-void limits_init()
+void limits_init()
{
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
@@ -52,48 +52,48 @@ void limits_init()
// special pinout for an e-stop, but it is generally recommended to just directly connect
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
// TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
-// interrupt without adding too much to it. All it would need is some way to stop one axis
+// interrupt without adding too much to it. All it would need is some way to stop one axis
// when its limit is triggered and continue the others. This may reduce some of the code, but
// would make Grbl a little harder to read and understand down road. Holding off on this until
// we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
-ISR(LIMIT_INT_vect)
+ISR(LIMIT_INT_vect)
{
// Only enter if the system alarm is not active.
- if (bit_isfalse(sys.execute,EXEC_ALARM)) {
+ if (bit_isfalse(sys.execute,EXEC_ALARM)) {
// Kill all processes upon hard limit event.
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
mc_alarm(); // Initiate system kill.
sys.state = STATE_LIMIT; // Set system state to indicate event.
- }
+ }
}
}
// Moves all specified axes in same specified direction (positive=true, negative=false)
-// and at the homing rate. Homing is a special motion case, where there is only an
-// acceleration followed by abrupt asynchronous stops by each axes reaching their limit
-// switch independently. Instead of shoehorning homing cycles into the main stepper
-// algorithm and overcomplicate things, a stripped-down, lite version of the stepper
+// and at the homing rate. Homing is a special motion case, where there is only an
+// acceleration followed by abrupt asynchronous stops by each axes reaching their limit
+// switch independently. Instead of shoehorning homing cycles into the main stepper
+// algorithm and overcomplicate things, a stripped-down, lite version of the stepper
// algorithm is written here. This also lets users hack and tune this code freely for
// their own particular needs without affecting the rest of Grbl.
// NOTE: Only the abort runtime command can interrupt this process.
-static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
- bool invert_pin, float homing_rate)
+static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
+ bool invert_pin, float homing_rate)
{
// Determine governing axes with finest step resolution per distance for the Bresenham
- // algorithm. This solves the issue when homing multiple axes that have different
+ // algorithm. This solves the issue when homing multiple axes that have different
// resolutions without exceeding system acceleration setting. It doesn't have to be
- // perfect since homing locates machine zero, but should create for a more consistent
+ // perfect since homing locates machine zero, but should create for a more consistent
// and speedy homing routine.
- // NOTE: For each axes enabled, the following calculations assume they physically move
+ // NOTE: For each axes enabled, the following calculations assume they physically move
// an equal distance over each time step until they hit a limit switch, aka dogleg.
- uint32_t steps[3];
+ uint32_t steps[N_AXIS];
clear_vector(steps);
if (x_axis) { steps[X_AXIS] = lround(settings.steps_per_mm[X_AXIS]); }
if (y_axis) { steps[Y_AXIS] = lround(settings.steps_per_mm[Y_AXIS]); }
if (z_axis) { steps[Z_AXIS] = lround(settings.steps_per_mm[Z_AXIS]); }
- uint32_t step_event_count = max(steps[X_AXIS], max(steps[Y_AXIS], steps[Z_AXIS]));
-
+ uint32_t step_event_count = max(steps[X_AXIS], max(steps[Y_AXIS], steps[Z_AXIS]));
+
// To ensure global acceleration is not exceeded, reduce the governing axes nominal rate
// by adjusting the actual axes distance traveled per step. This is the same procedure
// used in the main planner to account for distance traveled when moving multiple axes.
@@ -103,7 +103,7 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
// Compute the adjusted step rate change with each acceleration tick. (in step/min/acceleration_tick)
uint32_t delta_rate = ceil( ds*settings.acceleration/(60*ACCELERATION_TICKS_PER_SECOND));
-
+
// Nominal and initial time increment per step. Nominal should always be greater then 3
// usec, since they are based on the same parameters as the main stepper routine. Initial
// is based on the MINIMUM_STEPS_PER_MINUTE config. Since homing feed can be very slow,
@@ -111,12 +111,12 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
uint32_t dt_min = lround(1000000*60/(ds*homing_rate)); // Cruising (usec/step)
uint32_t dt = 1000000*60/MINIMUM_STEPS_PER_MINUTE; // Initial (usec/step)
if (dt > dt_min) { dt = dt_min; } // Disable acceleration for very slow rates.
-
- // Set default out_bits.
+
+ // Set default out_bits.
uint8_t out_bits0 = settings.invert_mask;
out_bits0 ^= (settings.homing_dir_mask & DIRECTION_MASK); // Apply homing direction settings
if (!pos_dir) { out_bits0 ^= DIRECTION_MASK; } // Invert bits, if negative dir.
-
+
// Initialize stepping variables
int32_t counter_x = -(step_event_count >> 1); // Bresenham counters
int32_t counter_y = counter_x;
@@ -127,14 +127,14 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
uint8_t out_bits;
uint8_t limit_state;
for(;;) {
-
+
// Reset out bits. Both direction and step pins appropriately inverted and set.
out_bits = out_bits0;
-
+
// Get limit pin state.
limit_state = LIMIT_PIN;
if (invert_pin) { limit_state ^= LIMIT_MASK; } // If leaving switch, invert to move.
-
+
// Set step pins by Bresenham line algorithm. If limit switch reached, disable and
// flag for completion.
if (x_axis) {
@@ -160,20 +160,20 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
else { z_axis = false; }
counter_z -= step_event_count;
}
- }
-
+ }
+
// Check if we are done or for system abort
protocol_execute_runtime();
if (!(x_axis || y_axis || z_axis) || sys.abort) { return; }
-
+
// Perform step.
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (out_bits & STEP_MASK);
delay_us(settings.pulse_microseconds);
STEPPING_PORT = out_bits0;
delay_us(step_delay);
-
+
// Track and set the next step delay, if required. This routine uses another Bresenham
- // line algorithm to follow the constant acceleration line in the velocity and time
+ // line algorithm to follow the constant acceleration line in the velocity and time
// domain. This is a lite version of the same routine used in the main stepper program.
if (dt > dt_min) { // Unless cruising, check for time update.
trap_counter += dt; // Track time passed since last update.
@@ -189,16 +189,16 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
}
-void limits_go_home()
-{
+void limits_go_home()
+{
// Enable only the steppers, not the cycle. Cycle should be complete.
st_wake_up();
-
+
// Jog all axes toward home to engage their limit switches at faster homing seek rate.
homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // First jog the z axis
homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // Then jog the x and y axis
delay_ms(settings.homing_debounce_delay); // Delay to debounce signal
-
+
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles
// to precisely hone in on the machine zero location. Moves at slower homing feed rate.
int8_t n_cycle = N_HOMING_CYCLE;
@@ -206,7 +206,7 @@ void limits_go_home()
// Leave all switches to release them. After cycles complete, this is machine zero.
homing_cycle(true, true, true, false, true, settings.homing_feed_rate);
delay_ms(settings.homing_debounce_delay);
-
+
if (n_cycle > 0) {
// Re-approach all switches to re-engage them.
homing_cycle(true, true, true, true, false, settings.homing_feed_rate);
@@ -214,5 +214,5 @@ void limits_go_home()
}
}
- st_go_idle(); // Call main stepper shutdown routine.
+ st_go_idle(); // Call main stepper shutdown routine.
}
View
94 motion_control.c
@@ -5,7 +5,7 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011-2012 Sungeun K. Jeon
Copyright (c) 2011 Jens Geisler
-
+
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
@@ -39,24 +39,24 @@
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
// (1 minute)/feed_rate time.
-// NOTE: This is the primary gateway to the grbl planner. All line motions, including arc line
+// NOTE: This is the primary gateway to the grbl planner. All line motions, including arc line
// segments, must pass through this routine before being passed to the planner. The seperation of
// mc_line and plan_buffer_line is done primarily to make backlash compensation integration simple
// and direct.
// TODO: Check for a better way to avoid having to push the arguments twice for non-backlash cases.
-// However, this keeps the memory requirements lower since it doesn't have to call and hold two
+// However, this keeps the memory requirements lower since it doesn't have to call and hold two
// plan_buffer_lines in memory. Grbl only has to retain the original line input variables during a
// backlash segment(s).
void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rate)
{
// TODO: Backlash compensation may be installed here. Only need direction info to track when
// to insert a backlash line motion(s) before the intended line motion. Requires its own
- // plan_check_full_buffer() and check for system abort loop. Also for position reporting
+ // plan_check_full_buffer() and check for system abort loop. Also for position reporting
// backlash steps will need to be also tracked. Not sure what the best strategy is for this,
// i.e. keep the planner independent and do the computations in the status reporting, or let
// the planner handle the position corrections. The latter may get complicated.
- // If the buffer is full: good! That means we are well ahead of the robot.
+ // If the buffer is full: good! That means we are well ahead of the robot.
// Remain in this loop until there is room in the buffer.
do {
protocol_execute_runtime(); // Check for any run-time commands
@@ -66,35 +66,35 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat
// If in check gcode mode, prevent motion by blocking planner.
if (bit_isfalse(gc.switches,BITFLAG_CHECK_GCODE)) {
plan_buffer_line(x, y, z, feed_rate, invert_feed_rate);
-
+
// Indicate to the system there is now a planned block in the buffer ready to cycle start.
// NOTE: If homing cycles are enabled, a position lost state will lock out all motions,
- // until a homing cycle has been completed. This is a safety feature to help prevent
+ // until a homing cycle has been completed. This is a safety feature to help prevent
// the machine from crashing.
if (!sys.state) { sys.state = STATE_QUEUED; }
-
- // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
- // a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start
+
+ // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
+ // a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start
// runtime command.
// NOTE: This is allows the user to decide to exclusively use the cycle start runtime command to
// begin motion or let grbl auto-start it for them. This is useful when: manually cycle-starting
- // when the buffer is completely full and primed; auto-starting, if there was only one g-code
+ // when the buffer is completely full and primed; auto-starting, if there was only one g-code
// command sent during manual operation; or if a system is prone to buffer starvation, auto-start
- // helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going.
+ // helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going.
if (sys.auto_start) { st_cycle_start(); }
}
}
-// Execute an arc in offset mode format. position == current xyz, target == target xyz,
+// Execute an arc in offset mode format. position == current xyz, target == target xyz,
// 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.
-// 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,
+// 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, uint8_t invert_feed_rate, float radius, uint8_t isclockwise)
-{
+{
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];
@@ -102,7 +102,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
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 (isclockwise) { // Correct atan2 output per direction
@@ -110,48 +110,48 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
} else {
if (angular_travel <= 0) { angular_travel += 2*M_PI; }
}
-
+
float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
if (millimeters_of_travel == 0.0) { return; }
uint16_t segments = floor(millimeters_of_travel/settings.mm_per_arc_segment);
// 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
+ // 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;
-
+
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
and phi is the angle of rotation. 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
+
+ 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.
+ tool precision in some cases. Therefore, arc path correction is implemented.
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
+ 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
+
+ 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.
+ 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[3];
+
+ float arc_target[N_AXIS];
float sin_Ti;
float cos_Ti;
float r_axisi;
@@ -162,9 +162,9 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
arc_target[axis_linear] = position[axis_linear];
for (i = 1; i<segments; i++) { // Increment (segments-1)
-
+
if (count < settings.n_arc_correction) {
- // Apply vector rotation matrix
+ // Apply vector rotation matrix
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
r_axis1 = r_axisi;
@@ -184,7 +184,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
arc_target[axis_1] = center_axis1 + r_axis1;
arc_target[axis_linear] += linear_per_segment;
mc_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], feed_rate, invert_feed_rate);
-
+
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
if (sys.abort) { return; }
}
@@ -194,7 +194,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// Execute dwell in seconds.
-void mc_dwell(float seconds)
+void mc_dwell(float seconds)
{
uint16_t i = floor(1000/DWELL_TIME_STEP*seconds);
plan_synchronize();
@@ -215,38 +215,38 @@ void mc_go_home()
{
sys.state = STATE_HOMING; // Set system state variable
PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt
-
+
limits_go_home(); // Perform homing routine.
if (sys.abort) {
sys.state = STATE_ALARM; // Homing routine did not complete.
- return;
+ return;
}
- // The machine should now be homed and machine zero has been located. Upon completion,
+ // The machine should now be homed and machine zero has been located. Upon completion,
// reset system position and sync internal position vectors.
clear_vector_float(sys.position); // Set machine zero
sys_sync_current_position();
sys.state = STATE_IDLE; // Set system state to IDLE to complete motion and indicate homed.
-
+
// Pull-off all axes from limit switches before continuing motion. This provides some initial
- // clearance off the switches and should also help prevent them from falsely tripping when
+ // clearance off the switches and should also help prevent them from falsely tripping when
// hard limits are enabled.
int8_t x_dir, y_dir, z_dir;
x_dir = y_dir = z_dir = -1;
if (bit_istrue(settings.homing_dir_mask,bit(X_DIRECTION_BIT))) { x_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = 1; }
- mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
+ mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
z_dir*settings.homing_pulloff, settings.homing_feed_rate, false);
- st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
+ st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes.
-
+
// The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors.
sys_sync_current_position();
// If hard limits feature enabled, re-enable hard limits interrupt after homing cycle.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); }
- // Finished!
+ // Finished!
}
@@ -254,14 +254,14 @@ void mc_go_home()
// and upon g-code parser error (when installed).
void mc_alarm()
{
- // Only this function can set the system alarm. This is done to prevent multiple kill calls
+ // Only this function can set the system alarm. This is done to prevent multiple kill calls
// by different processes.
if (bit_isfalse(sys.execute, EXEC_ALARM)) {
// Set system alarm flag to have the main program check for anything wrong with shutting
// down the system.
sys.execute |= EXEC_ALARM;
// Immediately force stepper, spindle, and coolant to stop.
- st_go_idle();
+ st_go_idle();
spindle_stop();
coolant_stop();
}
View
18 nuts_bolts.h
@@ -3,7 +3,7 @@
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
- Copyright (c) 2011-2012 Sungeun K. Jeon
+ Copyright (c) 2011-2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,17 +45,17 @@
#define min(a,b) (((a) < (b)) ? (a) : (b))
// Bit field and masking macros
-#define bit(n) (1 << n)
+#define bit(n) (1 << n)
#define bit_true(x,mask) (x |= mask)
#define bit_false(x,mask) (x &= ~mask)
#define bit_toggle(x,mask) (x ^= mask)
#define bit_istrue(x,mask) ((x & mask) != 0)
#define bit_isfalse(x,mask) ((x & mask) == 0)
-// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
+// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
// which notifies the main program to execute the specified runtime command asynchronously.
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
-// flags are always false, so the runtime protocol only needs to check for a non-zero value to
+// flags are always false, so the runtime protocol only needs to check for a non-zero value to
// know when there is a runtime command to execute.
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
@@ -83,16 +83,16 @@ typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
- int32_t position[3]; // Real-time machine (aka home) position vector in steps.
- // NOTE: This may need to be a volatile variable, if problems arise.
+ int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
+ // NOTE: This may need to be a volatile variable, if problems arise.
uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
// uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume.
-// volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
+// volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
} system_t;
extern system_t sys;
-// Read a floating point value from a string. Line points to the input buffer, char_counter
-// is the indexer pointing to the current character of the line, while float_ptr is
+// Read a floating point value from a string. Line points to the input buffer, char_counter
+// is the indexer pointing to the current character of the line, while float_ptr is
// a pointer to the result variable. Returns true when it succeeds
int read_float(char *line, uint8_t *char_counter, float *float_ptr);
View
234 planner.c
@@ -4,8 +4,8 @@
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011-2012 Sungeun K. Jeon
- Copyright (c) 2011 Jens Geisler
-
+ Copyright (c) 2011 Jens Geisler
+
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
@@ -22,7 +22,7 @@
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
-#include <inttypes.h>
+#include <inttypes.h>
#include <stdlib.h>
#include "planner.h"
#include "nuts_bolts.h"
@@ -38,17 +38,17 @@ static uint8_t next_buffer_head; // Index of the next buffer hea
// Define planner variables
typedef struct {
- int32_t position[3]; // The planner position of the tool in absolute steps. Kept separate
+ int32_t position[N_AXIS]; // The planner position of the tool in absolute steps. Kept separate
// from g-code position for movements requiring multiple line motions,
// i.e. arcs, canned cycles, and backlash compensation.
- float previous_unit_vec[3]; // Unit vector of previous path line segment
+ float previous_unit_vec[N_AXIS]; // Unit vector of previous path line segment
float previous_nominal_speed; // Nominal speed of previous path line segment
} planner_t;
static planner_t pl;
// Returns the index of the next block in the ring buffer
// NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
-static uint8_t next_block_index(uint8_t block_index)
+static uint8_t next_block_index(uint8_t block_index)
{
block_index++;
if (block_index == BLOCK_BUFFER_SIZE) { block_index = 0; }
@@ -57,7 +57,7 @@ static uint8_t next_block_index(uint8_t block_index)
// Returns the index of the previous block in the ring buffer
-static uint8_t prev_block_index(uint8_t block_index)
+static uint8_t prev_block_index(uint8_t block_index)
{
if (block_index == 0) { block_index = BLOCK_BUFFER_SIZE; }
block_index--;
@@ -65,9 +65,9 @@ static uint8_t prev_block_index(uint8_t block_index)
}
-// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the
+// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the
// given acceleration:
-static float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
+static float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
{
return( (target_rate*target_rate-initial_rate*initial_rate)/(2*acceleration) );
}
@@ -75,45 +75,45 @@ static float estimate_acceleration_distance(float initial_rate, float target_rat
/* + <- some maximum rate we don't care about
/|\
- / | \
- / | + <- final_rate
- / | |
- initial_rate -> +----+--+
- ^ ^
- | |
+ / | \
+ / | + <- final_rate
+ / | |
+ initial_rate -> +----+--+
+ ^ ^
+ | |
intersection_distance distance */
-// This function gives you the point at which you must start braking (at the rate of -acceleration) if
+// This function gives you the point at which you must start braking (at the rate of -acceleration) if
// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
// a total travel of distance. This can be used to compute the intersection point between acceleration and
// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
-static float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
+static float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
{
return( (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4*acceleration) );
}
-
+
// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity
// using the acceleration within the allotted distance.
// NOTE: sqrt() reimplimented here from prior version due to improved planner logic. Increases speed
// in time critical computations, i.e. arcs or rapid short lines from curves. Guaranteed to not exceed
// BLOCK_BUFFER_SIZE calls per planner cycle.
-static float max_allowable_speed(float acceleration, float target_velocity, float distance)
+static float max_allowable_speed(float acceleration, float target_velocity, float distance)
{
return( sqrt(target_velocity*target_velocity-2*acceleration*distance) );
}
// The kernel called by planner_recalculate() when scanning the plan from last to first entry.
-static void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next)
+static void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next)
{
if (!current) { return; } // Cannot operate on nothing.
-
- if (next) {
+
+ if (next) {
// If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
- // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
+ // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
// check for maximum allowable speed reductions to ensure maximum possible planned speed.
if (current->entry_speed != current->max_entry_speed) {
-
+
// If nominal length true, max junction speed is guaranteed to be reached. Only compute
// for max allowable speed if block is decelerating and nominal length is false.
if ((!current->nominal_length_flag) && (current->max_entry_speed > next->entry_speed)) {
@@ -121,21 +121,21 @@ static void planner_reverse_pass_kernel(block_t *previous, block_t *current, blo
max_allowable_speed(-settings.acceleration,next->entry_speed,current->millimeters));
} else {
current->entry_speed = current->max_entry_speed;
- }
- current->recalculate_flag = true;
-
+ }
+ current->recalculate_flag = true;
+
}
} // Skip last block. Already initialized and set for recalculation.
}
-// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
+// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
// implements the reverse pass.
-static void planner_reverse_pass()
+static void planner_reverse_pass()
{
uint8_t block_index = block_buffer_head;
block_t *block[3] = {NULL, NULL, NULL};
- while(block_index != block_buffer_tail) {
+ while(block_index != block_buffer_tail) {
block_index = prev_block_index( block_index );
block[2]= block[1];
block[1]= block[0];
@@ -147,14 +147,14 @@ static void planner_reverse_pass()
// The kernel called by planner_recalculate() when scanning the plan from first to last entry.
-static void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next)
+static void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next)
{
if(!previous) { return; } // Begin planning after buffer_tail
-
+
// If the previous block is an acceleration block, but it is not long enough to complete the
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
// speeds have already been reset, maximized, and reverse planned by reverse planner.
- // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
+ // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
if (!previous->nominal_length_flag) {
if (previous->entry_speed < current->entry_speed) {
float entry_speed = min( current->entry_speed,
@@ -165,18 +165,18 @@ static void planner_forward_pass_kernel(block_t *previous, block_t *current, blo
current->entry_speed = entry_speed;
current->recalculate_flag = true;
}
- }
+ }
}
}
-// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
+// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
// implements the forward pass.
-static void planner_forward_pass()
+static void planner_forward_pass()
{
uint8_t block_index = block_buffer_tail;
block_t *block[3] = {NULL, NULL, NULL};
-
+
while(block_index != block_buffer_head) {
block[0] = block[1];
block[1] = block[2];
@@ -188,74 +188,74 @@ static void planner_forward_pass()
}
-/* STEPPER RATE DEFINITION
+/* STEPPER RATE DEFINITION
+--------+ <- nominal_rate
- / \
- nominal_rate*entry_factor -> + \
- | + <- nominal_rate*exit_factor
- +-------------+
- time -->
-*/
+ / \
+ nominal_rate*entry_factor -> + \
+ | + <- nominal_rate*exit_factor
+ +-------------+
+ time -->
+*/
// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
// The factors represent a factor of braking and must be in the range 0.0-1.0.
// This converts the planner parameters to the data required by the stepper controller.
// NOTE: Final rates must be computed in terms of their respective blocks.
-static void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor)
-{
+static void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor)
+{
block->initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
block->final_rate = ceil(block->nominal_rate*exit_factor); // (step/min)
int32_t acceleration_per_minute = block->rate_delta*ACCELERATION_TICKS_PER_SECOND*60.0; // (step/min^2)
- int32_t accelerate_steps =
+ int32_t accelerate_steps =
ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration_per_minute));
- int32_t decelerate_steps =
+ int32_t decelerate_steps =
floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration_per_minute));
-
- // Calculate the size of Plateau of Nominal Rate.
+
+ // Calculate the size of Plateau of Nominal Rate.
int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
-
+
// Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
- // have to use intersection_distance() to calculate when to abort acceleration and start braking
+ // have to use intersection_distance() to calculate when to abort acceleration and start braking
// in order to reach the final_rate exactly at the end of this block.
- if (plateau_steps < 0) {
+ if (plateau_steps < 0) {
accelerate_steps = ceil(
intersection_distance(block->initial_rate, block->final_rate, acceleration_per_minute, block->step_event_count));
accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
accelerate_steps = min(accelerate_steps,block->step_event_count);
plateau_steps = 0;
- }
-
+ }
+
block->accelerate_until = accelerate_steps;
block->decelerate_after = accelerate_steps+plateau_steps;
-}
+}
-/* PLANNER SPEED DEFINITION
+/* PLANNER SPEED DEFINITION
+--------+ <- current->nominal_speed
- / \
- current->entry_speed -> + \
+ / \
+ current->entry_speed -> + \
| + <- next->entry_speed
- +-------------+
- time -->
-*/
-// Recalculates the trapezoid speed profiles for flagged blocks in the plan according to the
-// entry_speed for each junction and the entry_speed of the next junction. Must be called by
+ +-------------+
+ time -->
+*/
+// Recalculates the trapezoid speed profiles for flagged blocks in the plan according to the
+// entry_speed for each junction and the entry_speed of the next junction. Must be called by
// planner_recalculate() after updating the blocks. Any recalulate flagged junction will
-// compute the two adjacent trapezoids to the junction, since the junction speed corresponds
+// compute the two adjacent trapezoids to the junction, since the junction speed corresponds
// to exit speed and entry speed of one another.
-static void planner_recalculate_trapezoids()
+static void planner_recalculate_trapezoids()
{
uint8_t block_index = block_buffer_tail;
block_t *current;
block_t *next = NULL;
-
+
while(block_index != block_buffer_head) {
current = next;
next = &block_buffer[block_index];
if (current) {
// Recalculate if current block entry or exit junction speed has changed.
if (current->recalculate_flag || next->recalculate_flag) {
- // NOTE: Entry and exit factors always > 0 by all previous logic operations.
+ // NOTE: Entry and exit factors always > 0 by all previous logic operations.
calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed,
- next->entry_speed/current->nominal_speed);
+ next->entry_speed/current->nominal_speed);
current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
}
}
@@ -269,16 +269,16 @@ static void planner_recalculate_trapezoids()
// Recalculates the motion plan according to the following algorithm:
//
-// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_speed)
+// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_speed)
// so that:
// a. The junction speed is equal to or less than the maximum junction speed limit
-// b. No speed reduction within one block requires faster deceleration than the one, true constant
+// b. No speed reduction within one block requires faster deceleration than the one, true constant
// acceleration.
-// 2. Go over every block in chronological order and dial down junction speed values if
-// a. The speed increase within one block would require faster acceleration than the one, true
+// 2. Go over every block in chronological order and dial down junction speed values if
+// a. The speed increase within one block would require faster acceleration than the one, true
// constant acceleration.
//
-// When these stages are complete all blocks have an entry speed that will allow all speed changes to
+// When these stages are complete all blocks have an entry speed that will allow all speed changes to
// be performed using only the one, true constant acceleration, and where no junction speed is greater
// than the max limit. Finally it will:
//
@@ -288,33 +288,33 @@ static void planner_recalculate_trapezoids()
// All planner computations are performed with doubles (float on Arduinos) to minimize numerical round-
// off errors. Only when planned values are converted to stepper rate parameters, these are integers.
-static void planner_recalculate()
-{
+static void planner_recalculate()
+{
planner_reverse_pass();
planner_forward_pass();
planner_recalculate_trapezoids();
}
-void plan_reset_buffer()
+void plan_reset_buffer()
{
block_buffer_tail = block_buffer_head;
next_buffer_head = next_block_index(block_buffer_head);
}
-void plan_init()
+void plan_init()
{
plan_reset_buffer();
memset(&pl, 0, sizeof(pl)); // Clear planner struct
}
-inline void plan_discard_current_block()
+inline void plan_discard_current_block()
{
if (block_buffer_head != block_buffer_tail) {
block_buffer_tail = next_block_index( block_buffer_tail );
}
}
-inline block_t *plan_get_current_block()
+inline block_t *plan_get_current_block()
{
if (block_buffer_head == block_buffer_tail) { return(NULL); }
return(&block_buffer[block_buffer_tail]);
@@ -330,35 +330,35 @@ uint8_t plan_check_full_buffer()
// Block until all buffered steps are executed.
void plan_synchronize()
{
- while (plan_get_current_block()) {
+ while (plan_get_current_block()) {
protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort
- }
+ }
}
-// Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in
+// Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in
// millimeters. Feed rate specifies the speed of the motion. If feed rate is inverted, the feed
// rate is taken to mean "frequency" and would complete the operation in 1/feed_rate minutes.
-// All position data passed to the planner must be in terms of machine position to keep the planner
+// All position data passed to the planner must be in terms of machine position to keep the planner
// independent of any coordinate system changes and offsets, which are handled by the g-code parser.
// NOTE: Assumes buffer is available. Buffer checks are handled at a higher level by motion_control.
-void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rate)
+void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rate)
{
// Prepare to set up new block
block_t *block = &block_buffer[block_buffer_head];
// Calculate target position in absolute steps
- int32_t target[3];
+ int32_t target[N_AXIS];
target[X_AXIS] = lround(x*settings.steps_per_mm[X_AXIS]);
target[Y_AXIS] = lround(y*settings.steps_per_mm[Y_AXIS]);
- target[Z_AXIS] = lround(z*settings.steps_per_mm[Z_AXIS]);
+ target[Z_AXIS] = lround(z*settings.steps_per_mm[Z_AXIS]);
// Compute direction bits for this block
block->direction_bits = 0;
if (target[X_AXIS] < pl.position[X_AXIS]) { block->direction_bits |= (1<<X_DIRECTION_BIT); }
if (target[Y_AXIS] < pl.position[Y_AXIS]) { block->direction_bits |= (1<<Y_DIRECTION_BIT); }
if (target[Z_AXIS] < pl.position[Z_AXIS]) { block->direction_bits |= (1<<Z_DIRECTION_BIT); }
-
+
// Number of steps for each axis
block->steps_x = labs(target[X_AXIS]-pl.position[X_AXIS]);
block->steps_y = labs(target[Y_AXIS]-pl.position[Y_AXIS]);
@@ -367,16 +367,16 @@ void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert
// Bail if this is a zero-length block
if (block->step_event_count == 0) { return; };
-
+
// Compute path vector in terms of absolute step target and current positions
- float delta_mm[3];
+ float delta_mm[N_AXIS];
delta_mm[X_AXIS] = (target[X_AXIS]-pl.position[X_AXIS])/settings.steps_per_mm[X_AXIS];
delta_mm[Y_AXIS] = (target[Y_AXIS]-pl.position[Y_AXIS])/settings.steps_per_mm[Y_AXIS];
delta_mm[Z_AXIS] = (target[Z_AXIS]-pl.position[Z_AXIS])/settings.steps_per_mm[Z_AXIS];
- block->millimeters = sqrt(delta_mm[X_AXIS]*delta_mm[X_AXIS] + delta_mm[Y_AXIS]*delta_mm[Y_AXIS] +
+ block->millimeters = sqrt(delta_mm[X_AXIS]*delta_mm[X_AXIS] + delta_mm[Y_AXIS]*delta_mm[Y_AXIS] +
delta_mm[Z_AXIS]*delta_mm[Z_AXIS]);
- float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides
-
+ float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides
+
// Calculate speed in mm/minute for each axis. No divide by zero due to previous checks.
// NOTE: Minimum stepper speed is limited by MINIMUM_STEPS_PER_MINUTE in stepper.c
float inverse_minute;
@@ -387,31 +387,31 @@ void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert
}
block->nominal_speed = block->millimeters * inverse_minute; // (mm/min) Always > 0
block->nominal_rate = ceil(block->step_event_count * inverse_minute); // (step/min) Always > 0
-
+
// Compute the acceleration rate for the trapezoid generator. Depending on the slope of the line
// average travel per step event changes. For a line along one axis the travel per step event
// is equal to the travel/step in the particular axis. For a 45 degree line the steppers of both
// axes might step for every step event. Travel per step event is then sqrt(travel_x^2+travel_y^2).
- // To generate trapezoids with contant acceleration between blocks the rate_delta must be computed
+ // To generate trapezoids with contant acceleration between blocks the rate_delta must be computed
// specifically for each line to compensate for this phenomenon:
// Convert universal acceleration for direction-dependent stepper rate change parameter
- block->rate_delta = ceil( block->step_event_count*inverse_millimeters *
+ block->rate_delta = ceil( block->step_event_count*inverse_millimeters *
settings.acceleration / (60 * ACCELERATION_TICKS_PER_SECOND )); // (step/min/acceleration_tick)
- // Compute path unit vector
- float unit_vec[3];
+ // Compute path unit vector
+ float unit_vec[N_AXIS];
unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
- unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
+ unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
- // Let a circle be tangent to both previous and current path line segments, where the junction
- // deviation is defined as the distance from the junction to the closest edge of the circle,
- // colinear with the circle center. The circular segment joining the two paths represents the
+ // Let a circle be tangent to both previous and current path line segments, where the junction
+ // deviation is defined as the distance from the junction to the closest edge of the circle,
+ // colinear with the circle center. The circular segment joining the two paths represents the
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
- // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
- // path width or max_jerk in the previous grbl version. This approach does not actually deviate
+ // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
+ // path width or max_jerk in the previous grbl version. This approach does not actually deviate
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
// nonlinearities of both the junction angle and junction velocity.
// NOTE: This is basically an exact path mode (G61), but it doesn't come to a complete stop unless
@@ -426,10 +426,10 @@ void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert
if ((block_buffer_head != block_buffer_tail) && (pl.previous_nominal_speed > 0.0)) {
// Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
// NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
- float cos_theta = - pl.previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
- - pl.previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
+ float cos_theta = - pl.previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
+ - pl.previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
- pl.previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
-
+
// Skip and use default max junction speed for 0 degree acute junction.
if (cos_theta < 0.95) {
vmax_junction = min(pl.previous_nominal_speed,block->nominal_speed);
@@ -443,7 +443,7 @@ void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert
}
}
block->max_entry_speed = vmax_junction;
-
+
// Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
float v_allowable = max_allowable_speed(-settings.acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
block->entry_speed = min(vmax_junction, v_allowable);
@@ -463,15 +463,15 @@ void plan_buffer_line(float x, float y, float z, float feed_rate, uint8_t invert
// Update previous path unit_vector and nominal speed
memcpy(pl.previous_unit_vec, unit_vec, sizeof(unit_vec)); // pl.previous_unit_vec[] = unit_vec[]
pl.previous_nominal_speed = block->nominal_speed;
-
+
// Update buffer head and next buffer head indices
- block_buffer_head = next_buffer_head;
+ block_buffer_head = next_buffer_head;
next_buffer_head = next_block_index(block_buffer_head);
-
+
// Update planner position
memcpy(pl.position, target, sizeof(target)); // pl.position[] = target[]
- planner_recalculate();
+ planner_recalculate();
}
// Reset the planner position vector (in steps). Called by the system abort routine.
@@ -484,20 +484,20 @@ void plan_set_current_position(int32_t x, int32_t y, int32_t z)
// Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail.
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.
-void plan_cycle_reinitialize(int32_t step_events_remaining)
+void plan_cycle_reinitialize(int32_t step_events_remaining)
{
block_t *block = &block_buffer[block_buffer_tail]; // Point to partially completed block
-
- // Only remaining millimeters and step_event_count need to be updated for planner recalculate.
+
+ // Only remaining millimeters and step_event_count need to be updated for planner recalculate.
// Other variables (step_x, step_y, step_z, rate_delta, etc.) all need to remain the same to
// ensure the original planned motion is resumed exactly.
block->millimeters = (block->millimeters*step_events_remaining)/block->step_event_count;
block->step_event_count = step_events_remaining;
-
+
// Re-plan from a complete stop. Reset planner entry speeds and flags.
block->entry_speed = 0.0;
block->max_entry_speed = 0.0;
block->nominal_length_flag = false;
block->recalculate_flag = true;
- planner_recalculate();
+ planner_recalculate();
}
View
94 report.c
@@ -2,7 +2,7 @@
report.c - reporting and messaging methods
Part of Grbl
- Copyright (c) 2012 Sungeun K. Jeon
+ Copyright (c) 2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +18,11 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- This file functions as the primary feedback interface for Grbl. Any outgoing data, such
+/*
+ This file functions as the primary feedback interface for Grbl. Any outgoing data, such
as the protocol status messages, feedback messages, and status reports, are stored here.
- For the most part, these functions primarily are called from protocol.c methods. If a
- different style feedback is desired (i.e. JSON), then a user can change these following
+ For the most part, these functions primarily are called from protocol.c methods. If a
+ different style feedback is desired (i.e. JSON), then a user can change these following
methods to accomodate their needs.
*/
@@ -36,20 +36,20 @@
// Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
-// For every incoming line, this method responds with an 'ok' for a successful command or an
-// 'error:' to indicate some error event with the line or some critical system error during
+// For every incoming line, this method responds with an 'ok' for a successful command or an
+// 'error:' to indicate some error event with the line or some critical system error during
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
// from a critical error, such as a triggered hard limit. Interface should always monitor for these
// responses.
// NOTE: In silent mode, all error codes are greater than zero.
// TODO: Install silent mode to return only numeric values, primarily for GUIs.
-void report_status_message(uint8_t status_code)
+void report_status_message(uint8_t status_code)
{
if (status_code == 0) { // STATUS_OK
printPgmString(PSTR("ok\r\n"));
} else {
printPgmString(PSTR("error: "));
- switch(status_code) {
+ switch(status_code) {
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_EXPECTED_COMMAND_LETTER:
@@ -85,7 +85,7 @@ void report_status_message(uint8_t status_code)
// Prints feedback messages. This serves as a centralized method to provide additional
-// user feedback for things that are not of the status message response protocol. These
+// user feedback for things that are not of the status message response protocol. These
// are messages such as setup warnings and how to exit alarms.
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
// is installed, the message number codes are less than zero.
@@ -101,7 +101,7 @@ void report_feedback_message(int8_t message_code)
case MESSAGE_ENABLED:
printPgmString(PSTR("Enabled")); break;
case MESSAGE_DISABLED:
- printPgmString(PSTR("Disabled")); break;
+ printPgmString(PSTR("Disabled")); break;
case MESSAGE_HOMING_UNLOCK:
printPgmString(PSTR("Unlocked. MPos lost?")); break;
}
@@ -144,8 +144,8 @@ void report_grbl_settings() {
printPgmString(PSTR(" (z, step/mm)\r\n$3=")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$4=")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed, mm/min)\r\n$5=")); printFloat(settings.default_seek_rate);
- printPgmString(PSTR(" (default seek, mm/min)\r\n$6=")); printInteger(settings.invert_mask);
- printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.invert_mask);
+ printPgmString(PSTR(" (default seek, mm/min)\r\n$6=")); printInteger(settings.invert_mask);
+ printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.invert_mask);
printPgmString(PSTR(")\r\n$7=")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (step idle delay, msec)\r\n$8=")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9=")); printFloat(settings.junction_deviation);
@@ -158,12 +158,12 @@ void report_grbl_settings() {
printPgmString(PSTR(" (invert step enable, bool)\r\n$16=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$17=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$18=")); printInteger(settings.homing_dir_mask);
- printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask);
+ printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$19=")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$20=")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$21=")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce, msec)\r\n$22=")); printFloat(settings.homing_pulloff);
- printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
+ printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
}
@@ -172,11 +172,11 @@ void report_gcode_parameters()
{
float coord_data[N_AXIS];
uint8_t coord_select, i;
- for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
- if (!(settings_read_coord_data(coord_select,coord_data))) {
- report_status_message(STATUS_SETTING_READ_FAIL);
+ for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
+ if (!(settings_read_coord_data(coord_select,coord_data))) {
+ report_status_message(STATUS_SETTING_READ_FAIL);
return;
- }
+ }
switch (coord_select) {
case 0: printPgmString(PSTR("G54")); break;
case 1: printPgmString(PSTR("G55")); break;
@@ -186,15 +186,15 @@ void report_gcode_parameters()
case 5: printPgmString(PSTR("G59")); break;
case 6: printPgmString(PSTR("G28")); break;
case 7: printPgmString(PSTR("G30")); break;
- // case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 not supported. Hence not stored.
- }
- printPgmString(PSTR(":["));
+ // case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 not supported. Hence not stored.
+ }
+ printPgmString(PSTR(":["));
for (i=0; i<N_AXIS; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { printFloat(coord_data[i]*INCH_PER_MM); }
else { printFloat(coord_data[i]); }
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]\r\n")); }
- }
+ }
}
printPgmString(PSTR("G92:[")); // Print G92,G92.1 which are not persistent in memory
for (i=0; i<N_AXIS; i++) {
@@ -202,7 +202,7 @@ void report_gcode_parameters()
else { printFloat(gc.coord_offset[i]); }
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]\r\n")); }
- }
+ }
}
@@ -219,21 +219,21 @@ void report_gcode_modes()
printPgmString(PSTR(" G"));
printInteger(gc.coord_select+54);
-
+
if (gc.plane_axis_0 == X_AXIS) {
if (gc.plane_axis_1 == Y_AXIS) { printPgmString(PSTR(" G17")); }
else { printPgmString(PSTR(" G18")); }
} else { printPgmString(PSTR(" G19")); }
-
+
if (gc.inches_mode) { printPgmString(PSTR(" G20")); }
else { printPgmString(PSTR(" G21")); }
-
+
if (gc.absolute_mode) { printPgmString(PSTR(" G90")); }
else { printPgmString(PSTR(" G91")); }
-
+
if (gc.inverse_feed_rate_mode) { printPgmString(PSTR(" G93")); }
else { printPgmString(PSTR(" G94")); }
-
+
switch (gc.program_flow) {
case PROGRAM_FLOW_RUNNING : printPgmString(PSTR(" M0")); break;
case PROGRAM_FLOW_PAUSED : printPgmString(PSTR(" M1")); break;
@@ -245,7 +245,7 @@ void report_gcode_modes()
case -1 : printPgmString(PSTR(" M4")); break;
case 0 : printPgmString(PSTR(" M5")); break;
}
-
+
switch (gc.coolant_mode) {
case COOLANT_DISABLE : printPgmString(PSTR(" M9")); break;
case COOLANT_FLOOD_ENABLE : printPgmString(PSTR(" M8")); break;
@@ -253,14 +253,14 @@ void report_gcode_modes()
case COOLANT_MIST_ENABLE : printPgmString(PSTR(" M7")); break;
#endif
}
-
+
printPgmString(PSTR(" T"));
printInteger(gc.tool);
-
+
printPgmString(PSTR(" F"));
if (gc.inches_mode) { printFloat(gc.feed_rate*INCH_PER_MM); }
else { printFloat(gc.feed_rate); }
-
+
// Print active switches
if (gc.switches) {
if (bit_istrue(gc.switches,BITFLAG_CHECK_GCODE)) { printPgmString(PSTR(" $S0")); }
@@ -268,7 +268,7 @@ void report_gcode_modes()
if (bit_istrue(gc.switches,BITFLAG_SINGLE_BLOCK)) { printPgmString(PSTR(" $S2")); }
if (bit_istrue(gc.switches,BITFLAG_OPT_STOP)) { printPgmString(PSTR(" $S3")); }
}
-
+
printPgmString(PSTR("\r\n"));
}
@@ -280,44 +280,44 @@ void report_startup_line(uint8_t n, char *line)
printPgmString(PSTR("\r\n"));
}
- // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
+ // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
// and the actual location of the CNC machine. Users may change the following function to their
// specific needs, but the desired real-time data report must be as short as possible. This is
- // requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
+ // requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status()
{
- // **Under construction** Bare-bones status report. Provides real-time machine position relative to
+ // **Under construction** Bare-bones status report. Provides real-time machine position relative to
// the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). Eventually
// to be added are distance to go on block, processed block id, and feed rate. Also a settings bitmask
// for a user to select the desired real-time data.
uint8_t i;
- int32_t current_position[3]; // Copy current state of the system position variable
+ int32_t current_position[N_AXIS]; // Copy current state of the system position variable
memcpy(current_position,sys.position,sizeof(sys.position));
- float print_position[3];
+ float print_position[N_AXIS];
// Report machine position
- printPgmString(PSTR("MPos:["));
- for (i=0; i<= 2; i++) {
+ printPgmString(PSTR("MPos:["));
+ for (i=0; i < N_AXIS; i++) {
print_position[i] = current_position[i]/settings.steps_per_mm[i];
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
printFloat(print_position[i]);
- if (i < 2) { printPgmString(PSTR(",")); }
+ if (i < N_AXIS-1) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
-
+
// Report work position
- printPgmString(PSTR(",WPos:["));
- for (i=0; i<= 2; i++) {
+ printPgmString(PSTR(",WPos:["));
+ for (i=0; i < N_AXIS; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
print_position[i] -= (gc.coord_system[i]+gc.coord_offset[i])*INCH_PER_MM;
} else {
print_position[i] -= gc.coord_system[i]+gc.coord_offset[i];
}
printFloat(print_position[i]);
- if (i < 2) { printPgmString(PSTR(",")); }
+ if (i < N_AXIS-1) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]")); }
}
-
+
printPgmString(PSTR("\r\n"));
}
View
32 settings.c
@@ -1,9 +1,9 @@
/*
- settings.c - eeprom configuration handling
+ settings.c - eeprom configuration handling
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
- Copyright (c) 2011-2012 Sungeun K. Jeon
+ Copyright (c) 2011-2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ settings_t settings;
// Version 4 outdated settings record
typedef struct {
- float steps_per_mm[3];
+ float steps_per_mm[N_AXIS];
uint8_t microsteps;
uint8_t pulse_microseconds;
float default_feed_rate;
@@ -52,19 +52,19 @@ void settings_store_startup_line(uint8_t n, char *line)
// Method to store coord data parameters into EEPROM
void settings_write_coord_data(uint8_t coord_select, float *coord_data)
-{
+{
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
-}
+}
// Method to store Grbl global settings struct and version number into EEPROM
-void write_global_settings()
+void write_global_settings()
{
eeprom_put_char(0, SETTINGS_VERSION);
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
}
-// Method to reset Grbl global settings back to defaults.
+// Method to reset Grbl global settings back to defaults.
void settings_reset(bool reset_all) {
// Reset all settings or only the migration settings to the new version.
if (reset_all) {
@@ -117,19 +117,19 @@ uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
// Reset with default zero vector
- clear_vector_float(coord_data);
+ clear_vector_float(coord_data);
settings_write_coord_data(coord_select,coord_data);
return(false);
} else {
return(true);
}
-}
+}