Updated variable spindle and new probing. Minor bug fixes.

- Minor bug fix for variable spindle PWM output. Values smaller than
the minimum RPM for the spindle would overflow the PWM value. Thanks
Rob!

- Created an optional minimum spindle PWM low-mark value as a
compile-time option. This is for special circumstances when the PWM has
to be at a certain level to be read by the spindle controller.

- Refactored the new probing commands (G38.3, G38.4, G38.5) code to
work better with the rest of Grbl’s systems.

- Refactored mc_probe() and mc_arc() to accept the mode of the command,
i.e. clockwise vs counter, toward vs away, etc. This is to make these
functions independent of gcode state variables.

- Removed the pull off motion in the probing cycle. This is not an
official operation and was added for user simplicity, but wrongly did
so. So bye bye.

- Created a configure probe invert mask function to handle the
different probe pin setting and probing cycle modes with a single mask.

 - Minor bug fix with reporting motion modes via $G. G38.2 wasn’t
showing up. It now does, along with the other new probing commands.

- Refactored some of the new pin configurations for the future of Grbl.

-
This commit is contained in:
Sonny Jeon 2014-10-01 20:22:16 -06:00
parent 15071385f7
commit 7e67395463
11 changed files with 159 additions and 126 deletions

View File

@ -156,7 +156,7 @@
// The hardware PWM output on pin D11 is required for variable spindle output voltages. // The hardware PWM output on pin D11 is required for variable spindle output voltages.
// #define VARIABLE_SPINDLE // Default disabled. Uncomment to enable. // #define VARIABLE_SPINDLE // Default disabled. Uncomment to enable.
// Use by the variable spindle output only. These parameters set the maximum and minimum spindle speed // Used by the variable spindle output only. These parameters set the maximum and minimum spindle speed
// "S" g-code values to correspond to the maximum and minimum pin voltages. There are 256 discrete and // "S" g-code values to correspond to the maximum and minimum pin voltages. There are 256 discrete and
// equally divided voltage bins between the maximum and minimum spindle speeds. So for a 5V pin, 1000 // equally divided voltage bins between the maximum and minimum spindle speeds. So for a 5V pin, 1000
// max rpm, and 250 min rpm, the spindle output voltage would be set for the following "S" commands: // max rpm, and 250 min rpm, the spindle output voltage would be set for the following "S" commands:
@ -164,6 +164,12 @@
#define SPINDLE_MAX_RPM 1000.0 // Max spindle RPM. This value is equal to 100% duty cycle on the PWM. #define SPINDLE_MAX_RPM 1000.0 // Max spindle RPM. This value is equal to 100% duty cycle on the PWM.
#define SPINDLE_MIN_RPM 0.0 // Min spindle RPM. This value is equal to (1/256) duty cycle on the PWM. #define SPINDLE_MIN_RPM 0.0 // Min spindle RPM. This value is equal to (1/256) duty cycle on the PWM.
// Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled.
// When disabled, the PWM pin will still read 0V. Most users will not need this option, but it may be
// useful in certain scenarios. This setting does not update the minimum spindle RPM calculations. Any
// spindle RPM output lower than this value will be set to this value.
// #define MINIMUM_SPINDLE_PWM 5 // Default disabled. Uncomment to enable. Integer (0-255)
// Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at // Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at
// every buffer block junction, except for starting from rest and end of the buffer, which are always // every buffer block junction, except for starting from rest and end of the buffer, which are always
// zero. This value controls how fast the machine moves through junctions with no regard for acceleration // zero. This value controls how fast the machine moves through junctions with no regard for acceleration

View File

