Introduction: Arduino-Smart Distance Controlled Insect

In this project, you’ll create an Insect Robot that walks forward on four legs. Using ultrasound, the robot can see in the dark, just like a bat. When it detects an obstacle, it takes a few steps back, turns, and continues forward. The robot can walk over small obstructions, and it looks more human than its wheeled relatives.

Before starting this project, you should know what ultrasonic sensors are,and make sure that the “Hello World” Blink code is working properly with your Arduino. You’ll learn about some new things, including servo motors (motors that can be manipulated to rotate to a specific angular position), in this chapter. We will build a body for the insect by gluing two servos together and shaping legs for it from a wire clothes hanger. Arduino will turn the two servos one at a time, which moves each pair of metal legs like real legs so the insect can crawl forward. We will also make holders for the battery and Arduino so our insect can behave autonomously. The insect will need eyes to react to its environment. We will connect an ultrasonic sensor to the insect’s head to enable the robot to precisely measure its distance from objects in front of it. Finally, we will teach the insect to react to an obstacle by backing up and turning. The distance of the obstruction will trigger a series of commands that make the robot back up several steps, turn, and move forward several more steps. Then our Insect Robot will be able to move and avoid obstructions on its own. After you have spent some time observing your new pet’s movements, you can add new sensors to the robot or teach it new tricks.

Step 1: Tools and Parts

1. 9V battery clip (EL14: 34M2183; SFE: PRT-00091).

2. Two small metal rods. You could salvage these from other devices, such as an old typewriter. If you have metal snips and a small amount of sheet metal, you could also cut them yourself (but be sure to use a metal file or metal sandpaper to smooth the edges, which will be extremely sharp).

3. Heat-shrink tubing (14cm) for the feet (EL14: 90N7288). Hot glue works well, too.

4. 28cm and 25cm pieces from a wire clothes hanger.

5. Two pairs of pliers.

6. Wire strippers (EL14: 61M0803; SFE: TOL-08696).

