From 931445b47da28bd836e1d5a92ef0a9627eb244db Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Fri, 5 Apr 2019 09:31:01 -0700 Subject: [PATCH 1/4] Fix #3: Update min and max to sensible defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R/C servos have a standard pulse width range of 1000 to 2000µs[1](#f1), with the zero point between the two at 1500µs. Currently, Arduino's Servo library sets: - [`#define MIN_PULSE_WIDTH 544`](https://github.com/arduino-libraries/Servo/blob/4970d615a13f4c0d08026ee361cc8a01974924a2/src/Servo.h#L80) - [`#define MAX_PULSE_WIDTH 2400`](https://github.com/arduino-libraries/Servo/blob/4970d615a13f4c0d08026ee361cc8a01974924a2/src/Servo.h#L81) - [`#define DEFAULT_PULSE_WIDTH 1500`](https://github.com/arduino-libraries/Servo/blob/4970d615a13f4c0d08026ee361cc8a01974924a2/src/Servo.h#L82) This causes a lot of confusion[2](#f2), especially since [the docs say `write(90)` should correspond to the mid-point] (https://www.arduino.cc/en/Reference/ServoWrite); in actuality, it results in a call to `writeMicroseconds(1472)`[3](#f3). This change adjusts the defaults to align with R/C standards. Specifically, - `write(0)` now corresponds to the standard min pulse width of 1000µs. - `write(90)` now corresponds to the standard zero point pulse width, and aligns with the library's `DEFAULT_PULSE_WIDTH` variable. - `write(180)` now corresponds to the standard max pulse width of 2000µs. Tested on an Arduino Uno with a [Tower Pro Micro Servo SG90](http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf), and a [Parallax Feedback 360° High-Speed Servo](https://parallax.com/sites/default/files/downloads/900-00360-Feedback-360-HS-Servo-v1.2.pdf). --- 1: For example, http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf 2: For instance: - https://github.com/julianduque/beaglebone-io/issues/54 - https://github.com/arduino-libraries/Servo/issues/3 - https://toolguyd.com/oscilloscope-arduino-servo-pwm-signal-mistakes/ - https://makezine.com/2014/04/23/arduinos-servo-library-angles-microseconds-and-optional-command-parameters/ I also see a _lot_ of posts on https://forum.arduino.cc about this. 3: There is actually no way to set a standard servo to the zero-point using `write(angle)`; the closest you can get is `write(92)`, for a pulse of 1504µs. --- src/Servo.h | 8 ++++---- src/avr/Servo.cpp | 2 +- src/megaavr/Servo.cpp | 2 +- src/sam/Servo.cpp | 2 +- src/samd/Servo.cpp | 2 +- src/stm32f4/ServoTimers.h | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Servo.h b/src/Servo.h index a125658..cbf2d9f 100644 --- a/src/Servo.h +++ b/src/Servo.h @@ -77,8 +77,8 @@ #define Servo_VERSION 2 // software version of this library -#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 MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo +#define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) 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 @@ -106,8 +106,8 @@ class 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, int min, int max); // as above but also sets min and max values for writes. 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 + void write(int value); // if value is < the minimum pulse width it's treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) bool attached(); // return true if this servo is attached, otherwise false diff --git a/src/avr/Servo.cpp b/src/avr/Servo.cpp index ed7376e..9fe3a6d 100644 --- a/src/avr/Servo.cpp +++ b/src/avr/Servo.cpp @@ -264,7 +264,7 @@ void Servo::detach() void Servo::write(int value) { if(value < MIN_PULSE_WIDTH) - { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if(value < 0) value = 0; if(value > 180) value = 180; value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); diff --git a/src/megaavr/Servo.cpp b/src/megaavr/Servo.cpp index daf7596..7fb5e59 100644 --- a/src/megaavr/Servo.cpp +++ b/src/megaavr/Servo.cpp @@ -157,7 +157,7 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < MIN_PULSE_WIDTH) { if (value < 0) diff --git a/src/sam/Servo.cpp b/src/sam/Servo.cpp index 21f901f..d90ef02 100644 --- a/src/sam/Servo.cpp +++ b/src/sam/Servo.cpp @@ -228,7 +228,7 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < MIN_PULSE_WIDTH) { if (value < 0) diff --git a/src/samd/Servo.cpp b/src/samd/Servo.cpp index 42a3877..946ed06 100644 --- a/src/samd/Servo.cpp +++ b/src/samd/Servo.cpp @@ -243,7 +243,7 @@ void Servo::detach() void Servo::write(int value) { - // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < MIN_PULSE_WIDTH) { if (value < 0) diff --git a/src/stm32f4/ServoTimers.h b/src/stm32f4/ServoTimers.h index 12d55b7..f6b0124 100644 --- a/src/stm32f4/ServoTimers.h +++ b/src/stm32f4/ServoTimers.h @@ -75,8 +75,8 @@ #define MIN_ANGLE 0 #define MAX_ANGLE 180 -#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 MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo +#define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) sent to a servo /** Class for interfacing with RC servomotors. */ class Servo { @@ -103,12 +103,12 @@ class Servo { * @param minPulseWidth Minimum pulse width to write to pin, in * microseconds. This will be associated * with a minAngle degree angle. Defaults to - * SERVO_DEFAULT_MIN_PW = 544. + * MIN_PULSE_WIDTH. * * @param maxPulseWidth Maximum pulse width to write to pin, in * microseconds. This will be associated * with a maxAngle degree angle. Defaults to - * SERVO_DEFAULT_MAX_PW = 2400. + * MAX_PULSE_WIDTH. * * @param minAngle Target angle (in degrees) associated with * minPulseWidth. Defaults to From 36f25f4f3a18bbb048b9be3b8dc24d65f10ec273 Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Fri, 5 Apr 2019 12:13:01 -0700 Subject: [PATCH 2/4] Simplify min, max logic and increase range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Different servo models can accept a wide range of pulse widths. Even different servos of the same model might vary a bit. Currently, the Arduino Servo library has a severely restricted hard limit on the pulse widths that can be sent to servos. Specifically: - Minimum pulse width must be between [32, 1052]. - Maximum pulse width must be between [1888, 2908]. Many popular servos have min/max pulse widths that fall in that unavailable range between (1052, 1888). For instance, the [Parallax Feedback 360° High-Speed Servo](https://parallax.com/sites/default/files/downloads/900-00360-Feedback-360-HS-Servo-v1.2.pdf) operates between [1280, 1720]. Before this commit, each instance of `Servo` stored their `min` and `max` values as `int8_t`. Since that only leaves room for values in the range [-128, 127], it can't store meaningful servo pulse widths, which are typically in the ~[1000, 2000]µs range. To compensate, `min` and `max` store the distance from the default values, divided by 4… There are two problems with this: - The first, mentioned above, is that you can never stray more than 512µs from `MIN_PULSE_WIDTH` and `MAX_PULSE_WIDTH`. - The second is that unexpected and unnecessary rounding occurs. Simply storing `min` and `max` as `uint16_t` and using the values directly solves this problem, and reduces the complexity involved in working around it. This commit makes the library faster, and allows it to work with a wider range of servos. It also fixes some subtle bugs where the minimum value was hardcoded to `MIN_PULSE_WIDTH`. Tested on an Arduino Uno with a [Tower Pro Micro Servo SG90](http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf), and a [Parallax Feedback 360° High-Speed Servo](https://parallax.com/sites/default/files/downloads/900-00360-Feedback-360-HS-Servo-v1.2.pdf). --- src/Servo.h | 4 ++-- src/avr/Servo.cpp | 23 +++++++++-------------- src/megaavr/Servo.cpp | 24 ++++++++++-------------- src/sam/Servo.cpp | 22 +++++++++------------- src/samd/Servo.cpp | 22 +++++++++------------- 5 files changed, 39 insertions(+), 56 deletions(-) diff --git a/src/Servo.h b/src/Servo.h index cbf2d9f..123e88e 100644 --- a/src/Servo.h +++ b/src/Servo.h @@ -113,8 +113,8 @@ class Servo bool attached(); // return true if this servo is attached, otherwise false private: uint8_t servoIndex; // index into the channel data for this servo - int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH - int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH + int16_t min; // minimum pulse width in microseconds + int16_t max; // maximum pulse width in microseconds }; #endif diff --git a/src/avr/Servo.cpp b/src/avr/Servo.cpp index 9fe3a6d..8376700 100644 --- a/src/avr/Servo.cpp +++ b/src/avr/Servo.cpp @@ -44,9 +44,6 @@ uint8_t ServoCount = 0; // the total number #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - /************ static functions common to all instances ***********************/ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA) @@ -240,9 +237,8 @@ uint8_t Servo::attach(int pin, int min, int max) if(this->servoIndex < MAX_SERVOS ) { pinMode( pin, OUTPUT) ; // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); if(isTimerActive(timer) == false) @@ -263,11 +259,11 @@ void Servo::detach() void Servo::write(int value) { - if(value < MIN_PULSE_WIDTH) + if(value < this->min) { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if(value < 0) value = 0; if(value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } this->writeMicroseconds(value); } @@ -278,10 +274,10 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if( value < SERVO_MIN() ) // ensure pulse width is valid - value = SERVO_MIN(); - else if( value > SERVO_MAX() ) - value = SERVO_MAX(); + if( value < this->min ) // ensure pulse width is valid + value = this->min; + else if( value > this->max ) + value = this->max; value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 @@ -295,7 +291,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(this->readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() @@ -315,4 +311,3 @@ bool Servo::attached() } #endif // ARDUINO_ARCH_AVR - diff --git a/src/megaavr/Servo.cpp b/src/megaavr/Servo.cpp index 7fb5e59..9928631 100644 --- a/src/megaavr/Servo.cpp +++ b/src/megaavr/Servo.cpp @@ -20,9 +20,6 @@ static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the serv #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - void ServoHandler(int timer) { if (currentServoIndex[timer] < 0) { @@ -131,9 +128,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -158,14 +154,14 @@ void Servo::detach() void Servo::write(int value) { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + if (value < this->min) { if (value < 0) value = 0; else if (value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -176,10 +172,10 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); + if (value < this->min) // ensure pulse width is valid + value = this->min; + else if (value > this->max) + value = this->max; value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead @@ -189,7 +185,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() @@ -208,4 +204,4 @@ bool Servo::attached() return servos[this->servoIndex].Pin.isActive; } -#endif \ No newline at end of file +#endif diff --git a/src/sam/Servo.cpp b/src/sam/Servo.cpp index d90ef02..62ac760 100644 --- a/src/sam/Servo.cpp +++ b/src/sam/Servo.cpp @@ -38,9 +38,6 @@ static volatile int8_t Channel[_Nbr_16timers ]; // counter for the s #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - /************ static functions common to all instances ***********************/ //------------------------------------------------------------------------------ @@ -202,9 +199,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -229,14 +225,14 @@ void Servo::detach() void Servo::write(int value) { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + if (value < this->min) { if (value < 0) value = 0; else if (value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -247,10 +243,10 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); + if (value < this->min) // ensure pulse width is valid + value = this->min; + else if (value > this->max) + value = this->max; value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead @@ -260,7 +256,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() diff --git a/src/samd/Servo.cpp b/src/samd/Servo.cpp index 946ed06..1c86e50 100644 --- a/src/samd/Servo.cpp +++ b/src/samd/Servo.cpp @@ -38,9 +38,6 @@ static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the serv #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel -#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo -#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo - #define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY); /************ static functions common to all instances ***********************/ @@ -217,9 +214,8 @@ uint8_t Servo::attach(int pin, int min, int max) if (this->servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; - // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; + this->min = min; + this->max = max; // initialize the timer if it has not already been initialized timer = SERVO_INDEX_TO_TIMER(servoIndex); if (isTimerActive(timer) == false) { @@ -244,14 +240,14 @@ void Servo::detach() void Servo::write(int value) { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) - if (value < MIN_PULSE_WIDTH) + if (value < this->min) { if (value < 0) value = 0; else if (value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); } @@ -262,10 +258,10 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < SERVO_MIN()) // ensure pulse width is valid - value = SERVO_MIN(); - else if (value > SERVO_MAX()) - value = SERVO_MAX(); + if (value < this->min) // ensure pulse width is valid + value = this->min; + else if (value > this->max) + value = this->max; value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead @@ -275,7 +271,7 @@ void Servo::writeMicroseconds(int value) int Servo::read() // return the value as degrees { - return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map(readMicroseconds()+1, this->min, this->max, 0, 180); } int Servo::readMicroseconds() From 27cd8d4221f077df484c024e89b894a7804caa6e Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Fri, 5 Apr 2019 12:53:06 -0700 Subject: [PATCH 3/4] Misc style, spelling, and formatting fixes While working on 36f25f4f3a18 and 931445b47da2, I encountered some typos, trailing whitespace, etc. I've moved the fixes into its own commit to reduce noise in the functional diffs. The only logic change here is removing some boundary checking redundancy. I removed a redundant bounds check from `write()`, since the value is `constrain`ed in `writeMicroseconds()` anyway. In `writeMicroseconds()`, I changed: ```.cpp if (value < this->min) // ensure pulse width is valid value = this->min; else if (value > this->max) value = this->max; ``` to: ```.cpp value = constrain(value, this->min, this->max); // ensure pulse width is valid ``` They are functionally equivalent. --- src/Servo.h | 43 +++++++++++++++++++-------------------- src/avr/Servo.cpp | 8 +------- src/megaavr/Servo.cpp | 11 +--------- src/nrf52/Servo.cpp | 19 ++++++++--------- src/sam/Servo.cpp | 12 +---------- src/samd/Servo.cpp | 11 +--------- src/stm32f4/ServoTimers.h | 2 +- 7 files changed, 35 insertions(+), 71 deletions(-) diff --git a/src/Servo.h b/src/Servo.h index 123e88e..6583681 100644 --- a/src/Servo.h +++ b/src/Servo.h @@ -17,17 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - A servo is activated by creating an instance of the Servo class passing +/* + A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method. - The servos are pulsed in the background using the value most recently + The servos are pulsed in the background using the value most recently written using the write() method. - Note that analogWrite of PWM on pins associated with the timer are + Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached. - Timers are seized as needed in groups of 12 servos - 24 servos use two + Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four. - The sequence used to sieze timers is defined in timers.h + The sequence used to seize timers is defined in timers.h The methods are: @@ -35,14 +35,13 @@ 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 - + 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 - read() - Gets the last written servo pulse width as an angle between 0 and 180. + writeMicroseconds() - Sets the servo pulse width in microseconds + read() - Gets the last written servo pulse width as an angle between 0 and 180. readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) - attached() - Returns true if there is a servo attached. - detach() - Stops an attached servos from pulsing its i/o pin. + attached() - Returns true if there is a servo attached. + detach() - Stops an attached servos from pulsing its i/o pin. */ #ifndef Servo_h @@ -50,8 +49,8 @@ #include -/* - * Defines for 16 bit timers used with Servo library +/* + * Defines for 16 bit timers used with Servo library * * If _useTimerX is defined then TimerX is a 16 bit timer on the current board * timer16_Sequence_t enumerates the sequence that the timers should be allocated @@ -80,9 +79,9 @@ #define MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo #define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) 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 REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds -#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer +#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer #define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER) #define INVALID_SERVO 255 // flag indicating an invalid servo index @@ -91,8 +90,8 @@ typedef struct { uint8_t nbr :6 ; // a pin number from 0 to 63 - uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false -} ServoPin_t ; + uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false +} ServoPin_t ; typedef struct { ServoPin_t Pin; @@ -104,17 +103,17 @@ class Servo public: 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, int min, int max); // as above but also sets min and max values for writes. + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. void detach(); void write(int value); // if value is < the minimum pulse width it's treated as an angle, otherwise as pulse width in microseconds void writeMicroseconds(int value); // Write pulse width in microseconds int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) - bool attached(); // return true if this servo is attached, otherwise false + bool attached(); // return true if this servo is attached, otherwise false private: uint8_t servoIndex; // index into the channel data for this servo - int16_t min; // minimum pulse width in microseconds - int16_t max; // maximum pulse width in microseconds + uint16_t min; // minimum pulse width in microseconds + uint16_t max; // maximum pulse width in microseconds }; #endif diff --git a/src/avr/Servo.cpp b/src/avr/Servo.cpp index 8376700..301cb1c 100644 --- a/src/avr/Servo.cpp +++ b/src/avr/Servo.cpp @@ -261,8 +261,6 @@ void Servo::write(int value) { if(value < this->min) { // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) - if(value < 0) value = 0; - if(value > 180) value = 180; value = map(value, 0, 180, this->min, this->max); } this->writeMicroseconds(value); @@ -274,11 +272,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if( value < this->min ) // ensure pulse width is valid - value = this->min; - else if( value > this->max ) - value = this->max; - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 diff --git a/src/megaavr/Servo.cpp b/src/megaavr/Servo.cpp index 9928631..41655fd 100644 --- a/src/megaavr/Servo.cpp +++ b/src/megaavr/Servo.cpp @@ -156,11 +156,6 @@ void Servo::write(int value) // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); @@ -172,11 +167,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < this->min) // ensure pulse width is valid - value = this->min; - else if (value > this->max) - value = this->max; - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; diff --git a/src/nrf52/Servo.cpp b/src/nrf52/Servo.cpp index a49f093..092a069 100644 --- a/src/nrf52/Servo.cpp +++ b/src/nrf52/Servo.cpp @@ -35,7 +35,7 @@ Servo::Servo() { if (ServoCount < MAX_SERVOS) { this->servoIndex = ServoCount++; // assign a servo index to this instance - } else { + } else { this->servoIndex = INVALID_SERVO; // too many servos } @@ -43,7 +43,6 @@ Servo::Servo() uint8_t Servo::attach(int pin) { - return this->attach(pin, 0, 2500); } @@ -57,11 +56,11 @@ uint8_t Servo::attach(int pin, int min, int max) if(min < servo_min) min = servo_min; if (max > servo_max) max = servo_max; - this->min = min; - this->max = max; - + this->min = min; + this->max = max; + servos[this->servoIndex].Pin.isActive = true; - + } return this->servoIndex; } @@ -73,13 +72,13 @@ void Servo::detach() void Servo::write(int value) -{ +{ if (value < 0) value = 0; else if (value > 180) value = 180; value = map(value, 0, 180, MIN_PULSE, MAX_PULSE); - + writeMicroseconds(value); } @@ -117,7 +116,7 @@ int Servo::read() // return the value as degrees } int Servo::readMicroseconds() -{ +{ uint8_t channel, instance; uint8_t pin=servos[this->servoIndex].Pin.nbr; instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16; @@ -131,4 +130,4 @@ bool Servo::attached() return servos[this->servoIndex].Pin.isActive; } -#endif // ARDUINO_ARCH_NRF52 \ No newline at end of file +#endif // ARDUINO_ARCH_NRF52 diff --git a/src/sam/Servo.cpp b/src/sam/Servo.cpp index 62ac760..0762a73 100644 --- a/src/sam/Servo.cpp +++ b/src/sam/Servo.cpp @@ -227,11 +227,6 @@ void Servo::write(int value) // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); @@ -243,11 +238,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < this->min) // ensure pulse width is valid - value = this->min; - else if (value > this->max) - value = this->max; - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; @@ -276,4 +267,3 @@ bool Servo::attached() } #endif // ARDUINO_ARCH_SAM - diff --git a/src/samd/Servo.cpp b/src/samd/Servo.cpp index 1c86e50..5e0bd23 100644 --- a/src/samd/Servo.cpp +++ b/src/samd/Servo.cpp @@ -242,11 +242,6 @@ void Servo::write(int value) // treat values less than the minimum pulse width as angles in degrees (valid values in microseconds are handled as microseconds) if (value < this->min) { - if (value < 0) - value = 0; - else if (value > 180) - value = 180; - value = map(value, 0, 180, this->min, this->max); } writeMicroseconds(value); @@ -258,11 +253,7 @@ void Servo::writeMicroseconds(int value) byte channel = this->servoIndex; if( (channel < MAX_SERVOS) ) // ensure channel is valid { - if (value < this->min) // ensure pulse width is valid - value = this->min; - else if (value > this->max) - value = this->max; - + value = constrain(value, this->min, this->max); // ensure pulse width is valid value = value - TRIM_DURATION; value = usToTicks(value); // convert to ticks after compensating for interrupt overhead servos[channel].ticks = value; diff --git a/src/stm32f4/ServoTimers.h b/src/stm32f4/ServoTimers.h index f6b0124..c2923b6 100644 --- a/src/stm32f4/ServoTimers.h +++ b/src/stm32f4/ServoTimers.h @@ -65,7 +65,7 @@ // Pin number of unattached pins #define NOT_ATTACHED (-1) -#define _Nbr_16timers 14 // mumber of STM32F469 Timers +#define _Nbr_16timers 14 // Number of STM32F469 Timers #define SERVOS_PER_TIMER 4 // Number of timer channels From 6f7fe5a0613d726950713d00a33d80f8df432624 Mon Sep 17 00:00:00 2001 From: Riley Shaw Date: Fri, 5 Apr 2019 13:01:50 -0700 Subject: [PATCH 4/4] Bump version Since 36f25f4f3a and 931445b47d make changes to this library's public API, I thought it was worth bumping to the next major version. Feel free to drop this commit if you disagree, or have a larger release planned. --- library.properties | 2 +- src/Servo.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index a7a4772..4047ffe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Servo -version=1.1.3 +version=3.0.0 author=Michael Margolis, Arduino maintainer=Arduino sentence=Allows Arduino/Genuino boards to control a variety of servo motors. diff --git a/src/Servo.h b/src/Servo.h index 6583681..5ff9601 100644 --- a/src/Servo.h +++ b/src/Servo.h @@ -74,7 +74,7 @@ #error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor." #endif -#define Servo_VERSION 2 // software version of this library +#define Servo_VERSION 3 // software version of this library #define MIN_PULSE_WIDTH 1000 // the shortest pulse (in us) sent to a servo #define MAX_PULSE_WIDTH 2000 // the longest pulse (in us) sent to a servo