├── 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<