9. Two large servo motors (SFE: ROB-09064; http://parallax.com/Store: 900- 00005).

11. 9V battery.

12. Servo extension cable (SFE: ROB-08738; http://parallax.com/Store: 805- 00002).

13. Red, black, and yellow (or some other color) jumper wire (SHED: MKEL1; EL14: 10R0134; SFE: PRT-00124).

15. Thin metal wire/metal hanger.

17. PING ))) ultrasonic sensor (SHED: MKPX5; http://parallax.com/Store/)

18. Arduino Uno (SHED: MKSP4; EL14: 13T9285; SFE: DEV-09950). The older Duemilanove works just as well.

Step 2: ​Servo Motors

Servo motors come in different sizes and prices and are based on different technologies. In this context, we are talking about hobby servos, the kind used in remote-control cars, for example. Servo motors have a servo controller that directs the position of the motor wherever we want.The motor itself is a DC (direct current) motor with gears. Servo motors usually rotate rather slowly and with a relatively strong torque. You can buy hobby servo motors with either limited rotation or continuous rotation. Limited rotation models work for most purposes, and you can control their movement quite precisely by degrees of rotation. In continuous rotation servos, you can control only speed and direction.

Step 3: ​Wiring Up the Circuit

Connect the servo to the Arduino by attaching the servo’s black wire to any of the Arduino GND pins. The red wire indicates positive voltage; connect it to the Arduino +5V pin. The white or yellow data wire controls the servo; you will connect it to one of the digital pins. For this project, connect the data wire to the first available digital pin: digital pin 2 (D2). Figure 4-4 shows the connection, and Figure 4-5 shows the schematic.

Step 4: Using the Servo Library in Arduino

Libraries are collections of subroutines or classes that let us extend the basic

functionality of a platform or language such as Arduino. There are many different libraries that help us interpret data or use specific hardware in much simpler and cleaner ways. You can explore the libraries available for Arduino at http://arduino.cc/en/Reference/Libraries. As these libraries are meant to extend our code only when needed, we must declare each library in any sketch where one will be used. We do this with a single line of code. Here’s how to include the library for controlling servo motors: #include Now we can reference methods and objects from within that library at any time in our sketch. We will be using the Servo library to interface with our motors in this chapter. The Servo library comes with a standard installation of Arduino and can support up to 12 motors on most Arduino boards and 48 motors on the Arduino Mega. For each servo motor we are using, we must create an instance of the Servo object with Servo myServo;. In the setup() function, we must associate this instance of Servo to a specific pin, the same pin to which the data wire of our motor is attached, using the command myServo.attach(2);. Now talking to our motor is easy. There are several functions for communicating with it, including read(), write(), detach(), and more, all of which you can explore in the library reference at http://arduino.cc/en/Reference/Servo. For this chapter, when talking to our motors, we will use only the write() function, which requires a single argument: degree of rotation.

Step 5: Centering the Servo

This example shows how we use the Servo library to connect a single servo motor and rotate it toward the absolute center point.

1. Import the library.
2. Create an instance of Servo and name it myServo.

3. Attach myServo to pin 2.

4. Tell the servo to rotate 90 degrees.

Because we want the motor to move to one position and stay there, we can include all our code in the setup() function. The loop() function must be declared for Arduino to compile, but because we don’t need to do anything in the loop, it can remain empty. When we write() to a servo, we set it to a specific position. Limited rotation servo motors can turn from 0 to 180 degrees, so setting ours to 90 turns it exactly half of its maximum rotation. The servo is now perfectly centered, and it will remain that way until given further instruction.

<br><p>// servoCenter.pde - Center servo
#include  1
Servo myServo; 2
void setup()
{
myServo.attach(2); 3
myServo.write(90); 4
}
void loop()
{
delay(100);
}</p>

Step 6: Moving the Servo

Let’s write a small program that will rotate the servo first to the center, then to the maximum angle, back to center, and then to the minimum angle.

These are the only differences between this and the previous servo code:
1. The variable delayTime variable (set to 1,000 milliseconds, or 1 second) determines how much time to wait between each rotation.

2. Set the servo to a new angle of rotation, and then wait for a specified duration of time.

3. The duration, named delayTime, must also take into account how quickly the motor can turn. In this case, we must wait a minimum of 375 milliseconds before sending the motor a new command. It takes this much time for the motor to rotate 90 degrees. Play with the value of this variable. You will notice that any value less than 375ms is not enough time for the motor to reach its destination, so it will begin to malfunction.

4. Similarly, you can rotate the servo to other positions simply by changing the values written to myServo. Any value between 0 and 180 will function properly, because this is our range of rotation. In this example, these values are hardcoded, meaning they are written explicitly on each line. In the future, we’ll store these values in variables for more complicated and efficient applications.

the maximum angle, back to center, and then to the minimum angle.<br>// moveServo.pde - Move servo to center, maximum angle
// and to minumum angle
#include 
Servo myServo;
int delayTime = 1000; 1
void setup()
{
myServo.attach(2);
}
void loop()
{
myServo.write(90); 2
delay(delayTime); 3
myServo.write(180); 2
delay(delayTime);
myServo.write(90);
delay(delayTime);
myServo.write(0);
delay(delayTime);
}

Step 7: Constructing the Frame(optional)

Making the Legs

Cut two pieces from a wire clothes hanger: 28cm for the rear legs and 25cm for the front legs, as shown in.Bend the legs with pliers.It’s important to make the legs long enough and to make sure that the feet point backward, which lets them act as hooks and enables the robot to climb over obstacles. At this stage, don’t worry too much about the shape of the legs. You can adjust them later (and will likely need to).

The legs will have a better grip if you cover them with heat-shrink tubing, as shown in. Heat-shrink tubing is rubber tubing that will shrink in diameter by 50% when heated, for example, with a heat gun or hair dryer. Cut two 7cm pieces of the tubing and shrink them to fit around the back legs.

Next, attach the legs to the servos. The servos come with one or more plastic attachments that will connect to the servo axis. Attach the legs by pulling metal wires through the servo holes, and secure each leg by tightening the metal wire, as shown in. Cut any excess wire to keep it from hindering the motor’s movement. Finally, add hot glue to the underside to stabilize the legs,but do not fill the center screw hole with glue.

Assembling the Frame

The frame of the walker consists of two connected servo motors. Before gluing them together, you need to remove a small plastic extension (meant for mounting the servos) from both of the servo motors. Remove the extension next to the servo arm from the front-facing servo, and remove the opposite part from the rear-facing servo. You can do this easily with a utility knife, as shown in. It’s a good idea to smooth out the cutting seam with a small file to make sure that the glued joints do not become uneven and weak.

Spread the hot glue evenly on the rear servo, and immediately press the servos together, holding them steady for a while to give the glue time to set. The servos are connected so that the frontfacing servo arm points forward and the rear-facing arm points down. The top sides of the motors should be placed evenly, to make it easier to attach them to the Arduino. If you make a mistake gluing the parts together, it’s easy to separate them without too much force. (Hot-gluing is not necessarily ideal for building sturdy devices, but it is a quick and easy way to attach almost anything, and it works well with simple prototypes.)

Making the Holder for the Arduino

We will use two metal strips to build a holder on top of the robot that will make it easy to attach and detach the Arduino. Cut two 10cm metal pieces. Bend the sides of each strip so that the space in the middle is equal to the width of the Arduino and glue both strips to the servos.

The Arduino Duemilanove (and later models, such as the Uno) used in this project is 5.2cm wide. If the metal you’re using is flexible enough, it is helpful to bend the corner inward slightly. This way, you can snap the Arduino in place sturdily and, when you are finished, remove it painlessly for other uses.

Attaching a Battery

We’ll use Velcro tape to make an attachment system in the rear of the robot for the 9V battery. Cut a 16cm strip from the Velcro tape and attach the ends together. Make holes for two screws in the middle of the tape. Attach the Velcro tape with screws to the servo’s extension part in the rear of the robot.

Assembly

Now you can place the Arduino board on top of the servos. Attach the legs to the servos, but don’t screw them in tightly yet. We’ll connect the servos to each other and to the Arduino with jumper wires. First, connect the servos’ black (GND) wires using a black jumper wire from one servo to the other, and then use another black jumper wire to connect one of the servos to an Arduino GND pin. You might have to use a bit of force to insert two wires into one of the servo connection headers. Next, connect the red power wires in a similar manner, first from one servo to the other and then to the Arduino’s 5V power pin. Use white (the actual color may vary) jumper wires to control each servo, and connect a yellow jumper wire from the rear servo to Arduino pin 2 and from the front servo to Arduino pin 3.

Earlier , in the “Centering the Servo” section, you ran a sketch to center a single servo. If you run this code again to center the servo, you will be able to attach the leg in the correct position. But there are now two servos, so let’s alter the previous centering code to turn both servos toward the center:

The only difference between this and the earlier centering code is the addition
of two servo objects named frontServo and rearServo:

1. Define an instance of the Servo object for the rear servo.

2. Within setup, attach the rearServo to pin 3.

3. Send pulses to both of the motors, making them turn toward the center.

//twoServosCenter.pde - Center two servos
#include 
Servo frontServo;
Servo rearServo; 1
void setup()
{
frontServo.attach(2);
rearServo.attach(3); 2
frontServo.write(90); 3
rearServo.write(90);
}
void loop()
{
delay(100);
}

Step 8: Screwing the Legs in Place

Now that the servos are centered, you can screw the legs into place. It’s also a good idea to attach the battery now, because the additional weight will affect the way the robot walks. However, it is not necessary to connect the battery wires to the Arduino; you can take power straight from the USB cable while you are programming and testing the device.

Step 9: Programming the Walk

Walking Forward

If you power up the Arduino running the code that swings only one servo (see the earlier “Moving the Servo” section), it will start rocking on either its front or rear legs. Walking forward will require coordination between both front and rear legs. When the servos move at the same tempo, but in opposite directions, the robot starts to walk. Here is some code that will make the robot walk forward:

Let’s have a look at the code:
1. This is the center position for the servos. Ninety degrees is precisely half of 180 possible degrees of rotation.

2. Maximum position the right front leg will rise to.

3. Maximum position the left front leg will rise to. 4. Maximum position the right rear leg will bend to. 5. Maximum position the left rear leg will bend to.

6. The moveForward function turns the servos first to opposite directions. The variables defined in the preceding lines set how far each of the servos will rotate. Before we turn in another direction, we will tell the servos to rotate toward a predefined center point for a short span of time. This ensures that the servos don’t start drifting out of sync. We return to the center point at the end of every step to make the walk more elegant and efficient.

7. Call the moveForward function repeatedly within the loop, which will make our robot move one step forward. The subsequent delay controls how long the robot waits before taking its next step. Removing the delay is the equivalent of having the robot run as fast as it can.

// walkerForward.pde - Two servo walker. Forward.<br>// (c) Kimmo Karvinen & Tero Karvinen <a href="http://BotBook.com" rel="nofollow"> http://BotBook.com
</a>
// updated - Joe Saavedra, 2010
#include 
Servo frontServo;
Servo rearServo;
int centerPos = 90; 1
int frontRightUp = 72; 2
int frontLeftUp = 108; 3
int backRightForward = 75; 4
int backLeftForward = 105;5
void moveForward() 6
{
frontServo.write(frontRightUp);

<p>rearServo.write(backLeftForward);<br>delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(65);
frontServo.write(frontLeftUp);
rearServo.write(backRightForward);
delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(65);
}
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveForward(); 7
delay(150); //time between each step taken, speed of walk
}</p>

