diff --git a/libraries/Servo/src/Servo.cpp b/libraries/Servo/src/Servo.cpp index 3dc2c7753e..aff9afebbe 100644 --- a/libraries/Servo/src/Servo.cpp +++ b/libraries/Servo/src/Servo.cpp @@ -27,15 +27,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA uint32_t Servo::_servoMap = 0; // similiar to map but will have increased accuracy that provides a more -// symetric api (call it and use result to reverse will provide the original value) +// symmetrical api (call it and use result to reverse will provide the original value) int improved_map(int value, int minIn, int maxIn, int minOut, int maxOut) { const int rangeIn = maxIn - minIn; const int rangeOut = maxOut - minOut; const int deltaIn = value - minIn; // fixed point math constants to improve accurancy of divide and rounding - const int fixedHalfDecimal = 1; - const int fixedDecimal = fixedHalfDecimal * 2; + constexpr int fixedHalfDecimal = 1; + constexpr int fixedDecimal = fixedHalfDecimal * 2; return ((deltaIn * rangeOut * fixedDecimal) / (rangeIn) + fixedHalfDecimal) / fixedDecimal + minOut; } @@ -46,9 +46,9 @@ int improved_map(int value, int minIn, int maxIn, int minOut, int maxOut) Servo::Servo() { _attached = false; - _valueUs = DEFAULT_PULSE_WIDTH; - _minUs = MIN_PULSE_WIDTH; - _maxUs = MAX_PULSE_WIDTH; + _valueUs = DEFAULT_NEUTRAL_PULSE_WIDTH; + _minUs = DEFAULT_MIN_PULSE_WIDTH; + _maxUs = DEFAULT_MAX_PULSE_WIDTH; } Servo::~Servo() { @@ -58,10 +58,15 @@ Servo::~Servo() { uint8_t Servo::attach(int pin) { - return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); + return attach(pin, DEFAULT_MIN_PULSE_WIDTH, DEFAULT_MAX_PULSE_WIDTH); } uint8_t Servo::attach(int pin, uint16_t minUs, uint16_t maxUs) +{ + return attach(pin, minUs, maxUs, _valueUs); +} + +uint8_t Servo::attach(int pin, uint16_t minUs, uint16_t maxUs, int value) { if (!_attached) { digitalWrite(pin, LOW); @@ -76,7 +81,7 @@ uint8_t Servo::attach(int pin, uint16_t minUs, uint16_t maxUs) _maxUs = max((uint16_t)250, min((uint16_t)3000, maxUs)); _minUs = max((uint16_t)200, min(_maxUs, minUs)); - write(_valueUs); + write(value); return pin; } @@ -85,20 +90,20 @@ void Servo::detach() { if (_attached) { _servoMap &= ~(1 << _pin); + startWaveform(_pin, 0, REFRESH_INTERVAL, 1); + delay(REFRESH_INTERVAL / 1000); // long enough to complete active period under all circumstances. stopWaveform(_pin); _attached = false; - digitalWrite(_pin, LOW); + _valueUs = DEFAULT_NEUTRAL_PULSE_WIDTH; } } void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < _minUs) { + // treat any value less than 200 as angle in degrees (values equal or larger are handled as microseconds) + if (value < 200) { // assumed to be 0-180 degrees servo value = constrain(value, 0, 180); - // writeMicroseconds will contrain the calculated value for us - // for any user defined min and max, but we must use default min max value = improved_map(value, 0, 180, _minUs, _maxUs); } writeMicroseconds(value); @@ -106,6 +111,7 @@ void Servo::write(int value) void Servo::writeMicroseconds(int value) { + value = constrain(value, _minUs, _maxUs); _valueUs = value; if (_attached) { _servoMap &= ~(1 << _pin); @@ -117,8 +123,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - // read returns the angle for an assumed 0-180, so we calculate using - // the normal min/max constants and not user defined ones + // read returns the angle for an assumed 0-180 return improved_map(readMicroseconds(), _minUs, _maxUs, 0, 180); } diff --git a/libraries/Servo/src/Servo.h b/libraries/Servo/src/Servo.h index 45f593c0d8..38d78709a4 100644 --- a/libraries/Servo/src/Servo.h +++ b/libraries/Servo/src/Servo.h @@ -27,9 +27,9 @@ // // Servo - Class for manipulating servo motors connected to Arduino pins. // -// attach(pin ) - Attaches a servo motor to an i/o pin. -// attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds -// default min is 544, max is 2400 +// attach(pin) - Attaches a servo motor to an i/o pin. +// attach(pin, min, max) - Attaches to a pin setting min and max values in microseconds +// default min is 1000, max is 2000 // // write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds) // writeMicroseconds() - Sets the servo pulse width in microseconds @@ -44,13 +44,17 @@ #include -// the following are in us (microseconds) -// -#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo -#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo -#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached -#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds -#define MAX_SERVOS 12 +// The following values are in us (microseconds). +// Since the defaults can be overwritten in the new attach() member function, +// they were modified from the Arduino AVR defaults to be in the safe range +// of publically available specifications. While this implies that many 180° +// servos do not operate the full 0° to 180° sweep using these, it also prevents +// unsuspecting damage. For Arduino AVR, the same change is being discussed. +#define DEFAULT_MIN_PULSE_WIDTH 1000 // uncalibrated default, the shortest duty cycle sent to a servo +#define DEFAULT_MAX_PULSE_WIDTH 2000 // uncalibrated default, the longest duty cycle sent to a servo +#define DEFAULT_NEUTRAL_PULSE_WIDTH 1500 // default duty cycle when servo is attached +#define REFRESH_INTERVAL 20000 // classic default period to refresh servos in microseconds +#define MAX_SERVOS 9 // D0-D8 #if !defined(ESP8266) @@ -63,8 +67,16 @@ class Servo public: Servo(); ~Servo(); - uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure - uint8_t attach(int pin, uint16_t min, uint16_t max); // as above but also sets min and max values for writes. + // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure. + // returns channel number or 0 if failure. + uint8_t attach(int pin); + // attach the given pin to the next free channel, sets pinMode, min, and max values for write(). + // returns channel number or 0 if failure. + uint8_t attach(int pin, uint16_t min, uint16_t max); + // attach the given pin to the next free channel, sets pinMode, min, and max values for write(), + // and sets the initial value, the same as write(). + // returns channel number or 0 if failure. + uint8_t attach(int pin, uint16_t min, uint16_t max, int value); void detach(); void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds void writeMicroseconds(int value); // Write pulse width in microseconds