2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 Smoothie 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.
4 Smoothie 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.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
9 #include "Drillingcycles.h"
10 #include "checksumm.h"
12 #include "ConfigValue.h"
16 #include "SlowTicker.h"
17 #include "StepperMotor.h"
18 #include "StreamOutputPool.h"
19 #include <math.h> /* fmod */
27 #define RETRACT_TO_Z 0
28 #define RETRACT_TO_R 1
31 #define DWELL_UNITS_S 0 // seconds
32 #define DWELL_UNITS_P 1 // millis
35 #define drillingcycles_checksum CHECKSUM("drillingcycles")
36 #define enable_checksum CHECKSUM("enable")
37 #define dwell_units_checksum CHECKSUM("dwell_units")
39 Drillingcycles::Drillingcycles() {}
41 void Drillingcycles::on_module_loaded()
43 // if the module is disabled -> do nothing
44 if(! THEKERNEL
->config
->value(drillingcycles_checksum
, enable_checksum
)->by_default(false)->as_bool()) {
45 // as this module is not needed free up the resource
51 this->on_config_reload(this);
54 this->register_for_event(ON_GCODE_RECEIVED
);
57 this->cycle_started
= false;
58 this->retract_type
= RETRACT_TO_Z
;
66 void Drillingcycles::on_config_reload(void *argument
)
68 // take the dwell units configured by user, or select S (seconds) by default
69 string dwell_units
= THEKERNEL
->config
->value(drillingcycles_checksum
, dwell_units_checksum
)->by_default("S")->as_string();
70 this->dwell_units
= (dwell_units
== "P") ? DWELL_UNITS_P
: DWELL_UNITS_S
;
74 The canned cycles have been implemented as described on this page :
75 http://www.tormach.com/g81_g89_backgroung.html
77 /!\ This code expects a clean gcode, no fail safe at this time.
79 Implemented : G80-83, G98, G99
85 /* reset all sticky values, called before each cycle */
86 void Drillingcycles::reset_sticky()
88 this->sticky_z
= 0; // Z depth
89 this->sticky_r
= 0; // R plane
90 this->sticky_f
= 0; // feedrate
91 this->sticky_q
= 0; // peck drilling increment
92 this->sticky_p
= 0; // dwell in seconds
95 /* update all sticky values, called before each hole */
96 void Drillingcycles::update_sticky(Gcode
*gcode
)
98 if (gcode
->has_letter('Z')) this->sticky_z
= gcode
->get_value('Z');
99 if (gcode
->has_letter('R')) this->sticky_r
= gcode
->get_value('R');
100 if (gcode
->has_letter('F')) this->sticky_f
= gcode
->get_value('F');
101 if (gcode
->has_letter('Q')) this->sticky_q
= gcode
->get_value('Q');
102 if (gcode
->has_letter('P')) this->sticky_p
= gcode
->get_int('P');
105 if (this->retract_type
== RETRACT_TO_Z
)
106 this->r_plane
= this->initial_z
;
108 this->r_plane
= this->sticky_r
;
111 /* send a formatted Gcode line */
112 int Drillingcycles::send_gcode(const char* format
, ...)
114 // handle variable arguments
116 va_start(args
, format
);
117 // make the formatted string
118 char line
[32]; // max length for an gcode line
119 int n
= vsnprintf(line
, sizeof(line
), format
, args
);
121 // debug, print the gcode sended
122 //THEKERNEL->streams->printf(">>> %s\r\n", line);
123 // make gcode object and send it (right way)
124 Gcode
gc(line
, &(StreamOutput::NullStream
));
125 THEKERNEL
->call_event(ON_GCODE_RECEIVED
, &gc
);
126 // return the gcode srting length
130 /* G83: peck drilling */
131 void Drillingcycles::peck_hole()
134 float depth
= this->sticky_r
- this->sticky_z
; // travel depth
135 float cycles
= depth
/ this->sticky_q
; // cycles count
136 float rest
= fmod(depth
, this->sticky_q
); // final pass
137 float z_pos
= this->sticky_r
; // current z position
140 for (int i
= 1; i
< cycles
; i
++) {
142 z_pos
-= this->sticky_q
;
143 // feed down to depth at feedrate (F and Z)
144 this->send_gcode("G1 F%1.4f Z%1.4f", this->sticky_f
, z_pos
);
145 // rapids to retract position (R)
146 this->send_gcode("G0 Z%1.4f", this->sticky_r
);
149 // final depth not reached
151 // feed down to final depth at feedrate (F and Z)
152 this->send_gcode("G1 F%1.4f Z%1.4f", this->sticky_f
, this->sticky_z
);
156 void Drillingcycles::make_hole(Gcode
*gcode
)
158 // compile X and Y values
161 if (gcode
->has_letter('X'))
162 snprintf(x
, sizeof(x
), " X%1.4f", gcode
->get_value('X'));
163 if (gcode
->has_letter('Y'))
164 snprintf(y
, sizeof(y
), " Y%1.4f", gcode
->get_value('Y'));
167 this->send_gcode("G0%s%s", x
, y
);
168 // rapids to retract position (R)
169 this->send_gcode("G0 Z%1.4f", this->sticky_r
);
172 if (this->sticky_q
> 0)
175 // feed down to depth at feedrate (F and Z)
176 this->send_gcode("G1 F%1.4f Z%1.4f", this->sticky_f
, this->sticky_z
);
178 // if dwell, wait for x seconds
179 if (this->sticky_p
> 0) {
180 // dwell exprimed in seconds
181 if (this->dwell_units
== DWELL_UNITS_S
)
182 this->send_gcode("G4 S%u", this->sticky_p
);
183 // dwell exprimed in milliseconds
185 this->send_gcode("G4 P%u", this->sticky_p
);
188 // rapids retract at R-Plane (Initial-Z or R)
189 this->send_gcode("G0 Z%1.4f", this->r_plane
);
192 void Drillingcycles::on_gcode_received(void* argument
)
195 Gcode
*gcode
= static_cast<Gcode
*>(argument
);
197 // no "G" in gcode, exit...
205 if (code
== 98 || code
== 99) {
206 // wait for any moves left and current position is update
207 THEKERNEL
->conveyor
->wait_for_empty_queue();
208 // get actual position from robot
210 THEKERNEL
->robot
->get_axis_position(pos
);
211 // backup Z position as Initial-Z value
212 this->initial_z
= pos
[Z_AXIS
];
214 this->retract_type
= (code
== 98) ? RETRACT_TO_Z
: RETRACT_TO_R
;
215 // reset sticky values
216 this->reset_sticky();
217 // mark cycle started and gcode taken
218 this->cycle_started
= true;
221 else if (code
== 80) {
222 // mark cycle endded and gcode taken
223 this->cycle_started
= false;
225 // if retract position is R-Plane
226 if (this->retract_type
== RETRACT_TO_R
) {
227 // rapids retract at Initial-Z to avoid futur collisions
228 this->send_gcode("G0 Z%1.4f", this->initial_z
);
232 else if (this->cycle_started
) {
233 // relative mode not supported for now...
234 if (THEKERNEL
->robot
->absolute_mode
== false) {
235 gcode
->stream
->printf("Drillingcycles: relative mode not supported.\r\n");
236 gcode
->stream
->printf("Drillingcycles: skip hole...\r\n");
240 // implemented cycles
241 if (code
== 81 || code
== 82 || code
== 83) {
242 this->update_sticky(gcode
);
243 this->make_hole(gcode
);