Skip to content

Commit f878ec3

Browse files
author
ashelly
committed
Merge pull request #5 from keyme/homecounts
Improve support for encoders and home repeatability testing.
2 parents 79245ea + 8f8d05e commit f878ec3

File tree

13 files changed

+73
-102
lines changed

13 files changed

+73
-102
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
DEVICE ?= atmega2560
3232
CLOCK = 16000000
33-
PROGRAMMER ?= -c avrisp2 -P /dev/ttyUSB0 -v -v
33+
PROGRAMMER ?= -c avrisp2 -P /dev/ttyS0
3434
OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \
3535
protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \
3636
print.o probe.o report.o system.o counters.o
@@ -41,7 +41,7 @@ FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
4141

4242
# Tune the lines below only if you know what you are doing:
4343

44-
AVRDUDE = avrdude -v -v $(PROGRAMMER) -p $(DEVICE) -B 10 -F -D
44+
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10 -F
4545
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections
4646

4747
# symbolic targets:

counters.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ void counters_init()
4343
void counters_reset(uint8_t axis)
4444
{
4545
counters.counts[axis]=0;
46+
if (axis == Z_AXIS) { counters.idx=0; }
4647
}
4748

4849

4950
// Returns the counters pin state. Triggered = true. and counters state monitor.
50-
uint16_t counters_get_count(uint8_t axis)
51+
count_t counters_get_count(uint8_t axis)
5152
{
5253
return counters.counts[axis];
5354
}
@@ -56,7 +57,7 @@ uint8_t counters_get_state(){
5657
return counters.state;
5758
}
5859

59-
uint16_t counters_get_idx(){
60+
int16_t counters_get_idx(){
6061
return counters.idx;
6162
}
6263

@@ -81,8 +82,8 @@ ISR(FDBK_INT_vect) {
8182
if (idx_on) {
8283
counters.idx += counters.dir;
8384
//rezero counter.
84-
counters.counts[Z_AXIS]=(counters.counts[Z_AXIS]/DEFAULT_COUNTS_PER_IDX)*
85-
DEFAULT_COUNTS_PER_IDX + counters.idx_offset;
85+
// counters.counts[Z_AXIS]=(counters.counts[Z_AXIS]/DEFAULT_COUNTS_PER_IDX)*
86+
// DEFAULT_COUNTS_PER_IDX + counters.idx_offset;
8687
}
8788
}
8889
/* moved to probe for debounce TODO: NEEDS TESTING*/

counters.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
#ifndef counters_h
2222
#define counters_h
2323

24+
typedef int32_t count_t;
25+
2426
typedef struct counters {
25-
int32_t counts[N_AXIS];
27+
count_t counts[N_AXIS];
2628
int16_t idx; //encoder index counts
27-
int16_t idx_offset; //encoder index counts
29+
count_t idx_offset; //encoder index counts
2830
int8_t dir; //last known direction
2931
uint8_t state;
3032
uint8_t anew; //new a encode
@@ -40,9 +42,9 @@ void counters_init();
4042
uint8_t counters_get_state();
4143

4244
// Returns counts for a given axis
43-
uint16_t counters_get_count(uint8_t axis);
45+
count_t counters_get_count(uint8_t axis);
4446

45-
uint16_t counters_get_idx();
47+
int16_t counters_get_idx();
4648

4749

4850
void counters_reset(uint8_t axis);

gcode.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ uint8_t gc_execute_line(char *line)
401401
// Check for valid line number N value.
402402
if (bit_istrue(value_words,bit(WORD_N))) {
403403
// Line number value cannot be less than zero (done) or greater than max line number.
404-
if (gc_block.values.n > MAX_LINE_NUMBER) { FAIL(STATUS_GCODE_INVALID_LINE_NUMBER); } // [Exceeds max line number]
404+
if (gc_block.values.n > LINENUMBER_MAX) { FAIL(STATUS_GCODE_INVALID_LINE_NUMBER); } // [Exceeds max line number]
405405
}
406406
// bit_false(value_words,bit(WORD_N)); // NOTE: Single-meaning value word. Set at end of error-checking.
407407

@@ -872,8 +872,7 @@ uint8_t gc_execute_line(char *line)
872872
if (gc_block.non_modal_command == NON_MODAL_DWELL) {
873873
linenumber_insert(gc_block.values.n);
874874
mc_dwell(gc_block.values.p);
875-
sys.eol_flag = 1; //pop the number we just put in
876-
SYS_EXEC |= EXEC_STATUS_REPORT;
875+
request_report_status(1); //pop the number we just put in
877876
}
878877

879878
// [11. Set active plane ]:

limits.c

Lines changed: 40 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
#include "limits.h"
2929
#include "report.h"
3030

31-
#define HOMING_CYCLE_LINE_NUMBER MAX_LINE_NUMBER
31+
#define HOMING_ZERO_LINE_NUMBER (LINENUMBER_SPECIAL|0)
32+
#define HOMING_FINISHED_LINE_NUMBER (LINENUMBER_SPECIAL|1)
3233

3334
#define HOMING_AXIS_SEARCH_SCALAR 1.1 // Axis search distance multiplier. Must be > 1.
3435

@@ -49,11 +50,6 @@ void limits_init()
4950
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
5051
}
5152

52-
53-
/* LIMIT_PCMSK &= ~LIMIT_MASK; // prevent spurious interrupts while configuring
54-
PCICR |= LIMIT_INT; // Enable Pin Change Interrupt on correct port.
55-
*/
56-
5753
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
5854
limits_enable(LIMIT_MASK & HARDSTOP_MASK,0);
5955
} else {
@@ -81,62 +77,23 @@ void limits_disable()
8177
limits.active = 0;
8278
}
8379

