Improved constant laser power per rate mode. Re-factored for flash size. Minor bug fixes.
- NOTE: This commit has largely been untested. - Constant laser power per rate mode has been improved. Altered its implementation to be more responsive and accurate. - Based on LaserWeb dev feedback, only G1, G2, and G3 moves operate with constant laser power mode. Meaning that G0, G38.x, and $J jogging motions operate without it and will keep a constant power output. This was specifically requested as a way to focus the laser by keeping the laser on when not moving. Operationally, this shouldn’t alter how the laser mode operates. - Re-factored parts of the g-code parser and g-code state reports to save a few hundred bytes of flash. What was done makes the code a bit more unreadable (bad), but the flash space was in dire need. So, I’m willing to live with it for now. - Fixed a problem with $G g-code state reports. Showed `M0` program pause during a run state. Now fixed to show nothing during a run state. Also, `M30` program end was shown as `M2`. This was also corrected. - Improved spindle stop override responsiveness by removing the enforced spindle restoring delay. It’s not needed for a feature that is user controlled. - Fixed a bug with G2/3 arcs in inverse time mode. - Updated the interface.md document to make it more clear how WPos: or MPos: can be calculated from WCO:. Some GUI devs have failed to catch this in the documentation.
This commit is contained in:
		
							
								
								
									
										80
									
								
								grbl/gcode.c
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								grbl/gcode.c
									
									
									
									
									
								
							| @@ -149,35 +149,12 @@ uint8_t gc_execute_line(char *line) | ||||