@ -206,11 +206,11 @@
// a later date if flash and memory space allows. // a later date if flash and memory space allows.
#define COOLANT_FLOOD_DDR DDRC #define COOLANT_FLOOD_DDR DDRC
#define COOLANT_FLOOD_PORT PORTC #define COOLANT_FLOOD_PORT PORTC
#define COOLANT_FLOOD_BIT 4 // Uno Analog Pin 3 #define COOLANT_FLOOD_BIT 1 // Uno Analog Pin 1
#ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable. #ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable.
#define COOLANT_MIST_DDR DDRC #define COOLANT_MIST_DDR DDRC
#define COOLANT_MIST_PORT PORTC #define COOLANT_MIST_PORT PORTC
#define COOLANT_MIST_BIT 5 // Uno Analog Pin 4 #define COOLANT_MIST_BIT 2 // Uno Analog Pin 2
#endif #endif
// Define user-control pinouts (cycle start, reset, feed hold) input pins. // Define user-control pinouts (cycle start, reset, feed hold) input pins.
@ -218,9 +218,9 @@
#define PINOUT_DDR DDRC #define PINOUT_DDR DDRC
#define PINOUT_PIN PINC #define PINOUT_PIN PINC
#define PINOUT_PORT PORTC #define PINOUT_PORT PORTC
#define PIN_RESET 1 // Uno Analog Pin 1 #define PIN_RESET 3 // Uno Analog Pin 3
#define PIN_FEED_HOLD 2 // Uno Analog Pin 2 #define PIN_FEED_HOLD 4 // Uno Analog Pin 4
#define PIN_CYCLE_START 3 // Uno Analog Pin 3 #define PIN_CYCLE_START 5 // Uno Analog Pin 5
#define PINOUT_INT PCIE1 // Pin change interrupt enable pin #define PINOUT_INT PCIE1 // Pin change interrupt enable pin
#define PINOUT_INT_vect PCINT1_vect #define PINOUT_INT_vect PCINT1_vect
#define PINOUT_PCMSK PCMSK1 // Pin change interrupt register #define PINOUT_PCMSK PCMSK1 // Pin change interrupt register

81
gcode.c
View File

@ -123,8 +123,7 @@ uint8_t gc_execute_line(char *line)
char letter; char letter;
float value; float value;
uint8_t int_value = 0; uint8_t int_value = 0;
uint16_t mantissa = 0; // NOTE: For mantissa values > 255, variable type must be changed to uint16_t. uint16_t mantissa = 0;
uint8_t probe_mode = 0;
while (line[char_counter] != 0) { // Loop until no more g-code words in line. while (line[char_counter] != 0) { // Loop until no more g-code words in line.
@ -210,22 +209,10 @@ uint8_t gc_execute_line(char *line)
case 3: gc_block.modal.motion = MOTION_MODE_CCW_ARC; break; // G3 case 3: gc_block.modal.motion = MOTION_MODE_CCW_ARC; break; // G3
case 38: case 38:
switch(mantissa) { switch(mantissa) {
case 20: // G38.2 case 20: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD; break; // G38.2
gc_block.modal.motion = MOTION_MODE_PROBE; case 30: gc_block.modal.motion = MOTION_MODE_PROBE_TOWARD_NO_ERROR; break; // G38.3
break; case 40: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY; break; // G38.4
case 30: // G38.3 case 50: gc_block.modal.motion = MOTION_MODE_PROBE_AWAY_NO_ERROR; break; // G38.5
gc_block.modal.motion = MOTION_MODE_PROBE;
probe_mode = PROBE_NO_ERROR;
break;
case 40: // G38.4
gc_block.modal.motion = MOTION_MODE_PROBE;
probe_mode = PROBE_AWAY;
break;
case 50: // G38.5
gc_block.modal.motion = MOTION_MODE_PROBE;
probe_mode = PROBE_AWAY | PROBE_NO_ERROR;
break;
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command] default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command]
} }
mantissa = 0; // Set to zero to indicate valid non-integer G command. mantissa = 0; // Set to zero to indicate valid non-integer G command.
@ -811,7 +798,8 @@ uint8_t gc_execute_line(char *line)
} }
} }
break; break;
case MOTION_MODE_PROBE: case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_TOWARD_NO_ERROR:
case MOTION_MODE_PROBE_AWAY: case MOTION_MODE_PROBE_AWAY_NO_ERROR:
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate // [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
// is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning // is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning
// an error, it issues an alarm to prevent further motion to the probe. It's also done there to // an error, it issues an alarm to prevent further motion to the probe. It's also done there to
@ -838,6 +826,9 @@ uint8_t gc_execute_line(char *line)
need to update the state and execute the block according to the order-of-execution. need to update the state and execute the block according to the order-of-execution.
*/ */
// [0. Non-specific/common error-checks and miscellaneous setup]:
gc_state.line_number = gc_block.values.n;
// [1. Comments feedback ]: NOT SUPPORTED // [1. Comments feedback ]: NOT SUPPORTED
// [2. Set feed rate mode ]: // [2. Set feed rate mode ]:
@ -923,13 +914,13 @@ uint8_t gc_execute_line(char *line)
// and absolute and incremental modes. // and absolute and incremental modes.
if (axis_command) { if (axis_command) {
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n); mc_line(gc_block.values.xyz, -1.0, false, gc_state.line_number);
#else #else
mc_line(gc_block.values.xyz, -1.0, false); mc_line(gc_block.values.xyz, -1.0, false);
#endif #endif
} }
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(parameter_data, -1.0, false, gc_block.values.n); mc_line(parameter_data, -1.0, false, gc_state.line_number);
#else #else
mc_line(parameter_data, -1.0, false); mc_line(parameter_data, -1.0, false);
#endif #endif
@ -959,41 +950,71 @@ uint8_t gc_execute_line(char *line)
switch (gc_state.modal.motion) { switch (gc_state.modal.motion) {
case MOTION_MODE_SEEK: case MOTION_MODE_SEEK:
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n); mc_line(gc_block.values.xyz, -1.0, false, gc_state.line_number);
#else #else
mc_line(gc_block.values.xyz, -1.0, false); mc_line(gc_block.values.xyz, -1.0, false);
#endif #endif
break; break;
case MOTION_MODE_LINEAR: case MOTION_MODE_LINEAR:
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n); mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_state.line_number);
#else #else
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate); mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate);
#endif #endif
break; break;
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC: case MOTION_MODE_CW_ARC:
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, gc_block.values.n); gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, true, gc_state.line_number);
#else #else
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r, mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear); gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, true);
#endif #endif
break; break;
case MOTION_MODE_PROBE: case MOTION_MODE_CCW_ARC:
#ifdef USE_LINE_NUMBERS
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, false, gc_state.line_number);
#else
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, false);
#endif
break;
case MOTION_MODE_PROBE_TOWARD:
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So // NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same. // upon a successful probing cycle, the machine position and the returned value should be the same.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, probe_mode, gc_block.values.n); mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, false, gc_state.line_number);
#else #else
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, probe_mode); mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, false);
#endif
break;
case MOTION_MODE_PROBE_TOWARD_NO_ERROR:
#ifdef USE_LINE_NUMBERS
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, true, gc_state.line_number);
#else
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, false, true);
#endif
break;
case MOTION_MODE_PROBE_AWAY:
#ifdef USE_LINE_NUMBERS
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, false, gc_state.line_number);
#else
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, false);
#endif
break;
case MOTION_MODE_PROBE_AWAY_NO_ERROR:
#ifdef USE_LINE_NUMBERS
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, true, gc_state.line_number);
#else
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, true, true);
#endif #endif
} }
// As far as the parser is concerned, the position is now == target. In reality the // 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 // motion control system might still be processing the action and the real tool position
// in any intermediate location. // in any intermediate location.
memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc.position[] = target[]; memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc_state.position[] = gc_block.values.xyz[]
} }
} }

