-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMotorDriver.hpp
335 lines (279 loc) · 9.55 KB
/
MotorDriver.hpp
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
MotorDriver.hpp
Joel Goodman, 2020
@brief A set of easy to use Classes and Functions to help Arduino users control DC motors.
*/
#ifndef MOTORDRV_HPP
#define MOTORDRV_HPP
/* STL/C++ */
#include <math.h>
/* Others */
#include <Arduino.h>
struct RangeLimits
{
int minimum;
int maximum;
RangeLimits(const int _min, const int _max) :
minimum(_min),
maximum(_max)
{}
};
class MotorDriver
{
protected:
/* Arduino stuff. */
const unsigned int m_inputPin;
/* If this is true, we're taking in input from an analog source and we need to initialize
m_inputPin. */
const bool m_analogInput;
/* The scale factor will be applied to the max and min values. This is useful if you want to,
say, give your motors a speed limit but still want to use the full physical range of your
transmitter's sticks. */
float m_scaleFactor = 1.0;
RangeLimits m_controlRangeLimits;
/* These values should be determined experimentally if you are using a hobby transmitter or any
other type of controller that you bought off the shelf. */
const RangeLimits m_inputLimits;
/* You may want to set a range where the motor doesn't move to account for oversensitivity in
transmitters. */
const RangeLimits m_deadZoneLimits;
virtual void moveMotor(const int inputVal) const = 0;
public:
MotorDriver(const int inputFloor, const int inputCeiling,
const int deadZoneMin, const int deadZoneMax) :
m_inputPin(999),
m_analogInput(false),
m_controlRangeLimits(round(-255 * m_scaleFactor), round(255 * m_scaleFactor)),
m_inputLimits(inputFloor, inputCeiling),
m_deadZoneLimits(deadZoneMin, deadZoneMax)
{
const int lowerEndOfRange = round(-255 * m_scaleFactor);
const int upperEndOfRange = round( 255 * m_scaleFactor);
}
MotorDriver(const unsigned int inputPin,
const int inputFloor, const int inputCeiling,
const int deadZoneMin, const int deadZoneMax) :
m_inputPin(inputPin),
m_analogInput(true),
m_controlRangeLimits(round(-255 * m_scaleFactor), round(255 * m_scaleFactor)),
m_inputLimits(inputFloor, inputCeiling),
m_deadZoneLimits(deadZoneMin, deadZoneMax)
{}
virtual ~MotorDriver() = default;
void init()
{
/* Set input pin(s) */
pinMode(m_inputPin, INPUT);
}
void operator()() const
{
if(!m_analogInput)
return;
/* Read the input pin */
const int inputVal = pulseIn(m_inputPin, HIGH);
moveMotor(inputVal);
}
void operator()(const int inputVal) const
{
moveMotor(inputVal);
}
void setScaleFactor(const float& scaleFactor)
{
if(scaleFactor < 0.0)
m_scaleFactor = 0.0;
else if(scaleFactor > 1.0)
m_scaleFactor = 1.0;
else
m_scaleFactor = scaleFactor;
m_controlRangeLimits = RangeLimits(round(-255 * m_scaleFactor),
round(255 * m_scaleFactor));
}
};
class HBridge : public MotorDriver
{
/* Arduino stuff */
const unsigned int m_posPin;
const unsigned int m_negPin;
const unsigned int m_pwmPin;
public:
/* Use this constructor if you ARE NOT going to use a transmitter to control your motor. */
HBridge(const unsigned int posPin, const unsigned int negPin,
const unsigned int pwmPin,
const int inputFloor=-255, const int inputCeiling=255,
const int deadZoneMin=0, const int deadZoneMax=0) :
MotorDriver(inputFloor, inputCeiling, deadZoneMin, deadZoneMax),
m_posPin(posPin),
m_negPin(negPin),
m_pwmPin(pwmPin)
{
// pinMode(m_posPin, OUTPUT);
// pinMode(m_negPin, OUTPUT);
// pinMode(m_pwmPin, OUTPUT);
}
/* Use this constructor if you ARE going to use a transmitter to control your motor. */
HBridge(const unsigned int posPin, const unsigned int negPin,
const unsigned int pwmPin, const unsigned int inputPin,
const int inputFloor=-255, const int inputCeiling=255,
const int deadZoneMin=-10, const int deadZoneMax=10) :
MotorDriver(inputPin, inputFloor, inputCeiling, deadZoneMax, deadZoneMin),
m_posPin(posPin),
m_negPin(negPin),
m_pwmPin(pwmPin)
{
// pinMode(m_posPin, OUTPUT);
// pinMode(m_negPin, OUTPUT);
// pinMode(m_pwmPin, OUTPUT);
}
virtual ~HBridge() = default;
void init()
{
MotorDriver::init();
pinMode(m_posPin, OUTPUT);
pinMode(m_negPin, OUTPUT);
pinMode(m_pwmPin, OUTPUT);
}
protected:
void moveMotor(const int inputVal) const
{
const int controlVal = constrain(map(inputVal, m_inputLimits.minimum, m_inputLimits.maximum,
-255, 255),
m_controlRangeLimits.minimum,
m_controlRangeLimits.maximum);
if(controlVal < m_deadZoneLimits.minimum)
{
digitalWrite(m_posPin, LOW);
digitalWrite(m_negPin, HIGH);
analogWrite(m_pwmPin, controlVal);
}
else if(controlVal > m_deadZoneLimits.maximum)
{
digitalWrite(m_posPin, HIGH);
digitalWrite(m_negPin, LOW);
analogWrite(m_pwmPin, controlVal);
}
else
{
digitalWrite(m_posPin, LOW) ;
digitalWrite(m_negPin, HIGH) ;
analogWrite(m_pwmPin, 0) ;
}
}
};
class HBridgePair
{
HBridge& m_a;
HBridge& m_b;
public:
HBridgePair(HBridge& a, HBridge& b) :
m_a(a),
m_b(b)
{}
void operator()()
{
m_a();
m_b();
}
void operator()(const int& inputValA, const int& inputValB)
{
m_a(inputValA);
m_b(inputValB);
}
};
class HalfBridge : public MotorDriver
{
/* Arduino stuff */
const unsigned int m_enablePinA;
const unsigned int m_enablePinB;
const unsigned int m_pwmPinA;
const unsigned int m_pwmPinB;
protected:
void moveMotor(const int inputVal) const
{
const int controlVal = constrain(map(inputVal, m_inputLimits.minimum, m_inputLimits.maximum,
-255, 255),
m_controlRangeLimits.minimum,
m_controlRangeLimits.maximum);
if(controlVal < m_deadZoneLimits.minimum)
{
digitalWrite(m_enablePinA, HIGH);
digitalWrite(m_enablePinB, HIGH);
analogWrite(m_pwmPinA, 0) ;
analogWrite(m_pwmPinB, abs(controlVal)) ;
}
else if(controlVal > m_deadZoneLimits.maximum)
{
digitalWrite(m_enablePinA, HIGH);
digitalWrite(m_enablePinB, HIGH);
analogWrite(m_pwmPinA, abs(controlVal)) ;
analogWrite(m_pwmPinB, 0) ;
}
else
{
digitalWrite(m_enablePinA, LOW);
digitalWrite(m_enablePinB, LOW);
analogWrite(m_pwmPinA, 0) ;
analogWrite(m_pwmPinB, 0) ;
}
}
public:
/* Use this constructor if you ARE NOT going to use a transmitter to control your motor. */
HalfBridge(const unsigned int posPin, const unsigned int negPin,
const unsigned int pwmPinA, const unsigned int pwmPinB,
const unsigned int enablePinA, const unsigned int enablePinB,
const int inputFloor=-255, const int inputCeiling=255,
const int deadZoneMin=0, const int deadZoneMax=0) :
MotorDriver(inputFloor, inputCeiling, deadZoneMin, deadZoneMax),
m_enablePinA(enablePinA),
m_enablePinB(enablePinB),
m_pwmPinA(pwmPinA),
m_pwmPinB(pwmPinB)
{}
/* Use this constructor if you ARE going to use a transmitter to control your motor. */
HalfBridge(const unsigned int posPin, const unsigned int negPin,
const unsigned int pwmPinA, const unsigned int pwmPinB,
const unsigned int enablePinA, const unsigned int enablePinB,
const unsigned int inputPin,
const int inputFloor=-255, const int inputCeiling=255,
const int deadZoneMin=-10, const int deadZoneMax=10) :
MotorDriver(inputPin, inputFloor, inputCeiling, deadZoneMin, deadZoneMax),
m_enablePinA(enablePinA),
m_enablePinB(enablePinB),
m_pwmPinA(pwmPinA),
m_pwmPinB(pwmPinB)
{}
virtual ~HalfBridge() = default;
void init()
{
MotorDriver::init();
pinMode(m_enablePinA, OUTPUT);
pinMode(m_enablePinB, OUTPUT);
pinMode(m_pwmPinA, OUTPUT);
pinMode(m_pwmPinB, OUTPUT);
}
};
class TransmitterPot
{
const RangeLimits m_potLimits;
const unsigned int m_inputPin;
MotorDriver& m_motorDriver;
public:
TransmitterPot(const unsigned int inputPin,
MotorDriver& motorDriver,
const int minValue=0, const int maxValue=255) :
m_potLimits(minValue, maxValue),
m_inputPin(inputPin),
m_motorDriver(motorDriver)
{}
void init()
{
/* Set input pin(s) */
pinMode(m_inputPin, INPUT);
}
void operator()()
{
const int inputVal = pulseIn(m_inputPin, HIGH);
const float scaleFactor = static_cast<float>(inputVal)/static_cast<float>(m_potLimits.maximum);
m_motorDriver.setScaleFactor(scaleFactor);
}
};
#endif /* MOTORDRV_HPP */