advertisement

Print

The Straight and Narrow

by Jonathan Knudsen
05/23/2000

When I was a kid, my brother and I used to make up treasure maps. You'd have to start in a particular place in the backyard, then walk ten steps forward, turn left, walk twenty steps, and so forth. This wasn't a very reliable way to find treasure -- one person's steps are a different size than another person's steps, and it's hard to tell if you're moving exactly in a straight line or if you've turned exactly at right angles to your original path.

It turns out robots have a lot of the same trouble that my brother and I had. In this article, we'll examine one of these problems, moving in a straight line, in detail. Afterwards, I'll take a step back and look at the bigger picture of robot navigation.

Differential Drive

One of the easiest ways to build a robot is using a technique called differential drive. This means that the robot has two motors, each of which controls a wheel or tread on one side of the robot. The tank-style robot is a classic example. If you run both motors forward, the whole robot moves forward. Run both motors in reverse, and the robot backs up. If you run the motors in opposite directions, the robot spins in place, just like a tank or a bulldozer. The following picture shows such a robot:

A simple variation on this idea uses wheels instead of treads, as shown here:

Differential drive robots with wheels are a little more difficult to create than tank-style robots, simply because the robot needs some way to keep its balance. The robot shown above has an idler wheel at the back for support. The idler wheel has an unrewarding job, which is to keep the robot from falling over while not interfering with the movement dictated by the drive wheels. It swivels freely on a vertical axis, like the wheels on the front of a shopping cart.

Some wheeled differential drive robots have two idler wheels, one at the front and one in the back. Some don't have idler wheels at all, but a couple of supports that slide over the ground as the robot moves.

An aside: Don't confuse differential drive with a differential. Differential drive is a style of locomotion; a differential is a clever mechanical device that allows movement to be shared between two shafts. As you'll see, a differential is crucial in the construction of car-style robots.

The Bad News

Differential drive is great: easy to construct, easy to understand, easy to program. But the one thing your robot can't do is drive in a straight line. Sure, if you run both motors forward, the robot moves forward, sort of. But if you observe your robot, you'll notice it moves in a gentle arc. Why is this? You've used the same motors and the same parts on both sides of your robot, right?

In the real world of robotics, there are hardly ever two things that are exactly the same. Let's look at just a few of the reasons your robot won't go straight:

  1. When the robot moves forward, the motors are actually running in opposite directions. To prove this to yourself, look at each motor by facing its shaft. When the robot moves forward, one of the motors is spinning clockwise and one of them is spinning counterclockwise. Although this might not seem like a big deal, most electric motors are optimized for one direction or the other. Because the motors run in opposite directions, one of them is actually running a little more efficiently than the other, which can cause a curve in the robot's forward motion.
  2. The treads or tires may be slightly different sizes. Even if the motors ran at exactly the same speed, variations in the treads or tires would cause deviations from an absolutely straight course.
  3. The robot may not be driving on a completely uniform (or even flat) surface. If one tread of your tank-style robot is running on a hardwood floor, and one on a carpet, the robot will not move in a straight line.
What's a robot designer to do? One way to deal with the straight line problem is to examine the progress of the robot and make corrections. In engineering this is called feedback control.

Using Feedback