View File

@ -71,8 +71,11 @@
#define MOTION_MODE_LINEAR 1 // G1 #define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2 #define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3 #define MOTION_MODE_CCW_ARC 3 // G3
#define MOTION_MODE_PROBE 4 // G38.2, G38.3, G38.4, G38.5 #define MOTION_MODE_PROBE_TOWARD 4 // G38.2
#define MOTION_MODE_NONE 5 // G80 #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
// Modal Group G2: Plane select // Modal Group G2: Plane select
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero) #define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
@ -164,7 +167,7 @@ typedef struct {
float spindle_speed; // RPM float spindle_speed; // RPM
float feed_rate; // Millimeters/min float feed_rate; // Millimeters/min
uint8_t tool; // Tracks tool number. NOT USED. uint8_t tool; // Tracks tool number. NOT USED.
// int32_t line_number; // Last line number sent int32_t line_number; // Last line number sent
float position[N_AXIS]; // 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

View File

@ -95,7 +95,7 @@
// 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 // offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used // the direction of helical travel, radius == circle radius, isclockwise boolean. Used
// for vector transformation direction. // for vector transformation direction.
// The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance // The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance
@ -103,10 +103,10 @@
// distance from segment to the circle when the end points both lie on the circle. // distance from segment to the circle when the end points both lie on the circle.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number) uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc, int32_t line_number)
#else #else
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear) uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc)
#endif #endif
{ {
float center_axis0 = position[axis_0] + offset[axis_0]; float center_axis0 = position[axis_0] + offset[axis_0];
@ -118,7 +118,7 @@
// CCW angle between position and target from circle center. Only one atan2() trig computation required. // 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); float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if (gc_state.modal.motion == MOTION_MODE_CW_ARC) { // Correct atan2 output per direction if (is_clockwise_arc) { // Correct atan2 output per direction
if (angular_travel >= 0) { angular_travel -= 2*M_PI; } if (angular_travel >= 0) { angular_travel -= 2*M_PI; }
} else { } else {
if (angular_travel <= 0) { angular_travel += 2*M_PI; } if (angular_travel <= 0) { angular_travel += 2*M_PI; }
@ -287,9 +287,11 @@ void mc_homing_cycle()
// Perform tool length probe cycle. Requires probe switch. // Perform tool length probe cycle. Requires probe switch.
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state. // NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t mode, int32_t line_number) void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away,
uint8_t is_no_error, int32_t line_number)
#else #else
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t mode) void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away,
uint8_t is_no_error)
#endif #endif
{ {
// TODO: Need to update this cycle so it obeys a non-auto cycle start. // TODO: Need to update this cycle so it obeys a non-auto cycle start.
@ -298,10 +300,14 @@ void mc_homing_cycle()
// Finish all queued commands and empty planner buffer before starting probe cycle. // Finish all queued commands and empty planner buffer before starting probe cycle.
protocol_buffer_synchronize(); protocol_buffer_synchronize();
uint8_t auto_start_state = sys.auto_start; // Store run state uint8_t auto_start_state = sys.auto_start; // Store run state
uint8_t perform_pull_off = 1;
// Initialize probing control variables
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
probe_configure_invert_mask(is_probe_away);
// After syncing, check if probe is already triggered. If so, halt and issue alarm. // After syncing, check if probe is already triggered. If so, halt and issue alarm.
if (probe_get_state(mode) && probe_errors_enabled(mode)) { // NOTE: This probe initialization error applies to all probing cycles.
if ( probe_get_state() ) { // Check probe pin state.
bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); bit_true_atomic(sys.execute, EXEC_CRIT_EVENT);
protocol_execute_runtime(); protocol_execute_runtime();
} }
@ -314,8 +320,8 @@ void mc_homing_cycle()
mc_line(target, feed_rate, invert_feed_rate); mc_line(target, feed_rate, invert_feed_rate);
#endif #endif
// Activate the probing monitor in the stepper module. // Activate the probing state monitor in the stepper module.
sys.probe_state = PROBE_ACTIVE | mode; sys.probe_state = PROBE_ACTIVE;
// Perform probing cycle. Wait here until probe is triggered or motion completes. // Perform probing cycle. Wait here until probe is triggered or motion completes.
bit_true_atomic(sys.execute, EXEC_CYCLE_START); bit_true_atomic(sys.execute, EXEC_CYCLE_START);
@ -324,16 +330,16 @@ void mc_homing_cycle()
if (sys.abort) { return; } // Check for system abort if (sys.abort) { return; } // Check for system abort
} while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED)); } while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED));
// Probing motion complete. If the probe has not been triggered, error out. // Probing cycle complete!
if (sys.probe_state & PROBE_ACTIVE) {
if (probe_errors_enabled(mode)) { // Set state variables and error out, if the probe failed and cycle with error is enabled.
bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); if (sys.probe_state == PROBE_ACTIVE) {
} else { if (is_no_error) { memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS); }
perform_pull_off = 0; else { bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); }
probe_finalize(0); } else {
} sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
} }
sys.probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
protocol_execute_runtime(); // Check and execute run-time commands protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort if (sys.abort) { return; } // Check for system abort
@ -342,24 +348,11 @@ void mc_homing_cycle()
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared. plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
plan_sync_position(); // Sync planner position to current machine position. plan_sync_position(); // Sync planner position to current machine position.
if (perform_pull_off) { // TODO: Update the g-code parser code to not require this target calculation but uses a gc_sync_position() call.
// Pull-off triggered probe to the trigger location since we had to decelerate a little beyond uint8_t idx;
// it to stop the machine in a controlled manner. for(idx=0; idx<N_AXIS; idx++){
uint8_t idx; // NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
for(idx=0; idx<N_AXIS; idx++){ target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx];
// NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
target[idx] = (float)sys.probe_position[idx]/settings.steps_per_mm[idx];
}
#ifdef USE_LINE_NUMBERS
mc_line(target, feed_rate, invert_feed_rate, line_number);
#else
mc_line(target, feed_rate, invert_feed_rate);
#endif
// Execute pull-off motion and wait until it completes.
bit_true_atomic(sys.execute, EXEC_CYCLE_START);
protocol_buffer_synchronize();
if (sys.abort) { return; } // Return if system reset has been issued.
} }
sys.auto_start = auto_start_state; // Restore run state before returning sys.auto_start = auto_start_state; // Restore run state before returning

