Chapter 5. Wally the Wall-Bot

In the previous chapter, I showed you a simple use of infrared sensors to detect the color variations of the floor surface and choose a direction accordingly. Although an IR sensing robot is autonomous, you must place a line on the ground for the bot to follow. Using a different type of sensor called an Ultrasonic range finder, you can measure distances from 6 inches to 25 feet. In this chapter, we create a robot named Wally (Figure 5-1) that uses these sensors to autonomously navigate around a room without touching anything other than the floor.

First we build a homemade motor-controller on perforated prototyping board, using N-channel and P-channel mosfets to form a dual H-bridge. We then modify the base of a dual motor toy to be controlled using the Arduino. Here you will be able to choose any robot base that you want. After selecting a base, we modify it to hold the motor-controller, Arduino, three ultra-sonic sensors, and a battery pack. After assembled and wired, we can load the code and start testing.

Wall the Wall-bot ready to go

Figure 5.1. Wall the Wall-bot ready to go

How Wally Works

Wally the wall-following robot attempts to determine the distance of a nearby wall and follow the wall to its end point. This is accomplished by using three independent ultrasonic range finding sensors to determine the distance from the robot to the wall, and adjusting the speed and direction to keep these readings within the specified range. Two of the sensors are mounted on Wally's right side—one at the front corner and the other at the rear corner, both facing the wall (right). By placing two sensors on the right side, we not only know how far Wally is from the wall, but we can determine when the two sensors are parallel to the wall.

From the sensor placement we can determine that if the front-right and rear-right sensor readings are equal, the bot is parallel with the wall. If the front-right sensor is less than the rear-right sensor, the bot is heading toward the wall. Lastly, if the front-right sensor is greater than the rear-right sensor, the bot is heading away from the wall (see Figure 5-2).

This image shows Wally heading away from the wall.

Figure 5.2. This image shows Wally heading away from the wall.

Because we want the bot to sense the wall without actually touching it, I set the desired distance to be around 8 inches from the wall. This tells Wally that if he is more than 8 inches from the wall, he needs to steer back toward the wall. If he is closer than 8 inches to the wall, he should steer away from the wall. When both right sensors are equal to 8 inches, Wally will drive straight forward until the wall path changes. The idea is to stay exactly 8 inces from the wall, using it as the path around the room.

The center sensor is used to determine when a wall ends and serves to keep Wally from hitting anything in front of him. When the front center sensor falls below 12 inches (i.e., he is approaching the corner of a room), Wally is instructed to turn left a bit and see whether the path is clear. If so, he will continue following the new wall; if not, he will keep turning until there is enough room.

The end result is a small robot that will autonomously drive around a room, staying approximately 8–10 inches from the wall. When the bot reaches a corner (inside or outside corner), he will determine which direction to turn to keep following the wall. You can add obstacles to the wall to try and confuse Wally, but when properly tweaked, he will not be fooled and will continue on his journey around your room until he runs out of battery power.