84-
// This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing
85-
// limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
86-
// If a switch is triggered at all, something bad has happened and treat it as such, regardless
87-
// if a limit switch is being disengaged. It's impossible to reliably tell the state of a
88-
// bouncing pin without a debouncing method. A simple software debouncing feature may be enabled
89-
// through the config.h file, where an extra timer delays the limit pin read by several milli-
90-
// seconds to help with, not fix, bouncing switches.
91-
// NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during
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-
// Ignore limit switches if already in an alarm state or in-process of executing an alarm.
96-
// When in the alarm state, Grbl should have been reset or will force a reset, so any pending
80+
81+
// Limit checking moved to stepper ISR.
82+
// limits_enable() sets limits.active and limits.expected flags.
83+
// stepper stops an axis whenever LIMIT_PIN&limits.active != limits.expected,
84+
// in this case, it also sets limits.homenext to signal homing routine to continue.
85+
// If not homing, it does a hard reset and sets the alarm.state
86+
// (See `must_stop` section of ISR TIMER1_COMPA_vect)
87+
88+
// TODO: do we need special handling if already in an alarm state or in-process of executing an alarm.
89+
// Old comments said:
90+
// Ignore limit switches When in the alarm state:
91+
// Grbl should have been reset or will force a reset, so any pending
9792
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
9893
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
9994
// limit setting if their limits are constantly triggering after a reset and move their axes.
10095

10196

102-
void check_limit_pins()
103-
{
104-
uint8_t invert_mask = (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) ? LIMIT_MASK : 0;
105-
//sysflags.limit bits are set when limit is triggered
106-
SYS_EXEC |= EXEC_LIMIT_REPORT;
107-
sysflags.limits = (LIMIT_PIN ^ invert_mask );
108-
109-
if (sys.state & STATE_HOMING) {
110-
//clear axislock bits when limit toggled.
111-
sysflags.homing_axis_lock &= (LIMIT_PIN>>LIMIT_BIT_SHIFT)^limit_approach;
112-
}
113-
else if (sysflags.limits & LIMIT_MASK) {
114-
if (!(sys.state & STATE_ALARM)) {
115-
if (bit_isfalse(SYS_EXEC,EXEC_ALARM)) {
116-
mc_reset(); // Initiate system kill.
117-
SYS_EXEC |= (EXEC_ALARM | EXEC_CRIT_EVENT); // Indicate hard limit critical event
118-
}
119-
}
120-
}
121-
}
122-
123-
#ifndef ENABLE_SOFTWARE_DEBOUNCE
124-
ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
125-
{
126-
}
127-
#else // OPTIONAL: Software debounce limit pin routine.
128-
// Upon limit pin change, enable watchdog timer to create a short delay.
129-
ISR(LIMIT_INT_vect) {
130-
if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); }
131-
}
132-
ISR(WDT_vect) // Watchdog timer ISR
133-
{
134-
WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
135-
check_limit_pins();
136-
}
137-
#endif
138-
139-
14097
// Homes the specified cycle axes, sets the machine position, and performs a pull-off motion after
14198
// completing. Homing is a special motion case, which involves rapid uncontrolled stops to locate
14299
// the trigger point of the limit switches. The rapid stops are handled by a system level axis lock
@@ -154,50 +111,46 @@ void limits_go_home(uint8_t cycle_mask)
154111
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
155112
float target[N_AXIS];
156113