View File

@ -26,6 +26,7 @@
#ifndef motion_control_h #ifndef motion_control_h
#define motion_control_h #define motion_control_h
#include "gcode.h"
#define HOMING_CYCLE_LINE_NUMBER -1 #define HOMING_CYCLE_LINE_NUMBER -1
@ -40,14 +41,14 @@ void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate);
// 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 // 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 // the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
// for vector transformation direction. // for vector transformation direction.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number); uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc, int32_t line_number);
#else #else
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate, void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear); uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc);
#endif #endif
// Dwell for a specific number of seconds // Dwell for a specific number of seconds
@ -58,9 +59,11 @@ void mc_homing_cycle();
// Perform tool length probe cycle. Requires probe switch. // Perform tool length probe cycle. Requires probe switch.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t motion, int32_t line_number); void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away,
uint8_t is_no_error, int32_t line_number);
#else #else
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t motion); void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, uint8_t is_probe_away,
uint8_t is_no_error);
#endif #endif
// Performs system reset. If in motion state, kills all motion and sets system alarm. // Performs system reset. If in motion state, kills all motion and sets system alarm.

39
probe.c
View File

@ -22,7 +22,7 @@
#include "settings.h" #include "settings.h"
#include "probe.h" #include "probe.h"
// Inverts the probe pin state depending on user settings. // Inverts the probe pin state depending on user settings and probing cycle mode.
uint8_t probe_invert_mask; uint8_t probe_invert_mask;
@ -32,39 +32,38 @@ void probe_init()
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
if (bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN)) { if (bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN)) {
PROBE_PORT &= ~(PROBE_MASK); // Normal low operation. Requires external pull-down. PROBE_PORT &= ~(PROBE_MASK); // Normal low operation. Requires external pull-down.
probe_invert_mask = 0;
} else { } else {
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation. PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
probe_invert_mask = PROBE_MASK;
} }
// probe_configure_invert_mask(false); // Initialize invert mask. Not required. Updated when in-use.
}
// Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to
// appropriately set the pin logic according to setting for normal-high/normal-low operation
// and the probing cycle modes for toward-workpiece/away-from-workpiece.
void probe_configure_invert_mask(uint8_t is_probe_away)
{
probe_invert_mask = 0; // Initialize as zero.
if (bit_isfalse(settings.flags,BITFLAG_INVERT_PROBE_PIN)) { probe_invert_mask ^= PROBE_MASK; }
if (is_probe_away) { probe_invert_mask ^= PROBE_MASK; }
} }
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor. // Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
uint8_t probe_get_state(uint8_t mode) { uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); }
mode = ((mode >> PROBE_AWAY_BIT) & 1) << PROBE_BIT;
return mode ^ ((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask);
}
uint8_t probe_errors_enabled(uint8_t mode) {
return !(mode & PROBE_NO_ERROR);
}
void probe_finalize(uint8_t probe_succeeded) {
sys.probe_state = PROBE_OFF;
sys.probe_succeeded = probe_succeeded;
memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS);
bit_true(sys.execute, EXEC_FEED_HOLD);
}
// Monitors probe pin state and records the system position when detected. Called by the // Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick. // stepper ISR per ISR tick.
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR. // NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
void probe_state_monitor() void probe_state_monitor()
{ {
if (sys.probe_state != PROBE_OFF) { if (sys.probe_state == PROBE_ACTIVE) {
if (probe_get_state(sys.probe_state)) { if (probe_get_state()) {
probe_finalize(1); sys.probe_state = PROBE_OFF;
memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS);
bit_true(sys.execute, EXEC_FEED_HOLD);
} }
} }
} }

