├── library.properties
├── library.json
├── ESP32MotorControl.h
├── README.md
└── ESP32MotorControl.cpp
/library.properties:
--------------------------------------------------------------------------------
1 | name=ESP32MotorControl
2 | version=0.1.0
3 | author=Joao Lopes
4 | maintainer=Joao Lopes
5 | sentence=Motor control using ESP32 MCPWM
6 | paragraph=To control up 2 DC motors
7 | category=Other
8 | url=https://github.com/JoaoLopesF/ESP32MotorControl
9 | repository=https://github.com/JoaoLopesF/ESP32MotorControl.git
10 | architectures=*
11 |
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ESP32MotorControl",
3 | "keywords": "ESP32, Motor, H-bridge, MCPWM",
4 | "description": "Motor control using ESP32 MCPWM",
5 | "repository":
6 | {
7 | "type": "git",
8 | "url": "https://github.com/JoaoLopesF/ESP32MotorControl.git"
9 | },
10 | "version": "0.1.0",
11 | "frameworks": "arduino",
12 | "platforms": "*"
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/ESP32MotorControl.h:
--------------------------------------------------------------------------------
1 | /* Header for ESP32MotorControl
2 | *
3 | * Copyright (C) 2018 Joao Lopes https://github.com/JoaoLopesF/ESP32MotorControl
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, version 3.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | *
17 | * This header file describes the public API for SerialDebug.
18 | *
19 | */
20 |
21 | #ifndef ESP32MotorControl_H
22 | #define ESP32MotorControl_H
23 |
24 | #include "Arduino.h"
25 |
26 | //////// Defines
27 |
28 | #ifndef ESP32
29 | #error "this library is only for ESP32"
30 | #endif
31 |
32 | #define PWM_FREQ 1000 // PWM Frequency
33 |
34 | //////// Class
35 |
36 | class ESP32MotorControl
37 | {
38 | public:
39 |
40 | // Fields
41 |
42 | uint16_t mMotorSpeed[2] = {0, 0};
43 | boolean mMotorForward[2] = {true, true};
44 |
45 | // Methods:
46 |
47 | void attachMotor(uint8_t gpioIn1, uint8_t gpioIn2);
48 | void attachMotors(uint8_t gpioIn1, uint8_t gpioIn2, uint8_t gpioIn3, uint8_t gpioIn4);
49 |
50 | void motorFullForward(uint8_t motor);
51 | void motorForward(uint8_t motor, uint8_t speed);
52 | void motorFullReverse(uint8_t motor);
53 | void motorReverse(uint8_t motor, uint8_t speed);
54 | void motorStop(uint8_t motor);
55 |
56 | void motorsStop();
57 |
58 | void handle();
59 |
60 | uint8_t getMotorSpeed(uint8_t motor);
61 | boolean isMotorForward(uint8_t motor);
62 | boolean isMotorStopped(uint8_t motor);
63 |
64 | private:
65 |
66 | // Fields:
67 |
68 | boolean mMotorAttached[2] = {false, false};
69 |
70 | // Methods
71 |
72 | boolean isMotorValid(uint8_t motor);
73 | };
74 |
75 | #endif // ESP32MotorControl_H
76 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ESP32MotorControl
2 | Motor control using ESP32 MCPWM
3 |
4 | 
5 | 
6 |
7 | ### A library to ESP32 control motors using MCPWM
8 |
9 | #### Works only with ESP32.
10 |
11 | ## Contents
12 | - [About](#about)
13 | - [Wishlist](#wishlist)
14 | - [Using](#usage)
15 | - [Releases](#releases)
16 |
17 | ## About
18 |
19 | This library is for control motors with MCPWM of ESP32 board.
20 |
21 | [
22 | (from Espressif documentation)
23 |
24 | It is tested with [DRV8833](http://www.ti.com/lit/ds/symlink/drv8833.pdf) Dual H-Bridge Motor Driver,
25 | and can works with any controller with 4 input pinouts (AIN1, AIN2, BIN1 and BIN2) as DRV8825, A4988.
26 |
27 | Not yet working with 6 input pinouts controllers, as L298.
28 |
29 |
30 | ## Usage
31 |
32 | ###include
33 |
34 | ```cpp
35 | #include "ESP32MotorControl.h" // https://github.com/JoaoLopesF/ESP32MotorControl
36 | ```
37 | ###instance
38 | - After #include, before setup
39 | ```cpp
40 | // MotorControl instance
41 |
42 | ESP32MotorControl MotorControl = ESP32MotorControl();
43 | ```
44 | ###setup
45 |
46 | - In the setup function
47 | ```cpp
48 |
49 | // Attach 2 motors
50 |
51 | MotorControl.attachMotors(MOTOR_GPIO_IN1, MOTOR_GPIO_IN2, MOTOR_GPIO_IN3, MOTOR_GPIO_IN4);
52 |
53 | ```
54 | - To control the motors
55 |
56 | ```cpp
57 |
58 | // To stop all motors
59 |
60 | MotorControl.motorsStop();
61 |
62 | // To control the motors
63 |
64 | MotorControl.motorForward(0, speed);
65 | MotorControl.motorReverse(0, speed);
66 | MotorControl.motorForward(1, speed);
67 | MotorControl.motorReverse(1, speed);
68 |
69 | // To get info about motors
70 |
71 | speed = getMotorSpeed(0);
72 | forward = isMotorForward(0);
73 | stopped = isMotorStopped(0);
74 |
75 | ```
76 |
77 | ## Releases
78 |
79 | #### 0.1
80 | - First Beta
81 |
82 |
--------------------------------------------------------------------------------
/ESP32MotorControl.cpp:
--------------------------------------------------------------------------------
1 |
2 | /*****************************************
3 | * Library : ESP32MotorControl - Library for dual motor driver carrier for Arduino.
4 | * Programmer: Joao Lopes
5 | * Comments : This library is to use with dual motors ICs, as DRV8833, DRV8825 and L298.
6 | * And uses the MCPWM for control motors
7 | * Versions :
8 | * ------ ---------- -------------------------
9 | * 0.1.0 2018-12-26 First beta
10 | *****************************************/
11 |
12 | /*
13 | * Source for ESP32MotorControl
14 | *
15 | * Copyright (C) 2018 Joao Lopes https://github.com/JoaoLopesF/ESP32MotorControl
16 | *
17 | * This program is free software: you can redistribute it and/or modify
18 | * it under the terms of the GNU General Public License as published by
19 | * the Free Software Foundation, version 3.
20 | *
21 | * This program is distributed in the hope that it will be useful, but
22 | * WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 | * General Public License for more details.
25 | *
26 | * You should have received a copy of the GNU General Public License
27 | * along with this program. If not, see .
28 | *
29 | * This file contains the code for ESP32MotorControl library.
30 | *
31 | */
32 |
33 | /*
34 | * TODO list:
35 | * - Port to L298
36 | */
37 |
38 | /*
39 | * TODO known issues:
40 | */
41 |
42 | ////// Includes
43 |
44 | #include "Arduino.h"
45 |
46 | #include "ESP32MotorControl.h"
47 |
48 | #include
49 |
50 | #include "esp_system.h"
51 | #include "esp_attr.h"
52 |
53 | #include "driver/mcpwm.h"
54 | #include "soc/mcpwm_reg.h"
55 | #include "soc/mcpwm_struct.h"
56 |
57 | ///// Defines
58 |
59 | // debug
60 |
61 | //#define debug(fmt, ...)
62 | #define debug(fmt, ...) Serial.printf("%s: " fmt "\r\n", __func__, ##__VA_ARGS__)
63 |
64 | ///// Methods
65 |
66 | ///// Driver with 4 pins: DRV88nn, DRV8833, DRV8825, etc.
67 |
68 | // Attach one motor
69 |
70 | void ESP32MotorControl::attachMotor(uint8_t gpioIn1, uint8_t gpioIn2)
71 | {
72 | attachMotors(gpioIn1, gpioIn2, 0, 0);
73 | }
74 |
75 | // Attach two motors
76 |
77 | void ESP32MotorControl::attachMotors(uint8_t gpioIn1, uint8_t gpioIn2, uint8_t gpioIn3, uint8_t gpioIn4)
78 | {
79 | // debug
80 |
81 | debug("init MCPWM Motor 0");
82 |
83 | // Attach motor 0 input pins.
84 |
85 | // Set MCPWM unit 0
86 |
87 | mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, gpioIn1);
88 | mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, gpioIn2);
89 |
90 | // Indicate the motor 0 is attached.
91 |
92 | this->mMotorAttached[0] = true;
93 |
94 | // Attach motor 1 input pins.
95 |
96 | if (!(gpioIn3 == 0 && gpioIn4 ==0)) {
97 |
98 | debug("init MCPWM Motor 1");
99 |
100 | // Set MCPWM unit 1
101 |
102 | mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM1A, gpioIn3);
103 | mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM1B, gpioIn4);
104 |
105 | // Indicate the motor 1 is attached.
106 |
107 | this->mMotorAttached[1] = true;
108 | }
109 |
110 | // Initial MCPWM configuration
111 |
112 | debug ("Configuring Initial Parameters of MCPWM...");
113 |
114 | mcpwm_config_t pwm_config;
115 | pwm_config.frequency = 1000; //frequency,
116 | pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
117 | pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
118 | pwm_config.counter_mode = MCPWM_UP_COUNTER;
119 | pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
120 |
121 | mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
122 |
123 | mcpwm_init(MCPWM_UNIT_1, MCPWM_TIMER_1, &pwm_config); //Configure PWM1A & PWM1B with above settings
124 |
125 | debug ("MCPWM initialized");
126 | }
127 |
128 | // Motor full forward
129 |
130 | void ESP32MotorControl::motorFullForward(uint8_t motor)
131 | {
132 | if (!isMotorValid(motor)) {
133 | return;
134 | }
135 |
136 | // Full forward
137 |
138 | if (motor == 0) {
139 |
140 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
141 | mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
142 |
143 | } else {
144 |
145 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B);
146 | mcpwm_set_signal_high(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A);
147 | }
148 |
149 | mMotorSpeed[motor] = 100; // Save it
150 | mMotorForward[motor] = true;
151 |
152 | debug ("Motor %u full forward", motor);
153 | }
154 |
155 | // Motor set speed forward
156 |
157 | void ESP32MotorControl::motorForward(uint8_t motor, uint8_t speed)
158 | {
159 | if (!isMotorValid(motor)) {
160 | return;
161 | }
162 |
163 | if (speed == 100) { // Full speed
164 |
165 | motorFullForward(motor);
166 |
167 | } else {
168 |
169 | // Set speed -> PWM duty 0-100
170 |
171 | if (motor == 0) {
172 |
173 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
174 | mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, speed);
175 | mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_0); //call this each time, if operator was previously in low/high state
176 |
177 | } else {
178 |
179 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B);
180 | mcpwm_set_duty(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A, speed);
181 | mcpwm_set_duty_type(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A, MCPWM_DUTY_MODE_0); //call this each time, if operator was previously in low/high state
182 |
183 | }
184 |
185 | mMotorSpeed[motor] = speed; // Save it
186 | mMotorForward[motor] = true;
187 |
188 | debug("Motor %u forward speed %u", motor, speed);
189 | }
190 | }
191 |
192 | void ESP32MotorControl::motorFullReverse(uint8_t motor)
193 | {
194 | if (!isMotorValid(motor)) {
195 | return;
196 | }
197 |
198 | // Full forward
199 |
200 | if (motor == 0) {
201 |
202 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
203 | mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
204 |
205 | } else {
206 |
207 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A);
208 | mcpwm_set_signal_high(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B);
209 | }
210 |
211 | mMotorSpeed[motor] = 100; // Save it
212 | mMotorForward[motor] = false;
213 |
214 | debug ("Motor %u full reverse", motor);
215 | }
216 |
217 | // Motor set speed reverse
218 |
219 | void ESP32MotorControl::motorReverse(uint8_t motor, uint8_t speed)
220 | {
221 | if (!isMotorValid(motor)) {
222 | return;
223 | }
224 |
225 | if (speed == 100) { // Full speed
226 |
227 | motorFullReverse(motor);
228 |
229 | } else {
230 |
231 |
232 | // Set speed -> PWM duty 0-100
233 |
234 | if (motor == 0) {
235 |
236 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
237 | mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, speed);
238 | mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //call this each time, if operator was previously in low/high state
239 |
240 | } else {
241 |
242 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A);
243 | mcpwm_set_duty(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B, speed);
244 | mcpwm_set_duty_type(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //call this each time, if operator was previously in low/high state
245 |
246 | }
247 |
248 | mMotorSpeed[motor] = speed; // Save it
249 | mMotorForward[motor] = false;
250 |
251 | debug("Motor %u reverse speed %u", motor, speed);
252 | }
253 | }
254 |
255 |
256 | // Motor stop
257 |
258 | void ESP32MotorControl::motorStop(uint8_t motor)
259 | {
260 | if (!isMotorValid(motor)) {
261 | return;
262 | }
263 |
264 | // Motor stop
265 |
266 | if (motor == 0) {
267 |
268 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
269 | mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
270 |
271 | } else {
272 |
273 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A);
274 | mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_B);
275 |
276 | }
277 |
278 | mMotorSpeed[motor] = 0; // Save it
279 | mMotorForward[motor] = true; // For stop
280 |
281 | debug("Motor %u stop", motor);
282 | }
283 |
284 | // Motors stop
285 |
286 | void ESP32MotorControl::motorsStop()
287 | {
288 | motorStop(0);
289 | motorStop(1);
290 |
291 | debug("Motors stop");
292 | }
293 |
294 | // Get motor speed
295 |
296 | uint8_t ESP32MotorControl::getMotorSpeed(uint8_t motor) {
297 |
298 | if (!isMotorValid(motor)) {
299 | return false;
300 | }
301 | return mMotorSpeed[motor];
302 |
303 | }
304 |
305 | // Is motor in forward ?
306 |
307 | boolean ESP32MotorControl::isMotorForward(uint8_t motor) {
308 |
309 | if (!isMotorValid(motor)) {
310 | return false;
311 | }
312 |
313 | if (isMotorStopped(motor)) {
314 | return false;
315 | } else {
316 | return mMotorForward[motor];
317 | }
318 | }
319 |
320 | // Is motor stopped ?
321 |
322 | boolean ESP32MotorControl::isMotorStopped(uint8_t motor) {
323 |
324 |
325 | if (!isMotorValid(motor)) {
326 | return true;
327 | }
328 | return (mMotorSpeed[motor] == 0);
329 | }
330 |
331 | //// Privates
332 |
333 | // Is motor valid ?
334 |
335 | boolean ESP32MotorControl::isMotorValid(uint8_t motor) {
336 |
337 |
338 | if (motor > 1) {
339 | return false;
340 | }
341 |
342 | return mMotorAttached[motor];
343 | }
344 |
345 |
346 | ///// End
347 |
--------------------------------------------------------------------------------