├── README.md
└── grbl 1.1g SERVO - spindle_control.c
/README.md:
--------------------------------------------------------------------------------
1 | # grbl1-1g-Servo
2 | modified spindle_control.c to introduce RC Servo control into grbl 1.1g
3 |
4 | The modified 'spindle_control.c' is based on the current grbl (1.1g) version and provides full support for an RC Servo on Arduino Pin D11.
5 |
6 | To add RC Servo capability to grbl (1.1g), download the latest version of grbl (1.1g) from github and replace 'spindle_control.c' with the version provided above. You will also need to select/modify SPINDLE_TCCRB_INIT_MASK in 'cpu_map.h' to select the appropriate (61Hz) servo frequency rate and, of course, select/modify VARIABLE_SPINDLE in 'config.h' . . . all other required #define(s) are contained with the modified 'spindle_control.c'. All lines of code that have been added to 'spindle_control.c' are marked with a comment in column 100+ of their respective lines. Apart from these 31 new lines of code (and an additional SPINDLE_TCCRB_INIT_MASK in 'cpu_map.h'), in order to add RC Servo capability, the rest of the grbl (1.1g) source code remains unchanged.
7 |
8 | The #define RC_SERVO_SHORT (15) and RC_SERVO_LONG (31), in the modified 'spindle_control.c', set the PWM duty cycle for the RC Servo to 1.03ms and 2.05ms respectively (these are recommended values for standard RC Servos). There is also a #define that allows the servo to be inverted if movement of the arm is in the wrong direction.
9 |
10 | Note: the added RC Servo functionality will only operate in 'non laser' ($32=0) mode and will be ignored if you have $32 set to 1 (however, the frequency SPINDLE_TCCRB_INIT_MASK set 'cpu_map.h' will still be 61Hz rather than the default 0.98kHz used by most diode laser PWM/TTL inputs). To use this functionality use G-Code M3 to turn on the RC Servo and G-Code M5 to turn off the servo. The amount the RC Servo moves if controlled with G-Code S commands in the range 0-255.
11 |
12 | M3 S255 (turn servo full on)
13 | M5 (turn servo off)
14 | M3 S125 (turn servo half way)
15 | M3 S0 (turn servo on full off - similar to M5)
16 |
--------------------------------------------------------------------------------
/grbl 1.1g SERVO - spindle_control.c:
--------------------------------------------------------------------------------
1 | /*
2 | spindle_control.c - spindle control methods
3 | Part of Grbl
4 |
5 | Copyright (c) 2012-2017 Sungeun K. Jeon for Gnea Research LLC
6 | Copyright (c) 2009-2011 Simen Svale Skogsrud
7 |
8 | Grbl is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | Grbl is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with Grbl. If not, see .
20 | */
21 |
22 | #include "grbl.h"
23 |
24 | /* RC-Servo PWM modification: switch between 0.6ms and 2.5ms pulse-width at 61Hz
25 | Prescaler 1024 = 15625Hz / 256Steps = 61Hz 64µs/step -> Values 15 / 32 for 1ms / 2ms
26 | Reload value = 0x07
27 | Replace this file in C:\Program Files (x86)\Arduino\libraries\GRBL
28 |
29 | NOTE
30 | ====
31 |
32 | Make sure that the line below exists in cpu_map.h (introduce 61Hz 1/1024 prescaler in line 140 for servo)
33 |
34 | #define SPINDLE_TCCRB_INIT_MASK ((1<= settings.rpm_max) || (rpm >= RPM_MAX)) {
190 | rpm = RPM_MAX;
191 | pwm_value = SPINDLE_PWM_MAX_VALUE;
192 | } else if (rpm <= RPM_MIN) {
193 | if (rpm == 0.0) { // S0 disables spindle
194 | pwm_value = SPINDLE_PWM_OFF_VALUE;
195 | } else {
196 | rpm = RPM_MIN;
197 | pwm_value = SPINDLE_PWM_MIN_VALUE;
198 | }
199 | } else {
200 | // Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
201 | #if (N_PIECES > 3)
202 | if (rpm > RPM_POINT34) {
203 | pwm_value = floor(RPM_LINE_A4*rpm - RPM_LINE_B4);
204 | } else
205 | #endif
206 | #if (N_PIECES > 2)
207 | if (rpm > RPM_POINT23) {
208 | pwm_value = floor(RPM_LINE_A3*rpm - RPM_LINE_B3);
209 | } else
210 | #endif
211 | #if (N_PIECES > 1)
212 | if (rpm > RPM_POINT12) {
213 | pwm_value = floor(RPM_LINE_A2*rpm - RPM_LINE_B2);
214 | } else
215 | #endif
216 | {
217 | pwm_value = floor(RPM_LINE_A1*rpm - RPM_LINE_B1);
218 | }
219 | }
220 | sys.spindle_speed = rpm;
221 | return(pwm_value);
222 | }
223 |
224 | #else
225 |
226 | // Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
227 | uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
228 | {
229 | uint8_t pwm_value;
230 | rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
231 | // Calculate PWM register value based on rpm max/min settings and programmed rpm.
232 | if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
233 | // No PWM range possible. Set simple on/off spindle control pin state.
234 | sys.spindle_speed = settings.rpm_max;
235 | pwm_value = SPINDLE_PWM_MAX_VALUE;
236 | } else if (rpm <= settings.rpm_min) {
237 | if (rpm == 0.0) { // S0 disables spindle
238 | sys.spindle_speed = 0.0;
239 | pwm_value = SPINDLE_PWM_OFF_VALUE;
240 | } else { // Set minimum PWM output
241 | sys.spindle_speed = settings.rpm_min;
242 | pwm_value = SPINDLE_PWM_MIN_VALUE;
243 | }
244 | } else {
245 | // Compute intermediate PWM value with linear spindle speed model.
246 | // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
247 | sys.spindle_speed = rpm;
248 | pwm_value = floor((rpm-settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
249 | }
250 |
251 | if (!(settings.flags & BITFLAG_LASER_MODE)) { // RC Servo
252 | #ifdef RC_SERVO_SHORT // RC Servo
253 | #ifdef RC_SERVO_INVERT // RC Servo
254 | pwm_value = floor(RC_SERVO_LONG - rpm*(RC_SERVO_RANGE/(settings.rpm_max-settings.rpm_min))); // RC Servo
255 | #else // RC Servo
256 | pwm_value = floor(rpm*(RC_SERVO_RANGE/(settings.rpm_max-settings.rpm_min))+RC_SERVO_SHORT); // RC Servo
257 | #endif // RC Servo
258 | #endif // RC Servo
259 | } // RC Servo
260 |
261 | return(pwm_value);
262 | }
263 |
264 | #endif
265 | #endif
266 |
267 |
268 | // Immediately sets spindle running state with direction and spindle rpm via PWM, if enabled.
269 | // Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
270 | // sleep, and spindle stop override.
271 | #ifdef VARIABLE_SPINDLE
272 | void spindle_set_state(uint8_t state, float rpm)
273 | #else
274 | void _spindle_set_state(uint8_t state)
275 | #endif
276 | {
277 | if (sys.abort) { return; } // Block during abort.
278 | if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
279 |
280 | #ifdef VARIABLE_SPINDLE
281 | sys.spindle_speed = 0.0;
282 | #endif
283 | spindle_stop();
284 |
285 | } else {
286 |
287 | #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
288 | if (state == SPINDLE_ENABLE_CW) {
289 | SPINDLE_DIRECTION_PORT &= ~(1<