20
probe.h
View File

@ -22,25 +22,19 @@
#define probe_h #define probe_h
// Values that define the probing state machine. // Values that define the probing state machine.
#define PROBE_OFF 0 // No probing. (Must be zero.) #define PROBE_OFF 0 // Probing disabled or not in use. (Must be zero.)
#define PROBE_ACTIVE 1 // Actively watching the input pin. #define PROBE_ACTIVE 1 // Actively watching the input pin.
// Probe direction and error modes
#define PROBE_AWAY 2 // G38.4, G38.5
#define PROBE_NO_ERROR 4 // G38.3, G38.5
#define PROBE_AWAY_BIT 1
#define PROBE_NO_ERROR_BIT 2
// Probe pin initialization routine. // Probe pin initialization routine.
void probe_init(); void probe_init();
// Returns probe pin state. // Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to
uint8_t probe_get_state(uint8_t mode); // appropriately set the pin logic according to setting for normal-high/normal-low operation
// and the probing cycle modes for toward-workpiece/away-from-workpiece.
void probe_configure_invert_mask(uint8_t is_probe_away);
uint8_t probe_errors_enabled(uint8_t mode); // Returns probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
uint8_t probe_get_state();
void probe_finalize(uint8_t probe_succeeded);
// Monitors probe pin state and records the system position when detected. Called by the // Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick. // stepper ISR per ISR tick.

