My first project needs a motor assembly with high torque so I elected to purchase a Tamiya 72004 Worm Gearbox Kit from Pololu. Additionally I bought a T.I. DRV8833 H-Bridge board for about $7.00. I also bought a Radio Shack bread board and a Tamiya 70157 Universal Plate Set to hold everything together.
As you can see in the photos, I put the motor, a 3 cell AA battery pack and Arduino board (with grove extension) on one side, and another AA battery pack on the other side with the H-Bridge chip on the breadboard. (the assembly is being held by a PanaVise in the photographs).
I assembled the motor gear box for a 336:1 gear ratio but it can also be assembled with a 216:1 gear ratio. The axle is slow, maybe 1 RPS when the DC motor is at 100% so it has very high torque. In fact, if I clamp the drive shaft the motor is able to spin the entire assembly around in a circle with very little strain.
I have to admit that I was skeptical about having the batteries plugged into the Seeeduino board and then just plugging and unplugging the USB connector, but the board switches over with no problems. In fact while it's running with the usb connected it is running on the usb power, not my batteries, but pulling the usb connector causes the board to switch to the batteries with no glitch. Very cool.
Note that I soldered 3 noise suppression diodes to the motor. Pololu sells a noise suppression pack of three 0.1 uF capacitors. You can read more about DC motor noise suppression at the HydraRaptor blog. Note that I did not use ferrite beads in my suppression scheme as specified in the HydraRaptor blog.
Additionally I used a power supply decoupling capacitor based on this tutorial.
here is a diagram of my current project created with Fritzing.
I decided to split the power supply, one set to drive the motors and another set added to that to drive the Arduino board. If I decide I need more battery power, I'll add another 3 cell set in parallel to the "lower" set. I did this mainly because I can't drive the motors at 7.2 volts, I don't want to add a voltage regulator to drop 7.2 down to say 6 volts, and I didn't want to stress the onboard 5v regulator. So the motors will be driven at 3*1.2v or 3.6v. (note that a rechargeable 1.5 volt battery produces a constant 1.2 volts until it is fully discharged).
To control the motor I added a new Motor class to my Asynchronous Device Framework. The class is designed to control more DC H-Bridge motors than you could possibly put on an Arduino board, but if I get to 4 motors I'll not have to add any motor class controller code. Once again I use a linked list, in this case virtual motors, that get added at run-time.
There are only three public motor control members, one to start the controller in the ino setup, one to add a motor in the MyController start-up, and one to control it during run-time:
DCMotorControl_Start(uint8_t priority);
DCMotorControl_Add(uint8_t motorID, uint8_t pin1, uint8_t pin2);
DCMotorControl_Set(uint8_t motorID, uint8_t speedPercent,
DCMD_MODE motorMode);
Where DCMD_MODE is defined as
enum DCMD_MODE
{
{
DCMD_STOP,
DCMD_COAST,
DCMD_FORWARD,
DCMD_REVERSE
};
DCMD_COAST,
DCMD_FORWARD,
DCMD_REVERSE
};
In my code I define the motor pins, and an arbitrary but unique motor id as:
const uint8_t DCMOTORin1 = 5;
const uint8_t DCMOTORin2 = 6;
const uint8_t DC_SPIN_MOTOR = 56;
const uint8_t DCMOTORin2 = 6;
const uint8_t DC_SPIN_MOTOR = 56;
and then create it during runtime startup with:
DCMotorControl_Add(DC_SPIN_MOTOR, DCMOTORin1, DCMOTORin2);
and then control it in the MyController process with a 'make the spin motor go in reverse at 25%' :
DCMotorControl_Set(DC_SPIN_MOTOR, 25, DCMD_REVERSE);
The asynchronous device platform's capabilities far exceed the hardware capabilities of my Seeeduino board. The controller is intended to control a specific type of DC motor controller, the H-Bridge. I could envision a motor type DC_HBRIDGE or DC_STEPPER that would adapt to the controller in a generic way, or you could even create a specific type for a custom hardware controller.
The current ADF motor controller uses the following control logic based on the DRV8833 operation:
// recurse through the list of motor output devices
// and change the state as described in the event args
void DCMCListWalker(VMODevice * link, DCMDEventArg const * device)
{
if(link != NULL)
{
if( link->m_MotorID == device->motorID )
{
uint8_t speed = map(device->motorSpeedPercent,0,100,0,255);
if(device->motorMode == DCMD_COAST )
{
analogWrite(link->m_Pin1, 0);
analogWrite(link->m_Pin2, 0);
}
else if(device->motorMode == DCMD_FORWARD )
{
analogWrite(link->m_Pin1, speed);
analogWrite(link->m_Pin2, 0);
}
else if(device->motorMode == DCMD_REVERSE )
{
analogWrite(link->m_Pin1, 0);
analogWrite(link->m_Pin2, speed);
}
else // STOP
{
analogWrite(link->m_Pin1, 255);
analogWrite(link->m_Pin2, 255);
}
}
else if(link->m_NextVMODevice != NULL ) // not it, go deeper
DCMCListWalker(link->m_NextVMODevice, device);
}
}
// and change the state as described in the event args
void DCMCListWalker(VMODevice * link, DCMDEventArg const * device)
{
if(link != NULL)
{
if( link->m_MotorID == device->motorID )
{
uint8_t speed = map(device->motorSpeedPercent,0,100,0,255);
if(device->motorMode == DCMD_COAST )
{
analogWrite(link->m_Pin1, 0);
analogWrite(link->m_Pin2, 0);
}
else if(device->motorMode == DCMD_FORWARD )
{
analogWrite(link->m_Pin1, speed);
analogWrite(link->m_Pin2, 0);
}
else if(device->motorMode == DCMD_REVERSE )
{
analogWrite(link->m_Pin1, 0);
analogWrite(link->m_Pin2, speed);
}
else // STOP
{
analogWrite(link->m_Pin1, 255);
analogWrite(link->m_Pin2, 255);
}
}
else if(link->m_NextVMODevice != NULL ) // not it, go deeper
DCMCListWalker(link->m_NextVMODevice, device);
}
}
Also note that although I use forward and reverse, it would probably be good to add something like clockwise and counter-clockwise, or left and right to the enumerations for readability.
No comments:
Post a Comment