-
Notifications
You must be signed in to change notification settings - Fork 266
/
Copy pathServo.cpp
139 lines (114 loc) · 3.37 KB
/
Servo.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#if defined(ARDUINO_ARCH_MBED)
#include <Arduino.h>
#include <Servo.h>
#include <mbed.h>
#if defined __has_include
# if __has_include ("pinDefinitions.h")
# include "pinDefinitions.h"
# endif
#endif
class ServoImpl {
mbed::DigitalOut *pin;
mbed::Timeout timeout; // calls a callback once when a timeout expires
mbed::Ticker ticker; // calls a callback repeatedly with a timeout
public:
ServoImpl(PinName _pin) {
pin = new mbed::DigitalOut(_pin);
}
~ServoImpl() {
ticker.detach();
timeout.detach();
delete pin;
}
void start(uint32_t duration_us) {
duration = duration_us;
ticker.attach(mbed::callback(this, &ServoImpl::call), 0.02f);
}
void call() {
timeout.attach(mbed::callback(this, &ServoImpl::toggle), duration / 1e6);
toggle();
}
void toggle() {
*pin = !*pin;
}
int32_t duration = -1;
};
static ServoImpl* servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min) // minimum value in us for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max) // maximum value in us for this servo
#define TRIM_DURATION 15 //callback overhead (35 us) -> 15 us if toggle() is called after starting the timeout
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++;
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex] = new ServoImpl(digitalPinToPinName(pin));
this->min = (MIN_PULSE_WIDTH - min);
this->max = (MAX_PULSE_WIDTH - max);
return this->servoIndex;
}
void Servo::detach()
{
delete servos[this->servoIndex];
servos[this->servoIndex] = NULL;
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
if (!servos[this->servoIndex]) {
return;
}
// calculate and store the values for the given channel
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();
value = value - TRIM_DURATION;
if (servos[this->servoIndex]->duration == -1) {
servos[this->servoIndex]->start(value);
}
servos[this->servoIndex]->duration = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds(), SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
if (!servos[this->servoIndex]) {
return 0;
}
return servos[this->servoIndex]->duration + TRIM_DURATION;
}
bool Servo::attached()
{
return servos[this->servoIndex] != NULL;
}
#endif