gnea\grbl-Mega  1.0f
Source Code Documentation ( Internal Workings )
limits.c
Go to the documentation of this file.
1 /*
2  limits.c - code pertaining to limit-switches and performing the homing cycle
3  Part of Grbl
4 
5  Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
6  Copyright (c) 2009-2011 Simen Svale Skogsrud
7 
8  Grbl is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  Grbl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Grbl. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "grbl.h"
23 
25 #ifndef HOMING_AXIS_SEARCH_SCALAR
26  #define HOMING_AXIS_SEARCH_SCALAR 1.5
27 #endif
28 #ifndef HOMING_AXIS_LOCATE_SCALAR
29  #define HOMING_AXIS_LOCATE_SCALAR 5.0
30 #endif
31 
33 {
34  LIMIT_DDR &= ~(LIMIT_MASK);
35 
36  #ifdef DISABLE_LIMIT_PIN_PULL_UP
37  LIMIT_PORT &= ~(LIMIT_MASK);
38  #else
39  LIMIT_PORT |= (LIMIT_MASK);
40  #endif
41 
43  LIMIT_PCMSK |= LIMIT_MASK;
44  PCICR |= (1 << LIMIT_INT);
45  } else {
47  }
48 
49  #ifdef ENABLE_SOFTWARE_DEBOUNCE
50  MCUSR &= ~(1<<WDRF);
51  WDTCSR |= (1<<WDCE) | (1<<WDE);
52  WDTCSR = (1<<WDP0);
53  #endif
54 }
55 
58 {
59  LIMIT_PCMSK &= ~LIMIT_MASK;
60  PCICR &= ~(1 << LIMIT_INT);
61 }
62 
64 // triggered is 1 and not triggered is 0. Invert mask is applied. Axes are defined by their
65 // number in bit position, i.e. Z_AXIS is (1<<2) or bit 2, and Y_AXIS is (1<<1) or bit 1.
67 {
68  uint8_t limit_state = 0;
69  uint8_t pin = (LIMIT_PIN & LIMIT_MASK);
70  #ifdef INVERT_LIMIT_PIN_MASK
71  pin ^= INVERT_LIMIT_PIN_MASK;
72  #endif
73  if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { pin ^= LIMIT_MASK; }
74  if (pin) {
75  uint8_t idx;
76  for (idx=0; idx<N_AXIS; idx++) {
77  if (pin & get_limit_pin_mask(idx)) { limit_state |= (1 << idx); }
78  }
79  }
80  return(limit_state);
81 }
82 
84 // limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
85 // If a switch is triggered at all, something bad has happened and treat it as such, regardless
86 // if a limit switch is being disengaged. It's impossible to reliably tell the state of a
87 // bouncing pin because the Arduino microcontroller does not retain any state information when
88 // detecting a pin change. If we poll the pins in the ISR, you can miss the correct reading if the
89 // switch is bouncing.
90 //
92 // homing cycles and will not respond correctly. Upon user request or need, there may be a
93 // special pinout for an e-stop, but it is generally recommended to just directly connect
94 // your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
95 #ifndef ENABLE_SOFTWARE_DEBOUNCE
96  ISR(LIMIT_INT_vect)
97  {
98 // Ignore limit switches if already in an alarm state or in-process of executing an alarm.
99 // When in the alarm state, Grbl should have been reset or will force a reset, so any pending
100 // moves in the planner and serial buffers are all cleared and newly sent blocks will be
101 // locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
102 // limit setting if their limits are constantly triggering after a reset and move their axes.
103  if (sys.state != STATE_ALARM) {
104  if (!(sys_rt_exec_alarm)) {
105  #ifdef HARD_LIMIT_FORCE_STATE_CHECK
106 // Check limit pin state.
107  if (limits_get_state()) {
108  mc_reset();
110  }
111  #else
112  mc_reset();
114  #endif
115  }
116  }
117  }
118 #else
119 // Upon limit pin change, enable watchdog timer to create a short delay.
120  ISR(LIMIT_INT_vect) { if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); } }
121  ISR(WDT_vect)
122  {
123  WDTCSR &= ~(1<<WDIE);
124  if (sys.state != STATE_ALARM) {
125  if (!(sys_rt_exec_alarm)) {
126 // Check limit pin state.
127  if (limits_get_state()) {
128  mc_reset();
130  }
131  }
132  }
133  }
134 #endif
135 
136 
137 // Homes the specified cycle axes, sets the machine position, and performs a pull-off motion after
138 // completing. Homing is a special motion case, which involves rapid uncontrolled stops to locate
139 // the trigger point of the limit switches. The rapid stops are handled by a system level axis lock
140 // mask, which prevents the stepper algorithm from executing step pulses. Homing motions typically
141 // circumvent the processes for executing motions in normal operation.
142 //
145 void limits_go_home(uint8_t cycle_mask)
146 {
147  if (sys.abort) { return; }
148 
149 // Initialize plan data struct for homing motion. Spindle and coolant are disabled.
152  memset(pl_data,0,sizeof(plan_line_data_t));
155 
156 // Initialize variables used for homing computations.
157  uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
158  uint8_t step_pin[N_AXIS];
159  float target[N_AXIS];
160  float max_travel = 0.0;
161  uint8_t idx;
162  for (idx=0; idx<N_AXIS; idx++) {
163 // Initialize step pin masks
164  step_pin[idx] = get_step_pin_mask(idx);
165  #ifdef COREXY
166  if ((idx==A_MOTOR)||(idx==B_MOTOR)) { step_pin[idx] = (get_step_pin_mask(X_AXIS)|get_step_pin_mask(Y_AXIS)); }
167  #endif
168 
169  if (bit_istrue(cycle_mask,bit(idx))) {
170 // Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
171 //
173  max_travel = max(max_travel,(-HOMING_AXIS_SEARCH_SCALAR)*settings.max_travel[idx]);
174  }
175  }
176 
177 // Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
178  bool approach = true;
179  float homing_rate = settings.homing_seek_rate;
180 
181  uint8_t limit_state, axislock, n_active_axis;
182  do {
183 
185 
186 // Initialize and declare variables needed for homing routine.
187  axislock = 0;
188  n_active_axis = 0;
189  for (idx=0; idx<N_AXIS; idx++) {
190 // Set target location for active axes and setup computation for homing rate.
191  if (bit_istrue(cycle_mask,bit(idx))) {
192  n_active_axis++;
193  #ifdef COREXY
194  if (idx == X_AXIS) {
195  int32_t axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
196  sys_position[A_MOTOR] = axis_position;
197  sys_position[B_MOTOR] = -axis_position;
198  } else if (idx == Y_AXIS) {
199  int32_t axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
200  sys_position[A_MOTOR] = sys_position[B_MOTOR] = axis_position;
201  } else {
202  sys_position[Z_AXIS] = 0;
203  }
204  #else
205  sys_position[idx] = 0;
206  #endif
207 // Set target direction based on cycle mask and homing cycle approach state.
208 //
211  if (approach) { target[idx] = -max_travel; }
212  else { target[idx] = max_travel; }
213  } else {
214  if (approach) { target[idx] = max_travel; }
215  else { target[idx] = -max_travel; }
216  }
217 // Apply axislock to the step port pins active in this cycle.
218  axislock |= step_pin[idx];
219  }
220 
221  }
222  homing_rate *= sqrt(n_active_axis);
223  sys.homing_axis_lock = axislock;
224 
225 // Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
226  pl_data->feed_rate = homing_rate;
227  plan_buffer_line(target, pl_data);
228 
230  st_prep_buffer();
231  st_wake_up();
232  do {
233  if (approach) {
234 // Check limit state. Lock out cycle axes when they change.
235  limit_state = limits_get_state();
236  for (idx=0; idx<N_AXIS; idx++) {
237  if (axislock & step_pin[idx]) {
238  if (limit_state & (1 << idx)) {
239  #ifdef COREXY
240  if (idx==Z_AXIS) { axislock &= ~(step_pin[Z_AXIS]); }
241  else { axislock &= ~(step_pin[A_MOTOR]|step_pin[B_MOTOR]); }
242  #else
243  axislock &= ~(step_pin[idx]);
244  #endif
245  }
246  }
247  }
248  sys.homing_axis_lock = axislock;
249  }
250 
251  st_prep_buffer();
252 
254 // Exit routines: No time to run protocol_execute_realtime() in this loop.
256  uint8_t rt_exec = sys_rt_exec_state;
257 // Homing failure condition: Reset issued during cycle.
259 // Homing failure condition: Safety door was opened.
261 // Homing failure condition: Limit switch still engaged after pull-off motion
262  if (!approach && (limits_get_state() & cycle_mask)) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF); }
263 // Homing failure condition: Limit switch not found during approach.
265  if (sys_rt_exec_alarm) {
266  mc_reset();
268  return;
269  } else {
270 // Pull-off motion complete. Disable CYCLE_STOP from executing.
271  system_clear_exec_state_flag(EXEC_CYCLE_STOP);
272  break;
273  }
274  }
275 
276  } while (STEP_MASK & axislock);
277 
278  st_reset();
280 
281 // Reverse direction and reset homing rate for locate cycle(s).
282  approach = !approach;
283 
284 // After first cycle, homing enters locating phase. Shorten search to pull-off distance.
285  if (approach) {
287  homing_rate = settings.homing_feed_rate;
288  } else {
289  max_travel = settings.homing_pulloff;
290  homing_rate = settings.homing_seek_rate;
291  }
292 
293  } while (n_cycle-- > 0);
294 
295 // The active cycle axes should now be homed and machine limits have been located. By
296 // default, Grbl defines machine space as all negative, as do most CNCs. Since limit switches
297 // can be on either side of an axes, check and set axes machine zero appropriately. Also,
298 // set up pull-off maneuver from axes limit switches that have been homed. This provides
299 // some initial clearance off the switches and should also help prevent them from falsely
300 // triggering when hard limits are enabled or when more than one axes shares a limit pin.
301  int32_t set_axis_position;
302 // Set machine positions for homed limit switches. Don't update non-homed axes.
303  for (idx=0; idx<N_AXIS; idx++) {
304 //
306  if (cycle_mask & bit(idx)) {
307  #ifdef HOMING_FORCE_SET_ORIGIN
308  set_axis_position = 0;
309  #else
310  if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
311  set_axis_position = lround((settings.max_travel[idx]+settings.homing_pulloff)*settings.steps_per_mm[idx]);
312  } else {
313  set_axis_position = lround(-settings.homing_pulloff*settings.steps_per_mm[idx]);
314  }
315  #endif
316 
317  #ifdef COREXY
318  if (idx==X_AXIS) {
319  int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
320  sys_position[A_MOTOR] = set_axis_position + off_axis_position;
321  sys_position[B_MOTOR] = set_axis_position - off_axis_position;
322  } else if (idx==Y_AXIS) {
323  int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
324  sys_position[A_MOTOR] = off_axis_position + set_axis_position;
325  sys_position[B_MOTOR] = off_axis_position - set_axis_position;
326  } else {
327  sys_position[idx] = set_axis_position;
328  }
329  #else
330  sys_position[idx] = set_axis_position;
331  #endif
332 
333  }
334  }
336 }
337 
339 // the workspace volume is in all negative space, and the system is in normal operation.
340 //
342 void limits_soft_check(float *target)
343 {
344  if (system_check_travel_limits(target)) {
345  sys.soft_limit = true;
346 // Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
347 // workspace volume so just come to a controlled stop so position is not lost. When complete
348 // enter alarm mode.
349  if (sys.state == STATE_CYCLE) {
351  do {
353  if (sys.abort) { return; }
354  } while ( sys.state != STATE_IDLE );
355  }
356  mc_reset();
359  return;
360  }
361 }
uint8_t homing_dir_mask
Definition: settings.h:94
#define N_AXIS
Axis array index values. Must start with 0 and be continuous.
Definition: nuts_bolts.h:30
uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
Add a new linear movement to the buffer. target[N_AXIS] is the signed, absolute target position in mi...
Definition: planner.c:310
void limits_init()
Initialize the limits module.
Definition: limits.c:32
void limits_disable()
Disables hard limits.
Definition: limits.c:57
#define Y_AXIS
Definition: nuts_bolts.h:32
void system_convert_array_steps_to_mpos(float *position, int32_t *steps)
Updates a machine 'position' array based on the 'step' array sent.
Definition: system.c:295
#define HOMING_AXIS_SEARCH_SCALAR
Homing axis search distance multiplier. Computed by this value times the cycle travel.
Definition: limits.c:26
float homing_feed_rate
Definition: settings.h:95
void system_set_exec_state_flag(uint8_t mask)
Special handlers for setting and clearing Grbl's real-time execution flags.
Definition: system.c:340
float homing_seek_rate
Definition: settings.h:96
Planner data prototype. Must be used when passing new motions to the planner.
Definition: planner.h:78
#define EXEC_CYCLE_STOP
bitmask 00000100
Definition: system.h:33
#define EXEC_ALARM_HOMING_FAIL_DOOR
Definition: system.h:46
#define EXEC_ALARM_HOMING_FAIL_APPROACH
Definition: system.h:48
volatile uint8_t sys_rt_exec_alarm
Global realtime executor bitflag variable for setting various alarms.
Definition: system.h:135
uint8_t state
Tracks the current system state of Grbl.
Definition: system.h:112
#define HOMING_AXIS_LOCATE_SCALAR
Must be > 1 to ensure limit switch is cleared.
Definition: limits.c:29
void limits_go_home(uint8_t cycle_mask)
NOTE: Only the abort realtime command can interrupt this process.
Definition: limits.c:145
#define EXEC_RESET
bitmask 00010000
Definition: system.h:35
#define EXEC_SAFETY_DOOR
bitmask 00100000
Definition: system.h:36
#define PL_COND_FLAG_SYSTEM_MOTION
Single motion. Circumvents planner state. Used by home/park.
Definition: planner.h:34
#define X_AXIS
Axis indexing value.
Definition: nuts_bolts.h:31
#define bit(n)
Bit field and masking macros.
Definition: nuts_bolts.h:57
#define max(a, b)
Definition: nuts_bolts.h:53
uint8_t abort
System abort flag. Forces exit back to main loop for reset.
Definition: system.h:113
#define EXEC_ALARM_HOMING_FAIL_RESET
Definition: system.h:45
void limits_soft_check(float *target)
Performs a soft limit check. Called from mc_line() only. Assumes the machine has been homed...
Definition: limits.c:342
#define Z_AXIS
Definition: nuts_bolts.h:33
#define EXEC_ALARM_SOFT_LIMIT
Definition: system.h:41
#define STATE_CYCLE
Cycle is running or motions are being executed.
Definition: system.h:76
uint8_t flags
Contains default boolean settings.
Definition: settings.h:92
#define STATE_ALARM
In alarm state. Locks out all g-code processes. Allows settings access.
Definition: system.h:73
system_t sys
Declare system global variable structure.
Definition: main.c:25
uint8_t soft_limit
Tracks soft limit errors for the state machine. (boolean)
Definition: system.h:115
uint16_t homing_debounce_delay
Definition: settings.h:97
int32_t sys_position[N_AXIS]
NOTE: These position variables may need to be declared as volatiles, if problems arise.
Definition: system.h:130
#define EXEC_ALARM_HOMING_FAIL_PULLOFF
Definition: system.h:47
float steps_per_mm[N_AXIS]
Definition: settings.h:75
void system_clear_exec_state_flag(uint8_t mask)
Definition: system.c:347
#define bit_isfalse(x, mask)
Definition: nuts_bolts.h:61
uint8_t system_check_travel_limits(float *target)
CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps. ...
Definition: system.c:317
float homing_pulloff
Definition: settings.h:98
uint8_t step_control
Governs the step segment generator depending on system state.
Definition: system.h:116
void st_prep_buffer()
Prepares step segment buffer. Continuously called from main program.
Definition: stepper.c:594
float max_travel[N_AXIS]
Definition: settings.h:78
void st_wake_up()
BLOCK VELOCITY PROFILE DEFINITION.
Definition: stepper.c:199
int32_t line_number
Desired line number to report when executing.
Definition: planner.h:81
uint8_t get_step_pin_mask(uint8_t axis_idx)
Returns step pin mask according to Grbl internal axis indexing.
Definition: settings.c:308
uint8_t get_limit_pin_mask(uint8_t axis_idx)
Returns limit pin mask according to Grbl internal axis indexing.
Definition: settings.c:324
#define BITFLAG_HARD_LIMIT_ENABLE
Definition: settings.h:38
#define EXEC_ALARM_HARD_LIMIT
Alarm executor codes. Valid values (1-255). Zero is reserved.
Definition: system.h:40
volatile uint8_t sys_rt_exec_state
Global realtime executor bitflag variable for state management. See EXEC bitmasks.
Definition: system.h:134
memset(pl_data, 0, sizeof(plan_line_data_t))
Zero pl_data struct.
uint8_t homing_axis_lock
Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
Definition: system.h:118
#define EXEC_FEED_HOLD
bitmask 00001000
Definition: system.h:34
#define STEP_CONTROL_NORMAL_OP
Define step segment generator state flags.
Definition: system.h:92
#define HOMING_CYCLE_LINE_NUMBER
System motion commands must have a line number of zero.
#define PL_COND_FLAG_NO_FEED_OVERRIDE
Motion does not honor feed override.
Definition: planner.h:35
settings_t settings
Definition: settings.c:24
plan_line_data_t plan_data
STEP 4: EXECUTE!! Assumes that all error-checking has been completed and no failure modes exist...
Definition: gcode.c:858
#define N_HOMING_LOCATE_CYCLE
NOTE: The following are two examples to setup homing for 2-axis machines.
Definition: config.h:113
void protocol_execute_realtime()
This function is the general interface to Grbl's real-time command execution system. It is called.
Definition: protocol.c:213
float feed_rate
Desired feed rate for line motion. Value is ignored, if rapid motion.
Definition: planner.h:79
#define BITFLAG_INVERT_LIMIT_PINS
Definition: settings.h:41
void system_set_exec_alarm(uint8_t code)
Definition: system.c:354
uint8_t condition
Bitflag variable to indicate planner conditions. See defines above.
Definition: planner.h:82
void mc_reset()
Method to ready the system to reset by setting the realtime reset command and killing any...
#define STEP_CONTROL_EXECUTE_SYS_MOTION
Definition: system.h:95
void delay_ms(uint16_t ms)
Delays variable defined milliseconds. Compiler compatibility fix for _delay_ms(),.
Definition: nuts_bolts.c:129
plan_line_data_t * pl_data
Definition: gcode.c:859
void st_reset()
Reset and clear stepper subsystem variables.
Definition: stepper.c:476
ISR(LIMIT_INT_vect)
This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing.
Definition: limits.c:96
uint8_t limits_get_state()
Returns limit state as a bit-wise uint8 variable. Each bit indicates an axis limit, where.
Definition: limits.c:66
#define STATE_IDLE
Define system state bit map. The state variable primarily tracks the individual functions.
Definition: system.h:72
#define bit_istrue(x, mask)
Definition: nuts_bolts.h:60