@@ -56,6 +56,21 @@ static uint8_t s_servoCount = 0; // the total number of attached s_se
56
56
#define SERVO_INDEX_TO_TIMER (servoIndex ) ((ServoTimerSequence)(servoIndex / SERVOS_PER_TIMER)) // returns the timer controlling this servo
57
57
#define SERVO_INDEX (timerId, channel ) ((timerId * SERVOS_PER_TIMER) + channel) // macro to access servo index by timer and channel
58
58
59
+ // similiar to map but will have increased accuracy that provides a more
60
+ // symetric api (call it and use result to reverse will provide the original value)
61
+ //
62
+ int improved_map (int value, int minIn, int maxIn, int minOut, int maxOut)
63
+ {
64
+ const int rangeIn = maxIn - minIn;
65
+ const int rangeOut = maxOut - minOut;
66
+ const int deltaIn = value - minIn;
67
+ // fixed point math constants to improve accurancy of divide and rounding
68
+ const int fixedHalfDecimal = 1 ;
69
+ const int fixedDecimal = fixedHalfDecimal * 2 ;
70
+
71
+ return ((deltaIn * rangeOut * fixedDecimal) / (rangeIn) + fixedHalfDecimal) / fixedDecimal + minOut;
72
+ }
73
+
59
74
// ------------------------------------------------------------------------------
60
75
// Interrupt handler template method that takes a class that implements
61
76
// a standard set of methods for the timer abstraction
@@ -246,8 +261,10 @@ void Servo::write(int value)
246
261
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
247
262
if (value < MIN_PULSE_WIDTH) {
248
263
// assumed to be 0-180 degrees servo
249
- value = max (0 , min (180 , value));
250
- value = map (value, 0 , 180 , _minUs, _maxUs);
264
+ value = constrain (value, 0 , 180 );
265
+ // writeMicroseconds will contrain the calculated value for us
266
+ // for any user defined min and max, but we must use default min max
267
+ value = improved_map (value, 0 , 180 , MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
251
268
}
252
269
writeMicroseconds (value);
253
270
}
@@ -257,15 +274,17 @@ void Servo::writeMicroseconds(int value)
257
274
// ensure channel is valid
258
275
if ((_servoIndex < MAX_SERVOS)) {
259
276
// ensure pulse width is valid
260
- value = max (_minUs, min (_maxUs, value) );
277
+ value = constrain (value, _minUs, _maxUs );
261
278
262
279
s_servos[_servoIndex].usPulse = value;
263
280
}
264
281
}
265
282
266
283
int Servo::read () // return the value as degrees
267
284
{
268
- return map (readMicroseconds (), _minUs, _maxUs, 0 , 180 );
285
+ // read returns the angle for an assumed 0-180, so we calculate using
286
+ // the normal min/max constants and not user defined ones
287
+ return improved_map (readMicroseconds (), MIN_PULSE_WIDTH, MAX_PULSE_WIDTH, 0 , 180 );
269
288
}
270
289
271
290
int Servo::readMicroseconds ()
0 commit comments