114+
uint8_t flipped = settings.homing_dir_mask>>X_DIRECTION_BIT; //assumes keyme configuration.
115+
//replace with an instance of `if (bitistrue(h_d_m,X_DIRECTION_BIT)) { flipped|=1<<X_AXIS;}`
116+
//for each axis if the bits line up differently
117+
157118
// Determine travel distance to the furthest homing switch based on user max travel settings.
158119
float min_seek_rate = 1e9; //arbitrary maximum=1km/s, will be reduced by axis setting below
159120
float max_travel = 0;
121+
160122
for (idx=0; idx<N_AXIS; idx++){
161123
if (bit_istrue(cycle_mask,bit(idx))) {
162124
max_travel = max(max_travel,settings.max_travel[idx]);
163125
homing_rate = min(homing_rate,settings.homing_seek_rate[idx]);
164126
}
165127
}
166128
max_travel *= HOMING_AXIS_SEARCH_SCALAR; // Ensure homing switches engaged by over-estimating max travel.
129+
max_travel += settings.homing_pulloff;
167130
homing_rate = min_seek_rate;
168-
131+
169132
plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.
170-
133+
171134
do {
172-
173135
// Set target location and rate for active axes.
136+
// and reset homing axis locks based on cycle mask.
137+
uint8_t axislock = 0;
174138
uint8_t n_active_axis = 0;
175139
for (idx=0; idx<N_AXIS; idx++) {
176140
if (bit_istrue(cycle_mask,bit(idx))) {
177141
n_active_axis++;
178-
if (!approach) { target[idx] = max_travel; }
179-
else { target[idx] = -max_travel; }
180-
} else {
181-
target[idx] = 0.0;
182-
}
142+
axislock |= (1<<(X_STEP_BIT+idx)); //assumes axes are in bit order.
143+
if ((flipped&(1<<idx))^approach) { target[idx] = -max_travel; }
144+
else { target[idx] = max_travel; }
145+
}
146+
else { target[idx] = 0;
147+
}
183148
}
184-
if (bit_istrue(settings.homing_dir_mask,(1<<X_DIRECTION_BIT))) { target[X_AXIS] = -target[X_AXIS]; }
185-
if (bit_istrue(settings.homing_dir_mask,(1<<Y_DIRECTION_BIT))) { target[Y_AXIS] = -target[Y_AXIS]; }
186-
if (bit_istrue(settings.homing_dir_mask,(1<<Z_DIRECTION_BIT))) { target[Z_AXIS] = -target[Z_AXIS]; }
187-
if (bit_istrue(settings.homing_dir_mask,(1<<C_DIRECTION_BIT))) { target[C_AXIS] = -target[Z_AXIS]; }
188149

189150
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
151+
// homing_rate is reset each time through this loop, so it doesn't keep increasing
190152

191-
// Reset homing axis locks based on cycle mask.
192-
uint8_t axislock = 0;
193-
if (bit_istrue(cycle_mask,bit(X_AXIS))) { axislock |= (1<<X_STEP_BIT); }
194-
if (bit_istrue(cycle_mask,bit(Y_AXIS))) { axislock |= (1<<Y_STEP_BIT); }
195-
if (bit_istrue(cycle_mask,bit(Z_AXIS))) { axislock |= (1<<Z_STEP_BIT); }
196-
if (bit_istrue(cycle_mask,bit(C_AXIS))) { axislock |= (1<<C_STEP_BIT); }
197-
198-
// axis_lock bit is high if axis is homing, a 0 prevents it from being moved in stepper.
199-
sysflags.homing_axis_lock = axislock;
200-
limit_approach = approach; //limit_approach bits is high if approaching limit switch
153+
limit_approach = approach; //limit_approach bits is high if approaching limit switch
201154

202155
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
203156
#ifdef USE_LINE_NUMBERS
@@ -206,6 +159,7 @@ void limits_go_home(uint8_t cycle_mask)
206159
plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion.
207160
#endif
208161

162+
// axislock bit is high if axis is homing, so we only enable checking on moving axes.
209163
limits_enable(axislock,~approach); //expect 0 on approach (stop when 1). vice versa for pulloff
210164
limits.homenext =0;
211165