Step 10: ​Walking Backward

When walking forward works, walking backward is easy. This time, the servos move at the same pace and in the same direction:

Let’s see what has changed from the previous code:
1. The moveBackward() function is similar to moveForward(), but this time the right front leg will rise up when the right rear leg moves forward, and the left front leg rises when the left rear leg moves forward.

2. Now moveBackward() is called in the loop() function.

// walkerBackward.pde - Two servo walker. Backward.<br>
#include <br>Servo frontServo;
Servo rearServo;
int centerPos = 90;
int frontRightUp = 72;
int frontLeftUp = 108;
int backRightForward = 75;
int backLeftForward = 105;
void moveBackward() 1
{
frontServo.write(frontRightUp);
rearServo.write(backRightForward);
delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(65);
frontServo.write(frontLeftUp);
rearServo.write(backLeftForward);
delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(65);
}
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveBackward(); 2
delay(150); //time between each step taken, speed of walk
}

Step 11: Turning Backward

Moving the robot forward and backward is not enough if we want it to avoid obstacles. The preferred outcome is for the robot to detect the obstacle, turn in another direction, and continue to walk. Naturally, it could just back up and turn after that, but the turn would be more efficient if the robot first backs up to the right and then turns to the left The robot can turn to the right as it walks backward if you alter the center point of the servo and the threshold levels a bit toward the right side. This will also change the balance of the robot, which can easily lead to one of its front legs rising higher than the other. You can solve this problem by adding a bit of movement to the lowered leg, raising it into the air:

