Bring old toys back to life with Arduino: Part II

Revving Up

It's now time to apply what you know to motors. In the previous issue, you saw how to hook up some L293D motor controllers to the Arduino. Now, instead of connecting two of the Arduino's pins directly to the L293D's pins, you connect two of the ports from the MCP23017. For simplicity's sake, you should probably use GPB0 and GPB1 for one motor, GPB2 and GPB3 for another, and so on. (See the "Motor Speed" box for additional information.)

Motor Speed

At this point, you may be asking yourself how you control motor speed using an MCP23017. In short: You can't.

The MCP23017 is a purely digital chip, with digital I/O ports. The only thing you can send and get from it are HIGHs and LOWs, 1s and 0s.

Fortunately, for many projects, including this one involving Robosapien, controlling the motors' speeds is not that important. Robosapien's DC motors need to move in one direction or the other so that the robot can move its limbs into place. With one or two exceptions, what matters is the final position of each limb, not the speed at which they get there, as long as they move reasonably fast.

If you were building a quadcopter, however, things would be very different. You would need fine control over each of the motors' speeds to determine roll, pitch, and yaw, as well as vertical direction and velocity. In this case, you'd probably need an MC14051 [4] – a port expander similar to the MCP23017, but for analog I/O.

But that, dear reader, is an article for another time.

The hardware setup would look something like what you see in Figure 5. It may look complex; well, it is complex, but basically it is the setup you built above for the MCP23017 combined with the setup of the L293D seen in the previous issue. You connect 5V to the outermost legs of the L293D. The controlling inputs from the port expander pins connect to the second set of pins moving inward. Moving inward again, the next pair of legs of L293D connect to the motors. Finally, the innermost legs connect to GND. Figure 6 shows what things look like in real life.

Figure 5: Setting up four motors controlled by two pins from your Arduino.
Figure 6: Two L293D motor controllers hooked up to the MCP23017. The left-most L293D is also already connected to two motors.

If you notice that the 5V from the Arduino has insufficient oomph to drive the motors, you can boost the power by putting the L293Ds onto a separate breadboard and connecting a battery to the + and – rails. Remember, though, you will also have to connect the minus rail back to a GND pin on the Arduino.

DO NOT connect a battery to the rails on the MCP23017's board: That is exactly how I made magic smoke and fried my first port expander.

A sketch to test all this could look like what you see in Listing 3. Apart from defining ports, you also create constants to contain the three states of each motor: moving clockwise (line 7), counterclockwise (line 8), and stopped (line 9). In order not to get very bogged down, you will be moving only the upper half of Robosapien's body, namely rotating the shoulder and wrist motors. I define constants also for these on lines 11 through 14.

Listing 3

Robosapien Motor Control

01 #include "Wire.h"
03 const byte a_Ports = A4;
04 const byte b_Ports = A5;
05 const byte mcp_Add = 0x20;
07 const byte CW   = 1;
08 const byte CCW  = 2;
09 const byte STOP = 0;
11 const byte r_Shoulder =  1;
12 const byte r_Wrist    =  4;
13 const byte l_Shoulder = 16;
14 const byte l_Wrist    = 64;
16 void setup() {
18   Wire.begin();
20   Wire.beginTransmission(mcp_Add);
21     Wire.write(0x01);
22     Wire.write(0x00);
23   Wire.endTransmission();
25   Wire.beginTransmission(mcp_Add);
26     Wire.write(b_Ports);
27     Wire.write(0);
28   Wire.endTransmission();
29 }
31 void loop() {
32   moveLimb(r_Shoulder, CW, 250);
33   moveLimb(r_Wrist, CW, 250);
35   moveLimb(r_Shoulder, CCW, 250);
36   moveLimb(r_Wrist, CCW, 250);
39   moveLimb(l_Wrist, CCW, 500);
40   moveLimb(l_Shoulder, CW, 500);
42   moveLimb(l_Wrist, CCW, 500);
43   moveLimb(l_Wrist, CW, 500);
45   moveLimb(l_Shoulder, CCW, 500);
46   moveLimb(l_Wrist, CW, 500);
47 }
49 void moveLimb (byte limb, byte v_Direction, int time){
50   byte to_MCP=v_Direction * limb;
52   Wire.beginTransmission(mcp_Add);
53     Wire.write(b_Ports);
54     Wire.write(to_MCP);
55   Wire.endTransmission();
57   delay(time);
59   Wire.beginTransmission(mcp_Add);
60     Wire.write(b_Ports);
61     Wire.write(STOP);
62   Wire.endTransmission();
63 }

All this comes together in the moveLimb() function (line 49) that takes three parameters: the limb to move (left/right shoulder/wrist), the direction it will move (CW or CCW), and the duration of the movement in microseconds.

When you multiply the direction by the limb, you get the byte that tells the port expander which pin it needs to activate. So, say you want to rotate the left shoulder (16) counterclockwise (2): 16 x 2 = 32, the port expander receives B00010000, that is, the order to activate the BP4 pin. STOP just sets all pins to 0 and stops all movement.

You will have to test beforehand which ports on your Robosapien correspond to which motor and figure out which direction your motors rotate depending on the polarity of the cables, as well as how long you have to rotate them to get them into the position you want. This will involve a lot of trial and error. Take notes, wire up the L293Ds and adjust your sketch accordingly.

Figure 7 shows a close-up of wires coming from the motor controller connected to Robosapien's left shoulder (left) and left wrist (right) motor ports. Figure 8 shows the movement.

Figure 7: Close up of wires connected to two of Robosapien's motor ports.
Figure 8: Robosapien shakes his fist angrily at a desk piled high with junk.


Where do you go from here? The obvious next step is to make Robosapien walk. Be warned, however, that task is going to take some sophisticated motor coordination involving the waist motor and the two hip motors.

Another interesting challenge would be to make more than one motor rotate at the same time. Currently, if one motor is running, all the others have to wait. Getting several motors working at the same time will make for smoother movements but will also require some guru-level knowledge of interrupts and/or timer functions.

As for kitting Robosapien up, now you have some more ports you can play with, so fitting your robot with a few sensors more sophisticated than its standard touch sensors should be a priority. You could have him read data in from an ultrasound sensor and detect obstacles before actually crashing into them, for example.

Finally, you could give Robosapien a real brain. An Arduino is better than the brain he comes with out of the box, but what about fitting him with a Raspberry Pi or some other nanocomputer? The Pi has enough computing power to help Robosapien walk, talk, see, and hear, thus allowing him to become a fully autonomous robot. Exactly what you wanted when you were a kid, right?


  1. "Bring Old Toys Back to Life with Arduino: Part I" by Paul C. Brown, Raspberry Pi Geek, Issue 9, pg. 44:
  2. Get Robosapien on eBay for $20:
  3. Pull up and pull down resistors:
  4. MC14051's datasheet:

Buy this article as PDF

Express-Checkout as PDF

Pages: 8

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content