The sensors used on Wally can be any type that can calculate precise (+/− 1 inch) distance measurements from 6 inches to 5 feet. Though there are several range finders to choose from (using both IR and ultrasonic ranging), I selected some ultrasonic range finders from Maxbotics (Sparkfun part #SEN-00639) that have an built-in signal processor and output a simple Analog voltage that can be easily read by the Arduino using the analogRead(pin) command. The Analog output signal of each sensor is calibrated to centimeters, so if you want to convert the output to inches, simply divide by 2.54 (because there are 2.54 centimeters in 1 inch).

To read this sensor on your serial monitor, upload the following code to your Arduino, power the sensor with +5v and GND, and connect the Analog signal from the sensor into the Arduino A0 pin.

void setup(){
Serial.begin(9600);
}
void loop() {
int center_sensor = analogRead(0) / 2.54; // read sensor from pin A0 and convert to inches
Serial.println(center_sensor);  // displays the sensor reading in inches.
}

Though these sensors produce mostly reliable readings, it is recommended that you install a 100uF capacitor between the sensors +5v and GND to reduce glitches in the readings caused by unstable supply voltages. The capacitor acts as a small battery that supplies power to the sensor during power dips and voltage spikes, smoothing the overall operation.

The parts for Wally were mostly scavenged or homemade, with the exception of the ultrasonic sensors and the Arduino. Wally's frame came from a tank-steering toy with tracks (yes, tank tracks) from the thrift store. The term "tank-steering" refers to the use of two independent motors (one left and one right) that control both the speed and direction of the bot—there is no steering wheel on this type of drive-train. The frame does not have to have actual "tank tracks" on it (Linus was a tank-steering robot). I have found at least 10 different tank steering R/C cars at my local thrift store that work for Wally (all for under $3 each), though the gearing of the frame you choose is important. A slower moving drivetrain works better for Wally.

The motor-controller is a high-speed dual H-bridge made from 12 mosfets (8 power and 4 signal), 16 resistors, and 2 mosfet driver ICs. The mosfet drivers are simple high-speed signal buffers—they have 2 inputs, 2 outputs, VCC, and Ground. The mosfet drivers act as an amplifier for driving the low-side N-channel mosfets with a 0–100% PWM signal for full-speed control. The high-side P-channel mosfets use a small signal transistor to turn them on, but they are controlled by digital pins, not using PWM.

This simple H-bridge (x2) provides access to control all four switches of each H-bridge independently (called four-quadrant control), allowing for electric-braking (through either the high- or low-side mosfets), but incorporates no shoot-through protection so you must make sure you connect everything properly to avoid problems. Because the bridge uses a mosfet driver, you can switch the mosfets at ultrasonic PWM frequencies for silent operation (32kHz on the Arduino).

Note

Without the mosfet drivers, the H-bridge will still work, but the Arduino cannot supply the required current for such high PWM frequencies, so the switching speed is limited to around 1kHz.

Parts List for Wally

We need to order a handful of parts from an online electronics supplier, a few ultrasonic sensors from Sparkfun.com, and find a robot "base" or salvaged frame with wheels and motors (see Table 5-1). This project should work well with any tank-drive robot base.

Table 5.1. The Parts List for Wally

Part

Description

Price

(3) Ultrasonic sensors

Sparkfun (part #SEN-00639)—Maxbotics LV-EZ1 ultrasonic range finder. Range is 6 inches to 20 feet.

$25.95 ea

Frame

Thrift-store. I found a slow-moving toy with tank-steering for $3. It happens to have tank tracks (not required). Your frame should include both drive motors and all gearing. DFRobot.com (part #ROB0037).

$3.00–$41.00

Batteries

6–12v, rechargeable recommended—at least 1Ah capacity.

$5.00

Arduino

I used my Arduino MEGA, though any Arduino will work.

 

Hot-glue gun

This is not required, but makes mounting the sensors extremely easy. It is also removable without much effort for testing sensor placement.

$3.00

Aluminum bar

I used three small pieces of ⅛-inch thick x ¾-inch wide aluminum flat bar from the hardware store. Total length used is 24 inches.

$3.00

Nuts and bolts

I use #4 or #6 nuts and bolts, approximately 2 inches long, to mount the Arduino and motor-driver boards to the robot frame. These nuts/bolts are sold in 5 pcs/pack for under $1 each—I bought 2 packs.

$2.00

Power switch

Radio Shack (part #275-634). This is optional, but recommended. Simply place it in series with the positive supply from the battery. Digikey (part #EG4810).

$2.99

Male header pins

Sparkfun (part #PRT-00116) —I used these to connect the motors to the H-bridge. 40 pins per unit, I only used 6, but they are handy to have around.

$2.50

Motor-driver

This board controls both drive motors forward/reverse, with full-speed control at up to 32kHz PWM. Parts can be purchased at Digikey and Radio Shack.

 

(4) N-channel signal transistors

Digikey (part #2N7000) —These are 200ma logic-level N-channel mosfets used to interface the P-channel power mosfets. Almost any logic-level N-channel mosfet will work here.

$0.39 ea

(4) N-channel power mosfet

Digikey (part #FQP50N06L) —Any N-channel power mosfet will work. Rated for 52 amps at 60 volts.

$1.25 ea

(4) P-channel power mosfet

Digikey (part #FQP47P06) —This mosfet has a high Gate-to-Source voltage (Vgs) of +/−25v, though any P-channel power mosfet will work. Rated for 47 amps at 60 volts.

$2.26 ea

(2) TC4427 mosfet drivers

Digikey (part #TC4427) —This mosfet driver is used to switch the N-channel power mosfets at high PWM speeds (32kHz) for silent operation.

$1.33 ea

(4) 10k resistors

Digikey (part #ERD-S2TJ103V) —Sold in 10 packs for under $1. These can also be purchased at Radio Shack in a 5 pack for $0.99.

$0.78

(4) 150-ohm resistors

Digikey (part #ERD-S2TJ151V) —Sold in 10 packs for under $1. These can also be purchased at Radio Shack in a 5 pack for $0.99.

$0.78

(2) 8-pin IC sockets

Digikey (part #A24807) —These can also be purchased at Radio Shack.

$0.33 ea

(2) Female 6-pin headers

Digikey (part #3M9516) —These headers are the same type that are used on the Arduino analog A0-A5 pins, and make wiring the motor-controller to the Arduino easy.

$0.94 ea

Perforated PCB prototyping board

Radio Shack (part #276-147) or (part #276-168).

$3.99

The Motor-Controller

The motor-controller is important because without one your robot won't move. You can use any type of motor-controller that can support the motors on your bot, though I built a simple dual H-bridge on Radio Shack perforated copper-clad board with some components ordered from Digikey.com.

Wally requires forward and reverse control of each motor in order to turn fully at the end of a wall, so a full H-bridge must be used to control each motor. The simplest of solid-state H-bridges can contain as few as four transistors, but limitations in PWM frequency and heat generated from cross-conduction quickly make this type of bridge unappealing. Adding a few extra parts to the simple four-transistor H-bridge can provide a versatile and inexpensive motor-controller.

I decided to build the H-bridge for Wally to meet the following minimum criteria:

  • Continuous amperage = 5 amps

  • Voltage rating = 12vdc

  • Speed control capable (PWM)

  • Easy to build

  • Silent PWM switching speed (32kHz)

The High-Side Switches

The H-bridge uses P-channel mosfets for the high-side switches and N-channel mosfets for the low-side switches. Remember that a P-channel mosfet (like a PNP transistor) is turned on by supplying a voltage to the Gate pin that is around 5–10v below the positive supply voltage, usually Ground. To invert the signal required to turn the P-channel mosfets on, I used small N-channel signal mosfets to provide the GND supply to turn them on, whereas a 10k-ohm pull-up resistor (to V+) keeps them turned off when not used. These mosfets are intended to be controlled using a digital output pin and are not set up to be driven using a PWM signal.

The Low-Side Switches

The N-channel mosfets on the low-side of the bridge are the logic-level type and can be driven directly by the Arduino, but the 40mA supplied by the Arduino PWM pins is hardly enough to drive the mosfets at higher PWM frequencies. To remedy this, I used a mosfet driver chip that amplifies the Arduino PWM signal to supply around 2 amps to the mosfet Gate pins—that's about 100 times more current than the Arduino can supply! Because of this, the N-channel mosfets can be driven at much higher frequencies without causing any problems.

The motor-controller schematic shown in Figure 5-3 illustrates the operation of each H-bridge in the circuit. Because the circuit contains two full H-bridges, you must build two of the circuits in the schematic onto your prototyping board.

One side of the schematic for our simple H-bridge motor-controller. The complete circuit contains two of these schematics side by side, using a common V+ and GND.

Figure 5.3. One side of the schematic for our simple H-bridge motor-controller. The complete circuit contains two of these schematics side by side, using a common V+ and GND.

The mosfet driver uses the positive voltage supply from the batteries to power the N-channel mosfet Gate pins, and the voltage limit of the TC4427 mosfet driver IC is only 18v, so the maximum voltage of this circuit is 18vdc. I tested this circuit with both 6v and 12v battery packs with excellent results.

Using the parts list and circuit schematic, we can start building the motor-controller.

Building the Circuit

To get started building this dual H-bridge, you need the following materials: a soldering iron, rosin-core solder, wire, a prototyping board, two 8-pin IC sockets, two female 6-pin headers, four N-channel power mosfets, four P-channel power mosfets, and four N-channel signal mosfets. After you have the motor-controller parts together (refer to Table 5-1), the following steps guide you through the building process.

  1. Place the 8-pin IC sockets (onto the prototyping board and solder each tab): Next connect the pin 3 of each IC socket (bottom row, center right pin) together with a black wire because this is the Ground pin for each IC. Also tie the pin 6 of each IC (directly above the GND pin) to each other with a red wire because this is the V+ for each IC. I tied the two sets of wires into the center of the board between the IC sockets (see Figure 5-4).

    You should start building the H-bridge by placing the two IC sockets onto the prototyping board and connect the common V+ and GND pins of each to the center of the board.

    Figure 5.4. You should start building the H-bridge by placing the two IC sockets onto the prototyping board and connect the common V+ and GND pins of each to the center of the board.

  2. Pins 1 and 8 (the top left and bottom left pins) of the TC4427 mosfet driver IC are not internally connected to anything—there are only six active pins in this 8-pin package. To further illustrate this, I clipped the leads from pins 1 and 8 completely off to show that they are not needed (see Figure 5-5).

    The TC4427 mosfet driver IC uses six of its eight pins. To prove that they are not needed, I clipped pins 1 and 8 from the IC. If you solder these pins onto the board, they serve only as anchors to keep the chip secure.

    Figure 5.5. The TC4427 mosfet driver IC uses six of its eight pins. To prove that they are not needed, I clipped pins 1 and 8 from the IC. If you solder these pins onto the board, they serve only as anchors to keep the chip secure.

  3. Install mosfets: Repeat these instructions for each side of the motor-controller. Start by placing the N-channel power mosfets (FQP50-N06L) about 4–5 holes above the IC sockets—pin 5 (top right) of the TC4427 IC controls the lower right mosfet Gate pin, whereas pin 7 controls the lower left mosfet Gate pin. I used a 150-ohm resistor (each) between these pins and the mosfets Gate pin—these resistors are not required. Space the lower mosfets about 3–4 holes apart to give them room (you want to leave some room on the bottom to solder), as shown in Figure 5-6.

  4. Next place the P-channel power mosfets directly above the N-channel power mosfets, such that their tabs can be soldered together. The tab of a mosfet is almost always tied to the center pin (drain) of a TO-220 mosfet. By soldering the corresponding P and N channel mosfets drain tabs together, there is no need to connect the center pins of the mosfets beneath the PCB (you can even clip them off), though I soldered them to the PCB pad to help hold the mosfet in place. The motor terminal wires are soldered directly to these tabs (see Figure 5-6).

    All of the mosfets in the left H-bridge are installed—the same should be done for the right H-bridge.

    Figure 5.6. All of the mosfets in the left H-bridge are installed—the same should be done for the right H-bridge.

  5. Lastly place the N-channel signal mosfets (2n7000) above the P-channel power mosfets (FQP47-P06). The drain pin from the 2n7000 should connect to the Gate pin of the FQP47-P06, the Source pin of the 2n7000 should connect to Ground, and the Gate pin of the 2n7000 should be connected to the Arduino Input. I ran out of color coded wire, so I had to use black wire for the (4) 2n7000 connections—they are the wires going from each side of the IC sockets upward toward the 2n7000 signal mosfets in Figure 5-7.

  6. Install resistors: Remember that the mosfets have tiny capacitors inside of them that must be drained each time it is switched in order to fully turn off. This is easily done with a pull-up or pull-down resistor. Resistors can be installed any direction.

  7. The P-channel mosfets are turned off by setting the Gate pin voltage equal to the Source pin, which is connected to the positive voltage supply. So you want to place a 10k pull-up resistor from the Gate pin to the Source pin of each P-channel power mosfet. This ensures that unless turned on, these mosfets will stay off.

  8. Next install the 10k pull-down resistors to the N-channel signal mosfets (2n7000) from the Gate (center) to the Source (left), which keeps the signal mosfets off unless turned on by the Arduino.

  9. The pull-down resistors for the N-channel power mosfets are placed at the inputs of the TC4427 driver IC, from each input (pins 2 and 4) to Ground (pin 3) to ensure that they are turned off by default. Pull-down resistors at the Gate pins of the N-channel power mosfets are not necessary now that the mosfet driver IC will not leave them floating.

  10. Figure 5-7 shows where I placed the resistors on my prototyping board. The exact hole that each part goes through is not terribly important—just stick to the schematic to make sure you are connecting each part correctly. It is helpful to keep a list of the parts and their descriptions handy to reference while building. I constantly double-check the manufacturer's datasheet pinout diagrams of each part to make sure I know what pin goes where (the datasheet can usually be downloaded from the manufacturer's website).

    The top set of resistors are used to keep the P-channel power mosfets and N-channel signal mosfets turned off when not used. The bottom set of resistors are used to keep the mosfet driver IC outputs turned off unless commanded on by the Arduino.

    Figure 5.7. The top set of resistors are used to keep the P-channel power mosfets and N-channel signal mosfets turned off when not used. The bottom set of resistors are used to keep the mosfet driver IC outputs turned off unless commanded on by the Arduino.

  11. The top and bottom boxes in Figure 5-8, show where the pull-up and pull-down resistors go (all 10k ohm). The center boxes show the optional Gate resistors (150 ohm) for the N-channel power mosfets. These are not required and can be replaced with jumper wires. The bottom boxes show the TC4427 input pull-down resistors.

  12. Install headers and make connections: I used (2) 5-pin female headers from Digikey for easy connections to the motor-controller.

    • Header Pin 1 (far left): Controls the AHI (A high-side input) of each bridge, which turns on the P-channel power mosfet using the N-channel signal mosfet. This input should be connected to the Gate pin of the 2n7000.

    • Header Pin 2: Connects to the TC4427 pin 2 (IN-A), which controls the ALI (a low-side input) of each bridge. You should use a PWM signal to control this input.

    • Header Pin 3: Connects to Ground.

    • Header Pin 4: Connects to the TC4427 pin 4 (IN-B), which controls the BLI (B low-side input) of each bridge. You should use a PWM signal to control this input.

    • Header Pin 5 (far right): Controls the BHI (B high-side input) of each bridge, which turns on the P-channel power mosfet using the N-channel signal mosfet. This input should be connected to the Gate pin of the 2n7000.

After connecting the Header Pins, make common connections like the + Voltage and the Ground supply. The + Voltage wire should run from the P-channel mosfets Source pins down to the + Voltage supply of each TC4427 IC (pin 6). This supply wire should then connect to the positive battery power supply. I made some of these connections on the bottom of the board as shown in Figure 5-8. The Ground wire should connect all of the N-channel mosfets (power mosfet and signal mosfet) Source pins, as well as the Ground supply of each TC4427 IC (pin 3) —this wire can then also be connected to the negative battery power supply.

After completed, the motor-controller should look similar to Figure 5-9.

The underside of the perforated prototyping board

Figure 5.8. The underside of the perforated prototyping board

The completed dual H-bridge that will serve as the motor-controller for this project

Figure 5.9. The completed dual H-bridge that will serve as the motor-controller for this project

As you can see in Figure 5-10, using perf-board looks a bit messy because there are several wires running on the top of the board, but if each connection is soldered properly, it will work just as well as an etched PCB.

Building the Frame

Using a tank steering setup, you can control the direction of the bot by varying the speed to each motor. By powering both motors equally, the bot travels forward. To turn right, reduce the speed of the right motor. Likewise reducing the speed of the left motor forces the bot to turn left. With bi-directional control of each motor, you can turn each wheel opposing directions to achieve a zero-turn radius (meaning it can turn 360 degrees without moving forward or backwards).

To achieve this type of control, you simply need a frame with two drive wheels, one on each side of the bot. You can build your own tank steering setup with two gear motors or continuous rotation servos as we did with Linus the line-bot, or you can use a tank steering toy or robot base, like the one I was able to find at my local thrift-store. If you cannot find a frame to salvage, you might be interested in one of the several robot bases from DFRobot.com, like the RP5 mobile tank platform for a reasonable $41.00 (see Figure 5-11).

I was able to find an R/C toy with tank tracks for $3 from the thrift-store. The base of the toy was the perfect size for Wally, so I removed everything but the base of the frame with the tank treads and motors mounted inside. The top of the frame had enough room to mount the Arduino and motor-controller, whereas the bottom of the frame was large enough to mount (2) 6v rechargeable batteries.

  1. Strip frame down to motors and base: If salvaging an old toy, you can remove all of the electronics because you will build your own motor-controller and the Arduino will provide the control signals. All that is needed, is access to the terminal wires of each motor. In Figure 5-10, the battery compartment is in the center of the base and a 6-pin plug is used to connect both motors and the power supply wires to the main board.

    Here you can see the underside of the frame base, including both drive motors attached into the black gear boxes and the wiring harness.

    Figure 5.10. Here you can see the underside of the frame base, including both drive motors attached into the black gear boxes and the wiring harness.

    The DFRobot RP5 Mobile Tank Platform includes two drive motors with gearing, wheels, and tank tracks. You can easily mount your Arduino, batteries, motor-controller, and sensors to this frame.

    Figure 5.11. The DFRobot RP5 Mobile Tank Platform includes two drive motors with gearing, wheels, and tank tracks. You can easily mount your Arduino, batteries, motor-controller, and sensors to this frame.

  2. Mount the motor-controller and Arduino: used a marker to mark the mounting holes onto the frame, and a drill to make the holes. After drilling the holes, secure four bolts to hold the motor-controller and three or four bolts to hold the Arduino (three holes for a regular Arduino and four holes for the Arduino Mega). Secure a nut to each bolt with the bolts pointing upward through the frame. I had to use #8 bolts for the motor-controller board and #4 bolts for the Arduino (see Figure 5-12).

    The frame with mounting bolts installed

    Figure 5.12. The frame with mounting bolts installed

  3. Making connections: Now you can install the Arduino and motor-controller onto the bolts and wire up the Arduino to the motor-controller (see Figure 5-13). You need (4) PWM outputs and (4) digital outputs to control both bridges. Use Table 5-2 to connect each motor-controller input to the Arduino outputs, double checking each wire when you are done.

The frame base with motor-controller and Arduino mounted

Figure 5.13. The frame base with motor-controller and Arduino mounted

In the code, we will change the Arduino system timers 1 and 2 in the setup() function to allow for silent PWM switching at 32kHz. On a regular Arduino, this changes PWM outputs 9, 10, 11, and 3. On the Arduino Mega, this will change PWM outputs 9, 10, 11, and 12. The digital outputs (AHI and BHI for each bridge) can be assigned to any available pins.

You can use either board, but it does matter how you connect each bridge. That is, you must take care to connect the A High-side input (AHI), A Low-side input (ALI), B High-side input (BHI), and B Low-side input (BLI) connections for each bridge correctly, as shown in Figure 5-14. If not connected properly, the bridges can be commanded into a short circuit. Make sure you have everything connected according to the circuit schematic, and take a moment to look at Table 5-2, to make sure each connection is wired properly to the Arduino.

Table 5.2. Motor-Controller Connections to Arduino

Bridge Connection

Arduino Code

Arduino Pin

Arduino Mega Pin

Motor 2 - AHI

M2_AHI

8

8

Motor 2 - ALI (PWM)

M2_ALI

9

9

Motor 2 - BLI (PWM)

M2_BLI

10

10

Motor 2 - BHI

M2_BHI

7

7

Motor 1 - AHI

M1_AHI

2

2

Motor 1 - ALI (PWM)

M1_ALI

11

11

Motor 1 - BLI (PWM)

M1_BLI

3

12

Motor 1 - BHI

M1_BHI

4

4

Note

If using a standard Arduino, M1-BLI should connect to PWM pin 3. If using the Arduino Mega, M1-BLI should connect to PWM pin 12. The other connections are the same regardless of what board you use.

Here you can see the labels for each connection on the motor-controller. Use Table 5-2 to make these connections to the Arduino.

Figure 5.14. Here you can see the labels for each connection on the motor-controller. Use Table 5-2 to make these connections to the Arduino.

With both H-bridges connected to the Arduino as per Table 5-2, we lack connecting only the sensors and batteries to finish Wally. Let's begin by making a few mounting brackets to secure the ultrasonic range sensors to Wally's frame.

Installing the Sensors

With the bot ready to move, you now need to install the sensors to guide it along its path. Start by finding a place on the frame to mount each sensor.

Two of the ultrasonic sensors should be placed on the right side of the bot facing the wall—one mounted on the front corner of the frame and the other mounted on the rear corner. The third sensor should be placed on the rear of the bot facing forward (straight ahead), so that the bot will know when it is getting close to the end of the wall. They must be placed high enough that their view of the wall is not obstructed by anything, so you will likely need to make some mounting brackets.

I used a piece of ¾-inch wide, ⅛-inch thick aluminum flat bar to make a few mounting brackets for the sensors. I started by cutting three identical 4-inch long pieces of the aluminum flat bar. Then measure 1 inch from the end of each piece and bend at a 90-degree angle, as shown in Figure 5-15. This makes an "L" shaped bracket (1 inch x 3 inches) that is easily mounted to the frame to hold a sensor.

The side sensor brackets were made from a piece of ¾-inch wide aluminum flat bar.

Figure 5.15. The side sensor brackets were made from a piece of ¾-inch wide aluminum flat bar.

I used an all-purpose hot-glue gun to secure the sensors to the brackets and the brackets to the frame. A standard crafting hot-glue gun is an excellent tool for prototyping, because you can easily make semi-permanent connections quickly. I glued the sensor to the top of each mounting bracket as shown in Figure 5-16, and then glued the bottom of each bracket to the top of the frame deck. Remember, the side sensors should be mounted at the front and rear corners of Wally's right side, facing the wall (see Figure 5-18). The rear sensor should be mounted somewhere in the center of the bot, facing forward.

This image shows the sensor glued to the sensor bracket.

Figure 5.16. This image shows the sensor glued to the sensor bracket.

The backside of the sensor shows the labeling for each output pin (see Figure 5-17). The Analog output is the easiest pin to read with the Arduino. You need only three wires to operate each sensor: GND (pin 1), +5v (pin 2), and the Analog output, marked "AN" (pin 5). I used a 6-pin female header with long pins soldered to the sensor, then bent downward at a 90-degree angle to allow for easy mounting. Because these sensors are so lightweight, I chose to mount them to the aluminum brackets with a hot-glue gun. Just a dab of glue on the black header should securely hold the sensor to the top of the bracket. The hot-glue holds securely, but is also removable with a little prying or a razor knife.

The Maxbotics MaxSonar LV1 series ultrasonic range finder

Figure 5.17. The Maxbotics MaxSonar LV1 series ultrasonic range finder

The third sensor should be mounted to the rear of the bot, facing toward the front to prevent it from hitting anything. Because the distance that the bot will stay from the wall is determined in the code and can be changed to fit your course, exact sensor placement is usually not required. You are able to check the readings of the each sensor on the Serial monitor in the Arduino IDE, in order to calibrate the desired distances.

The manufacturer (Maxbotix) recommends installing a 100uf capacitor between the GND and +5v pins of each sensor to smooth the sensor output during any power supply dips, resulting in more accurate readings. Simply solder the capacitor terminals to the rear of the sensor. Make sure the voltage rating of the capacitor is at least double the working voltage (in this case, a 10v rating or better).

This is a photo of all three sensors installed on Wally. The two side sensors are a different model than the larger center sensor, but they are all three made by Maxbotix and have the same output pins, meaning that they are read by the Arduino in the same way.

Figure 5.18. This is a photo of all three sensors installed on Wally. The two side sensors are a different model than the larger center sensor, but they are all three made by Maxbotix and have the same output pins, meaning that they are read by the Arduino in the same way.

For the center range finder, I used a larger Maxbotics sensor (Sparkfun part #SEN-09009) that I purchased to use on a different robot—it is a nicer, all-weather version of the other two Maxbotics sensors that has a 25-foot range (about 5 feet farther than the others), but costs quite a bit more at around $100 each. Any of the Maxbotics sensors will work in the place of the center sensor.

Installing the Battery and Power Switch

With the Arduino, motor-controller, and sensors installed on the frame, you need only a power source and switch (optional) to finish the building process and start testing. You can use any type of battery pack that you have handy from 6v to 18v, because we can adjust the top speed of the PWM output in the Arduino code to limit the voltage to the motors. Because Wally will likely require some tuning to fit your setup, it is recommended that you have batteries with at least 1 Amp/Hour (1000mAH) rating or higher to allow a decent run-time before recharging.

Battery packs can be found at garage sales, thrift stores, and even clearance sections at Radio Shack and hobby stores. During a sale a few years ago, Radio Shack was clearing out its 6v–1AH NiCd battery packs commonly used in R/C cars, to replace them with the newer NiMh equivalents. For some reason, it priced each battery pack at $0.50 each including a wall charger, so I bought about 10 of them for $5.00. They have been a valuable purchase for powering various bots that I have built. I usually either arrange two packs in series to produce 12v–1Ah for higher speed, or two in parallel to produce 6v–2Ah for longer run-time at slower speeds.

You can also buy battery holders from Radio Shack (part #270-391—about $2 each) to use with standard AA or rechargeable AA batteries, that have two wire leads for you to wire into your project. The holders are wired in series, so the four AA pack produce 6v using standard 1.5v batteries, or 4.8v using rechargeable 1.2v batteries. The eight AA pack produce 12v with standard batteries or 9.6v with rechargeable batteries. Although almost any battery pack between 3v–18v will work, the voltage level of the battery pack determines Wally's overall speed. I recommend using a battery pack voltage of 6v–12v, and if you find that Wally is a bit too fast, you can adjust his top speed in the code.

I used (2) 6v–1Ah rechargeable NiCd battery packs wired in series to produce 12v for this bot. The motors have plenty of power to turn and add top-speed if needed, but is also slow enough to get accurate readings from each wall while driving.

Installing a Power Switch

A power switch is needed to easily turn off the power to the bot without removing any wires. A simple SPST switch works—just connect the positive lead from the battery to one pole of the switch and the other pole should connect to the Arduino and motor-controller power supply (see Figure 5-19). The Ground wire from the battery can be permanently connected to the Ground supply of the Arduino and motor-controller and does not need to run through a switch.

The power switch (SPST) is wired in series with the positive battery supply.

Figure 5.19. The power switch (SPST) is wired in series with the positive battery supply.

In Figure 5-19 you can see how the positive lead (red wire) from the battery connects to the switch (yellow wire), which then goes through the switch and connects to the main power supply. The negative black wire connects directly to the main ground supply. The switch is mounted at the rear of the bot (top of the picture).

With the batteries, sensors, motor-controller, and Arduino mounted to the robot base, it is time to discuss what we want Wally to do, and how to write that into the code.

The Code

In this chapter, we must control eight different Arduino output pins to command both H-bridges. To make this easier, we use a function() in the Arduino language. You can create a function that is a specific set of commands with a function name—and anytime this function name is called in the main loop, the specific set of commands will be processed.

For example, to get both motors to go forward, you have to type all of the commands in Listing 5-1, each time you want to change speed, direction, or stop.

Example 5.1. Required Code to move Forward at varying speeds

Void loop(){

  // Command motor 1 forward at speed 255
  digitalWrite(m1_AHS, LOW);
  digitalWrite(m1_BLS, LOW);
  digitalWrite(m1_BHS, HIGH);
  analogWrite(m1_ALS, 255);
 // Command motor 2 forward at speed 128
  digitalWrite(m2_AHS, LOW);
  digitalWrite(m2_BLS, LOW);
  digitalWrite(m2_BHS, HIGH);
  analogWrite(m2_ALS, 128);

 delay(1000);

  // Command motor 1 forward at speed 64
  digitalWrite(m1_AHS, LOW);
  digitalWrite(m1_BLS, LOW);
  digitalWrite(m1_BHS, HIGH);
  analogWrite(m1_ALS, 64);
 // Command motor 2 forward at speed 192
  digitalWrite(m2_AHS, LOW);
  digitalWrite(m2_BLS, LOW);
  digitalWrite(m2_BHS, HIGH);
  analogWrite(m2_ALS, 192);

  delay(1000);

}

By defining these common sets of commands into functions once using the void() declaration (see Listing 5-2), we can simply call the function name anytime we want to use that particular set of commands. This code is the same as Listing 5-1, but instead uses functions() to declare the cumbersome coding sequences once. The function() names are then called throughout the loop() as they are needed. This makes the loop() function much less cluttered, easier to read, and is also less prone to coding errors.

Example 5.2. Using Functions to Declare Coding Sequences

void loop(){
        // In the loop, we will call the function names declared below
        // Remember to include a speed value into the parentheses for int x or int y.
        m1_forward(255); // drive motor 1 forward at full speed of 255
        m2_forward(128); // drive motor 2 forward at half speed of 128

        delay(1000);

        m1_forward(64); // drive motor 1 forward at full speed of 64
        m2_forward(192); // drive motor 2 forward at half speed of 192

        delay(1000);

}

// motor functions
void m1_forward(int x){
  digitalWrite(m1_AHS, LOW);
  digitalWrite(m1_BLS, LOW);
  digitalWrite(m1_BHS, HIGH);
  analogWrite(m1_ALS, x);
}
void m2_forward(int y){
  digitalWrite(m2_AHS, LOW);
  digitalWrite(m2_BLS, LOW);
  digitalWrite(m2_BHS, HIGH);
  analogWrite(m2_ALS, y);
}

Just remember that you must call the function each time you want to use it—simply declaring the function does not cause it to be used. I have declared several functions in this sketch to define repetitive actions like commanding each motor separately to go forward, reverse, or stop. Each function is declared separately at the end of the sketch (placement of the function declaration does not matter).

You will notice that there is a number in parentheses after the forward or reverse commands, this is called an argument. The argument is used to declare the PWM speed that you want the motors to receive (defined by the variables "int x" and "int y" in the motor functions below the loop). The number can be between 0 (stopped) to 255 (full-speed) PWM range. The stop command for each motor does not require a number in the parentheses because stopping does not have a speed.

There are also several "if/else" conditional statements used in this code to test the sensor readings against the defined threshold values. The code can look confusing, but I tried to explain each line so you can figure out what is happening as you read through it.

Code Objectives

Wally's main goal is to keep his right side parallel with the wall, while traveling around the room. If one of the side sensors reads higher or lower than the other, the code will adjust the outputs of each motor to correct his position and make the sensor readings equal again. The third center sensor is used to "keep an eye on the road" and make sure he doesn't accidentally hit anything. If the center sensor reading falls below a set threshold, Wally will turn left and continue along the next wall. Wally's course is adjusted by reducing the power to the motor in the direction you want him to turn. I mentioned that if you power both motors equally (M1 and M2), the bot will travel in a straight line. If you want to turn left, reduce the power to (or stop) the left motor (M1) and Wally will turn left; if you want to turn right, reduce the power to (or stop) the right motor (M2).

In Figure 5-20, Wally is heading toward the wall—when the front-right sensor reads 7 inches and the back-right sensor reads 9 inches, Wally knows that he is no longer parallel to the wall and should reduce the power to M1 while applying full power to M2 to correct his orientation.

When Wally is not parallel to the wall, his side sensor readings will not be equal and he will attempt to correct his position.

Figure 5.20. When Wally is not parallel to the wall, his side sensor readings will not be equal and he will attempt to correct his position.

To keep the side sensor readings equal, pick a range in which to travel. We do this by selecting a minimum and maximum threshold. The minimum threshold determines when the bot is too close to the wall and should move away. Likewise the maximum threshold determines when the bot is too far away from the wall and should return. In Figure 5-21, I chose 8 inches as the lower threshold and 10 inches as the upper threshold (leaving a 2-inch padding). This tells Wally that if both of his side sensors are within this range, go straight ahead, and if either of the two side sensors are out of this range (either above or below) check and correct this error by adjusting the motors.

This means that Wally has a 2-inch padding to compensate for irregularities in the wall and still continue straight. If he wanders outside this 2-inch padding zone, the Arduino will correct his position until both of his right-side sensors are between 8 and 10 inches from the wall. You can adjust the lower and upper limits for the right sensors from 8 and 10 to whatever you want; they can even be the same if you want a tight tolerance with no padding.

The center sensor is used to determine when Wally is approaching the end of a wall, and prevents him from running into it. As long as the center sensor reading is above the threshold (in this case, 12 inches), the Arduino will use the right-side sensors to adjust the motor output and keep Wally on track. If the center sensor falls below the threshold, Wally will stop, turn left, and then continue following the next wall (see Figure 5-21). If the wall is an outside corner, when Wally's side sensors reach the corner of the wall, they will instruct him to turn right and continue following the wall.

Ideally, Wally would travel parallel to the wall with his side sensors both within the shaded line (8–10 inches from wall) while traveling forward. Realistically, small bumps in the drive-train and irregularities in the walls cause his path to be somewhat less than a perfectly straight line. But after some tweaking, Wally is able to maneuver around most of the house without assistance (or touching any walls).

Wally will stop when the center sensor falls below its threshold; I tested Wally with a center threshold between 12–20 inches.

Figure 5.21. Wally will stop when the center sensor falls below its threshold; I tested Wally with a center threshold between 12–20 inches.

Now that we understand how Wally should work, let's upload the code.

Uploading the code in Listing 5-3 provides the code to use with the standard Arduino. If you use the Arduino Mega, change "m1_BLS 3" to "m1_BLI 12, and use Table 5-2 to make sure that you have the H-bridge connected properly before proceeding.

Example 5.3. The Main Code for Wally

// Wally the wall-bot.
// Follow a right-hand wall and traverse obstacles, using 3 ultrasonic sensors
// Connect Maxbotics ultrasonic sensors to Arduino analog inputs A0, A1, and A2.
// H-bridge motor pins are listed below and shown in Figure 5-14

// create variables for each sensor reading
int front_right_sensor = 0;
int back_right_sensor = 0;
int center_sensor = 0;
// define pins for motor 1

int m1_AHI = 2;
int m1_ALI = 11;
int m1_BLI = 3;   // 12 on Ardiuno Mega
int m1_BHI = 4;

// define pins for motor 2
int m2_AHI = 8;
int m2_ALI = 9;
int m2_BLI = 10;
int m2_BHI = 7;

// variables to hold upper and lower limits
int threshold = 20;  // Use this to adjust the center sensor threshold.
int right_upper_limit = 10; // Use this to adjust the upper right sensor limit.
int right_lower_limit = 8;  // Use this to adjust the lower right sensor limit.

// speed variables
int speed1 = 64;  // setting for 1/4 speed
int speed2 = 128; // setting for 1/2 speed
int speed3 = 192; // setting for 3/4 speed
int speed4 = 255; // setting for full speed

// end of variables

void setup(){

  // change the PWM frequency for Timer 1 of Arduino
  // pins 9 & 10 on standard Arduino or pins 11 and 12 on Arduino Mega
  TCCR1B = TCCR1B & 0b11111000 | 0x01;
  // change the PWM frequency for Timer 2 of Arduino
  // pins 3 & 11 on standard Arduino or pins 9 & 10 on Arduino Mega
  TCCR2B = TCCR2B & 0b11111000 | 0x01;

  Serial.begin(9600);

  // set motor pins as outputs

  pinMode(m1_AHI, OUTPUT);
  pinMode(m1_ALI, OUTPUT);
  pinMode(m1_BHI, OUTPUT);
  pinMode(m1_BLI, OUTPUT);

  pinMode(m2_AHI, OUTPUT);
  pinMode(m2_ALI, OUTPUT);
  pinMode(m2_BHI, OUTPUT);
  pinMode(m2_BLI, OUTPUT);

}
void gather(){

  // function for updating all sensor values
  // Divide each sensor by 2.54 to get the reading in Inches.
  back_right_sensor = analogRead(0) / 2.54;
  front_right_sensor = analogRead(1) / 2.54;
  center_sensor = analogRead(2) / 2.54;
}

void loop(){

  gather();  // call function to update sensors

  // first, check to see if the center sensor is above its threshold:
  if (center_sensor > threshold) {

    // is the Front Right Sensor (FRS) below the lower threshold value?
    if (front_right_sensor < right_lower_limit){
      // if so, check to see if the Back Right Sensor (BRS) is also below lower threshold:
      if (back_right_sensor < right_lower_limit){
        // Wally is too close to wall, go back:
        m1_stop();
        m2_forward(speed3);
      }
      // otherwise, see if BRS is above the upper threshold:
      else if (back_right_sensor > right_upper_limit){
        // Wally is heading toward wall - correct this:
        m1_stop();
        m2_forward(speed3);
      }
      // (else) If BRS is not above upper threshold or below lower threshold, it must be
The Main Code for Wally
within range: else{ // Wally is just slightly off track, make minor adjustment away from wall: m1_forward(speed2); m2_forward(speed3); } } // else, if FRS is not below the lower threshold, see if it is above the upper threshold: else if (front_right_sensor > right_upper_limit){ // FRS is above upper threshold, make sure it can still detect a wall nearby (use
The Main Code for Wally
center sensor threshold value): if (front_right_sensor > threshold){ // Wally might be reading an outside corner wall, check BRS: if (back_right_sensor < right_upper_limit){ // If BRS is still within range, make minor adjustment: m1_forward(speed3); m2_forward(speed2); } // Otherwise, check to see if BRS is also above the threshold: else if (back_right_sensor > threshold){
// Wally has found an outside corner! Turn right:
          m1_forward(speed4);
          m2_reverse(speed1);
        }
      }
      // FRS is above upper threshold, see if BRS is below lower threshold:
      else if (back_right_sensor < right_lower_limit){
        // if so, bring Wally back toward the wall
        m1_forward(speed3);
        m2_forward(speed1);
      }
      // if not, check to see if BRS is also above the upper threshold:
      else if (back_right_sensor > right_upper_limit){
        // if so, bring Wally back towards wall:
        m1_forward(speed2);
        m2_stop();
      }
      // Otherwise,
      else{
        // else, make minor adjustments to bring Wally back on track
        m1_forward(speed3);
        m2_forward(speed2);
      }
    }

    // else; FRS is within both side thresholds, so we can proceed to check the BRS.
    else {
      // see if BRS is above the upper threshold:
      if (back_right_sensor > right_upper_limit){
        // is so, make adjusment:
        m1_forward(speed1);
        m2_forward(speed3);
      }
      // if BRS is within upper threshold, check to see if it is below lower threshold:
      else if (back_right_sensor < right_lower_limit) {
        // if so, make opposite adjustment:
        m1_forward(speed3);
        m2_forward(speed1);
      }
      // otherwise, BOTH side sensors are within range:
      else {
        // So drive straight ahead!
        m1_forward(speed2);
        m2_forward(speed2);
      }
    }

  }

  // If center sensor is not above the upper threshold, it must be below it, time to STOP!
  else {
    // If center sensor is BELOW threshold, turn left and re-evaluate walls
// Stop Wally
    m1_stop();
    m2_stop();
    delay(200);
    // Turn Wally left (for 500 milliseconds)
    m1_reverse(speed4);
    m2_forward(speed4);
    delay(500);
    // Stop again
    m1_stop();
    m2_stop();
    delay(200);
  }

  // Now print sensor values on the Serial monitor
  Serial.print(back_right_sensor);
  Serial.print("          ");
  Serial.print(front_right_sensor);
  Serial.print("          ");
  Serial.print(center_sensor);
  Serial.println("          ");

  // End of loop

}


// Create functions for motor-controller actions

void m1_reverse(int x){
  // function for motor 1 reverse
  digitalWrite(m1_BHI, LOW);
  digitalWrite(m1_ALI, LOW);
  digitalWrite(m1_AHI, HIGH);
  analogWrite(m1_BLI, x);
}


void m1_forward(int x){
  // function for motor 1 forward
  digitalWrite(m1_AHI, LOW);
  digitalWrite(m1_BLI, LOW);
  digitalWrite(m1_BHI, HIGH);
  analogWrite(m1_ALI, x);
}


void m1_stop(){
  // function for motor 1 stop
  digitalWrite(m1_ALI, LOW);
  digitalWrite(m1_BLI, LOW);
digitalWrite(m1_AHI, HIGH); // electric brake using high-side fets
  digitalWrite(m1_BHI, HIGH); // electric brake using high-side fets
}


void m2_forward(int y){
  // function for motor 2 forward
  digitalWrite(m2_AHI, LOW);
  digitalWrite(m2_BLI, LOW);
  digitalWrite(m2_BHI, HIGH);
  analogWrite(m2_ALI, y);
}


void m2_reverse(int y){
  // function for motor 2 reverse
  digitalWrite(m2_BHI, LOW);
  digitalWrite(m2_ALI, LOW);
  digitalWrite(m2_AHI, HIGH);
  analogWrite(m2_BLI, y);
}


void m2_stop(){
  // function for motor 2 stop
  digitalWrite(m2_ALI, LOW);
  digitalWrite(m2_BLI, LOW);
  digitalWrite(m2_AHI, HIGH);  // electric brake using high-side fets
  digitalWrite(m2_BHI, HIGH);  // electric brake using high-side fets
}


void motors_release(){
  // function to release both motors (no electric brake)
  // release all motors by opening every switch. The bot will coast or roll if on a hill.
  digitalWrite(m1_AHI, LOW);
  digitalWrite(m1_ALI, LOW);
  digitalWrite(m1_BHI, LOW);
  digitalWrite(m1_BLI, LOW);

  digitalWrite(m2_AHI, LOW);
  digitalWrite(m2_ALI, LOW);
  digitalWrite(m2_BHI, LOW);
  digitalWrite(m2_BLI, LOW);
}

After loading the code onto your Arduino, and double-checking all of your connections to the H-bridge and sensors, power on your bot and place it near a wall. If all the sensors are connected properly and the motors are spinning in the correct direction, the bot should start following the wall.

I verified that it would stay the set distance from the wall by letting it follow a long (15 foot) wall with no obstructions. After completing a few runs without any issues, I began adding some obstacles for it to traverse. A box or piece of wood placed perpendicular to the wall forces Wally to stop and go around the obstacle, staying the set distance from the obstacle as it does from the wall. The size, shape, and thickness of the obstacles determines how well the ultrasonic sensors will be able to "see" them and react properly.

You can adjust the threshold settings and speeds to tweak your wall-bot for varying motor speed, battery voltage, and turn radius to get it working the way you want. See Listing 5-4 for a list of the variables that can be adjusted to Wally's performance.

Example 5.4. Variables that Can Be Changed During Testing

// variables to hold upper and lower limits
int threshold = 20;  // Use this to adjust the center sensor threshold.
int right_upper_limit = 10; // Use this to adjust the upper right sensor limit.
int right_lower_limit = 8;  // Use this to adjust the lower right sensor limit.

// speed variables
int speed1 = 64;  // setting for 1/4 speed
int speed2 = 128; // setting for 1/2 speed
int speed3 = 192; // setting for 3/4 speed
int speed4 = 255; // setting for full speed

The speed variables are simply there to provide several options to play with when testing. You can change these throughout the code (or insert your own speed values to test 0-255). To see the readings from Wally's sensors, plug him into your PC and hold him next to a wall.

Summary

In this chapter, we used ultrasonic range finders to detect nearby objects and avoid hitting them, while the robot travels around a room. Because most rooms have walls, I decided to use the wall as a guide for the robot to use. Using the three sensors strategically mounted around the robot frame, we are able to detect objects to the right and in front of the robot.

To save some money on parts, I went on a salvage trip to the local thrift store and found an old robotic toy with tank tracks on its base. I bought the toy, removed the top, stripped out the electronics, and began prepping it for my own electronics. If you cannot find a second-hand toy that will work, there are several robot bases available online including one that is a perfect substitute for the base used on Wally—DFRobot.com (part #ROB0037).

We built our own dual H-bridge motor-controller on perforated prototyping board, which receives its commands from the Arduino. The motor-controller requires several component parts from Digikey.com and some patience for assembly. After completed, we mounted the motor-controller and Arduino on the base using several small nuts and bolts. We then wired each connection from the motor-controller to the Arduino according to Table 5-2, double-checking each connection.

The sensor brackets were made from ¾-inch wide aluminum flat bar, and attached to the frame using glue. The sensors were glued to the top of each mounting bracket, and then wired to the Arduino analog inputs (A0, A1, and A2). Lastly, we installed the power switch and battery pack to the base of the frame.

In the next chapter, we discuss the process of designing circuits on your computer using (freeware) CAD software, and then make printed circuit boards from your designs at home in your back yard! All you need is a clothes iron, some basic chemicals, access to a laser printer, and some magazine paper, and you can have long-lasting circuit boards that are easy to replicate and can be custom tailored to any project. We also learn how to build our very own Arduino-compatible programming boards to use in future projects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset