-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMotors.ino
283 lines (246 loc) · 10.1 KB
/
Motors.ino
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
/**
* @mainpage Arduino Motors Project
*
* @section description_main Description
* An Arduino sketch that interfaces with an Adafruit DRV8833 DC/Stepper Motor
* Driver Breakout Board to drive two small DC motors.
*
* @section circuit_main Circuit
* - An Adafruit DRV8833 DC/Stepper Motor Driver Breakout Board is connected
* as shown below.
* - SLP pin is connected to pin D2.
* - FLT pin is connected to pin D3.
* - AIN1 pin is connected to pin D5.
* - AIN2 pin is connected to pin D6.
* - BIN1 pin is connected to pin D9.
* - BIN2 pin is connected to pin D10.
* - AOUT1 pin is connected to motor A positive pin.
* - AOUT2 pin is connected to motor A negative pin.
* - BOUT1 pin is connected to motor B positive pin.
* - BOUT2 pin is connected to motor B negative pin.
* - VMOTOR+ pin is connected to a 6-9 volt power supply.
* - A 10K potentiometer is connected to pin A0.
*
* @section notes_main Notes
* - Use the Serial Monitor to view output while in DEBUG mode.
*
* Copyright (c) 2022 Woolsey Workshop. All rights reserved.
*/
/**
* @file Motors.ino
*
* @brief The primary Arduino sketch implementation file.
*
* @section description_motors_ino Description
* The primary Arduino sketch implementation file.
*
* @section libraries_motors_ino Libraries
* - Motor Class (local)
* - Provides a generic simple interface for controlling a DC motor.
*
* @section notes_motors_ino Notes
* - Comments are Doxygen compatible.
*
* @section todo_motors_ino TODO
* - None.
*
* @section author_motors_ino Author(s)
* - Created by John Woolsey on 08-01-2021.
* - Modified by John Woolsey on 06-28-2022.
*
* Copyright (c) 2022 Woolsey Workshop. All rights reserved.
*/
// Includes
#include "Motor.h"
// Defines
#define DEBUG 1 ///< The mode of operation; 0 = normal, 1 = debug.
#define OP_DURATION 5000 ///< The operation duration in milliseconds.
// Pin Mapping
const uint8_t DRV8833_SLP = 2; ///< The pin connected to the SLP (sleep) pin of the DRV8833 motor driver board.
const uint8_t DRV8833_FLT = 3; ///< The pin connected to the FLT (fault) pin of the DRV8833 motor driver board.
const uint8_t DRV8833_AIN1 = 5; ///< The pin connected to the AIN1 (motor A control 1) pin of the DRV8833 motor driver board.
const uint8_t DRV8833_AIN2 = 6; ///< The pin connected to the AIN2 (motor A control 2) pin of the DRV8833 motor driver board.
const uint8_t DRV8833_BIN1 = 9; ///< The pin connected to the BIN1 (motor B control 1) pin of the DRV8833 motor driver board.
const uint8_t DRV8833_BIN2 = 10; ///< The pin connected to the BIN2 (motor B control 2) pin of the DRV8833 motor driver board.
const uint8_t Pot = A0; ///< The pin connected to the 10 KΩ potentiometer.
// Global Variables
volatile bool motorDriverFaultDetected = false; ///< The fault detected status of the motor driver. The 'volatile' specifier is used since its value can be changed from within an interrupt service routine.
volatile bool motorDriverFaultCleared = false; ///< The fault cleared status of the motor driver. The 'volatile' specifier is used since its value can be changed from within an interrupt service routine.
// Global Instances
Motor motorA = Motor(DRV8833_AIN1, DRV8833_AIN2); ///< The instance of motor A. Uses default arguments of command = Coast, speed = 0, name = "Unknown"
Motor motorB = Motor(DRV8833_BIN1, DRV8833_BIN2, Coast, 0, "B"); ///< The instance of motor B. All arguments are specified.
/**
* Standard Arduino setup function used for setup and configuration tasks.
*/
void setup() {
// Serial Monitor
if (DEBUG) {
Serial.begin(9600); // initialize serial bus
while (!Serial); // wait for serial connection
Serial.println(F("Running in DEBUG mode. Turn off for normal operation."));
}
// Pin configurations
pinMode(DRV8833_SLP, OUTPUT);
pinMode(DRV8833_FLT, INPUT_PULLUP); // utilize microprocessor's internal pull-up resistor
// Initialize interrupt service routine
// Calls motorDriverFaultPinChanged() if change detected on DRV8833_FLT pin
attachInterrupt(digitalPinToInterrupt(DRV8833_FLT), motorDriverFaultPinChanged, CHANGE);
// Enable (turn on) motor driver
digitalWrite(DRV8833_SLP, HIGH);
}
/**
* Standard Arduino loop function used for repeating tasks.
*/
void loop() {
checkForMotorDriverFault();
basicOperations(); // perform basic motor control operations on motor A
// rampingSpeed(); // ramp up and down the speed of motor A
// potentiometerControl(); // control motor B speed with a potentiometer
}
/**
* Demonstrates the basic operations available with the Motor class.
*/
void basicOperations() {
// Basic operations with default attributes
motorA.drive(); // drive forward at full throttle
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.stop(); // coast (soft) to a stop
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
// Basic operations with specific attributes
motorA.drive(Forward, 75); // drive forward at 75% throttle
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.stop(Coast); // coast (soft) to a stop
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.drive(Reverse, 50); // drive in reverse at 50% throttle
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.stop(Brake); // brake (hard) to a stop
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
// Setting attributes
motorA.setName("A"); // change name of motor to A
if (DEBUG) printMotorStatus(motorA);
motorA.setCommand(Forward); // drive forward at previously set speed
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.setSpeed(75); // set speed to 75% throttle with previously set command
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.setSpeed(0); // set speed to 0% throttle with previously set command
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.setCommand(Reverse); // drive in reverse with previously set speed
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.setSpeed(75); // set speed to 75% throttle with previously set command
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
motorA.setCommand(Coast); // coast (soft) to a stop
if (DEBUG) printMotorStatus(motorA);
delay(OP_DURATION);
// Getting attributes
// The command(), name(), and speed() methods retrieve the motor instance's
// current command, name, and speed values respectively and are utilized
// within the printMotorStatus() function used above.
}
/**
* Checks and reports the fault status of the motor driver.
*/
void checkForMotorDriverFault() {
if (motorDriverFaultDetected) {
if (DEBUG) Serial.println(F("Motor driver fault detected."));
motorDriverFaultDetected = false; // reset detected flag
}
if (motorDriverFaultCleared) {
if (DEBUG) Serial.println(F("Motor driver fault cleared."));
motorDriverFaultCleared = false; // reset cleared flag
}
}
/**
* Sets the motorDriverFaultDetected and motorDriverFaultCleared flags when a
* change in the motor driver's FLT pin is detected.
*
* Invoked as an interrupt service routine (ISR), if enabled.
*/
void motorDriverFaultPinChanged() {
if (digitalRead(DRV8833_FLT) == LOW) motorDriverFaultDetected = true;
else motorDriverFaultCleared = true;
}
/**
* Sets the speed of motor B relative to the value retrieved from the
* potentiometer.
*/
void potentiometerControl() {
static int previousReading = 0;
int currentReading = analogRead(Pot);
if (abs(currentReading - previousReading) > 10) { // minimize unnecessary updates
if (DEBUG) {
Serial.print(F("Potentiometer reading: "));
Serial.println(currentReading);
}
motorB.drive(Forward, map(currentReading, 0, 1023, 0, 100)); // maps ADC reading range to percentage range before driving
if (DEBUG) printMotorStatus(motorB);
previousReading = currentReading;
}
}
/**
* Prints the status of the motor to the Serial Monitor.
*
* @param motor The motor instance.
*/
void printMotorStatus(Motor motor) {
const char* const command_states[] = {"Forward", "Reverse", "Brake", "Coast"}; // constant array of constant strings
Serial.print(F("Motor "));
Serial.print(motor.name());
Serial.print(F(": Command = "));
Serial.print(command_states[motor.command()]);
Serial.print(F(", Speed = "));
Serial.println(motor.speed());
}
/**
* Ramps up and down the speed of motor A.
*/
void rampingSpeed() {
rampUp(motorA, Forward, OP_DURATION); // ramp up forward speed for OP_DURATION ms
rampDown(motorA, Forward, OP_DURATION); // ramp down forward speed for OP_DURATION ms
}
/**
* Ramps down the speed of a motor from 100% to 0% throttle over a specified
* time period.
*
* @param motor The motor instance.
* @param command The motor's drive command (Forward or Reverse).
* @param duration The length of time, in milliseconds, to ramp down the speed
* of the motor.
*/
void rampDown(Motor motor, MotorCommand command, unsigned long duration) {
if (command == Forward || command == Reverse) {
motor.setCommand(command);
for (int8_t speed = 100; speed >= 0; speed--) { // signed integer used to avoid rollover issues
motor.setSpeed(speed);
delay(duration/100);
}
}
}
/**
* Ramps up the speed of a motor from 0% to 100% throttle over a specified
* time period.
*
* @param motor The motor instance.
* @param command The motor's drive command (Forward or Reverse).
* @param duration The length of time, in milliseconds, to ramp up the speed of
* the motor.
*/
void rampUp(Motor motor, MotorCommand command, unsigned long duration) {
if (command == Forward || command == Reverse) {
motor.setCommand(command);
for (uint8_t speed = 0; speed <= 100; speed++) {
motor.setSpeed(speed);
delay(duration/100);
}
}
}