/* gcode.c - rs274/ngc parser. Part of Grbl Copyright (c) 2011-2014 Sungeun K. Jeon Copyright (c) 2009-2011 Simen Svale Skogsrud 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 (at your option) any later version. Grbl is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grbl. If not, see . */ /* This code is inspired by the Arduino GCode Interpreter by Mike Ellery and the NIST RS274/NGC Interpreter by Kramer, Proctor and Messina. */ #include "system.h" #include "settings.h" #include "gcode.h" #include "planner.h" #include "motion_control.h" #include "spindle_control.h" #include "coolant_control.h" #include "report.h" // Declare gc extern struct parser_state_t gc; #define FAIL(status) gc.status_code = status; static uint8_t next_statement(char *letter, float *float_ptr, char *line, uint8_t *char_counter); static void gc_convert_arc_radius_mode(float *target) __attribute__((noinline)); 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() { memset(&gc, 0, sizeof(gc)); gc.feed_rate = settings.default_feed_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); } } // Sets g-code parser position in mm. Input in steps. Called by the system abort and hard // limit pull-off routines. void gc_sync_position(int32_t x, int32_t y, int32_t z) { uint8_t i; for (i=0; i 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 { if (int_value > 0) { int_value--; } // Adjust P1-P6 index to EEPROM coordinate data indexing. else { int_value = gc.coord_select; } // Index P0 as the active coordinate system float coord_data[N_AXIS]; if (!settings_read_coord_data(int_value,coord_data)) { return(STATUS_SETTING_READ_FAIL); } // Update axes defined only in block. Always in machine coordinates. Can change non-active system. for (idx=0; idx 'Z')) { FAIL(STATUS_EXPECTED_COMMAND_LETTER); return(0); } (*char_counter)++; if (!read_float(line, char_counter, float_ptr)) { FAIL(STATUS_BAD_NUMBER_FORMAT); return(0); }; return(1); } static void gc_convert_arc_radius_mode(float *target) { /* 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 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 [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 - | - | - | h - | [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 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(gc.arc_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. float h_x2_div_d = 4 * gc.arc_radius*gc.arc_radius - x*x - y*y; if (h_x2_div_d < 0) { FAIL(STATUS_ARC_RADIUS_ERROR); return; } // Finish computing h_x2_div_d. 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 // 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 (gc.arc_radius < 0) { h_x2_div_d = -h_x2_div_d; gc.arc_radius = -gc.arc_radius; // Finished with r. Set to positive for mc_arc } // Complete the operation by calculating the actual center of the arc gc.arc_offset[gc.plane_axis_0] = 0.5*(x-(y*h_x2_div_d)); gc.arc_offset[gc.plane_axis_1] = 0.5*(y+(x*h_x2_div_d)); } /* Not supported: - Canned cycles - Tool radius compensation - A,B,C-axes - Evaluation of expressions - Variables - Probing - Override control (TBD) - Tool changes - Switches (*) 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) group 4 = {M1} (Optional stop, ignored) group 6 = {M6} (Tool change) group 8 = {*M7} enable mist coolant group 9 = {M48, M49} enable/disable feed and speed override switches group 13 = {G61, G61.1, G64} path control mode */