Skip to content

Commit

Permalink
G38.2 probe feature rough draft installed. Working but needs testing.
Browse files Browse the repository at this point in the history
- G38.2 straight probe now supported. Rough draft. May be tweaked more
as testing ramps up.

- G38.2 requires at least one axis word. Multiple axis words work too.
When commanded, the probe cycle will move at the last ‘F’ feed rate
specified in a straight line.

- During a probe cycle: If the probe pin goes low (normal high), Grbl
will record that immediate position and engage a feed hold. Meaning
that the CNC machine will move a little past the probe switch point, so
keep federates low to stop sooner. Once stopped, Grbl will issue a move
to go back to the recorded probe trigger point.

- During a probe cycle: If the probe switch does not engage by the time
the machine has traveled to its target coordinates, Grbl will issue an
ALARM and the user will be forced to reset Grbl. (Currently G38.3 probe
without error isn’t supported, but would be easy to implement later.)

- After a successful probe, Grbl will send a feedback message
containing the recorded probe coordinates in the machine coordinate
system. This is as the g-code standard on probe parameters specifies.

- The recorded probe parameters are retained in Grbl memory and can be
viewed with the ‘$#’ print parameters command. Upon a power-cycle, not
a soft-reset, Grbl will re-zero these values.

- Moved ‘$#’ command to require IDLE or ALARM mode, because it accesses
EEPROM to fetch the coordinate system offsets.

- Updated the Grbl version to v0.9d.

- The probe cycle is subject to change upon testing or user-feedback.
  • Loading branch information
chamnit committed Mar 1, 2014
1 parent 4d7ca76 commit 76ab1b6
Show file tree
Hide file tree
Showing 17 changed files with 195 additions and 210 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ CLOCK = 16000000
PROGRAMMER ?= -c avrisp2 -P usb
OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \
protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \
print.o report.o system.o
print.o probe.o report.o system.o
# FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
# update that line with this when programmer is back up:
Expand Down
11 changes: 9 additions & 2 deletions cpu_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,18 @@
#define PIN_RESET 0 // Uno Analog Pin 0
#define PIN_FEED_HOLD 1 // Uno Analog Pin 1
#define PIN_CYCLE_START 2 // Uno Analog Pin 2
#define PIN_PROBE 5 // Uno Analog Pin 5
#define PINOUT_INT PCIE1 // Pin change interrupt enable pin
#define PINOUT_INT_vect PCINT1_vect
#define PINOUT_PCMSK PCMSK1 // Pin change interrupt register
#define PINOUT_MASK ((1<<PIN_RESET)|(1<<PIN_FEED_HOLD)|(1<<PIN_CYCLE_START)|(1<<PIN_PROBE))
#define PINOUT_MASK ((1<<PIN_RESET)|(1<<PIN_FEED_HOLD)|(1<<PIN_CYCLE_START))

// Define probe switch input pin.
#define PROBE_DDR DDRC
#define PROBE_PIN PINC
#define PROBE_PORT PORTC
#define PROBE_BIT 5 // Uno Analog Pin 5
#define PROBE_MASK (1<<PROBE_BIT)


#ifdef VARIABLE_SPINDLE
// Advanced Configuration Below You should not need to touch these variables
Expand Down
44 changes: 15 additions & 29 deletions gcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ uint8_t gc_execute_line(char *line)
// Set modal group values
switch(int_value) {
case 4: case 10: case 28: case 30: case 53: case 92: group_number = MODAL_GROUP_0; break;
case 0: case 1: case 2: case 3: case 80: group_number = MODAL_GROUP_1; break;
case 0: case 1: case 2: case 3: case 38: case 80: group_number = MODAL_GROUP_1; break;
case 17: case 18: case 19: group_number = MODAL_GROUP_2; break;
case 90: case 91: group_number = MODAL_GROUP_3; break;
case 93: case 94: group_number = MODAL_GROUP_5; break;
Expand Down Expand Up @@ -152,8 +152,10 @@ uint8_t gc_execute_line(char *line)
case 38:
int_value = trunc(10*value); // Multiply by 10 to pick up Gxx.1
switch(int_value) {
case 382: non_modal_action = NON_MODAL_PROBE_WITH_ERROR; break;
case 383: non_modal_action = NON_MODAL_PROBE_NO_ERROR; break;
case 382: gc.motion_mode = MOTION_MODE_PROBE; break;
// case 383: gc.motion_mode = MOTION_MODE_PROBE_NO_ERROR; break; // Not supported.
// case 384: // Not supported.
// case 385: // Not supported.
default: FAIL(STATUS_UNSUPPORTED_STATEMENT);
}
break;
Expand Down Expand Up @@ -366,32 +368,6 @@ uint8_t gc_execute_line(char *line)
memcpy(gc.position, coord_data, sizeof(coord_data)); // gc.position[] = coord_data[];
axis_words = 0; // Axis words used. Lock out from motion modes by clearing flags.
break;
case NON_MODAL_PROBE_WITH_ERROR:
if (!axis_words) { // No axis words
FAIL(STATUS_INVALID_STATEMENT);
break;
}
#ifdef USE_LINE_NUMBERS
if(mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode, line_number)){
#else
if(mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode)){
#endif
FAIL(STATUS_PROBE_ERROR);
}
axis_words = 0;
break;
case NON_MODAL_PROBE_NO_ERROR:
if (!axis_words) { // No axis words
FAIL(STATUS_INVALID_STATEMENT);
break;
}
#ifdef USE_LINE_NUMBERS
mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode, line_number);
#else
mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode);
#endif
axis_words = 0;
break;
case NON_MODAL_SET_HOME_0: case NON_MODAL_SET_HOME_1:
if (non_modal_action == NON_MODAL_SET_HOME_0) {
settings_write_coord_data(SETTING_INDEX_G28,gc.position);
Expand Down Expand Up @@ -512,6 +488,16 @@ uint8_t gc_execute_line(char *line)
#endif
}
break;
case MOTION_MODE_PROBE:
if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT); }
else {
#ifdef USE_LINE_NUMBERS
mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode, line_number);
#else
mc_probe_cycle(target, (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.feed_rate, gc.inverse_feed_rate_mode);
#endif
}
break;
}

