Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
133 lines (94 sloc) 5.05 KB
Part of Grbl_ESP32
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
CPU. Do not use this with Grbl for atMega328P
Grbl 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.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <>.
Servo Axis Class
The Servo axis feature allows you to use a hobby servo on any axis.
This is done using a repeating RTOS task. Grbl continues to calculate
the position of the axis in real time. The task looks at the current position of
the axis and calculates the required PWM value to go to that location. You define the travel
of the servo in millimeters.
Grbl still uses the acceleration and speed values you have in the settings, so it
will coordinate servo axes with stepper motor axes. This assumes these values are within the
capabilities of the servo
1. In config.h un-comment #define USE_SERVO_AXES
2. In a cpu_map.h section, define servo pins and PWM channels like this ....
undefine any step and direction pins associated with that axis
3. In servo_axis.cpp init_servos() function, configure servos like this ....
X_Servo_Axis.set_range(0.0, 20.0); // millimeter
The positions can be calibrated using the settings. $10x (resolution) settings adjust the minimum
position and $13x (max travel) settings adjust the maximum position. If the servo is traveling
backwards from what you want, you can use the $3 direction setting to compensate.
#ifndef servo_axis_h
#define servo_axis_h
// this is the pulse range of a the servo. Typical servos are 0.001 to 0.002 seconds
// some servos have a wider range. You can adjust this here or in the calibration feature
#define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds
#define SERVO_MAX_PULSE_SEC 0.002 // max pulse in seconds
#define SERVO_PULSE_FREQ 50 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster
#define SERVO_PULSE_RES_BITS 16 // bits of resolution of PWM (16 is max)
#define SERVO_PULSE_RES_COUNT 65535 // see above the math here 2^SERVO_PULSE_RES_BITS
#define SERVO_TIME_PER_BIT ((1.0 / (float)SERVO_PULSE_FREQ) / ((float)SERVO_PULSE_RES_COUNT) ) // seconds
#define SERVO_MIN_PULSE (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
#define SERVO_MAX_PULSE (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
#define SERVO_CAL_MIN 20.0 // Percent: the minimum allowable calibration value
#define SERVO_CAL_MAX 180.0 // Percent: the maximum allowable calibration value
#define SERVO_TIMER_INT_FREQ 20 // Hz This is the task frequency
#define SERVO_HOMING_OFF 0 // servo is off during homing
#define SERVO_HOMING_TARGET 1 // servo is send to a location during homing
extern float my_location;
void init_servos();
void servosSyncTask(void *pvParameters);
class ServoAxis{
ServoAxis(uint8_t axis, uint8_t pin_num, uint8_t channel_num); // constructor
void init();
void set_location();
void disable(); // sets PWM to 0% duty cycle. Most servos can be manually moved in this state
void set_range(float min, float max);
void set_homing_type(uint8_t homing_type);
void set_homing_position(float homing_position);
void set_disable_on_alarm (bool disable_on_alarm);
void set_disable_with_steppers(bool disable_with_steppers);
void set_use_mpos(bool use_mpos);
int _axis; // these should be assign in constructor using Grbl X_AXIS type values
int _pin_num; // The GPIO pin being used
int _channel_num; // The PWM channel
bool _showError;
uint32_t _pwm_freq = SERVO_PULSE_FREQ;
uint32_t _pwm_resolution_bits = SERVO_PULSE_RES_BITS;
float _pulse_min = SERVO_MIN_PULSE; // in pwm counts
float _pulse_max = SERVO_MAX_PULSE; // in pwm counts
float _position_min = SERVO_POSITION_MIN_DEFAULT; // position in millimeters
float _position_max = SERVO_POSITION_MAX_DEFAULT; // position in millimeters
uint8_t _homing_type = SERVO_HOMING_OFF;
float _homing_position = SERVO_POSITION_MAX_DEFAULT;
bool _disable_on_alarm = true;
bool _disable_with_steppers = false;
bool _use_mpos = true;
bool _validate_cal_settings();
void _write_pwm(uint32_t duty);
bool _cal_is_valid(); // checks to see if calibration values are in acceptable range
You can’t perform that action at this time.