Commit | Line | Data |
---|---|---|
ca037905 | 1 | /* |
58baeec1 MM |
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/>. | |
cd011f58 AW |
6 | */ |
7 | ||
5673fe39 MM |
8 | #include "Extruder.h" |
9 | ||
4cff3ded AW |
10 | #include "libs/Module.h" |
11 | #include "libs/Kernel.h" | |
5673fe39 | 12 | |
3fceb8eb | 13 | #include "modules/robot/Conveyor.h" |
4cff3ded | 14 | #include "modules/robot/Block.h" |
5673fe39 | 15 | #include "StepperMotor.h" |
61134a65 | 16 | #include "SlowTicker.h" |
61134a65 JM |
17 | #include "Config.h" |
18 | #include "StepperMotor.h" | |
19 | #include "Robot.h" | |
7af0714f | 20 | #include "checksumm.h" |
8d54c34c | 21 | #include "ConfigValue.h" |
66383b80 | 22 | #include "Gcode.h" |
fc7b9a7b | 23 | #include "libs/StreamOutput.h" |
d87968be | 24 | #include "PublicDataRequest.h" |
928467c0 JM |
25 | #include "StreamOutputPool.h" |
26 | #include "ExtruderPublicAccess.h" | |
5673fe39 | 27 | |
5dcb2ff3 | 28 | #include <mri.h> |
4cff3ded | 29 | |
ec6fde0b | 30 | // OLD config names for backwards compatibility, NOTE new configs will not be added here |
43424972 JM |
31 | #define extruder_module_enable_checksum CHECKSUM("extruder_module_enable") |
32 | #define extruder_steps_per_mm_checksum CHECKSUM("extruder_steps_per_mm") | |
74079661 | 33 | #define extruder_filament_diameter_checksum CHECKSUM("extruder_filament_diameter") |
43424972 JM |
34 | #define extruder_acceleration_checksum CHECKSUM("extruder_acceleration") |
35 | #define extruder_step_pin_checksum CHECKSUM("extruder_step_pin") | |
36 | #define extruder_dir_pin_checksum CHECKSUM("extruder_dir_pin") | |
37 | #define extruder_en_pin_checksum CHECKSUM("extruder_en_pin") | |
38 | #define extruder_max_speed_checksum CHECKSUM("extruder_max_speed") | |
cade6b9a | 39 | #define extruder_default_feed_rate_checksum CHECKSUM("extruder_default_feed_rate") |
43424972 | 40 | |
ec6fde0b | 41 | // NEW config names |
43424972 JM |
42 | |
43 | #define default_feed_rate_checksum CHECKSUM("default_feed_rate") | |
44 | #define steps_per_mm_checksum CHECKSUM("steps_per_mm") | |
74079661 | 45 | #define filament_diameter_checksum CHECKSUM("filament_diameter") |
43424972 JM |
46 | #define acceleration_checksum CHECKSUM("acceleration") |
47 | #define step_pin_checksum CHECKSUM("step_pin") | |
48 | #define dir_pin_checksum CHECKSUM("dir_pin") | |
49 | #define en_pin_checksum CHECKSUM("en_pin") | |
50 | #define max_speed_checksum CHECKSUM("max_speed") | |
8adf2390 L |
51 | #define x_offset_checksum CHECKSUM("x_offset") |
52 | #define y_offset_checksum CHECKSUM("y_offset") | |
53 | #define z_offset_checksum CHECKSUM("z_offset") | |
54 | ||
ec6fde0b JM |
55 | #define retract_length_checksum CHECKSUM("retract_length") |
56 | #define retract_feedrate_checksum CHECKSUM("retract_feedrate") | |
57 | #define retract_recover_length_checksum CHECKSUM("retract_recover_length") | |
58 | #define retract_recover_feedrate_checksum CHECKSUM("retract_recover_feedrate") | |
76ddeb67 JM |
59 | #define retract_zlift_length_checksum CHECKSUM("retract_zlift_length") |
60 | #define retract_zlift_feedrate_checksum CHECKSUM("retract_zlift_feedrate") | |
ec6fde0b | 61 | |
8a3ae3d0 | 62 | #define PI 3.14159265358979F |
74079661 | 63 | |
41fd89e0 | 64 | |
374d0777 JM |
65 | /* |
66 | As the actual motion is handled by the planner and the stepticker, this module just handles Extruder specific gcodes | |
67 | and settings. | |
68 | In a multi extruder setting it must be selected to be addressed. (using T0 T1 etc) | |
4464301d AW |
69 | */ |
70 | ||
13ad7234 | 71 | Extruder::Extruder( uint16_t config_identifier) |
17c89e4d | 72 | { |
29e809e0 | 73 | this->selected = false; |
ea356db4 JM |
74 | this->identifier = config_identifier; |
75 | this->retracted = false; | |
76 | this->volumetric_multiplier = 1.0F; | |
77 | this->extruder_multiplier = 1.0F; | |
9c72d468 | 78 | this->stepper_motor = nullptr; |
9c72d468 | 79 | this->max_volumetric_rate = 0; |
d43bc398 | 80 | this->g92e0_detected = false; |
48a10598 | 81 | memset(this->offset, 0, sizeof(this->offset)); |
436a2cd1 | 82 | } |
4cff3ded | 83 | |
3494f3d0 JM |
84 | Extruder::~Extruder() |
85 | { | |
86 | delete stepper_motor; | |
87 | } | |
88 | ||
17c89e4d JM |
89 | void Extruder::on_module_loaded() |
90 | { | |
4cff3ded | 91 | // Settings |
29e809e0 | 92 | this->config_load(); |
3494f3d0 | 93 | |
4cff3ded | 94 | // We work on the same Block as Stepper, so we need to know when it gets a new one and drops one |
6989211c | 95 | this->register_for_event(ON_GCODE_RECEIVED); |
d87968be | 96 | this->register_for_event(ON_GET_PUBLIC_DATA); |
d467fcad | 97 | this->register_for_event(ON_SET_PUBLIC_DATA); |
4cff3ded AW |
98 | } |
99 | ||
2bb8b390 | 100 | // Get config |
29e809e0 | 101 | void Extruder::config_load() |
17c89e4d | 102 | { |
14ecdbd7 | 103 | |
df56baf2 | 104 | Pin step_pin, dir_pin, en_pin; |
29e809e0 JM |
105 | step_pin.from_string( THEKERNEL->config->value(extruder_checksum, this->identifier, step_pin_checksum )->by_default("nc" )->as_string())->as_output(); |
106 | dir_pin.from_string( THEKERNEL->config->value(extruder_checksum, this->identifier, dir_pin_checksum )->by_default("nc" )->as_string())->as_output(); | |
107 | en_pin.from_string( THEKERNEL->config->value(extruder_checksum, this->identifier, en_pin_checksum )->by_default("nc" )->as_string())->as_output(); | |
14ecdbd7 | 108 | |
df56baf2 JM |
109 | float steps_per_millimeter = THEKERNEL->config->value(extruder_checksum, this->identifier, steps_per_mm_checksum)->by_default(1)->as_number(); |
110 | float acceleration = THEKERNEL->config->value(extruder_checksum, this->identifier, acceleration_checksum)->by_default(1000)->as_number(); | |
111 | ||
29e809e0 JM |
112 | this->offset[X_AXIS] = THEKERNEL->config->value(extruder_checksum, this->identifier, x_offset_checksum )->by_default(0)->as_number(); |
113 | this->offset[Y_AXIS] = THEKERNEL->config->value(extruder_checksum, this->identifier, y_offset_checksum )->by_default(0)->as_number(); | |
114 | this->offset[Z_AXIS] = THEKERNEL->config->value(extruder_checksum, this->identifier, z_offset_checksum )->by_default(0)->as_number(); | |
8adf2390 | 115 | |
29e809e0 | 116 | this->filament_diameter = THEKERNEL->config->value(extruder_checksum, this->identifier, filament_diameter_checksum )->by_default(0)->as_number(); |
ec6fde0b JM |
117 | this->retract_length = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_length_checksum)->by_default(3)->as_number(); |
118 | this->retract_feedrate = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_feedrate_checksum)->by_default(45)->as_number(); | |
119 | this->retract_recover_length = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_recover_length_checksum)->by_default(0)->as_number(); | |
120 | this->retract_recover_feedrate = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_recover_feedrate_checksum)->by_default(8)->as_number(); | |
76ddeb67 | 121 | this->retract_zlift_length = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_zlift_length_checksum)->by_default(0)->as_number(); |
d43bc398 | 122 | this->retract_zlift_feedrate = THEKERNEL->config->value(extruder_checksum, this->identifier, retract_zlift_feedrate_checksum)->by_default(100 * 60)->as_number() / 60.0F; // mm/min |
ec6fde0b | 123 | |
1da77df4 | 124 | if(filament_diameter > 0.01F) { |
79f65cbb JM |
125 | this->volumetric_multiplier = 1.0F / (powf(this->filament_diameter / 2, 2) * PI); |
126 | } | |
3494f3d0 JM |
127 | |
128 | // Stepper motor object for the extruder | |
29e809e0 | 129 | stepper_motor = new StepperMotor(step_pin, dir_pin, en_pin); |
d43bc398 | 130 | motor_id = THEROBOT->register_motor(stepper_motor); |
29e809e0 JM |
131 | |
132 | stepper_motor->set_max_rate(THEKERNEL->config->value(extruder_checksum, this->identifier, max_speed_checksum)->by_default(1000)->as_number()); | |
133 | stepper_motor->set_acceleration(acceleration); | |
134 | stepper_motor->change_steps_per_mm(steps_per_millimeter); | |
135 | stepper_motor->set_selected(false); // not selected by default | |
136 | } | |
137 | ||
13ad7234 | 138 | void Extruder::select() |
29e809e0 | 139 | { |
d43bc398 | 140 | selected = true; |
29e809e0 | 141 | stepper_motor->set_selected(true); |
121094a5 | 142 | // set the function pointer to return the current scaling |
41269f21 | 143 | THEROBOT->get_e_scale_fnc = std::bind(&Extruder::get_e_scale, this); |
29e809e0 JM |
144 | } |
145 | ||
13ad7234 | 146 | void Extruder::deselect() |
29e809e0 | 147 | { |
d43bc398 | 148 | selected = false; |
29e809e0 | 149 | stepper_motor->set_selected(false); |
d43bc398 | 150 | THEROBOT->get_e_scale_fnc = nullptr; |
436a2cd1 AW |
151 | } |
152 | ||
9c72d468 JM |
153 | void Extruder::on_get_public_data(void *argument) |
154 | { | |
155 | PublicDataRequest *pdr = static_cast<PublicDataRequest *>(argument); | |
d87968be JM |
156 | |
157 | if(!pdr->starts_with(extruder_checksum)) return; | |
158 | ||
ed68c716 JM |
159 | if(!this->selected) return; |
160 | ||
161 | // pointer to structure to return data to is provided | |
d43bc398 JM |
162 | pad_extruder_t *e = static_cast<pad_extruder_t *>(pdr->get_data_ptr()); |
163 | e->steps_per_mm = stepper_motor->get_steps_per_mm(); | |
164 | e->filament_diameter = this->filament_diameter; | |
165 | e->flow_rate = this->extruder_multiplier; | |
166 | e->accleration = stepper_motor->get_acceleration(); | |
167 | e->retract_length = this->retract_length; | |
168 | e->current_position = stepper_motor->get_current_position(); | |
ed68c716 | 169 | pdr->set_taken(); |
d87968be | 170 | } |
81b547a1 | 171 | |
d467fcad JM |
172 | void Extruder::on_set_public_data(void *argument) |
173 | { | |
174 | PublicDataRequest *pdr = static_cast<PublicDataRequest *>(argument); | |
175 | ||
176 | if(!pdr->starts_with(extruder_checksum)) return; | |
177 | ||
928467c0 | 178 | // handle extrude rates request from robot |
928467c0 | 179 | if(pdr->second_element_is(target_checksum)) { |
fe484657 | 180 | // disabled extruders do not reply NOTE only one enabled extruder supported |
29e809e0 | 181 | if(!this->selected) return; |
928467c0 | 182 | |
9c72d468 | 183 | float *d = static_cast<float *>(pdr->get_data_ptr()); |
29e809e0 | 184 | float delta = d[0]; // the E passed in on Gcode is the delta volume in mm³ |
9c72d468 | 185 | float isecs = d[1]; // inverted secs |
928467c0 | 186 | |
fe484657 | 187 | // check against maximum speeds and return rate modifier |
d43bc398 | 188 | d[1] = check_max_speeds(delta, isecs); |
928467c0 JM |
189 | pdr->set_taken(); |
190 | return; | |
191 | } | |
192 | ||
de2ee57c JM |
193 | // save or restore extruder state |
194 | if(pdr->second_element_is(save_state_checksum)) { | |
55783268 | 195 | save_position(); |
d43bc398 | 196 | this->saved_selected = this->selected; |
de2ee57c JM |
197 | pdr->set_taken(); |
198 | ||
199 | } else if(pdr->second_element_is(restore_state_checksum)) { | |
d43bc398 | 200 | this->selected = this->saved_selected; |
de2ee57c | 201 | // NOTE this only gets called when the queue is empty so the milestones will be the same |
55783268 | 202 | restore_position(); |
de2ee57c JM |
203 | pdr->set_taken(); |
204 | } | |
d467fcad JM |
205 | } |
206 | ||
55783268 JM |
207 | void Extruder::save_position() |
208 | { | |
209 | // we need to save these separately as they may have been scaled | |
d43bc398 | 210 | this->saved_position = std::make_tuple(THEROBOT->get_axis_position(motor_id), stepper_motor->get_last_milestone(), stepper_motor->get_last_milestone_steps()); |
55783268 JM |
211 | } |
212 | ||
213 | void Extruder::restore_position() | |
214 | { | |
215 | THEROBOT->reset_axis_position(std::get<0>(this->saved_position), motor_id); | |
216 | stepper_motor->set_last_milestones(std::get<1>(this->saved_position), std::get<2>(this->saved_position)); | |
217 | } | |
218 | ||
219 | // check against maximum speeds and return the rate modifier | |
220 | float Extruder::check_max_speeds(float delta, float isecs) | |
221 | { | |
222 | float rm = 1.0F; // default no rate modification | |
223 | ||
224 | if(this->max_volumetric_rate > 0 && this->filament_diameter > 0.01F) { | |
225 | // volumetric enabled and check for volumetric rate | |
226 | float v = delta * isecs; // the flow rate in mm³/sec | |
227 | ||
228 | // return the rate change needed to stay within the max rate | |
229 | if(v > max_volumetric_rate) { | |
230 | rm = max_volumetric_rate / v; | |
231 | } | |
232 | //THEKERNEL->streams->printf("requested flow rate: %f mm³/sec, corrected flow rate: %f mm³/sec\n", v, v * rm); | |
233 | } | |
234 | ||
235 | return rm; | |
236 | } | |
237 | ||
17c89e4d JM |
238 | void Extruder::on_gcode_received(void *argument) |
239 | { | |
240 | Gcode *gcode = static_cast<Gcode *>(argument); | |
5dcb2ff3 | 241 | |
eafc2241 | 242 | // M codes most execute immediately, most only execute if enabled |
17c89e4d | 243 | if (gcode->has_m) { |
df56baf2 | 244 | if (gcode->m == 114 && this->selected) { |
4d9f562f | 245 | char buf[16]; |
df56baf2 | 246 | if(gcode->subcode == 0) { |
d43bc398 | 247 | float pos = THEROBOT->get_axis_position(motor_id); |
ed68c716 | 248 | int n = snprintf(buf, sizeof(buf), " E:%1.3f ", pos); |
df56baf2 JM |
249 | gcode->txt_after_ok.append(buf, n); |
250 | ||
d43bc398 | 251 | } else if(gcode->subcode == 1) { // realtime position |
41269f21 | 252 | int n = snprintf(buf, sizeof(buf), " E:%1.3f ", stepper_motor->get_current_position() / get_e_scale()); |
72420864 JM |
253 | gcode->txt_after_ok.append(buf, n); |
254 | ||
d43bc398 | 255 | } else if(gcode->subcode == 3) { // realtime actuator position |
df56baf2 JM |
256 | int n = snprintf(buf, sizeof(buf), " E:%1.3f ", stepper_motor->get_current_position()); |
257 | gcode->txt_after_ok.append(buf, n); | |
258 | } | |
33e4cc02 | 259 | |
72420864 | 260 | |
29e809e0 | 261 | } else if (gcode->m == 92 && ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier) ) ) { |
13ad7234 | 262 | float spm = stepper_motor->get_steps_per_mm(); |
6b451be8 | 263 | if (gcode->has_letter('E')) { |
7369629d | 264 | spm = gcode->get_value('E'); |
13ad7234 | 265 | stepper_motor->change_steps_per_mm(spm); |
4cba6755 JM |
266 | } |
267 | ||
29e809e0 | 268 | gcode->stream->printf("E:%f ", spm); |
7369629d | 269 | gcode->add_nl = true; |
33e4cc02 | 270 | |
29e809e0 | 271 | } else if (gcode->m == 200 && ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) { |
f39a2ecf | 272 | if (gcode->has_letter('D')) { |
112ad2fc | 273 | this->filament_diameter = gcode->get_value('D'); |
d43bc398 | 274 | float last_scale = this->volumetric_multiplier; |
d22755f7 | 275 | if(filament_diameter > 0.01F) { |
79f65cbb | 276 | this->volumetric_multiplier = 1.0F / (powf(this->filament_diameter / 2, 2) * PI); |
9c72d468 | 277 | } else { |
79f65cbb JM |
278 | this->volumetric_multiplier = 1.0F; |
279 | } | |
3eb37d11 JM |
280 | // the trouble here is that the last milestone will be for the previous multiplier so a change can cause a big blob |
281 | // so we must change the E last milestone accordingly so it continues smoothly.... | |
282 | // change E last milestone to what it would have been if it had used this new multiplier | |
d43bc398 JM |
283 | float delta = this->volumetric_multiplier / last_scale; |
284 | float nm = this->stepper_motor->get_last_milestone() * delta; | |
3eb37d11 JM |
285 | this->stepper_motor->change_last_milestone(nm); |
286 | ||
9c72d468 | 287 | } else { |
d22755f7 JM |
288 | if(filament_diameter > 0.01F) { |
289 | gcode->stream->printf("Filament Diameter: %f\n", this->filament_diameter); | |
9c72d468 | 290 | } else { |
d22755f7 JM |
291 | gcode->stream->printf("Volumetric extrusion is disabled\n"); |
292 | } | |
f39a2ecf | 293 | } |
8a3ae3d0 | 294 | |
29e809e0 | 295 | } else if (gcode->m == 203 && ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) { |
928467c0 JM |
296 | // M203 Exxx Vyyy Set maximum feedrates xxx mm/sec and/or yyy mm³/sec |
297 | if(gcode->get_num_args() == 0) { | |
298 | gcode->stream->printf("E:%g V:%g", this->stepper_motor->get_max_rate(), this->max_volumetric_rate); | |
299 | gcode->add_nl = true; | |
300 | ||
9c72d468 JM |
301 | } else { |
302 | if(gcode->has_letter('E')) { | |
928467c0 JM |
303 | this->stepper_motor->set_max_rate(gcode->get_value('E')); |
304 | } | |
9c72d468 JM |
305 | if(gcode->has_letter('V')) { |
306 | this->max_volumetric_rate = gcode->get_value('V'); | |
928467c0 JM |
307 | } |
308 | } | |
309 | ||
0db12234 | 310 | } else if (gcode->m == 204 && gcode->has_letter('E') && |
29e809e0 | 311 | ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) { |
0db12234 | 312 | // extruder acceleration M204 Ennn mm/sec^2 (Pnnn sets the specific extruder for M500) |
29e809e0 | 313 | stepper_motor->set_acceleration(gcode->get_value('E')); |
0db12234 | 314 | |
29e809e0 | 315 | } else if (gcode->m == 207 && ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) { |
d80bdf7b | 316 | // M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop] Q[zlift feedrate mm/min] |
ec6fde0b | 317 | if(gcode->has_letter('S')) retract_length = gcode->get_value('S'); |
9c72d468 | 318 | if(gcode->has_letter('F')) retract_feedrate = gcode->get_value('F') / 60.0F; // specified in mm/min converted to mm/sec |
84ebdc10 | 319 | if(gcode->has_letter('Z')) retract_zlift_length = gcode->get_value('Z'); // specified in mm |
13ad7234 | 320 | if(gcode->has_letter('Q')) retract_zlift_feedrate = gcode->get_value('Q') / 60.0F; // specified in mm/min converted to mm/sec |
ec6fde0b | 321 | |
29e809e0 | 322 | } else if (gcode->m == 208 && ( (this->selected && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) { |
ec6fde0b JM |
323 | // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min] |
324 | if(gcode->has_letter('S')) retract_recover_length = gcode->get_value('S'); | |
9c72d468 | 325 | if(gcode->has_letter('F')) retract_recover_feedrate = gcode->get_value('F') / 60.0F; // specified in mm/min converted to mm/sec |
ec6fde0b | 326 | |
29e809e0 | 327 | } else if (gcode->m == 221 && this->selected) { // M221 S100 change flow rate by percentage |
adba2978 | 328 | if(gcode->has_letter('S')) { |
d43bc398 | 329 | float last_scale = this->extruder_multiplier; |
9c72d468 | 330 | this->extruder_multiplier = gcode->get_value('S') / 100.0F; |
3eb37d11 JM |
331 | // the trouble here is that the last milestone will be for the previous multiplier so a change can cause a big blob |
332 | // so we must change the E last milestone accordingly so it continues smoothly.... | |
333 | // change E last milestone to what it would have been if it had used this new multiplier | |
d43bc398 JM |
334 | float delta = this->extruder_multiplier / last_scale; |
335 | float nm = this->stepper_motor->get_last_milestone() * delta; | |
3eb37d11 JM |
336 | this->stepper_motor->change_last_milestone(nm); |
337 | ||
9c72d468 | 338 | } else { |
9ef9f45b | 339 | gcode->stream->printf("Flow rate at %6.2f %%\n", this->extruder_multiplier * 100.0F); |
adba2978 | 340 | } |
ea356db4 | 341 | |
17c89e4d | 342 | } else if (gcode->m == 500 || gcode->m == 503) { // M500 saves some volatile settings to config override file, M503 just prints the settings |
13ad7234 | 343 | gcode->stream->printf(";E Steps per mm:\nM92 E%1.4f P%d\n", stepper_motor->get_steps_per_mm(), this->identifier); |
29e809e0 | 344 | gcode->stream->printf(";E Filament diameter:\nM200 D%1.4f P%d\n", this->filament_diameter, this->identifier); |
d43bc398 | 345 | gcode->stream->printf(";E retract length, feedrate:\nM207 S%1.4f F%1.4f Z%1.4f Q%1.4f P%d\n", this->retract_length, this->retract_feedrate * 60.0F, this->retract_zlift_length, this->retract_zlift_feedrate * 60.0F, this->identifier); |
29e809e0 JM |
346 | gcode->stream->printf(";E retract recover length, feedrate:\nM208 S%1.4f F%1.4f P%d\n", this->retract_recover_length, this->retract_recover_feedrate * 60.0F, this->identifier); |
347 | gcode->stream->printf(";E acceleration mm/sec²:\nM204 E%1.4f P%d\n", stepper_motor->get_acceleration(), this->identifier); | |
348 | gcode->stream->printf(";E max feed rate mm/sec:\nM203 E%1.4f P%d\n", stepper_motor->get_max_rate(), this->identifier); | |
349 | if(this->max_volumetric_rate > 0) { | |
350 | gcode->stream->printf(";E max volumetric rate mm³/sec:\nM203 V%1.4f P%d\n", this->max_volumetric_rate, this->identifier); | |
17c89e4d | 351 | } |
76ddeb67 JM |
352 | } |
353 | ||
d43bc398 | 354 | } else if( gcode->has_g && this->selected ) { |
13ad7234 JM |
355 | |
356 | if( (gcode->g == 10 || gcode->g == 11) && !gcode->has_letter('L') ) { | |
cf833a52 | 357 | // firmware retract command (Ignore if has L parameter that is not for us) |
eafc2241 | 358 | // check we are in the correct state of retract or unretract |
78af0407 | 359 | if(gcode->g == 10 && !retracted) { |
9c72d468 JM |
360 | this->retracted = true; |
361 | this->cancel_zlift_restore = false; | |
d43bc398 | 362 | this->g92e0_detected = false; |
9c72d468 JM |
363 | } else if(gcode->g == 11 && retracted) { |
364 | this->retracted = false; | |
78af0407 | 365 | } else |
eafc2241 JM |
366 | return; // ignore duplicates |
367 | ||
13ad7234 JM |
368 | if(gcode->g == 10) { |
369 | // retract | |
d43bc398 | 370 | float delta[motor_id + 1]; |
13ad7234 | 371 | for (int i = 0; i < motor_id; ++i) { |
d43bc398 | 372 | delta[i] = 0; |
9c72d468 | 373 | } |
ccecf58b | 374 | |
41269f21 | 375 | delta[motor_id] = -retract_length / get_e_scale(); // convert from mm to mm³, and unapply flow_rate |
d43bc398 | 376 | THEROBOT->delta_move(delta, retract_feedrate, motor_id + 1); |
0c97ae7b | 377 | |
13ad7234 JM |
378 | // zlift |
379 | if(retract_zlift_length > 0) { | |
d43bc398 | 380 | float delta[3] {0, 0, retract_zlift_length}; |
121094a5 | 381 | THEROBOT->delta_move(delta, retract_zlift_feedrate, 3); |
f8dc0043 | 382 | } |
ca037905 | 383 | |
d43bc398 | 384 | } else if(gcode->g == 11) { |
13ad7234 JM |
385 | // unretract |
386 | if(retract_zlift_length > 0 && !this->cancel_zlift_restore) { | |
387 | // reverse zlift happens before unretract | |
388 | // NOTE we do not do this if cancel_zlift_restore is set to true, which happens if there is an absolute Z move inbetween G10 and G11 | |
d43bc398 | 389 | float delta[3] {0, 0, -retract_zlift_length}; |
121094a5 | 390 | THEROBOT->delta_move(delta, retract_zlift_feedrate, 3); |
ca037905 MM |
391 | } |
392 | ||
d43bc398 | 393 | float delta[motor_id + 1]; |
13ad7234 | 394 | for (int i = 0; i < motor_id; ++i) { |
d43bc398 | 395 | delta[i] = 0; |
13ad7234 | 396 | } |
55783268 JM |
397 | // HACK ALERT due to certain slicers reseting E with G92 E0 between the G10 and G11 we need to restore |
398 | // the current position after we do the unretract, this is horribly hacky :( | |
399 | // also as the move has not completed yet, when we restore the current position will be incorrect once the move finishes, | |
400 | // however this is not fatal for an extruder | |
d43bc398 | 401 | if(g92e0_detected) save_position(); |
41269f21 | 402 | delta[motor_id] = (retract_length + retract_recover_length) / get_e_scale(); // convert from mm to mm³, and unapply flow_rate |
d43bc398 JM |
403 | THEROBOT->delta_move(delta, retract_recover_feedrate, motor_id + 1); |
404 | if(g92e0_detected) restore_position(); | |
6b451be8 | 405 | } |
99826186 | 406 | |
99826186 | 407 | |
13ad7234 JM |
408 | } else if( this->retracted && (gcode->g == 0 || gcode->g == 1) && gcode->has_letter('Z')) { |
409 | // NOTE we cancel the zlift restore for the following G11 as we have moved to an absolute Z which we need to stay at | |
410 | this->cancel_zlift_restore = true; | |
d43bc398 JM |
411 | |
412 | } else if( this->retracted && gcode->g == 92 && gcode->has_letter('E')) { | |
413 | // old versions of slic3rs issued a G92 E0 after G10, handle that case | |
414 | this->g92e0_detected= true; | |
4464301d | 415 | } |
d43bc398 | 416 | |
8519d744 | 417 | } |
feb204be | 418 | |
be8332cd | 419 | } |