remove the unhandled gcode hack, and all the cruft it required
[clinton/Smoothieware.git] / src / modules / tools / drillingcycles / Drillingcycles.cpp
CommitLineData
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 39Drillingcycles::Drillingcycles() {}
b4a89b87 40
13320983 41void 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 66void 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/*
74The canned cycles have been implemented as described on this page :
75http://www.tormach.com/g81_g89_backgroung.html
76
77/!\ This code expects a clean gcode, no fail safe at this time.
78
d82c0a53 79Implemented : G80-83, G98, G99
b4a89b87
SM
80Absolute mode : yes
81Relative mode : no
d82c0a53 82Incremental (L) : no
b4a89b87
SM
83*/
84
d82c0a53 85/* reset all sticky values, called before each cycle */
13320983 86void 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 96void 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 112int 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 131void 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 156void 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 192void 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}