DC Motors
A Direct-Current (DC) motor is one of the more common electric motors available for prototyping. Brushed DC motors are great for rotating things. You can convert rotational movement into lateral movement through the use of linkages, cams or articulated joints. The motor in your basic kit is an example of a brushed motor.
Some DC motors also have reduction gears to slow the output shaft (and also provide more torque). In either case, it’s important to note that if you want to use more powerful motors (> 5V), the higher voltage power source (either another battery pack, or a wall-wart transformer) must NEVER be connected to your microcontroller (which will ABSOLUTELY DESTROY it).
Here we combine the basic potentiometer again with the DFRobot TB6612FNG DC Motor Controller to drive a brushed DC motor’s speed. Turning the potentiometer knob increases and decreases the speed of the DC motor. Try replacing the potentiometer with another sensor, along with the right integration of code from the other sensing recipes!
Too slow… & whining?
You might notice that when the potentiometer is set a little bit too ‘low’, the DC motor’s output shaft will refuse to turn, instead emitting a high-pitched ‘whining’ noise. This is normal – it’s when the electrical energy is insufficient to break the starting rotational friction of the motor.
Caveats – Speed, Torque & Power Requirements
DC motors are convenient devices that provide rotational movement. Most DC motors however have an extremely high rotational speed (typically thousands of revolutions per minute (RPM)), and the smaller motors also tend to have very low torque when they are spinning at top speed. For example, it is relatively easy to stop the soft rubber blades of a small portable fan with our arm.
There are larger, more powerful DC motors but they also draw a lot more current. The TB6612FNG motor controller can only deliver up to 1.2A of current, which isn’t a lot when it comes to larger DC motors that require upwards of 3-5A.
Long story short? DC motors can spin fast, but aren’t powerful, unless you add reduction gears to gain more torque at the expense of speed. Be aware of power supply requirements when using larger DC motors. Refer to the Power article to build a better background and usage tips.
Trivia
How does this compare to the servo and the stepper motor?
Wiring & Code
For a refresher on how to use the code in this recipe, click here.
For this recipe, we will use a potentiometer to adjust the speed of a single DC motor.
-
Breadboard diagram
Download DC Motors Fritzing file
Libraries Used
Code
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
#include "Ticker.h" // how long (ms) between each sensor update? feel free to // change this value from 5 to 5000; use 10 as a start #define INTERVAL_BETWEEN_SENSE 10 #define MOTOR_SPD_PIN 11 // connects to PWM1 #define MOTOR_DIR_PIN 8 // connects to DIR1 #define BTN_PIN 7 // pushbutton to the Arduino to set the direction // initialise the Ticker void doDataUpdate(); Ticker dataUpdateTimer(doDataUpdate, INTERVAL_BETWEEN_SENSE); // track direction of rotation bool isCW = true; // code in this setup function runs just once, when Photon is powered up or reset void setup() { Serial.begin(115200); // Open a connection via the Serial port – useful for debugging delay(5000); // Common practice to allow board to 'settle' after connecting online pinMode(MOTOR_SPD_PIN, OUTPUT); pinMode(MOTOR_DIR_PIN, OUTPUT); // we're also connecting a pushbotton to set CW/CCW direction control pinMode(BTN_PIN, INPUT_PULLUP); dataUpdateTimer.start(); // start our dataUpdateTimer } // code in this loop function runs forever, until you cut power! void loop() { updateButtonStates(); dataUpdateTimer.update(); // keep updating the Ticker } void updateButtonStates() { // read the states of the buttons, and write them to the DRV8871's IN1/IN2 pins // this is updated as quickly as possible to maintain good interface response bool btnState = digitalRead(BTN_PIN); if(btnState==LOW) { isCW = true; } else { isCW = false; } // motor will be instructed to respond in the doDataUpdate function below } // doDataUpdate runs every interval as set by INTERVAL_BETWEEN_SENSE void doDataUpdate() { int A0State = analogRead(A0); // read potentiometer sensor range (0-1023) from A0 // here we want the potentiometer to drive the 'speed' of the motor. // effectively, we want to scale the sensed range to a usable range of 0-255 int scaled = map(A0State, 0, 1023, 0, 255); // tweak these numbers accordingly! scaled = constrain(scaled, 0, 255); // make sure scaled ranged is within 0-255 // finally, write out the direction states to the motor driver, // and use analogWrite to drive the overall speed: if(isCW) { digitalWrite(MOTOR_DIR_PIN, HIGH); } else { digitalWrite(MOTOR_DIR_PIN, LOW); } analogWrite(MOTOR_SPD_PIN, scaled); // form a human-readable output for viewing via the Serial port String output = "raw:" + String(A0State) + ",scaled:" + String(scaled); // prints this out the Serial port for us humans to verify Serial.println(output); } /* Please note that the code provided here is licensed under the MIT license. The MIT License (MIT) Copyright © 2024 Chuan Khoo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-
Breadboard diagram
[wiring diagram coming soon]
Download DC Motors Fritzing file
Libraries Used
- none
Code
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
// how long (ms) between each sensor update? feel free to // change this value from 5 to 5000; use 10 as a start #define INTERVAL_BETWEEN_SENSE 10 #define MOTOR_SPD_PIN D0 // connects to PWM1 #define MOTOR_DIR_PIN D1 // connects to DIR1 #define BTN_PIN D2 // pushbutton to the Arduino to set the direction // initialise the timer Timer dataUpdateTimer(INTERVAL_BETWEEN_SENSE, doDataUpdate); // track direction of rotation bool isCW = true; // code in this setup function runs just once, when Photon is powered up or reset void setup() { Serial.begin(115200); // Open a connection via the Serial port – useful for debugging delay(5000); // Common practice to allow board to 'settle' after connecting online pinMode(MOTOR_SPD_PIN, OUTPUT); pinMode(MOTOR_DIR_PIN, OUTPUT); // we're also connecting a pushbotton to set CW/CCW direction control pinMode(BTN_PIN, INPUT_PULLDOWN); dataUpdateTimer.start(); // start our dataUpdateTimer } // code in this loop function runs forever, until you cut power! void loop() { updateButtonStates(); } void updateButtonStates() { // read the states of the buttons, and write them to the DRV8871's IN1/IN2 pins // this is updated as quickly as possible to maintain good interface response bool btnState = digitalRead(BTN_PIN); if(btnState==HIGH) { isCW = true; } else { isCW = false; } // motor will be instructed to respond in the doDataUpdate function below } // doDataUpdate runs every interval as set by INTERVAL_BETWEEN_SENSE void doDataUpdate() { int A0State = analogRead(A0); // read ambient light sensor range (0-4095) from A0 // here we want the light sensor to drive the 'speed' of the motor. // we want to scale the sensed range to a usable range of 0-255 int scaled = map(A0State, 0, 4095, 0, 255); // tweak these numbers accordingly! scaled = constrain(scaled, 0, 255); // make sure scaled ranged is within 0-255 // finally, write out the direction states to the motor driver, // and use analogWrite to drive the overall speed: if(isCW) { digitalWrite(MOTOR_DIR_PIN, HIGH); } else { digitalWrite(MOTOR_DIR_PIN, LOW); } analogWrite(MOTOR_SPD_PIN, scaled); // form a human-readable output for viewing via the Serial port String output = "raw:" + String(A0State) + ",scaled:" + String(scaled); // prints this out the Serial port for us humans to verify Serial.println(output); } /* Please note that the code provided here is licensed under the MIT license. The MIT License (MIT) Copyright © 2024 Chuan Khoo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */