Transistor-based DC Motor Control
The best way to work with the DC motors is to use a specialized Motor Shield.
At first - we did not have it. But still, we were desperately eager to try our new chassis in action.
We were lucky - while building our starting kit, we took a couple of NPN transistors 2N2222A. Here and here we found a nice and short explanation how to use a transistor to control high currents of the DC motors without the risk to damage the Arduino board.
The higher voltage (current) you apply to the transistor's base, the more current will be allowed to run through the motor. The trick is in the fact that the current from the Arduino can be way smaller, comparing to the current running through the motor. Thus you can throw high currents at the motors by operating the currents which are small and safe for Arduino.
This scheme is not ideal - it wastes too much energy since still requires relatively high currents to be sent to the transistor base. Also, it does not allow going reverse. For the sake of simplicity, we even removed the protective diode - the resistance of the reducer and trucks leaves no possibility for the motor to generate parasitic currents when the robot is slowing down.
We mounted such circuit for two DC motors on a breadboard and connected the controlling wires to the pins #9 and #10 on Arduino. If you'd like to have variable speed - make sure you are using PWM pins.
It is still hard for us remembering all these "collectors" and "emitters" stuff - maybe you have the same problem. Don't worry. If the circuit does not work and motor does not start - just turn the transistor around. The only thing you should remember - the middle pin is the "base", a wire from Arduino should be connected here.
The simplicity of the robot assumes also easiness of the programming :-)
Since our motors are connected to the pins #9 and #10 of Arduino, the only thing you need to do is just set the high-level voltage (5 V) at these pins, and the robot will go. Of course, if you did not miss anything in the connections.
Those who passed the beginners ramp-up courses can easily read and understand the corresponding program:
// store the motors controlling pins int rightMotorPin = 9; int leftMotorPin = 10; void setup() { // switch the ports to the output mode pinMode(rightMotorPin, OUTPUT); pinMode(leftMotorPin, OUTPUT); // turn on both motors digitalWrite(rightMotorPin, HIGH); digitalWrite(leftMotorPin, HIGH); // move forward for 6 seconds delay(6000); // stop the right motor - the robot will start turning right digitalWrite(rightMotorPin, LOW); // turning for 6 seconds delay(6000); // start again the right motor digitalWrite(rightMotorPin, HIGH); // move forward for 6 seconds delay(6000); // stop the left motor - the robot will start turning left digitalWrite(leftMotorPin, LOW); // turning left for 6 seconds delay(6000); // stop the robot completely so you can catch it up digitalWrite(rightMotorPin, LOW); } void loop(){ }
You can find a complete functioning firmware under the version 1.1 branch: https://github.com/rmaryan/ardurobot/tree/ardurobot-1.1
And here is the moment of truth
IT'S ALIVE!!!
Motor Shield Selection
While choosing a Motor Shield for our robot we made a mistake. At a first glance everything was quite simple - just get anything reasonably-priced and the motors will run. But afterward, we discovered that applying more intelligence could be really helpful here.
We purchased the cheapest v. 1.x Motor Shield version: Motor Drive Shield L293D For Arduino Duemilanove Mega UNO
This module does what it was expected to do, but not more. You can install it as a shield on top of the Arduino board (UNO or MEGA). It can control up to 4 DC motors plus two servos. Unfortunately - this module covers all the sockets of the Arduino board and has no possibility to connect anything even to those pins which are not used. The only way to connect any extra module is to solder wires right to the contact points on the top of the shield.
The much wiser choice could be a stand-alone small board, placed separately, next to the Arduino and connected to it by wires. Like this one: L293D Motor Drive Expansion Shield Dual H-Bridge For Arduino.
This module can control only two motors but this is pretty enough for our case.
"Deluxe" version of the shield we use is 2 Channel Motor + 16 Channel Servo Expansion Board For Arduino.
It is based on the same L293D motor driver chip and can control 2 DC motors and 16 servos. What is interesting - commands for the servos are sent using I2C protocol. So using just 2 Arduino pins you can get 16 fully functional PWM output ports. Also, these two I2C pins are not lost - many other devices can be connected to them simultaneously. This shield is ideal for the use with the robotized arms and other manipulators of this kind.
And finally - the most up to date and modern Motor Shield (version 2.x): DC Stepper Motor Shield V2 TB6612FNG PWN Drive Module For Arduino.
Most probably this is a clone of the Adafruit Motor/Stepper/Servo Shield for Arduino v2. If so - that shield would be the best choice for our case.
- Stacking headers allow installing more shields on top.
- All shield operations are controlled through I2C protocol, so you save 6 pins comparing to the previous version. Maybe you can even stick to Arduino UNO and don't need to upgrade to Arduino MEGA (at least not because of running out of free pins).
- You can use a small breadboard-like set of the metalized holes for any additional connections and schematics. So you can place here, for example, an MP3 module, or a sound amplifier, or a shift register to control some LED's.
Experience is simply the name we give our mistakes. We hope you can also learn something from ours.
Connecting the Motor Shield to the Robot
Having the Arduino MEGA 2560 installed on the chassis, we started to think about how to install all the other modules.
Besides the Motor Shield, we also have ESP13 - a WiFi shield based on ESP8266 microcontroller. We will use it to implement the remote control. To be honest - that is also not the best choice. We've got this shield accidentally and decided to adopt it for the project. Having this planned in advance - we would stick to something more compact like ESP8266 ESP-01S Remote Serial Port WIFI Transceiver Wireless Module.
The main problem we face is a lack of stackable headers on top of the Motor Shield. Of course, for hardcore electronics experts this is not a problem at all. Replacing the regular pins with the proper header is not a big deal. But not for us. Soldering is maybe not that complicated task, but DEsoldering and removing the old pins is something really scary - you can easily overheat the board or blow away useful parts by a heating fan… No-no - this is not for us.
We decided to install Motor Shield on top of the Arduino board and place ESP13 as a stand-alone module. ESP13 requires 4 wires to operate properly: 5V, GND, TX, RX. These are just two power lines and serial port transfer and receive lines. We soldered 4 wires to the corresponding contacts on the Motor Shield board.
Finally - the installed Motor Shield looks like this:
Please notice, we used EXT_PWR socket to receive power for the motors directly from the battery. If needed it is possible to use this interface to power the Arduino itself. We'll discuss this in more details in the next post.
At the ESP13 shield, we found a very convenient socket labeled "UART" which combined all 4 lines required for the operations. From some old board we extracted a connector which fits this port perfectly well:
The ESP13 board was moved far from other electronics and screwed to the upper plate of the chassis. Thus it is easier for the WiFi radio waves to reach the antenna.
A nice explanation on how to use the motor shield is provided in the Adafruit Tutorial (or version 2 tutorial if you've got that one).
Working with the motor drivers requires more complicated code. It is convenient to use a library which hides all these complications from your sight: https://github.com/adafruit/Adafruit-Motor-Shield-library
Now the code which controls motors looks more professionally:
// connect to the Adafruit motor shield library #include "AFMotor.h" // in our firmware we can group all motors-related code // into a single class RobotMotors class RobotMotors: public TaskInterface { private: // ID's of the sockets, which we used // to connect our motors on a shield const uint8_t leftDriveID = 3; const uint8_t rightDriveID = 4; // hepling objects to control motors through the library AF_DCMotor* leftMotor; AF_DCMotor* rightMotor; ... } // constructor is a method called automatically when // an object is created RobotMotors::RobotMotors() { ... // create the motors objects (from library) leftMotor = new AF_DCMotor(leftDriveID, MOTOR34_64KHZ); rightMotor = new AF_DCMotor(rightDriveID, MOTOR34_64KHZ); } // destructor is called automatically // when the object is released // in real life this method will never be used // since our motors object will never be released RobotMotors::~RobotMotors() { // stop the motors fullStop(); // release the memory delete leftMotor; delete rightMotor; } // standard set of methods to move and turn // the only difference is motor direction void RobotMotors::driveForward(uint8_t speed, uint16_t duration) { runDrives(speed, duration, FORWARD, FORWARD); } void RobotMotors::driveBackward(uint8_t speed, uint16_t duration) { runDrives(speed, duration, BACKWARD, BACKWARD); } void RobotMotors::turnRight(uint8_t speed, uint16_t duration) { runDrives(speed, duration, FORWARD, BACKWARD); } void RobotMotors::turnLeft(uint8_t speed, uint16_t duration) { runDrives(speed, duration, BACKWARD, FORWARD); } // this is the method which actually manipulates the motors void RobotMotors::runDrives(uint8_t speed, uint16_t duration, uint8_t leftDirection, uint8_t rightDirection) { leftMotor->setSpeed(speed); rightMotor->setSpeed(speed); leftMotor->run(leftDirection); rightMotor->run(rightDirection); scheduleTimedTask(duration); } // full stop of the motors void RobotMotors::fullStop() { leftMotor->run(RELEASE); rightMotor->run(RELEASE); }
Using this class in your program gives the possibility to reverse and turn faster since the trucks can now run in both directions.
You can find a complete functioning firmware with this code under the version 1.2 branch: https://github.com/rmaryan/ardurobot/tree/ardurobot-1.2 (don't pay much attention on the Remote Control and the sound generation parts yet - we'll discuss this separately).
Having the boards finally placed, we installed the upper deck on the chassis and now the robot looks really neat!
Next time we'll talk about how to build an optimal power source for the robot. Stay tuned.
No comments:
Post a Comment