Wednesday, March 25, 2015

Build an RC Car with Wii Remote + Arduino + LEGO (Part 2): Driving DC Motors

Table of contents
  1. Wii Remote + Arduino + LEGO RC Car (Part 1): Parts Selection
  2. Wii Remote + Arduino + LEGO RC Car (Part 2): Driving DC Motors
  3. Wii Remote + Arduino + LEGO RC Car (Part 3): Bluetooth Dongle via USB Host Shield
  4. [Finished!] Wii Remote + Arduino + LEGO RC Car (Part 4): Controlling DC Motors with the Wii Remote


Last time we gathered all the parts. Now let's get a DC motor spinning.



Jumping straight to controlling both tracks would be complicated, so let's start with just one motor.

Here's what the finished result looks like:







And here's the circuit diagram:



DC motor driver circuit diagram



You'll notice a variable resistor and a fixed resistor that weren't in the previous post —

these can also be replaced with software on the Arduino side.

For a wiring approach without the fixed resistor, see Kousaku Kousaku Zemi 2008.



Motor Driver TA7291P

The IC has 10 pins. The side with the notch cut out of the metal tab is pin 1.

Here's what each pin does:


  • Pin 1: GND

    Ground. Connect to Arduino GND.

  • Pin 2: OUT1

    Motor output. Connect to one terminal of the motor.

    If the motor spins the wrong direction, just swap pins 2 and 10.

  • Pin 3: NC

    Not connected.

    If you accidentally insert the IC backwards, this pin lines up with Vs (pin 8), the motor power supply.

    Grounding pin 3 protects the circuit from a backwards insertion — clever design.

  • Pin 4: Vref

    Motor control pin.

    Normally you'd connect an Arduino PWM output here to control motor speed, with pins 5 and 6 set to digital output.

    In this build I'm using a fixed resistor on pin 4 and PWM on pins 5 and 6 instead — either approach works.

    For a good explanation of PWM, see the Kousaku Kousaku Zemi 2008 article.

  • Pin 5: IN1

    Motor control input. Connect to Arduino pin 6 in this build.

    IN1 HIGH + IN2 LOW → motor runs forward.

    IN1 LOW + IN2 HIGH → motor runs in reverse.

    Vref voltage controls speed.

    In our case, Vref is fixed, so we vary IN1 and IN2 to control both speed and direction together.

    Internally, the TA7291P uses (IN1 − Vref) and (IN2 − Vref) to determine how much voltage to push from the motor supply to the motor.

  • Pin 6: IN2

    Motor control input, used together with pin 5. Connect to Arduino pin 5.

    Both IN1 and IN2 LOW → motor stops.

  • Pin 7: Vcc

    Connect to Arduino 5V pin.

  • Pin 8: Vs

    Motor power supply input. Accepts up to 20V.

    Never feed 20V directly to Arduino — that's why Arduino power and motor power must be kept separate.

    Note: if Vs drops below Vref, the TA7291P can be damaged.

    Four Eneloop cells in series (1.2V × 4 = 4.8V) dips below USB's 5V, so be careful.

    One workaround is to drop USB power and feed the motor supply into Arduino's 5V pin instead,

    but accidentally exceeding Arduino's voltage tolerance will destroy the board, so handle with care.

    Side note: if you want more motor power but only one battery pack, you can step down a higher voltage (e.g. 20V) to 5V with a voltage divider — sometimes done to save weight on quadcopters — but the resulting voltage is less stable, so I wouldn't recommend it generally.

  • Pin 9: NC

    Not connected. If inserted backwards, this aligns with OUT1 (pin 2), cutting the motor circuit.

  • Pin 10: OUT2

    Motor output.



Arduino UNO

Finally, the Arduino.

There are plenty of tutorials on uploading sketches, so I'll keep this brief:


  1. Download and install the Arduino IDE from the official Arduino site.

  2. Connect the Arduino UNO to your PC via USB.

  3. Launch the IDE — it should detect the board automatically.



Here's the sketch used in this build.

It's based almost entirely on the example at hiramine.com — only the pin numbers differ. Many thanks.

Upload this sketch and turn the variable resistor to see the motor spin as in the video.

Attach LEGO pieces as you like.



#define IN1PIN  5
#define IN2PIN  6
#define VOLUMEPIN  0

void setup()
{
pinMode(IN1PIN, OUTPUT);
pinMode(IN2PIN, OUTPUT);
}

void loop(){
int iValue = analogRead(VOLUMEPIN);
int iMotor = Map(iValue, 0, 1023, -255, 255, true);

MotorDrive( IN1PIN, IN2PIN, iMotor );
delay(15);
}

int Map(int iIn, int iIn1, int iIn2, int iOut1, int iOut2, boolean bConstrain = false) {
double dValue = (double)(iIn - iIn1) * (iOut2 - iOut1) / (iIn2 - iIn1) + iOut1;
int iValue = (0 < dValue) ? (int)(dValue + 0.5) : (int)(dValue - 0.5);
if( bConstrain ) {
int iOutMin, iOutMax;
if( iOut1 < iOut2 ){
iOutMin = iOut1;
iOutMax = iOut2;
} else {
iOutMin = iOut2;
iOutMax = iOut1;
}
if( iOutMin > iValue ){
return iOutMin;
}
if( iOutMax < iValue )
{
return iOutMax;
}
return iValue;
}
}

void MotorDrive( int iIn1Pin, int iIn2Pin, int iMotor ){
if( -5 < iMotor && iMotor < 5 ){
digitalWrite(iIn1Pin, LOW);
digitalWrite(iIn2Pin, LOW);
} else if( 0 < iMotor ) {
analogWrite(iIn1Pin, iMotor);
analogWrite(iIn2Pin, 0);
} else {
analogWrite(iIn1Pin, 0);
analogWrite(iIn2Pin, -iMotor);
}
}


Sketch Walkthrough


  • void setup()

    Runs once when Arduino starts. Always required.

    pinMode(PIN, MODE) sets the specified pin to the given mode.

  • void loop()

    Runs repeatedly after setup(). Also always required.

    analogRead(PIN) reads a value from an analog pin, returning 0–1023.

    delay(N) adds a short sleep to prevent the loop from spinning too fast.

  • int Map

    Remaps a value from one range to another.

    Arduino has a built-in map() function worth comparing: Arduino map reference.

  • void MotorDrive

    If the variable resistor is in the positive range, the motor runs forward; negative range, it runs in reverse.

    digitalWrite(PIN, VALUE): HIGH sets the pin to 5V, LOW sets it to 0V.

    analogWrite(PIN, VALUE): on a PWM pin, outputs a PWM signal equivalent to VALUE. Does not work correctly on non-PWM digital pins.



That covers single-motor control. Next time we'll tackle the track assembly.


No comments:

Post a Comment