The next logical step would be to use a sensor to tell if the robot is turning or moving straight. One way to do this is to measure how far each wheel or tread has turned, which is a way of measuring how far each side of the robot has traveled. (I'm ignoring some assumptions here that will come back and bite us in the butt later.) The simplest way to measure the rotation of the robot's wheels or treads is to add a rotation sensor to the drive shaft of each side. The rotation sensor does not come with the Robotics Invention System or any of the other Mindstorms kits. However, you can purchase these sensors for $16.50 each (postage included!) from the Lego Shop-At-Home service at 800-453-4652. The item number is 9756.

The sensor itself looks like a Lego brick with a shaft hole, as shown below. You can use this sensor to measure how far a shaft in the hole has rotated. The programming environment that comes with the Robotics Invention System, the RCX, measures rotations in the clockwise or counterclockwise directions, with 16 units per full revolution. For example, rotate the shaft one way by a full turn and the sensor will read 16. Rotate it the other way by two full turns and the sensor will read -16.


After attaching two rotation sensors to your robot, one for each side, you could use the following algorithm to keep the robot moving mostly straight:
 

while (true) {
  if (left rotation sensor is greater than right rotation sensor)
    turn slightly left
  else if (left rotation sensor is less than right rotation sensor)
    turn slightly right
  else if (left rotation sensor equals right rotation sensor)
    full power to left and right motors
}

Introducing the Differential

While the above solution would work, it costs $33.00 and it sucks up two of the inputs on the RCX. What if we could just use one rotation sensor to measure the difference between the right and left shaft rotations? Then we'd only have to buy one rotation sensor and use up one of our precious inputs on the RCX.

This is indeed possible -- all we have to do is find a way to mechanically combine the rotations from the left and right motors. I already mentioned the solution, the differential. The best way to understand a differential is to hold it in your hands and play with it. Lego's differential piece looks like a cutout cylinder with a gear at either end. To fully assemble it, use three 12t gears and a couple of shafts, as shown here:

The differential can split or combine motion. In a rear-wheel-drive car, the differential takes the motion from the motor and shares it between the two back wheels. In this scenario, the engine would be driving the differential itself (the dark gray piece) on one of the sides where it has gear teeth. The wheels of the car would be attached to the shafts coming out of the sides of the differential, as shown:

When a car turns corners, the rear wheels don't move at the same speed. To understand this, think of the distances the wheels have to travel. The outside wheel has to travel through a greater arc in the same time the inner wheel travels through a smaller arc. Thus, the outer wheel must be moving faster than the inner wheel.

The differential takes care of splitting the engine's driving power between the two wheels. If you just had a straight axle connecting the two rear wheels, you'd have trouble when the car was turning -- either one of the wheels would have to slip, or the axle would have to break.

A Smarter Solution

To make our robot drive straight, we'll use the differential in a slightly different way. We'll take the motion from both motors and feed it into the sides of the differential. If the side axles are rotating at the same speed, in opposite directions, the main gears of the differential (the dark gray piece) will not move at all. You can try this with the assembled differential. Just rotate the side axles at about the same speed; the differential itself won't rotate at all. We can attach the differential to a rotation sensor. If the rotation sensor registers any change, we'll know that we're off course.

The gearing is a little tricky, but not impossible. First, we need to invert the direction of one of the motor outputs so the outputs are moving in opposite directions when they enter the differential assembly. To do this, we'll use two 16t gears on one side and three 8t gears on the other. These two combinations of gears take up the same amount of space, but invert the rotation direction on one side. This is what it looks like:

The shafts sticking out on the sides will be linked to the drive motors.

To measure the difference between the rotation of the two drive shafts, we need to attach the rotation sensor to the differential, as shown here:

Finally, we'll tack the whole thing on the back of a tank-style robot, adding a couple of gears to link things to the drive motors. The following illustration shows how the rotation sensor and differential can be added to the back of RoboTag, one of the projects from The Unofficial Guide to LEGO MINDSTORMS Robots. Building instructions for RoboTag are available online, although you'll need to deviate from the instructions to add the differential and rotation sensor assembly.

Programming

Once we've got the rotation sensor mechanically attached to the two drive shafts, the programming is pretty straightforward. Here is a program in NQC (Not Quite C) that examines the rotation sensor as the robot drives forward. If it deviates from 0, the robot turns left or right to adjust its course.

task main() {
  // Configure input 3 as a rotation sensor.
  SetSensor(SENSOR_3, SENSOR_ROTATION);
  // Start moving forward.
  OnFwd(OUT_A + OUT_C);
  // Reset the rotation counter.
  ClearSensor(SENSOR_3);
  // Adjust course if necessary.
  int angle;
  while (true) {
    angle = SENSOR_3;
    if (angle < 0) {
      // Turn right.
      On(OUT_A);
      Off(OUT_C);
    }
    else if (angle > 0) {
      // Turn left.
      Off(OUT_A);
      On(OUT_C);
    }
    else On(OUT_A + OUT_C);
  }
}
The call to ClearSensor() sets the rotation count to 0. This should be done every time the robot starts moving forward.

An interesting side effect of our differential and rotation sensor setup is that we can measure turns with a fair degree of accuracy. When the motors turn in opposite directions to spin the robot, the rotation sensor will measure how far the robot is turning (although it cannot account for the differences in the motors or treads, which is the purpose when the robot moves forward).

About Dead Reckoning

Having gone through all the trouble of attaching a differential and a rotation sensor to our robot, it's now time to step back and look at the larger question. Why would you want to move in a straight line to begin with? Moving in a straight line is important in a navigational technique called dead reckoning. In dead reckoning, you start from a known point. Then you move in a certain direction, and, based on how fast you're moving and in what direction, you can calculate a new location. When using dead reckoning in ships, it's prudent to periodically use celestial navigation to more accurately determine your position, then use dead reckoning for the next leg of your journey. Or, more likely, you'll probably just bring along a GPS receiver to pinpoint your position.

Lego robots, however, are unlikely to use celestial navigation (or GPS receivers) and thus would have to rely on dead reckoning alone. Dead reckoning is impractical, over time, because there are so many things that can go wrong. One of the treads or wheels of the robot might slip over the surface on which the robot is driving. Even using our rotation sensor feedback, we have no way of knowing whether the robot wheels or treads are actually driving or just slipping. If one side is gripping and the other is slipping, the robot's direction can change radically without the robot being aware of it. If both treads are slipping, the robot will believe it is moving when it really isn't. With dead reckoning, small errors become large errors over time, which is why navigators on ships synchronize with the stars now and then.

If you can use an alternative to dead reckoning, it's definitely worth considering. Can your robot locate a light beacon, or follow a wall until it bumps into its destination? Can the robot follow a line on the floor to get where it's going? Or perhaps dead reckoning is a reasonable choice, as long as the robot has a chance to accurately determine its location periodically.

Bring It on Home

The best approach is to combine navigational techniques. Your robot might have a home base, for example, that could act as a navigational reference point. Starting from this known location, it could seek out other destinations using dead reckoning based on the feedback from the rotation sensor. The home base might be a bright light or a mechanical dock of some sort. To go back home, you could again use dead reckoning, then home in on the light at the dock to correct for navigational errors. After all, we only had to use one of the RCX's input ports to make the robot go straight. We can certainly spare another input port for a light sensor, to find the home base.

Sensor feedback is the key to success in robot navigation. Appropriately placed sensors can tell your robot if it's where it wants to be or not. With feedback control, a robot can find treasure much more accurately than my brother or I.


Read more Lego Mindstorms columns.

Discuss this article in the Mindstorms forum.

Return to the O'Reilly Network.