// Report any errors.
Expand Down
11 changes: 5 additions & 6 deletions gcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
// 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
#define MODAL_GROUP_1 2 // [G0,G1,G2,G3,G80] Motion
#define MODAL_GROUP_1 2 // [G0,G1,G2,G3,G38.2,G80] Motion
#define MODAL_GROUP_2 3 // [G17,G18,G19] Plane selection
#define MODAL_GROUP_3 4 // [G90,G91] Distance mode
#define MODAL_GROUP_4 5 // [M0,M1,M2,M30] Stopping
Expand All @@ -47,7 +47,8 @@
#define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3
#define MOTION_MODE_CANCEL 4 // G80
#define MOTION_MODE_PROBE 4 // G38.x
#define MOTION_MODE_CANCEL 5 // G80

#define PROGRAM_FLOW_RUNNING 0
#define PROGRAM_FLOW_PAUSED 1 // M0, M1
Expand All @@ -60,10 +61,8 @@
#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_PROBE_WITH_ERROR 7 //G38.2
#define NON_MODAL_PROBE_NO_ERROR 8 //G38.3
#define NON_MODAL_SET_COORDINATE_OFFSET 9 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 10 //G92.1
#define NON_MODAL_SET_COORDINATE_OFFSET 7 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1

typedef struct {
uint8_t status_code; // Parser status for current block
Expand Down
6 changes: 3 additions & 3 deletions limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
if (sys.state != STATE_ALARM) {
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
mc_reset(); // Initiate system kill.
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
sys.execute |= (EXEC_ALARM | EXEC_CRIT_EVENT); // Indicate hard limit critical event
}
}
}
Expand All @@ -103,7 +103,7 @@ ISR(WDT_vect) // Watchdog timer ISR
if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { bits ^= LIMIT_MASK; }
if (bits & LIMIT_MASK) {
mc_reset(); // Initiate system kill.
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
sys.execute |= (EXEC_ALARM | EXEC_CRIT_EVENT); // Indicate hard limit critical event
}
}
}
Expand Down Expand Up @@ -267,7 +267,7 @@ void limits_soft_check(float *target)
}

mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
sys.execute |= EXEC_CRIT_EVENT; // Indicate soft limit critical event
sys.execute |= (EXEC_ALARM | EXEC_CRIT_EVENT); // Indicate soft limit critical event
protocol_execute_runtime(); // Execute to enter critical event loop and system abort
return;

Expand Down
2 changes: 2 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "coolant_control.h"
#include "motion_control.h"
#include "limits.h"
#include "probe.h"
#include "report.h"


Expand Down Expand Up @@ -73,6 +74,7 @@ int main(void)
spindle_init();
coolant_init();
limits_init();
probe_init();
plan_reset(); // Clear block buffer and planner variables
st_reset(); // Clear stepper subsystem variables.

Expand Down
98 changes: 25 additions & 73 deletions motion_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "spindle_control.h"
#include "coolant_control.h"
#include "limits.h"
#include "probe.h"
#include "report.h"


Expand Down Expand Up @@ -270,75 +271,39 @@ void mc_homing_cycle()
}


