├── 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 | ![build badge](https://img.shields.io/badge/version-v0.1.0-blue.svg) 5 | ![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg) 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 | [![image](https://docs.espressif.com/projects/esp-idf/en/latest/_images/mcpwm-brushed-dc-control.png) 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 | --------------------------------------------------------------------------------