|             // No break. Continues to next line. | ||||
|           case 4: case 53: | ||||
|             word_bit = MODAL_GROUP_G0; | ||||
|             switch(int_value) { | ||||
|               case 4: gc_block.non_modal_command = NON_MODAL_DWELL; break; // G4 | ||||
|               case 10: gc_block.non_modal_command = NON_MODAL_SET_COORDINATE_DATA; break; // G10 | ||||
|               case 28: | ||||
|                 switch(mantissa) { | ||||
|                   case 0: gc_block.non_modal_command = NON_MODAL_GO_HOME_0; break;  // G28 | ||||
|                   case 10: gc_block.non_modal_command = NON_MODAL_SET_HOME_0; break; // G28.1 | ||||
|                   default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G28.x command] | ||||
|                 } | ||||
|                 mantissa = 0; // Set to zero to indicate valid non-integer G command. | ||||
|                 break; | ||||
|               case 30: | ||||
|                 switch(mantissa) { | ||||
|                   case 0: gc_block.non_modal_command = NON_MODAL_GO_HOME_1; break;  // G30 | ||||
|                   case 10: gc_block.non_modal_command = NON_MODAL_SET_HOME_1; break; // G30.1 | ||||
|                   default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G30.x command] | ||||
|                 } | ||||
|                 mantissa = 0; // Set to zero to indicate valid non-integer G command. | ||||
|                 break; | ||||
|               case 53: gc_block.non_modal_command = NON_MODAL_ABSOLUTE_OVERRIDE; break; // G53 | ||||
|               case 92: | ||||
|                 switch(mantissa) { | ||||
|                   case 0: gc_block.non_modal_command = NON_MODAL_SET_COORDINATE_OFFSET; break; // G92 | ||||
|                   case 10: gc_block.non_modal_command = NON_MODAL_RESET_COORDINATE_OFFSET; break; // G92.1 | ||||
|                   default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G92.x command] | ||||
|                 } | ||||
|                 mantissa = 0; // Set to zero to indicate valid non-integer G command. | ||||
|                 break; | ||||
|             } | ||||
|             gc_block.non_modal_command = int_value; | ||||
|             if ((int_value == 28) || (int_value == 30) || (int_value == 92)) { | ||||
|               if ((mantissa != 0) || (mantissa != 10)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } | ||||
|               gc_block.non_modal_command += mantissa; | ||||
|               mantissa = 0; // Set to zero to indicate valid non-integer G command. | ||||
|             }                 | ||||
|             break; | ||||
|           case 0: case 1: case 2: case 3: case 38: | ||||
|             // Check for G0/1/2/3/38 being called with G10/28/30/92 on same block. | ||||
| @@ -187,37 +164,22 @@ uint8_t gc_execute_line(char *line) | ||||
|             // No break. Continues to next line. | ||||
|           case 80: | ||||
|             word_bit = MODAL_GROUP_G1; | ||||
|             switch(int_value) { | ||||
|               case 0: gc_block.modal.motion = MOTION_MODE_SEEK; break; // G0 | ||||
|               case 1: gc_block.modal.motion = MOTION_MODE_LINEAR; break; // G1 | ||||
|               case 2: gc_block.modal.motion = MOTION_MODE_CW_ARC; break; // G2 | ||||
|               case 3: gc_block.modal.motion = MOTION_MODE_CCW_ARC; break; // G3 | ||||
|               case 38: | ||||
|                 switch(mantissa) { | ||||
|                   case 20: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD; break; // G38.2 | ||||
|                   case 30: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD_NO_ERROR; break; // G38.3 | ||||
|                   case 40: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY; break; // G38.4 | ||||
|                   case 50: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY_NO_ERROR; break; // G38.5 | ||||
|                   default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command] | ||||
|                 } | ||||
|                 mantissa = 0; // Set to zero to indicate valid non-integer G command. | ||||
|                 break; | ||||
|               case 80: gc_block.modal.motion = MOTION_MODE_NONE; break; // G80 | ||||
|             } | ||||
|             gc_block.modal.motion = int_value; | ||||
|             if (int_value == 38){ | ||||
|               if ((mantissa != 20) || (mantissa != 30) || (mantissa != 40) || (mantissa != 50)) { | ||||
|                 FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command] | ||||
|               } | ||||
|               gc_block.modal.motion += (mantissa/10)+100; | ||||
|             }   | ||||
|             break; | ||||
|           case 17: case 18: case 19: | ||||
|             word_bit = MODAL_GROUP_G2; | ||||
|             switch(int_value) { | ||||
|               case 17: gc_block.modal.plane_select = PLANE_SELECT_XY; break; | ||||
|               case 18: gc_block.modal.plane_select = PLANE_SELECT_ZX; break; | ||||
|               case 19: gc_block.modal.plane_select = PLANE_SELECT_YZ; break; | ||||
|             } | ||||
|             gc_block.modal.plane_select = int_value - 17; | ||||
|             break; | ||||
|           case 90: case 91: | ||||
|             if (mantissa == 0) { | ||||
|               word_bit = MODAL_GROUP_G3; | ||||
|               if (int_value == 90) { gc_block.modal.distance = DISTANCE_MODE_ABSOLUTE; } // G90 | ||||
|               else { gc_block.modal.distance = DISTANCE_MODE_INCREMENTAL; } // G91 | ||||
|               gc_block.modal.distance = int_value - 90; | ||||
|             } else { | ||||
|               word_bit = MODAL_GROUP_G4; | ||||
|               if ((mantissa != 10) || (int_value == 90)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G90.1 not supported] | ||||
| @@ -227,13 +189,11 @@ uint8_t gc_execute_line(char *line) | ||||
|             break; | ||||
|           case 93: case 94: | ||||
|             word_bit = MODAL_GROUP_G5; | ||||
|             if (int_value == 93) { gc_block.modal.feed_rate = FEED_RATE_MODE_INVERSE_TIME; } // G93 | ||||
|             else { gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; } // G94 | ||||
|             gc_block.modal.feed_rate = 94 - int_value; | ||||
|             break; | ||||
|           case 20: case 21: | ||||
|             word_bit = MODAL_GROUP_G6; | ||||
|             if (int_value == 20) { gc_block.modal.units = UNITS_MODE_INCHES; }  // G20 | ||||
|             else { gc_block.modal.units = UNITS_MODE_MM; } // G21 | ||||
|             gc_block.modal.units = 21 - int_value; | ||||
|             break; | ||||
|           case 40: | ||||
|             word_bit = MODAL_GROUP_G7; | ||||
| @@ -258,7 +218,7 @@ uint8_t gc_execute_line(char *line) | ||||
|           case 54: case 55: case 56: case 57: case 58: case 59: | ||||
|             // NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.) | ||||
|             word_bit = MODAL_GROUP_G12; | ||||
|             gc_block.modal.coord_select = int_value-54; // Shift to array indexing. | ||||
|             gc_block.modal.coord_select = int_value - 54; // Shift to array indexing. | ||||
|             break; | ||||
|           case 61: | ||||
|             word_bit = MODAL_GROUP_G13; | ||||
| @@ -284,7 +244,7 @@ uint8_t gc_execute_line(char *line) | ||||
|             switch(int_value) { | ||||
|               case 0: gc_block.modal.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause | ||||
|               case 1: break; // Optional stop not supported. Ignore. | ||||
|               case 2: case 30: gc_block.modal.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset | ||||
|               default: gc_block.modal.program_flow = int_value; // Program end and reset | ||||
|             } | ||||
|             break; | ||||
|           #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN | ||||
| @@ -891,7 +851,7 @@ uint8_t gc_execute_line(char *line) | ||||
|  | ||||
|   // [2. Set feed rate mode ]: | ||||
|   gc_state.modal.feed_rate = gc_block.modal.feed_rate; | ||||
|   pl_data->condition |= gc_state.modal.feed_rate; // Set condition flag for planner use. | ||||
|   if (gc_state.modal.feed_rate) { pl_data->condition |= PL_COND_FLAG_INVERSE_TIME; } // Set condition flag for planner use. | ||||
|  | ||||
|   // [3. Set feed rate ]: | ||||
|   gc_state.feed_rate = gc_block.values.f; // Always copy this value. See feed rate error-checking. | ||||
|   | ||||
							
								
								
									
										54
									
								
								grbl/gcode.h
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								grbl/gcode.h
									
									
									
									
									
								
							| @@ -51,54 +51,60 @@ | ||||
|  | ||||
| // Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used | ||||
| // internally by the parser to know which command to execute. | ||||
| // NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing  | ||||
| // compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not | ||||
| // ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c  | ||||
| // to see how they are used, if you need to alter them. | ||||
|  | ||||
| // Modal Group G0: Non-modal actions | ||||
| #define NON_MODAL_NO_ACTION 0 // (Default: Must be zero) | ||||
| #define NON_MODAL_DWELL 1 // G4 | ||||
| #define NON_MODAL_SET_COORDINATE_DATA 2 // G10 | ||||
| #define NON_MODAL_GO_HOME_0 3 // G28 | ||||
| #define NON_MODAL_SET_HOME_0 4 // G28.1 | ||||
| #define NON_MODAL_GO_HOME_1 5 // G30 | ||||
| #define NON_MODAL_SET_HOME_1 6 // G30.1 | ||||
| #define NON_MODAL_ABSOLUTE_OVERRIDE 7 // G53 | ||||
| #define NON_MODAL_SET_COORDINATE_OFFSET 8 // G92 | ||||
| #define NON_MODAL_RESET_COORDINATE_OFFSET 9 //G92.1 | ||||
| #define NON_MODAL_DWELL 4 // G4 (Do not alter value) | ||||
| #define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value) | ||||
| #define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value) | ||||
| #define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value) | ||||
| #define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value) | ||||
| #define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value) | ||||
| #define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value) | ||||
| #define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value) | ||||
| #define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value) | ||||
|  | ||||
| // Modal Group G1: Motion modes | ||||
| #define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero) | ||||
| #define MOTION_MODE_LINEAR 1 // G1 | ||||
| #define MOTION_MODE_CW_ARC 2  // G2 | ||||
| #define MOTION_MODE_CCW_ARC 3  // G3 | ||||
| #define MOTION_MODE_PROBE_TOWARD 4 // G38.2 NOTE: G38.2, G38.3, G38.4, G38.5 must be sequential. See report_gcode_modes(). | ||||
| #define MOTION_MODE_PROBE_TOWARD_NO_ERROR 5 // G38.3 | ||||
| #define MOTION_MODE_PROBE_AWAY 6 // G38.4 | ||||
| #define MOTION_MODE_PROBE_AWAY_NO_ERROR 7 // G38.5 | ||||
| #define MOTION_MODE_NONE 8 // G80 | ||||
| #define MOTION_MODE_LINEAR 1 // G1 (Do not alter value) | ||||
| #define MOTION_MODE_CW_ARC 2  // G2 (Do not alter value) | ||||
| #define MOTION_MODE_CCW_ARC 3  // G3 (Do not alter value) | ||||
| #define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value) | ||||
| #define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value) | ||||
| #define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value) | ||||
| #define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value) | ||||
| #define MOTION_MODE_NONE 80 // G80 (Do not alter value) | ||||
|  | ||||
| // Modal Group G2: Plane select | ||||
| #define PLANE_SELECT_XY 0 // G17 (Default: Must be zero) | ||||
| #define PLANE_SELECT_ZX 1 // G18 | ||||
| #define PLANE_SELECT_YZ 2 // G19 | ||||
| #define PLANE_SELECT_ZX 1 // G18 (Do not alter value) | ||||
| #define PLANE_SELECT_YZ 2 // G19 (Do not alter value) | ||||
|  | ||||
| // Modal Group G3: Distance mode | ||||
| #define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero) | ||||
| #define DISTANCE_MODE_INCREMENTAL 1 // G91 | ||||
| #define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value) | ||||
|  | ||||
| // Modal Group G4: Arc IJK distance mode | ||||
| #define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero) | ||||
|  | ||||
| // Modal Group M4: Program flow | ||||
| #define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero) | ||||
| #define PROGRAM_FLOW_PAUSED 1 // M0, M1 | ||||
| #define PROGRAM_FLOW_COMPLETED 2 // M2, M30 | ||||
| #define PROGRAM_FLOW_PAUSED 3 // M0 | ||||
| #define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored. | ||||
| #define PROGRAM_FLOW_COMPLETED_M2  2 // M2 (Do not alter value) | ||||
| #define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value) | ||||
|  | ||||
| // Modal Group G5: Feed rate mode | ||||
| #define FEED_RATE_MODE_UNITS_PER_MIN  0 // G94 (Default: Must be zero) | ||||
| #define FEED_RATE_MODE_INVERSE_TIME   PL_COND_FLAG_INVERSE_TIME // G93 (NOTE: Uses planner condition bit flag) | ||||
| #define FEED_RATE_MODE_INVERSE_TIME   1 // G93 (Do not alter value) | ||||
|  | ||||
| // Modal Group G6: Units mode | ||||
| #define UNITS_MODE_MM 0 // G21 (Default: Must be zero) | ||||
| #define UNITS_MODE_INCHES 1 // G20 | ||||
| #define UNITS_MODE_INCHES 1 // G20 (Do not alter value) | ||||
|  | ||||
| // Modal Group G7: Cutter radius compensation mode | ||||
| #define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero) | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
|  | ||||
| // Grbl versioning system | ||||
| #define GRBL_VERSION "1.1d" | ||||
| #define GRBL_VERSION_BUILD "20161027" | ||||
| #define GRBL_VERSION_BUILD "20161104" | ||||
|  | ||||
| // Define standard libraries used by Grbl. | ||||
| #include <avr/io.h> | ||||
|   | ||||
| @@ -106,8 +106,11 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of | ||||
|     // Multiply inverse feed_rate to compensate for the fact that this movement is approximated | ||||
|     // by a number of discrete segments. The inverse feed_rate should be correct for the sum of | ||||
|     // all segments. | ||||
|     if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) { pl_data->feed_rate *= segments; } | ||||
|  | ||||
|     if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {  | ||||
|       pl_data->feed_rate *= segments;  | ||||
|       bit_false(pl_data->condition,PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments. | ||||
|     } | ||||
|      | ||||
|     float theta_per_segment = angular_travel/segments; | ||||
|     float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments; | ||||
|  | ||||
|   | ||||
| @@ -40,7 +40,7 @@ | ||||
| #define PL_COND_FLAG_RAPID_MOTION      bit(0) | ||||
| #define PL_COND_FLAG_SYSTEM_MOTION     bit(1) // Single motion. Circumvents planner state. Used by home/park. | ||||
| #define PL_COND_FLAG_NO_FEED_OVERRIDE  bit(2) // Motion does not honor feed override. | ||||
| #define PL_COND_FLAG_INVERSE_TIME      bit(3) | ||||
| #define PL_COND_FLAG_INVERSE_TIME      bit(3) // Interprets feed rate value as inverse time when set. | ||||
| #define PL_COND_FLAG_SPINDLE_CW        bit(4) | ||||
| #define PL_COND_FLAG_SPINDLE_CCW       bit(5) | ||||
| #define PL_COND_FLAG_COOLANT_FLOOD     bit(6) | ||||
|   | ||||
| @@ -716,7 +716,6 @@ static void protocol_exec_rt_suspend() | ||||
|                 bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); | ||||
|               } else { | ||||
|                 spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed); | ||||
|                 delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND); | ||||
|               } | ||||
|             } | ||||
|             if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) { | ||||
|   | ||||
| @@ -33,6 +33,8 @@ | ||||
| void report_util_setting_prefix(uint8_t n) { serial_write('$'); print_uint8_base10(n); serial_write('='); } | ||||
| static void report_util_line_feed() { printPgmString(PSTR("\r\n")); } | ||||
| static void report_util_feedback_line_feed() { serial_write(']'); report_util_line_feed(); } | ||||
| static void report_util_gcode_modes_G() { printPgmString(PSTR(" G")); } | ||||
| static void report_util_gcode_modes_M() { printPgmString(PSTR(" M")); } | ||||
| // static void report_util_comment_line_feed() { serial_write(')'); report_util_line_feed(); } | ||||
| static void report_util_axis_values(float *axis_value) { | ||||
|   uint8_t idx; | ||||
| @@ -439,54 +441,48 @@ void report_gcode_modes() | ||||
|   #else | ||||
|     printPgmString(PSTR("[GC:G")); | ||||
|   #endif | ||||
|   switch (gc_state.modal.motion) { | ||||
|     case MOTION_MODE_SEEK : serial_write('0'); break; | ||||
|     case MOTION_MODE_LINEAR : serial_write('1'); break; | ||||
|     case MOTION_MODE_CW_ARC : serial_write('2'); break; | ||||
|     case MOTION_MODE_CCW_ARC : serial_write('3'); break; | ||||
|     case MOTION_MODE_NONE : printPgmString(PSTR("80")); break; | ||||
|     default: | ||||
|       printPgmString(PSTR("38.")); | ||||
|       print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2)); | ||||
|   if (gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) { | ||||
|     printPgmString(PSTR("38.")); | ||||
|     print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2)); | ||||
|   } else { | ||||
|     print_uint8_base10(gc_state.modal.motion); | ||||
|   } | ||||
|  | ||||
|   printPgmString(PSTR(" G")); | ||||
|   report_util_gcode_modes_G(); | ||||
|   print_uint8_base10(gc_state.modal.coord_select+54); | ||||
|  | ||||
|   printPgmString(PSTR(" G1")); | ||||
|   switch (gc_state.modal.plane_select) { | ||||
|     case PLANE_SELECT_XY : serial_write('7'); break; | ||||
|     case PLANE_SELECT_ZX : serial_write('8'); break; | ||||
|     case PLANE_SELECT_YZ : serial_write('9'); break; | ||||
|   report_util_gcode_modes_G(); | ||||
|   print_uint8_base10(gc_state.modal.plane_select+17); | ||||
|  | ||||
|   report_util_gcode_modes_G(); | ||||
|   print_uint8_base10(21-gc_state.modal.units); | ||||
|  | ||||
|   report_util_gcode_modes_G(); | ||||
|   print_uint8_base10(gc_state.modal.distance+90); | ||||
|  | ||||
|   report_util_gcode_modes_G(); | ||||
|   print_uint8_base10(94-gc_state.modal.feed_rate); | ||||
|  | ||||
|   if (gc_state.modal.program_flow) { | ||||
|     report_util_gcode_modes_M(); | ||||
|     switch (gc_state.modal.program_flow) { | ||||
|       case PROGRAM_FLOW_PAUSED : serial_write('0'); break; | ||||
|       // case PROGRAM_FLOW_OPTIONAL_STOP : serial_write('1'); break; // M1 is ignored and not supported. | ||||
|       case PROGRAM_FLOW_COMPLETED_M2 :  | ||||
|       case PROGRAM_FLOW_COMPLETED_M30 :  | ||||
|         print_uint8_base10(gc_state.modal.program_flow); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   printPgmString(PSTR(" G2")); | ||||
|   if (gc_state.modal.units == UNITS_MODE_MM) { serial_write('1'); } | ||||
|   else { serial_write('0'); } | ||||
|  | ||||
|   printPgmString(PSTR(" G9")); | ||||
|   if (gc_state.modal.distance == DISTANCE_MODE_ABSOLUTE) { serial_write('0'); } | ||||
|   else { serial_write('1'); } | ||||
|  | ||||
|   printPgmString(PSTR(" G9")); | ||||
|   if (gc_state.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { serial_write('3'); } | ||||
|   else { serial_write('4'); } | ||||
|  | ||||
|   printPgmString(PSTR(" M")); | ||||
|   switch (gc_state.modal.program_flow) { | ||||
|     case PROGRAM_FLOW_RUNNING : serial_write('0'); break; | ||||
|     case PROGRAM_FLOW_PAUSED : serial_write('1'); break; | ||||
|     case PROGRAM_FLOW_COMPLETED : serial_write('2'); break; | ||||
|   } | ||||
|  | ||||
|   printPgmString(PSTR(" M")); | ||||
|   report_util_gcode_modes_M(); | ||||
|   switch (gc_state.modal.spindle) { | ||||
|     case SPINDLE_ENABLE_CW : serial_write('3'); break; | ||||
|     case SPINDLE_ENABLE_CCW : serial_write('4'); break; | ||||
|     case SPINDLE_DISABLE : serial_write('5'); break; | ||||
|   } | ||||
|  | ||||
|   printPgmString(PSTR(" M")); | ||||
|   report_util_gcode_modes_M(); | ||||
|   #ifdef ENABLE_M7 | ||||
|     if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time. | ||||
|       if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { serial_write('7'); } | ||||
|   | ||||
| @@ -152,7 +152,7 @@ void spindle_stop() | ||||
|       } | ||||
|     } else {  | ||||
|       // Compute intermediate PWM value with linear spindle speed model. | ||||
|       // NOTE: A nonlinear model could be installed here, if required, but keep it light-weight. | ||||
|       // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight. | ||||
|       sys.spindle_speed = rpm; | ||||
|       pwm_value = floor( (rpm-settings.rpm_min)*pwm_gradient + (SPINDLE_PWM_MIN_VALUE+0.5) ); | ||||
|     } | ||||
|   | ||||
| @@ -58,12 +58,16 @@ | ||||
| // discarded when entirely consumed and completed by the segment buffer. Also, AMASS alters this | ||||
| // data for its own use. | ||||
| typedef struct { | ||||
|   uint8_t direction_bits; | ||||
|   #ifdef VARIABLE_SPINDLE | ||||
|     uint8_t spindle_pwm; | ||||
|   #endif | ||||
|   uint32_t steps[N_AXIS]; | ||||
|   uint32_t step_event_count; | ||||
|   uint8_t direction_bits; | ||||
|   #ifdef VARIABLE_SPINDLE | ||||
|     #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|       uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate | ||||
|     #else | ||||
|       uint8_t spindle_pwm; | ||||
|     #endif | ||||
|   #endif | ||||
| } st_block_t; | ||||
| static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1]; | ||||
|  | ||||
| @@ -72,14 +76,17 @@ static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1]; | ||||
| // planner buffer. Once "checked-out", the steps in the segments buffer cannot be modified by | ||||
| // the planner, where the remaining planner block steps still can. | ||||
| typedef struct { | ||||
|   uint16_t n_step;          // Number of step events to be executed for this segment | ||||
|   uint8_t st_block_index;   // Stepper block data index. Uses this information to execute this segment. | ||||
|   uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate. | ||||
|   uint16_t n_step;           // Number of step events to be executed for this segment | ||||
|   uint16_t cycles_per_tick;  // Step distance traveled per ISR tick, aka step rate. | ||||
|   uint8_t  st_block_index;   // Stepper block data index. Uses this information to execute this segment. | ||||
|   #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING | ||||
|     uint8_t amass_level;    // Indicates AMASS level for the ISR to execute this segment | ||||
|   #else | ||||
|     uint8_t prescaler;      // Without AMASS, a prescaler is required to adjust for slow timing. | ||||
|   #endif | ||||
|   #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|     uint8_t rate_adjusted_pwm; | ||||
|   #endif | ||||
| } segment_t; | ||||
| static segment_t segment_buffer[SEGMENT_BUFFER_SIZE]; | ||||
|  | ||||
| @@ -153,7 +160,7 @@ typedef struct { | ||||
|   float decelerate_after; // Deceleration ramp start measured from end of block (mm) | ||||
|  | ||||
|   #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|     float inv_rate;    // Used by PWM laser mode | ||||
|     float inv_rate;    // Used by PWM laser mode to speed up segment calculations. | ||||
|   #endif | ||||
| } st_prep_t; | ||||
| static st_prep_t prep; | ||||
| @@ -353,12 +360,20 @@ ISR(TIMER1_COMPA_vect) | ||||
|  | ||||
|       #ifdef VARIABLE_SPINDLE | ||||
|         // Set real-time spindle output as segment is loaded, just prior to the first step. | ||||
|         spindle_set_speed(st.exec_block->spindle_pwm); | ||||
|         #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|           spindle_set_speed(st.exec_segment->rate_adjusted_pwm); | ||||
|         #else | ||||
|           spindle_set_speed(st.exec_block->spindle_pwm); | ||||
|         #endif | ||||
|       #endif | ||||
|  | ||||
|     } else { | ||||
|       // Segment buffer empty. Shutdown. | ||||
|       st_go_idle(); | ||||
|       #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|         // Ensure pwm is set properly upon completion of rate-controlled motion. | ||||
|         if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); } | ||||
|       #endif | ||||
|       system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end | ||||
|       return; // Nothing to do but exit. | ||||
|     } | ||||
| @@ -650,8 +665,14 @@ void st_prep_buffer() | ||||
|         } | ||||
|          | ||||
|         #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|           // Pre-compute inverse programmed rate to speed up PWM updating per step segment. | ||||
|           prep.inv_rate = 1.0/pl_block->programmed_rate; | ||||
|           // Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the | ||||
|           // spindle off.  | ||||
|           st_prep_block->is_pwm_rate_adjusted = false; | ||||
|           if (settings.flags & BITFLAG_LASER_MODE) { | ||||
|             // Pre-compute inverse programmed rate to speed up PWM updating per step segment. | ||||
|             prep.inv_rate = 1.0/pl_block->programmed_rate; | ||||
|             if (!(pl_block->condition & PL_COND_MOTION_MASK)) { st_prep_block->is_pwm_rate_adjusted = true; } | ||||
|           } | ||||
|         #endif | ||||
|       } | ||||
|  | ||||
| @@ -746,7 +767,7 @@ void st_prep_buffer() | ||||
| 				} | ||||
| 			} | ||||
|        | ||||
|       #ifdef VARIABLE_SPINDLE   | ||||
|       #ifdef VARIABLE_SPINDLE | ||||
|         bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); // Force update whenever updating block. | ||||
|       #endif | ||||
|     } | ||||
| @@ -856,34 +877,36 @@ void st_prep_buffer() | ||||
|       } | ||||
|     } while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete. | ||||
|  | ||||
|     /* ----------------------------------------------------------------------------------- | ||||
|        Compute spindle speed PWM output for step segment | ||||
|     */ | ||||
|     #ifdef VARIABLE_SPINDLE | ||||
|  | ||||
|       /* ----------------------------------------------------------------------------------- | ||||
|         Compute spindle speed PWM output for step segment | ||||
|       */ | ||||
|       #ifdef LASER_CONSTANT_POWER_PER_RATE     | ||||
|         if ((settings.flags & BITFLAG_LASER_MODE) || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) { | ||||
|         if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) { | ||||
|           if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) { | ||||
|             float rpm = pl_block->spindle_speed; | ||||
|             // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.         | ||||
|             if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); } | ||||
|             // If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE) | ||||
|             // but this would be instantaneous only and during a motion. May not matter at all. | ||||
|             prep_segment->rate_adjusted_pwm = spindle_compute_pwm_value(rpm); | ||||
|           } else {  | ||||
|             sys.spindle_speed = 0.0; | ||||
|             prep_segment->rate_adjusted_pwm = SPINDLE_PWM_OFF_VALUE; | ||||
|           } | ||||
|           bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM); | ||||
|         } | ||||
|       #else | ||||
|         if (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM) { | ||||
|           if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) { | ||||
|             st_prep_block->spindle_pwm = spindle_compute_pwm_value(pl_block->spindle_speed); | ||||
|           } else {  | ||||
|             sys.spindle_speed = 0.0; | ||||
|             st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE; | ||||
|           } | ||||
|           bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM); | ||||
|         } | ||||
|       #endif | ||||
| 			  if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) { | ||||
|           float rpm = pl_block->spindle_speed; | ||||
|           #ifdef LASER_CONSTANT_POWER_PER_RATE | ||||
|             // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.         | ||||
|             if (settings.flags & BITFLAG_LASER_MODE) {  | ||||
|               // If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE) | ||||
|               // but this would be instantaneous only and during a motion. May not matter at all. | ||||
|               rpm *= (prep.current_speed * prep.inv_rate); | ||||
|             } | ||||
|           #endif | ||||
|           st_prep_block->spindle_pwm = spindle_compute_pwm_value(rpm); | ||||
|         } else {  | ||||
| 					sys.spindle_speed = 0.0; | ||||
| 					st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE; | ||||
| 				} | ||||
|         bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM); | ||||
|       } | ||||
|  | ||||
|     #endif | ||||
|      | ||||
|     /* ----------------------------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user