The new moveBackRight() function is similar to the moveBack() function in
the previous example.

1. The movement of the rear servo is reduced by 6 degrees, which will move its center point to the right. As we noted earlier, the changed rear servo position will likely change the balance of the entire robot. To account for this, we add 9 degrees to the frontLeftUp value. If any of your own robot’s legs stay in the air or drag, you can increase or decrease these values as needed.

// walkerTurnBackward.pde - Two servo walker. Turn backward.
#include 
Servo frontServo;
Servo rearServo;
int centerPos = 90;
int frontRightUp = 72;
int frontLeftUp = 108;
int backRightForward = 75;
int backLeftForward = 105;
void moveBackRight() 1
{
frontServo.write(frontRightUp);
rearServo.write(backRightForward-6);
delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos-6);
delay(65);
frontServo.write(frontLeftUp+9);
rearServo.write(backLeftForward-6);
delay(125);
frontServo.write(centerPos);
rearServo.write(centerPos);
delay(65);
}
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveBackRight();
delay(150); //time between each step taken, speed of walk
}

Step 12: ​Turning Forward

A turn forward resembles otherwise normal forward walking, but now the center points of both servos are changed. The movement of one front leg must also be adjusted to keep it from rising too high.

1. Create a new variable that will define the center point of the servos during a turn (the center turn position). Notice we are 9 degrees away from the motor’s halfway point.

