@@ -53,6 +53,21 @@ static uint8_t s_servoCount = 0; // the total number of attached s_se
53
53
#define SERVO_INDEX_TO_TIMER (servoIndex ) ((ServoTimerSequence)(servoIndex / SERVOS_PER_TIMER)) // returns the timer controlling this servo
54
54
#define SERVO_INDEX (timerId, channel ) ((timerId * SERVOS_PER_TIMER) + channel) // macro to access servo index by timer and channel
55
55
56
+ // similiar to map but will have increased accuracy that provides a more
57
+ // symetric api (call it and use result to reverse will provide the original value)
58
+ //
59
+ int improved_map (int value, int minIn, int maxIn, int minOut, int maxOut)
60
+ {
61
+ const int rangeIn = maxIn - minIn;
62
+ const int rangeOut = maxOut - minOut;
63
+ const int deltaIn = value - minIn;
64
+ // fixed point math constants to improve accurancy of divide and rounding
65
+ const int fixedHalfDecimal = 1 ;
66
+ const int fixedDecimal = fixedHalfDecimal * 2 ;
67
+
68
+ return ((deltaIn * rangeOut * fixedDecimal) / (rangeIn) + fixedHalfDecimal) / fixedDecimal + minOut;
69
+ }
70
+
56
71
// ------------------------------------------------------------------------------
57
72
// Interrupt handler template method that takes a class that implements
58
73
// a standard set of methods for the timer abstraction
@@ -218,8 +233,10 @@ void Servo::write(int value)
218
233
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
219
234
if (value < MIN_PULSE_WIDTH) {
220
235
// assumed to be 0-180 degrees servo
221
- value = max (0 , min (180 , value));
222
- value = map (value, 0 , 180 , _minUs, _maxUs);
236
+ value = constrain (value, 0 , 180 );
237
+ // writeMicroseconds will contrain the calculated value for us
238
+ // for any user defined min and max, but we must use default min max
239
+ value = improved_map (value, 0 , 180 , MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
223
240
}
224
241
writeMicroseconds (value);
225
242
}
@@ -229,15 +246,17 @@ void Servo::writeMicroseconds(int value)
229
246
// ensure channel is valid
230
247
if ((_servoIndex < MAX_SERVOS)) {
231
248
// ensure pulse width is valid
232
- value = max (_minUs, min (_maxUs, value) );
249
+ value = constrain (value, _minUs, _maxUs );
233
250
234
251
s_servos[_servoIndex].usPulse = value;
235
252
}
236
253
}
237
254
238
255
int Servo::read () // return the value as degrees
239
256
{
240
- return map (readMicroseconds (), _minUs, _maxUs, 0 , 180 );
257
+ // read returns the angle for an assumed 0-180, so we calculate using
258
+ // the normal min/max constants and not user defined ones
259
+ return improved_map (readMicroseconds (), MIN_PULSE_WIDTH, MAX_PULSE_WIDTH, 0 , 180 );
241
260
}
242
261
243
262
int Servo::readMicroseconds ()
0 commit comments