1
+ #ifndef PrecisionServo_h
2
+ #define PrecisionServo_h
3
+
4
+ #define SERVO_SLOW_SMOOTH 0
5
+ #define SERVO_SLOW_PRECISE 1
6
+ #define SERVO_SLOW_ENDPOINT 2
7
+
8
+ #define SERVO_MEDIUM_SMOOTH 3
9
+ #define SERVO_MEDIUM_PRECISE 4
10
+ #define SERVO_MEDIUM_ENDPOINT 5
11
+
12
+ #define SERVO_FAST_SMOOTH 6
13
+ #define SERVO_FAST_PRECISE 7
14
+ #define SERVO_FAST_ENDPOINT 8
15
+
16
+ // The maximum number of degrees that we ask the servo to move at once
17
+ // higher values -> faster, less accurate movement
18
+ #define SLOW_SMOOTH_MAX_MOVEMENT 3
19
+ #define SLOW_PRECISE_MAX_MOVEMENT 10
20
+ #define SLOW_ENDPOINT_MAX_MOVEMENT 10
21
+
22
+ #define MEDIUM_SMOOTH_MAX_MOVEMENT 5
23
+ #define MEDIUM_PRECISE_MAX_MOVEMENT 12
24
+ #define MEDIUM_ENDPOINT_MAX_MOVEMENT 12
25
+
26
+ #define FAST_SMOOTH_MAX_MOVEMENT 8
27
+ #define FAST_PRECISE_MAX_MOVEMENT 15
28
+ #define FAST_ENDPOINT_MAX_MOVEMENT 15
29
+
30
+ // The number of times we send our orders to the servo when we change its
31
+ // angle by max movement. Each iteration is roughly 20ms
32
+ #define SLOW_SMOOTH_MOVEMENT_ITERATIONS 3
33
+ #define SLOW_PRECISE_MOVEMENT_ITERATIONS 2
34
+ #define SLOW_ENDPOINT_MOVEMENT_ITERATIONS 2
35
+
36
+ #define MEDIUM_SMOOTH_MOVEMENT_ITERATIONS 2
37
+ #define MEDIUM_PRECISE_MOVEMENT_ITERATIONS 1
38
+ #define MEDIUM_ENDPOINT_MOVEMENT_ITERATIONS 1
39
+
40
+ #define FAST_SMOOTH_MOVEMENT_ITERATIONS 1
41
+ #define FAST_PRECISE_MOVEMENT_ITERATIONS 1
42
+ #define FAST_ENDPOINT_MOVEMENT_ITERATIONS 1
43
+
44
+ // The extra iterations we do when changing directions (each is roughly 20ms)
45
+ // These are at our old position; by sending extra it prepares the servo
46
+ // If the new direction additional iterations and max movement is high while
47
+ // movement iterations is low, you get full-speed movement to endpoints followed
48
+ // by a pause.
49
+ #define SLOW_SMOOTH_NEW_DIR_ADD_ITERS 0
50
+ #define SLOW_PRECISE_NEW_DIR_ADD_ITERS 3
51
+ #define SLOW_ENDPOINT_NEW_DIR_ADD_ITERS 25
52
+
53
+ #define MEDIUM_SMOOTH_NEW_DIR_ADD_ITERS 0
54
+ #define MEDIUM_PRECISE_NEW_DIR_ADD_ITERS 2
55
+ #define MEDIUM_ENDPOINT_NEW_DIR_ADD_ITERS 35
56
+
57
+ #define FAST_SMOOTH_NEW_DIR_ADD_ITERS 0
58
+ #define FAST_PRECISE_NEW_DIR_ADD_ITERS 1
59
+ #define FAST_ENDPOINT_NEW_DIR_ADD_ITERS 45
60
+
61
+ // The extra iterations we do when we've been given a new target, regardless
62
+ // of if it's in a new direction.
63
+ #define SLOW_SMOOTH_NEW_TAR_ADD_ITERS 0
64
+ #define SLOW_PRECISE_NEW_TAR_ADD_ITERS 25
65
+ #define SLOW_ENDPOINT_NEW_TAR_ADD_ITERS 0
66
+
67
+ #define MEDIUM_SMOOTH_NEW_TAR_ADD_ITERS 0
68
+ #define MEDIUM_PRECISE_NEW_TAR_ADD_ITERS 35
69
+ #define MEDIUM_ENDPOINT_NEW_TAR_ADD_ITERS 0
70
+
71
+ #define FAST_SMOOTH_NEW_TAR_ADD_ITERS 0
72
+ #define FAST_PRECISE_NEW_TAR_ADD_ITERS 45
73
+ #define FAST_ENDPOINT_NEW_TAR_ADD_ITERS 0
74
+
75
+ #include <Arduino.h>
76
+ #include <inttypes.h>
77
+
78
+ /**
79
+ * Contains information about a servo that can be sent
80
+ * to the servo manager
81
+ *
82
+ * @author Timothy Moore
83
+ * @author Elizabeth Moore
84
+ */
85
+ struct PrecisionServo
86
+ {
87
+ /**
88
+ * Which pin this servo is operating on. The pin
89
+ * can be assumed to have been set to output mode
90
+ * (done manually or via servo manager setup)
91
+ */
92
+ uint8_t pin ;
93
+
94
+ /**
95
+ * The last angle that we told the servo to go to
96
+ * in degrees. Starts at 0
97
+ */
98
+ uint8_t angleDegrees ;
99
+
100
+ /**
101
+ * How many more times we should ask the servo to go to angleDegrees
102
+ * before moving on.
103
+ */
104
+ int8_t iterationsLeftOnCurrentIncrement ;
105
+
106
+ /**
107
+ * Which angle we are trying to get to on this servo.
108
+ */
109
+ uint8_t targetAngleDegrees ;
110
+
111
+ /**
112
+ * If the target has recently changed.
113
+ */
114
+ bool targetChanged ;
115
+
116
+ /**
117
+ * The sign (-1, 0, +1) for the last direction we tried to move
118
+ * the servo in. The servo often loses accuracy when changing
119
+ * direction, so if we try to change direction we add extra
120
+ * delay.
121
+ */
122
+ int8_t lastDirection ;
123
+
124
+ /**
125
+ * Set the target for the servo to the given degrees.
126
+ * @param angle the direction to go to, in degrees
127
+ */
128
+ void setTarget (uint8_t angle ) {
129
+ if (angle != targetAngleDegrees ) {
130
+ targetAngleDegrees = angle ;
131
+ targetChanged = true;
132
+ }
133
+ }
134
+
135
+ /** Configure this servo to the given settings.
136
+ *
137
+ * @details This switch might be taking a lot of memory space. It could
138
+ * perhaps be avoided using a compiler macro instead of a setSetting
139
+ * function?
140
+ *
141
+ * @param setting The setting that this servo is using.
142
+ *
143
+
144
+ * Valid Options:
145
+ * SERVO_SLOW_SMOOTH
146
+ * SERVO_SLOW_PRECISE
147
+ * SERVO_SLOW_ENDPOINT
148
+ * SERVO_MEDIUM_SMOOTH
149
+ * SERVO_MEDIUM_PRECISE
150
+ * SERVO_MEDIUM_ENDPOINT
151
+ * SERVO_FAST_SMOOTH
152
+ * SERVO_FAST_PRECISE
153
+ * SERVO_FAST_ENDPOINT
154
+ *
155
+ * SLOW/MEDIUM/FAST controls how rapidly the servo is going to the target
156
+ *
157
+ * SMOOTH - No additional pauses are used; the servo chases the target but
158
+ * often won't quite reach it. This is great for if you are trying
159
+ * to follow a sensor and the angles your asking for are inherently
160
+ * inprecise.
161
+ *
162
+ * PRECISE - The servo pauses at the *old* target whenever the target changes.
163
+ * This helps ensure it makes it exactly to the requested angles,
164
+ * assuming that you are using waitUntilFinished or sufficient delays
165
+ * between changing targets. This is ideal if you are hardcoding a
166
+ * sequence of movements and want the most consistent behavior possible.
167
+ *
168
+ * ENDPOINT - Acts very similiarly to PRECISE, except skips the pause when given
169
+ * orders that continue in the same direction (the servo is often
170
+ * less accurate when changing directions)
171
+ */
172
+ void setSetting (uint8_t setting ) {
173
+ switch (setting ) {
174
+ case SERVO_SLOW_SMOOTH :
175
+ this -> maxMovement = SLOW_SMOOTH_MAX_MOVEMENT ;
176
+ this -> movementIters = SLOW_SMOOTH_MOVEMENT_ITERATIONS ;
177
+ this -> newDirAddIters = SLOW_SMOOTH_NEW_DIR_ADD_ITERS ;
178
+ this -> newTarAddIters = SLOW_SMOOTH_NEW_TAR_ADD_ITERS ;
179
+ break ;
180
+ case SERVO_SLOW_PRECISE :
181
+ this -> maxMovement = SLOW_PRECISE_MAX_MOVEMENT ;
182
+ this -> movementIters = SLOW_PRECISE_MOVEMENT_ITERATIONS ;
183
+ this -> newDirAddIters = SLOW_PRECISE_NEW_DIR_ADD_ITERS ;
184
+ this -> newTarAddIters = SLOW_PRECISE_NEW_TAR_ADD_ITERS ;
185
+ break ;
186
+ case SERVO_SLOW_ENDPOINT :
187
+ this -> maxMovement = SLOW_ENDPOINT_MAX_MOVEMENT ;
188
+ this -> movementIters = SLOW_ENDPOINT_MOVEMENT_ITERATIONS ;
189
+ this -> newDirAddIters = SLOW_ENDPOINT_NEW_DIR_ADD_ITERS ;
190
+ this -> newTarAddIters = SLOW_ENDPOINT_NEW_TAR_ADD_ITERS ;
191
+ break ;
192
+ case SERVO_MEDIUM_SMOOTH :
193
+ this -> maxMovement = MEDIUM_SMOOTH_MAX_MOVEMENT ;
194
+ this -> movementIters = MEDIUM_SMOOTH_MOVEMENT_ITERATIONS ;
195
+ this -> newDirAddIters = MEDIUM_SMOOTH_NEW_DIR_ADD_ITERS ;
196
+ this -> newTarAddIters = MEDIUM_SMOOTH_NEW_TAR_ADD_ITERS ;
197
+ break ;
198
+ case SERVO_MEDIUM_PRECISE :
199
+ this -> maxMovement = MEDIUM_PRECISE_MAX_MOVEMENT ;
200
+ this -> movementIters = MEDIUM_PRECISE_MOVEMENT_ITERATIONS ;
201
+ this -> newDirAddIters = MEDIUM_PRECISE_NEW_DIR_ADD_ITERS ;
202
+ this -> newTarAddIters = MEDIUM_PRECISE_NEW_TAR_ADD_ITERS ;
203
+ break ;
204
+ case SERVO_MEDIUM_ENDPOINT :
205
+ this -> maxMovement = MEDIUM_ENDPOINT_MAX_MOVEMENT ;
206
+ this -> movementIters = MEDIUM_ENDPOINT_MOVEMENT_ITERATIONS ;
207
+ this -> newDirAddIters = MEDIUM_ENDPOINT_NEW_DIR_ADD_ITERS ;
208
+ this -> newTarAddIters = MEDIUM_ENDPOINT_NEW_TAR_ADD_ITERS ;
209
+ break ;
210
+ case SERVO_FAST_SMOOTH :
211
+ this -> maxMovement = FAST_SMOOTH_MAX_MOVEMENT ;
212
+ this -> movementIters = FAST_SMOOTH_MOVEMENT_ITERATIONS ;
213
+ this -> newDirAddIters = FAST_SMOOTH_NEW_DIR_ADD_ITERS ;
214
+ this -> newTarAddIters = FAST_SMOOTH_NEW_TAR_ADD_ITERS ;
215
+ break ;
216
+ case SERVO_FAST_PRECISE :
217
+ this -> maxMovement = FAST_PRECISE_MAX_MOVEMENT ;
218
+ this -> movementIters = FAST_PRECISE_MOVEMENT_ITERATIONS ;
219
+ this -> newDirAddIters = FAST_PRECISE_NEW_DIR_ADD_ITERS ;
220
+ this -> newTarAddIters = FAST_PRECISE_NEW_TAR_ADD_ITERS ;
221
+ break ;
222
+ case SERVO_FAST_ENDPOINT :
223
+ this -> maxMovement = FAST_ENDPOINT_MAX_MOVEMENT ;
224
+ this -> movementIters = FAST_ENDPOINT_MOVEMENT_ITERATIONS ;
225
+ this -> newDirAddIters = FAST_ENDPOINT_NEW_DIR_ADD_ITERS ;
226
+ this -> newTarAddIters = FAST_ENDPOINT_NEW_TAR_ADD_ITERS ;
227
+ break ;
228
+ }
229
+ }
230
+
231
+ // servo settings; see defines at the top. Only change
232
+ // these directly if none of the presets are satisfactory.
233
+ uint8_t maxMovement ;
234
+ uint8_t movementIters ;
235
+ uint8_t newDirAddIters ;
236
+ uint8_t newTarAddIters ;
237
+ };
238
+ #endif
0 commit comments