View File

@ -281,12 +281,18 @@ void report_ngc_parameters()
// Print current gcode parser mode state // Print current gcode parser mode state
void report_gcode_modes() void report_gcode_modes()
{ {
printPgmString(PSTR("["));
switch (gc_state.modal.motion) { switch (gc_state.modal.motion) {
case MOTION_MODE_SEEK : printPgmString(PSTR("[G0")); break; case MOTION_MODE_SEEK : printPgmString(PSTR("G0")); break;
case MOTION_MODE_LINEAR : printPgmString(PSTR("[G1")); break; case MOTION_MODE_LINEAR : printPgmString(PSTR("G1")); break;
case MOTION_MODE_CW_ARC : printPgmString(PSTR("[G2")); break; case MOTION_MODE_CW_ARC : printPgmString(PSTR("G2")); break;
case MOTION_MODE_CCW_ARC : printPgmString(PSTR("[G3")); break; case MOTION_MODE_CCW_ARC : printPgmString(PSTR("G3")); break;
case MOTION_MODE_NONE : printPgmString(PSTR("[G80")); break; case MOTION_MODE_PROBE_TOWARD : printPgmString(PSTR("G38.2")); break;
case MOTION_MODE_PROBE_TOWARD_NO_ERROR : printPgmString(PSTR("G38.3")); break;
case MOTION_MODE_PROBE_AWAY : printPgmString(PSTR("G38.4")); break;
case MOTION_MODE_PROBE_AWAY_NO_ERROR : printPgmString(PSTR("G38.5")); break;
case MOTION_MODE_NONE : printPgmString(PSTR("G80")); break;
} }
printPgmString(PSTR(" G")); printPgmString(PSTR(" G"));

View File

@ -86,10 +86,16 @@ void spindle_run(uint8_t direction, float rpm)
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM) #define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER); TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
rpm -= SPINDLE_MIN_RPM; if ( rpm < SPINDLE_MIN_RPM ) { rpm = 0; }
if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow else {
rpm -= SPINDLE_MIN_RPM;
if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow
}
uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5); uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5);
OCR_REGISTER = current_pwm; #ifdef MINIMUM_SPINDLE_PWM
if (current_pwm < MINIMUM_SPINDLE_PWM) { current_pwm = MINIMUM_SPINDLE_PWM; }
#endif
OCR_REGISTER = current_pwm; // Set PWM pin output
#ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared. #ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared.
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);

View File

@ -73,13 +73,15 @@ typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset. uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl. uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks. volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
uint8_t homing_axis_lock;
int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps. 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. // 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 auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
uint8_t homing_axis_lock; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
volatile uint8_t probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR. volatile uint8_t probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
int32_t probe_position[N_AXIS]; // Last probe position in machine coordinates and steps. int32_t probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
uint8_t probe_succeeded; uint8_t probe_succeeded; // Tracks if last probing cycle was successful.
} system_t; } system_t;
extern system_t sys; extern system_t sys;