2. Calculate the maximum position to which the right front leg will rise by deducting 18 degrees from the center turn position.

3. Calculate the position of the left front leg in the same way as the right front leg, but instead of adding 18 degrees to the center turn position, add 36 (to balance the front legs).

4. Calculate the position for the right rear leg by deducting 15 degrees from the center turn position.

5. Add the same distance to the left rear leg.

6. The MoveTurnLeft() function is similar to all the other walks. This time, the variables just mentioned are used for turning, and both servos are centered to a different position than when walking forward.

7. Repeat turning forward in the loop and the delay to control the speed of our walk.

// walkerTurnForward.pde - Two servo walker. Turn forward.
#include 
Servo frontServo;
Servo rearServo;
int centerTurnPos = 81; 1
int frontTurnRightUp = 63; 2
int frontTurnLeftUp = 117; 3
int backTurnRightForward = 66; 4
int backTurnLeftForward = 96;5
void moveTurnLeft() 6
{
frontServo.write(frontTurnRightUp);
rearServo.write(backTurnLeftForward);
delay(125);
frontServo.write(centerTurnPos);
rearServo.write(centerTurnPos);
delay(65);
frontServo.write(frontTurnLeftUp);
rearServo.write(backTurnRightForward);
delay(125);
frontServo.write(centerTurnPos);
rearServo.write(centerTurnPos);
delay(65);
}
void setup()
{
frontServo.attach(2);
rearServo.attach(3);
}
void loop()
{
moveTurnLeft(); 7
delay(150); //time between each step taken, speed of walk
}

Step 13: Avoiding Obstacles Using Ultrasound

Attaching the Ultrasonic Sensor

Use the servo extension cable to attach the sensor. \Using hot glue, we connected the other end of the extension cable to the front of the robot with the connector part pointing down (if you’d rather have it pointing up, that will work, too). If the connector doesn’t snap in easily, you can glue the wires in place. The pin assignments are marked on top of the pins. After the glue has dried, you can snap the ultrasonic sensor into place on the connector. Connect the other end of the servo extension cable to the Arduino. The red goes to the Arduino 5V port, black to the GND port, and white to the digital pin 4. Since the Arduino does not have many free pins left, you can connect the black and red wires in the same holes as the servo cables.

Step 14: The Final Circuit

Step 15: Code

See the file below.

Because we went through the code for various turning techniques earlier, we will cover only the combination of the sketches here:

1. Declare global variables in the beginning, gathering all global variables here from previous sketches. At the same time, check that there are no conflicts with the names.

2. These functions (microsecondsToInches, microsecondsToCentimeters, and distanceCm) come from the distance sensor code.

3. Pull in functions relating to walking such as moveForward() from earlier sketches in this chapter.

4. Add all the lines from the setup() function within the new program’s setup() function. The setup code for the pin modes is identical to the previous example.

5. There is new code in the main program’s loop() function. This is the central program logic.

6. Measure a distance toward an object in front of us with the distanceCm() function.

7. Sometimes, the PING))) sensor might return an incorrect reading of 0.00. This is not uncommon for sensors of this type; however, we must compensate for these false readings with a simple filter. This if statement allows only readings above 1cm to pass through.

8. If the measured distance (distanceFront) is longer than 1cm but shorter than the declared startAvoidanceDistance, an obstacle is detected and must be avoided.

9. Avoid the obstacle by backing up and turning to the right for nine steps. The delay for walkSpeed is keeping the rhythm of our steps consistent. Then, take 11 steps forward and turn simultaneously to the left. bk. If there is no obstacle within the 20cm range, take a step forward with moveForward().

Now the insect can walk forward. It will also avoid obstacles without touching them.

Arduino All The Things! Contest

Participated in the
Arduino All The Things! Contest