Commit | Line | Data |
---|---|---|
b4a89b87 SM |
1 | /* |
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/>. | |
6 | */ | |
7 | ||
8 | #include "Kernel.h" | |
13320983 | 9 | #include "Drillingcycles.h" |
d82c0a53 SM |
10 | #include "checksumm.h" |
11 | #include "Config.h" | |
12 | #include "ConfigValue.h" | |
b4a89b87 SM |
13 | #include "Gcode.h" |
14 | #include "Robot.h" | |
15 | #include "Conveyor.h" | |
d82c0a53 | 16 | #include "SlowTicker.h" |
b4a89b87 SM |
17 | #include "StepperMotor.h" |
18 | #include "StreamOutputPool.h" | |
d82c0a53 | 19 | #include <math.h> /* fmod */ |
b4a89b87 | 20 | |
ae839285 | 21 | // axis index |
b4a89b87 SM |
22 | #define X_AXIS 0 |
23 | #define Y_AXIS 1 | |
24 | #define Z_AXIS 2 | |
25 | ||
d82c0a53 | 26 | // retract modes |
b4a89b87 SM |
27 | #define RETRACT_TO_Z 0 |
28 | #define RETRACT_TO_R 1 | |
29 | ||
10f1fcf5 SM |
30 | // dwell units |
31 | #define DWELL_UNITS_S 0 // seconds | |
32 | #define DWELL_UNITS_P 1 // millis | |
d82c0a53 SM |
33 | |
34 | // config names | |
13320983 SM |
35 | #define drillingcycles_checksum CHECKSUM("drillingcycles") |
36 | #define enable_checksum CHECKSUM("enable") | |
37 | #define dwell_units_checksum CHECKSUM("dwell_units") | |
d82c0a53 | 38 | |
13320983 | 39 | Drillingcycles::Drillingcycles() {} |
b4a89b87 | 40 | |
13320983 | 41 | void Drillingcycles::on_module_loaded() |
b4a89b87 | 42 | { |
d82c0a53 | 43 | // if the module is disabled -> do nothing |
13320983 | 44 | if(! THEKERNEL->config->value(drillingcycles_checksum, enable_checksum)->by_default(false)->as_bool()) { |
d82c0a53 SM |
45 | // as this module is not needed free up the resource |
46 | delete this; | |
47 | return; | |
48 | } | |
6e92ab91 | 49 | |
d82c0a53 SM |
50 | // Settings |
51 | this->on_config_reload(this); | |
52 | ||
b4a89b87 SM |
53 | // events |
54 | this->register_for_event(ON_GCODE_RECEIVED); | |
55 | ||
56 | // reset values | |
57 | this->cycle_started = false; | |
58 | this->retract_type = RETRACT_TO_Z; | |
59 | ||
60 | this->initial_z = 0; | |
61 | this->r_plane = 0; | |
62 | ||
d82c0a53 SM |
63 | this->reset_sticky(); |
64 | } | |
65 | ||
13320983 | 66 | void Drillingcycles::on_config_reload(void *argument) |
d82c0a53 | 67 | { |
10f1fcf5 | 68 | // take the dwell units configured by user, or select S (seconds) by default |
13320983 | 69 | string dwell_units = THEKERNEL->config->value(drillingcycles_checksum, dwell_units_checksum)->by_default("S")->as_string(); |
10f1fcf5 | 70 | this->dwell_units = (dwell_units == "P") ? DWELL_UNITS_P : DWELL_UNITS_S; |
b4a89b87 SM |
71 | } |
72 | ||
73 | /* | |
74 | The canned cycles have been implemented as described on this page : | |
75 | http://www.tormach.com/g81_g89_backgroung.html | |
76 | ||
77 | /!\ This code expects a clean gcode, no fail safe at this time. | |
78 | ||
d82c0a53 | 79 | Implemented : G80-83, G98, G99 |
b4a89b87 SM |
80 | Absolute mode : yes |
81 | Relative mode : no | |
d82c0a53 | 82 | Incremental (L) : no |
b4a89b87 SM |
83 | */ |
84 | ||
d82c0a53 | 85 | /* reset all sticky values, called before each cycle */ |
13320983 | 86 | void Drillingcycles::reset_sticky() |
d8f4a4ae | 87 | { |
d82c0a53 SM |
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 | |
93 | } | |
94 | ||
95 | /* update all sticky values, called before each hole */ | |
13320983 | 96 | void Drillingcycles::update_sticky(Gcode *gcode) |
d8f4a4ae | 97 | { |
b4a89b87 SM |
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'); | |
d82c0a53 SM |
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'); | |
6e92ab91 | 103 | |
d82c0a53 | 104 | // set retract plane |
6e92ab91 | 105 | if (this->retract_type == RETRACT_TO_Z) |
b4a89b87 | 106 | this->r_plane = this->initial_z; |
6e92ab91 | 107 | else |
b4a89b87 SM |
108 | this->r_plane = this->sticky_r; |
109 | } | |
110 | ||
111 | /* send a formatted Gcode line */ | |
13320983 | 112 | int Drillingcycles::send_gcode(const char* format, ...) |
d8f4a4ae | 113 | { |
d82c0a53 | 114 | // handle variable arguments |
b4a89b87 SM |
115 | va_list args; |
116 | va_start(args, format); | |
d82c0a53 | 117 | // make the formatted string |
b4a89b87 SM |
118 | char line[32]; // max length for an gcode line |
119 | int n = vsnprintf(line, sizeof(line), format, args); | |
120 | va_end(args); | |
d82c0a53 SM |
121 | // debug, print the gcode sended |
122 | //THEKERNEL->streams->printf(">>> %s\r\n", line); | |
ae839285 | 123 | // make gcode object and send it (right way) |
b4a89b87 | 124 | Gcode gc(line, &(StreamOutput::NullStream)); |
ae839285 | 125 | THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc); |
d82c0a53 | 126 | // return the gcode srting length |
b4a89b87 SM |
127 | return n; |
128 | } | |
129 | ||
d82c0a53 | 130 | /* G83: peck drilling */ |
13320983 | 131 | void Drillingcycles::peck_hole() |
d82c0a53 SM |
132 | { |
133 | // start values | |
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 | |
138 | ||
139 | // for each cycle | |
140 | for (int i = 1; i < cycles; i++) { | |
141 | // decrement depth | |
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); | |
147 | } | |
148 | ||
149 | // final depth not reached | |
150 | if (rest > 0) { | |
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); | |
153 | } | |
154 | } | |
155 | ||
13320983 | 156 | void Drillingcycles::make_hole(Gcode *gcode) |
b4a89b87 | 157 | { |
d82c0a53 | 158 | // compile X and Y values |
b4a89b87 SM |
159 | char x[16] = ""; |
160 | char y[16] = ""; | |
b4a89b87 SM |
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')); | |
165 | ||
166 | // rapids to X/Y | |
d82c0a53 | 167 | this->send_gcode("G0%s%s", x, y); |
b4a89b87 | 168 | // rapids to retract position (R) |
d82c0a53 | 169 | this->send_gcode("G0 Z%1.4f", this->sticky_r); |
6e92ab91 | 170 | |
d82c0a53 | 171 | // if peck drilling |
6e92ab91 | 172 | if (this->sticky_q > 0) |
d82c0a53 SM |
173 | this->peck_hole(); |
174 | else | |
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); | |
6e92ab91 | 177 | |
d82c0a53 SM |
178 | // if dwell, wait for x seconds |
179 | if (this->sticky_p > 0) { | |
180 | // dwell exprimed in seconds | |
10f1fcf5 | 181 | if (this->dwell_units == DWELL_UNITS_S) |
d82c0a53 SM |
182 | this->send_gcode("G4 S%u", this->sticky_p); |
183 | // dwell exprimed in milliseconds | |
184 | else | |
185 | this->send_gcode("G4 P%u", this->sticky_p); | |
186 | } | |
6e92ab91 | 187 | |
b4a89b87 | 188 | // rapids retract at R-Plane (Initial-Z or R) |
d82c0a53 | 189 | this->send_gcode("G0 Z%1.4f", this->r_plane); |
b4a89b87 SM |
190 | } |
191 | ||
13320983 | 192 | void Drillingcycles::on_gcode_received(void* argument) |
b4a89b87 | 193 | { |
d82c0a53 | 194 | // received gcode |
b4a89b87 SM |
195 | Gcode *gcode = static_cast<Gcode *>(argument); |
196 | ||
d82c0a53 | 197 | // no "G" in gcode, exit... |
6e92ab91 | 198 | if (! gcode->has_g) |
b4a89b87 | 199 | return; |
6e92ab91 | 200 | |
d82c0a53 | 201 | // "G" value |
b4a89b87 SM |
202 | int code = gcode->g; |
203 | ||
d82c0a53 | 204 | // cycle start |
b4a89b87 | 205 | if (code == 98 || code == 99) { |
d82c0a53 | 206 | // wait for any moves left and current position is update |
b4a89b87 | 207 | THEKERNEL->conveyor->wait_for_empty_queue(); |
ae839285 SM |
208 | // get actual position from robot |
209 | float pos[3]; | |
210 | THEKERNEL->robot->get_axis_position(pos); | |
211 | // backup Z position as Initial-Z value | |
212 | this->initial_z = pos[Z_AXIS]; | |
d82c0a53 | 213 | // set retract type |
b4a89b87 | 214 | this->retract_type = (code == 98) ? RETRACT_TO_Z : RETRACT_TO_R; |
d82c0a53 SM |
215 | // reset sticky values |
216 | this->reset_sticky(); | |
217 | // mark cycle started and gcode taken | |
b4a89b87 | 218 | this->cycle_started = true; |
b4a89b87 | 219 | } |
d82c0a53 | 220 | // cycle end |
b4a89b87 | 221 | else if (code == 80) { |
d82c0a53 | 222 | // mark cycle endded and gcode taken |
b4a89b87 | 223 | this->cycle_started = false; |
6e92ab91 | 224 | |
d82c0a53 | 225 | // if retract position is R-Plane |
b4a89b87 | 226 | if (this->retract_type == RETRACT_TO_R) { |
d82c0a53 SM |
227 | // rapids retract at Initial-Z to avoid futur collisions |
228 | this->send_gcode("G0 Z%1.4f", this->initial_z); | |
b4a89b87 SM |
229 | } |
230 | } | |
d82c0a53 | 231 | // in cycle |
b4a89b87 SM |
232 | else if (this->cycle_started) { |
233 | // relative mode not supported for now... | |
234 | if (THEKERNEL->robot->absolute_mode == false) { | |
13320983 SM |
235 | gcode->stream->printf("Drillingcycles: relative mode not supported.\r\n"); |
236 | gcode->stream->printf("Drillingcycles: skip hole...\r\n"); | |
d82c0a53 | 237 | // exit |
b4a89b87 SM |
238 | return; |
239 | } | |
d82c0a53 SM |
240 | // implemented cycles |
241 | if (code == 81 || code == 82 || code == 83) { | |
b4a89b87 | 242 | this->update_sticky(gcode); |
d82c0a53 | 243 | this->make_hole(gcode); |
b4a89b87 SM |
244 | } |
245 | } | |
4aac85ef | 246 | } |