// Perform tool length probe cycle. Requires probe switch.
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
#ifdef USE_LINE_NUMBERS
uint8_t mc_probe_cycle(float *t, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
#else
uint8_t mc_probe_cycle(float *t, float feed_rate, uint8_t invert_feed_rate)
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate)
#endif
{
protocol_buffer_synchronize(); //finish all queued commands
protocol_buffer_synchronize(); // Finish all queued commands
if (sys.abort) { return; } // Return if system reset has been issued.

if (sys.abort) { return STATUS_OK; } // Return if system reset has been issued.

uint8_t i;
float target[N_AXIS];

//copy target position since we'll be modifying it with the probe position on a successful move
//The gc_sync_position() at the end may elimiante the need for this. Not sure though.
for(i=0; i<N_AXIS; ++i){
target[i] = t[i];
}

plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.

// Perform probing cycle. Planner buffer should be empty at this point.
// An empty buffer is needed because we need to enable the probe pin along the same move that we're about to execute.

sys.state = STATE_CYCLE;

#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, feed_rate, invert_feed_rate, line_number); // Bypass mc_line(). Directly plan homing motion.
mc_line(target, feed_rate, invert_feed_rate, line_number);
#else
plan_buffer_line(target, feed_rate, invert_feed_rate); // Bypass mc_line(). Directly plan homing motion.
mc_line(target, feed_rate, invert_feed_rate);
#endif
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
st_wake_up(); // Initiate motion

sys.probe_state = PROBE_ACTIVE;
//TODO - make sure the probe isn't already closed
do {

if( sys.probe_state == PROBE_OFF ){
sys.execute |= EXEC_FEED_HOLD;
protocol_execute_runtime();
break;
}
protocol_execute_runtime();
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.

if (sys.execute & EXEC_RESET) {
sys.probe_state = PROBE_OFF;
protocol_execute_runtime();
return STATUS_OK;
}

//Check for motion ended because switch never triggered
if(sys.state != STATE_CYCLE && sys.state != STATE_HOLD){
sys.probe_state = PROBE_OFF;
report_realtime_status_probe();
return STATUS_PROBE_ERROR;
}

} while (1);
//TODO - make sure the probe isn't already closed
sys.probe_state = PROBE_ACTIVE;

//report_realtime_status(); //debug
sys.execute |= EXEC_CYCLE_START;
do {
protocol_execute_runtime();
if (sys.abort) { return; } // Check for system abort
} while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED));

while((sys.execute & EXEC_CYCLE_STOP) == 0 && (sys.state == STATE_CYCLE || sys.state == STATE_HOLD)){
protocol_execute_runtime();
if (sys.abort) { return STATUS_OK; } // Check for system abort
}
if (sys.probe_state == PROBE_ACTIVE) { sys.execute |= EXEC_CRIT_EVENT; }
protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort

//Prep the new target based on the position that the probe triggered
uint8_t i;
for(i=0; i<N_AXIS; ++i){
target[i] = (float)sys.probe_position[i]/settings.steps_per_mm[i];
}
Expand All @@ -349,37 +314,24 @@ uint8_t mc_probe_cycle(float *t, float feed_rate, uint8_t invert_feed_rate)
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure homing motion is cleared.
plan_sync_position(); // Sync planner position to current machine position for pull-off move.

//report_realtime_status(); //debug

#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, feed_rate, invert_feed_rate, line_number); // Bypass mc_line(). Directly plan homing motion.
mc_line(target, feed_rate, invert_feed_rate, line_number); // Bypass mc_line(). Directly plan homing motion.
#else
plan_buffer_line(target, feed_rate, invert_feed_rate); // Bypass mc_line(). Directly plan homing motion.
mc_line(target, feed_rate, invert_feed_rate); // Bypass mc_line(). Directly plan homing motion.
#endif
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
st_wake_up(); // Initiate motion

protocol_execute_runtime();
sys.execute |= EXEC_CYCLE_START;
protocol_buffer_synchronize(); // Complete pull-off motion.

//report_realtime_status(); //debug

protocol_execute_runtime(); // Check for reset and set system abort.
if (sys.abort) { return STATUS_OK; } // Did not complete. Alarm state set by mc_alarm.
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.

// Gcode parser position was circumvented by the this routine, so sync position now.
gc_sync_position();

// Set idle state after probing completes and before returning to main program.
sys.state = STATE_IDLE;
st_go_idle();

//TODO - ouput a mandatory status update with the probe position. What if another was recently sent?
report_realtime_status_probe();
return STATUS_OK;
report_probe_parameters();
}


// Method to ready the system to reset by setting the runtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
Expand Down
6 changes: 2 additions & 4 deletions motion_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ void mc_dwell(float seconds);
void mc_homing_cycle();

// Perform tool length probe cycle. Requires probe switch.
// Returns STATUS_OK in all cases except when the motion is completed without the probe being triggered.
// In that case, it returns a STATUS_PROBE_ERROR
#ifdef USE_LINE_NUMBERS
uint8_t mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number);
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number);
#else
uint8_t mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate);
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate);
#endif

// Performs system reset. If in motion state, kills all motion and sets system alarm.
Expand Down
45 changes: 45 additions & 0 deletions probe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
probe.c - code pertaining to probing methods
Part of Grbl
Copyright (c) 2014 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
(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 <http://www.gnu.org/licenses/>.
*/

#include "system.h"
#include "probe.h"


// Probe pin initialization routine.
void probe_init()
{
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
}


// Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick.
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
void probe_state_monitor()
{
if (sys.probe_state == PROBE_ACTIVE) {
if (!(PROBE_PIN & PROBE_MASK)) {
sys.probe_state = PROBE_OFF;
memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS);
sys.execute |= EXEC_FEED_HOLD;
}
}
}
Loading

0 comments on commit 76ab1b6

Please sign in to comment.