@@ -224,7 +178,6 @@ void limits_go_home(uint8_t cycle_mask)
224178
protocol_execute_runtime();
225179
return;
226180
}
227-
228181
} while (!limits.homenext); //stepper isr sets this when limit is hit
229182

230183
limits_disable();
@@ -240,6 +193,11 @@ void limits_go_home(uint8_t cycle_mask)
240193

241194
} while (n_cycle-- > 0);
242195

196+
//force report of known position for compare to zero.
197+
linenumber_insert(HOMING_ZERO_LINE_NUMBER);
198+
request_report_status(1);
199+
protocol_execute_runtime();
200+
243201
// The active cycle axes should now be homed and machine limits have been located. By
244202
// default, grbl defines machine space as all negative, as do most CNCs. Since limit switches
245203
// can be on either side of an axes, check and set axes machine zero appropriately. Also,
@@ -258,15 +216,15 @@ void limits_go_home(uint8_t cycle_mask)
258216
sys.position[idx] = -settings.homing_pulloff*settings.steps_per_mm[idx];
259217
target[idx] = 0;
260218
}
261-
if (settings.homing_pulloff == 0.0) { SYS_EXEC|=EXEC_STATUS_REPORT; } //force report if we are not going to move
219+
if (settings.homing_pulloff == 0.0) {SYS_EXEC|=EXEC_STATUS_REPORT; } //force report if we are not going to move TODO TEST
262220
} else { // Non-active cycle axis. Set target to not move during pull-off.
263221
target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx];
264222
}
265223
}
266224
plan_sync_position(); // Sync planner position to current machine position for pull-off move.
267225

268226
#ifdef USE_LINE_NUMBERS
269-
plan_buffer_line(target, min_seek_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan motion.
227+
plan_buffer_line(target, min_seek_rate, false, HOMING_FINISHED_LINE_NUMBER); // Bypass mc_line(). Directly plan motion.
270228
#else
271229
plan_buffer_line(target, min_seek_rate, false); // Bypass mc_line(). Directly plan motion.
272230
#endif

planner.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "protocol.h"
2828
#include "stepper.h"
2929
#include "settings.h"
30-
30+
#include "report.h"
3131

3232
#define SOME_LARGE_VALUE 1.0E+38 // Used by rapids and acceleration maximization calculations. Just needs
3333
// to be larger than any feasible (mm/min)^2 or mm/sec^2 value.
@@ -310,8 +310,7 @@ void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate)
310310
if (block->step_event_count == 0) {
311311
if (linenumber_insert(block->line_number|LINENUMBER_EMPTY_BLOCK) == 1) {
312312
//was empty, so report immediately;
313-
sys.eol_flag = 1;
314-
SYS_EXEC |= EXEC_STATUS_REPORT;
313+
request_report_status(1);
315314
}
316315
return;
317316
}
@@ -419,6 +418,9 @@ void plan_sync_position()
419418
}
420419
}
421420

421+
float plan_get_position(uint8_t axis){ //in mm
422+
return (float)pl.position[axis]/settings.steps_per_mm[axis];
423+
}
422424

423425
// Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail.
424426
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.

planner.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,8 @@ void plan_cycle_reinitialize();
9898
// Returns the status of the block ring buffer. True, if buffer is full.
9999
uint8_t plan_check_full_buffer();
100100

101+
//returns last planned pos for `axis` in mm
102+
float plan_get_position(uint8_t axis);
103+
104+
101105
#endif

probe.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
probe.c - code pertaining to probing methods
33
Part of Grbl
44
5-
Copyright (c) 2014 Sungeun K. Jeon
5+
Copyright (c) 2014 Sungeun K. Jeon, Adam Shelly
66
77
Grbl is free software: you can redistribute it and/or modify
88
it under the terms of the GNU General Public License as published by

report.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ void report_grbl_help() {
152152
"$X (kill alarm lock)\r\n"
153153
"$H<x=single axis> (run homing cycle)\r\n"
154154
"$E<x=clear axis> (report encoders)\r\n"
155+
"$Hx=axis (run homing cycle)\r\n"
155156
"~ (cycle start)\r\n"
156157
"! (feed hold)\r\n"
157158
"? (current status)\r\n"

report.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,7 @@ void report_build_info(char *line);
113113

114114
// Prints current limit word
115115
void report_limit_pins();
116+
117+
//called to trigger status report, with line number if eol set.
118+
#define request_report_status(eol) sys.eol_flag = (eol);SYS_EXEC|=EXEC_STATUS_REPORT
116119
#endif

0 commit comments

Comments
 (0)