14
Motors and Movement

In this chapter you will

  • Use a servo to create an analog thermometer
  • Learn how to control the speed and direction of DC electric motors
  • Learn how to control small stepper motors
  • Use an Arduino motor shield
  • Begin work on a motorized robot vehicle
  • Use simple microswitches for collision avoidance
  • Use infrared and ultrasonic distance sensors for collision avoidance

Making Small Motions with Servos

A servo (short for servomechanism) is an electric motor with a built-in sensor. It can be commanded to rotate to a specific angular position. By attaching the shaft of the servo to other machines, like wheels, gears, and levers, you can precisely control items in the external world. For example, you might use a servo to control the steering of a remote control car by connecting the servo to a horn, a small arm or bar that the servo rotates. An example of a horn is one of the hands on an analog clock. Figure 14-1 shows a servo and three types of horns.

f14001

Figure 14-1: A servo and various horns

Selecting a Servo

When you’re selecting a servo, consider several parameters:

  1. Speed The time it takes for the servo to rotate, usually measured in seconds per angular degree, revolutions per minute (RPM), or seconds per 60 degrees.
  2. Rotational range The angular range through which the servo can rotate—for example, 180 degrees (half of a full rotation) or 360 degrees (one complete rotation).
  3. Current How much current the servo draws. When using a servo with an Arduino, you may need to use an external power supply for the servo.
  4. Torque The amount of force the servo can exert when rotating. The greater the torque, the heavier the item the servo can control. The torque produced is generally proportional to the amount of current used.

The servo shown in Figure 14-1 is a generic SG90-type servo. It is inexpensive and can rotate up to 180 degrees, as shown in Figure 14-2.

f14002

Figure 14-2: Example servo rotation range

Connecting a Servo

It’s easy to connect a servo to an Arduino because it needs only three wires. If you’re using the SG90, the darkest wire connects to GND, the center wire connects to 5 V, and the lightest wire (the pulse or data wire) connects to a digital pin. If you’re using a different servo, check its data sheet for the correct wiring.

Putting a Servo to Work

Now let’s put our servo to work. In this sketch, the servo will turn through its rotational range. Connect the servo to your Arduino as described, with the pulse wire connected to digital pin 4, and then enter and upload the sketch in Listing 14-1.

// Listing 14-1

#include <Servo.h>
Servo myservo; 

void setup()
{
  myservo.attach(4); 
}

void loop()
{
    myservo.write(180);
    delay(1000);
    myservo.write(90);
    delay(1000);
    myservo.write(0);
    delay(1000);
}

Listing 14-1: Servo demonstration sketch

In this sketch, we use the Servo library, which needs to be installed. Follow the instructions outlined in Chapter 7. In the Library Manager, find and then install the “Servo by Michael Margolis, Arduino” library. Create an instance of the servo with the following:

#include <Servo.h>
Servo myservo;

Then, in void setup(), we tell the Arduino which digital pin the servo control is using:

myservo.attach(4); // control pin on digital 4

Now we simply move the servo with the following:

myservo.write(x);

Here, x is an integer between 0 and 180 representing the angular position to which the servo will be moved. When running the sketch in Listing 14-1, the servo will rotate across its maximum range, stopping at the extremes (0 degrees and 180 degrees) and at the midpoint (90 degrees). When looking at your servo, note that the 180-degree position is on the left and 0 degrees is on the right.

In addition to pushing or pulling objects, servos can be used to communicate data in a similar way as an analog gauge. For example, you could use a servo as an analog thermometer, as you’ll see in Project 37.

Project #37: Building an Analog Thermometer

Using our servo and the TMP36 temperature sensor from earlier chapters, we’ll build an analog thermometer. We’ll measure the temperature and then convert this measurement to an angle between 0 and 180 degrees to indicate a temperature between 0 and 30 degrees Celsius. The servo will rotate to the angle that matches the current temperature.

The Hardware

The required hardware is minimal:

  • One TMP36 temperature sensor
  • One breadboard
  • One small servo
  • Various connecting wires
  • Arduino and USB cable

The Schematic

The circuit is also very simple, as shown in Figure 14-3.

f14003

Figure 14-3: Schematic for Project 37

The Sketch

The sketch will determine the temperature using the same method used in Project 8 in Chapter 4. Then it will convert the temperature into an angular rotation value for the servo.

Enter and upload the following sketch:

// Project 37 - Building an Analog Thermometer

float voltage = 0;
float sensor = 0;
float currentC = 0;
int      angle = 0;

#include <Servo.h> 
Servo myservo;

void setup() 
{
  myservo.attach(4);
}
1 int calculateservo(float temperature) 
{
  float resulta;
  int resultb;
  resulta = -6 * temperature;
  resulta = resulta + 180;
  resultb = int(resulta);               
  return resultb;
}

void loop() 
{
  // read current temperature
  sensor = analogRead(0);       
  voltage = (sensor*5000)/1024; 
  voltage = voltage-500;        
  currentC = voltage/10;        

  // display current temperature on servo
 1  angle = calculateservo(currentC); 
  // convert temperature to a servo position
  if (angle>=0 && angle <=30)
  {
    myservo.write(angle); // set servo to temperature
    delay(1000); 
  }
}

Most of this sketch should be clear to you at this point, but the function calculateservo() at 1 is new. This function converts the temperature into the matching angle for the servo to use according to the following formula:

angle = (–6 × temperature) + 180

You might find it useful to make a backing sheet to show the range of temperatures that the servo will display, with a small arrow to create a realistic effect. An example is shown in Figure 14-4. You can download a printable version of the backing sheet from the book’s website: https://nostarch.com/arduino-workshop-2nd-edition/.

f14004

Figure 14-4: A backing sheet indicates the temperature on our thermometer.

Using Electric Motors

The next step in our motor-controlling journey is to work with small electric motors. Small motors are used for many applications, from small fans to toy cars to model railroads.

Selecting a Motor

As with servos, you need to consider several parameters when you’re choosing an electric motor:

  1. The operating voltage The voltage at which the motor is designed to operate. This can vary, from 3 V to more than 12 V.
  2. The current without a load The amount of current the motor uses at its operating voltage while spinning freely, without anything connected to the motor’s shaft.
  3. The stall current The amount of current used by the motor when it is trying to turn but cannot because of the load on the motor.
  4. The speed at the operating voltage The motor’s speed in RPM.

Our example will use a small, inexpensive electric motor with a speed of 8,540 RPM when running on 3 V, similar to the one shown in Figure 14-5.

f14005

Figure 14-5: Our small electric motor

To control our motor we’ll use a transistor, introduced in Chapter 3. Because our motor uses up to 0.7 A of current (more than can be passed by the BC548 transistor), we’ll use a transistor called a Darlington for this project.

The TIP120 Darlington Transistor

A Darlington transistor is nothing more than two transistors connected together. It can handle high currents and voltages. The TIP120 Darlington can pass up to 5 A of current at 60 V, which is more than enough to control our small motor. The TIP120 uses a similar schematic symbol as the BC548, as shown in Figure 14-6, but the TIP120 transistor is physically larger than the BC548.

f14006

Figure 14-6: TIP120 schematic symbol

The TIP120 uses the TO-220 housing style, as shown in Figure 14-7.

f14007

Figure 14-7: The TIP120

When you’re looking at the TIP120 from the labeled side, the pins from left to right are base (B), collector (C), and emitter (E). The metal heat sink tab is also connected to the collector.

Project #38: Controlling the Motor

In this project, we’ll control the motor by adjusting the speed.

The Hardware

The following hardware is required:

  • One small 3 V electric motor
  • One 1 kΩ resistor (R1)
  • One breadboard
  • One 1N4004 diode
  • One TIP120 Darlington transistor
  • A separate 3 V power source
  • Various connecting wires
  • Arduino and USB cable

You must use a separate power source for motors, because the Arduino cannot supply enough current for the motor in all possible situations. If the motor becomes stuck, then it will draw up to its stall current, which could be more than 1 A. That’s more than the Arduino can supply, and if it attempts to supply that much current the Arduino could be permanently damaged.

A separate battery holder is a simple solution. For a 3 V supply, a two-cell AA battery holder with flying leads will suffice, such as the one shown in Figure 14-8.

f14008

Figure 14-8: A two-cell AA battery holder

The Schematic

Assemble the circuit as shown in the schematic in Figure 14-9.

f14009

Figure 14-9: Schematic for Project 38

The Sketch

In this project, we’ll adjust the speed of the motor from stopped (zero) to the maximum and then reduce it back to zero. Enter and upload the following sketch:

// Project 38 - Controlling the Motor

void setup() 
{
  pinMode(5, OUTPUT);
}

void loop() 
{
1   for (int a=0; a<256; a++) 
  {
    analogWrite(5, a);
2     delay(100); 
  }
3   delay(5000);
4   for (int a=255; a>=0; a--)
  {
    analogWrite(5,a);
    delay(100);
  }
  delay(5000);
}

We control the speed of the motor using pulse-width modulation (as demonstrated in Project 3 in Chapter 3). Recall that we can do this only with digital pins 3, 5, 6, 9, 10, and 11. Using this method, current is applied to the motor in short bursts: the longer the burst, the faster the speed, as the motor is on more than it is off during a set period of time. So at 1, the motor speed starts at zero and increases slowly; you can control the acceleration by changing the delay value at 2. At 3, the motor is running as fast as possible and holds that speed for 5 seconds. Then, from 4, the process reverses, and the motor slows to a stop.

The diode is used in the same way it was with the relay control circuit described in Figure 3-19 on page 42 to protect the circuit. When the current is switched off from the motor, stray current exists for a brief time inside the motor’s coil and has to go somewhere. The diode allows the stray current to loop around through the coil until it dissipates as a tiny amount of heat.

Using Small Stepper Motors

Stepper motors are different from regular DC motors, in that they divide a full rotation of the motor into a fixed number of steps. They do this by using two coil windings that are independently controlled. So instead of controlling a rotation with varying voltage as with a regular DC motor, you instead turn on or off the coils in a stepper motor in a certain pattern to rotate the shaft in either direction a set number of times. This control makes steppers ideal for jobs that need precise motor positioning. They are quite commonly found in devices from computer printers to advanced manufacturing devices.

We will demonstrate stepper motor operation using the model 28BYJ-48, as shown in Figure 14-10. This type of stepper motor can be controlled to rotate to one of 4,096 positions; that is, one full rotation is divided into 4,096 steps.

f14010

Figure 14-10: A stepper motor and controller board

The board next to the motor is used as an interface between your Arduino and the stepper motor, making connection easy and fast. It is usually supplied along with the stepper motor. A close-up is shown in Figure 14-11.

f14011

Figure 14-11: The stepper motor controller board

Now to connect your stepper motor to the Arduino. Make the connections as shown in Table 14-1.

Table 14-1: Connections Between the Stepper Motor Controller Board and the Arduino

Control board pin label Arduino pin
IN1 D8
IN2 D9
IN3 D10
IN4 D11
5–12 V+ 5 V
5–12 V− GND

You can briefly run the stepper motor using power from your Arduino if nothing else is drawing power from the Arduino. However, this is not recommended. Instead, use an external 5 V power supply such as a plug pack or other convenient source. As the controller board doesn’t have a DC socket, you can use an external socket with terminal blocks to make easy, solderless connections, as shown in Figure 14-12.

f14012

Figure 14-12: DC socket terminal block

You can then connect jumper wires from the + and – connectors on the terminal blocks to those on the stepper motor controller board. To simplify controlling the stepper motor in our Arduino sketches, you can use a neat Arduino library called CheapStepper. You can download it from https://github.com/tyhenry/CheapStepper/archive/master.zip and install it using the method described in Chapter 7.

Once you have successfully installed the library and connected your stepper motor as described earlier, enter and upload Listing 14-2.

// Listing 14-2
1 #include <CheapStepper.h>
2 CheapStepper stepper (8, 9, 10, 11);
3 boolean clockwise = true;
boolean cclockwise = false;

4 void setup()
{
  stepper.setRpm(20);
  Serial.begin(9600);
}

void loop()
{
  Serial.println("stepper.moveTo (Clockwise, 0)");
5   stepper.moveTo (clockwise, 0);
  delay(1000);

  Serial.println("stepper.moveTo (Clockwise, 1024)");
5   stepper.moveTo (clockwise, 1024);
  delay(1000);

  Serial.println("stepper.moveTo (Clockwise, 2048)");
  stepper.moveTo (clockwise, 2048);
  delay(1000);

  Serial.println("stepper.moveTo (Clockwise, 3072)");
  stepper.moveTo (clockwise, 3072);
  delay(1000);

  Serial.println("stepper.moveTo (CClockwise, 512)");
5   stepper.moveTo (cclockwise, 512);
  delay(1000);

  Serial.println("stepper.moveTo (CClockwise, 1536)");
5   stepper.moveTo (cclockwise, 1536);
  delay(1000);

  Serial.println("stepper.moveTo (CClockwise, 2560)");
  stepper.moveTo (cclockwise, 2560);
  delay(1000);

  Serial.println("stepper.moveTo (CClockwise, 3584)");
  stepper.moveTo (cclockwise, 3584);
  delay(1000);
}

Listing 14-2: Testing the stepper motor

Operation of the stepper motor is quite simple. We first include the library at 1 and create an instance of the motor at 2. (If you wish to change the digital pins used for the controller board, update them here.) The control function uses true and false for clockwise and counterclockwise rotation, respectively, so we assign these to Boolean variables at 3 to make things clearer. Finally, the motor can be instructed to rotate to one of the 4,096 positions using the function:

Stepper.moveTo(direction, location);

where the direction is either clockwise or cclockwise and the location is a value between 0 and 4,095. This is done starting at 5 and repeatedly through the end of the sketch.

Furthermore, in void setup() at 4, we set the motor’s rotational speed to 20 RPM using:

stepper.setRpm(20);

This is the recommended speed for our stepper motor. Other motors will vary, so you should check with the supplier for these details.

A few moments after you upload the sketch, your stepper motor will start rotating to various positions, and you can see the commands echoed in the Serial Monitor, as shown in Figure 14-13.

f14013

Figure 14-13: Commands sent to the stepper motor

Project #39: Building and Controlling a Robot Vehicle

Although controlling the speed of one DC motor can be useful, let’s move into more interesting territory by controlling four DC motors at once and affecting their speed and direction. Our goal is to construct a four-wheeled vehicle-style robot that we’ll continue to work on in the next few chapters. Here I’ll describe the construction and basic control of our robot.

Our robot has four motors that each control one wheel, allowing it to travel at various speeds as well as rotate in place. You will be able to control the speed and direction of travel, and you will also learn how to add parts to enable collision avoidance and remote control. Once you have completed the projects in this book, you will have a solid foundation for creating your own versions of this robot and bringing your ideas to life.

The Hardware

You’ll need the following hardware :

  • Robot vehicle chassis with four DC motors and wheels
  • Four-cell AA battery holder with wired output
  • Four alkaline AA cells
  • L293D Motor Drive Shield for Arduino
  • Arduino and USB cable

The Chassis

The foundation of any robot is a solid chassis containing the motors, drivetrain, and power supply. An Arduino-powered robot also needs to have room to mount the Arduino and various external parts.

You can choose from many chassis models available on the market. To keep things simple, we’re using an inexpensive robot chassis that includes four small DC motors that operate at around 6 V DC and matching wheels, as shown in Figure 14-14.

f14014

Figure 14-14: Our robot chassis

The task of physically assembling the robot chassis will vary between models, and you may need a few basic tools such as screwdrivers and pliers. If you’re not sure about your final design but wish to get your robot moving, a favored technique is to hold the electronics to the chassis with sticky products such as Blu Tack.

The Power Supply

The motors included with the robot chassis typically operate at around 6 V DC, so we’ll use a four-cell AA battery holder to power our robot, as shown in Figure 14-15.

f14015

Figure 14-15: A battery holder for four AA cells

Some AA cell battery holders will not have the wiring needed to connect to our project and instead will have connections for a 9 V battery snap (as our unit in Figure 14-15 does). In this case, you’ll need a battery snap like the one in Figure 14-16.

f14016

Figure 14-16: A battery cable used to connect the battery holder to the Arduino

The Schematic

The final requirement is to create the circuitry to control the four motors in the chassis. Although we could use the circuitry shown in Figure 14-9 for each of the motors, this wouldn’t allow us to control the direction of the motors and could be somewhat inconvenient to wire up ourselves. Instead, we’ll use a motor shield. A motor shield contains the circuitry we need to handle the higher current drawn by the motors and accepts commands from the Arduino to control both the speed and direction of the motors. For our robot, we’ll use an L293D Motor Drive Shield for Arduino, as shown in Figure 14-17.

f14017

Figure 14-17: An L293D Motor Drive Shield for Arduino

Connecting the Motor Shield

Making the required connections to the motor shield is simple: connect the wires from the battery holder to the terminal block at the bottom left of the shield, as shown in Figure 14-18. The black wire (negative) must be on the right side and the red wire on the left.

f14018

Figure 14-18: DC power connection

Next you need to connect each DC motor to the motor shield. We’ll refer to the two DC motors at the front of the chassis as motor 2 (left) and motor 1 (right) and the two DC motors at the rear as motor 3 (left) and motor 4 (right). Each motor will have a red and a black wire, so connect them to the matching terminal blocks on the left-hand and right-hand side of the motor shield, as shown in Figure 14-19.

f14019

Figure 14-19: Connecting the motors

When connecting the wires from the DC motors, note that the black wires are on the outside ends of the terminal blocks and the red wires are on the internal ends. Furthermore, each terminal block is labeled with our matching motor number (M1, M2, M3, and M4) for easy reference.

If your motor’s wires are not color coded, you may have to swap them after the first run to determine which way is forward or backward.

After you’ve connected the power and motor wires to the shield and the shield to your Arduino, the robot should look something like the one in Figure 14-20.

f14020

Figure 14-20: Our robot is ready for action!

The Sketch

Now to get the robot moving. To simplify its operation, we first need to download and install the Arduino library for the motor drive shield. Follow the instructions outlined in Chapter 7. In the Library Manager, find and then install the “Adafruit Motor Shield library by Adafruit.”

After a moment, the Adafruit Motor Shield library v1 will appear. Click Install and wait for the library to be installed. You can then close the Library Manager window.

Now we’ll create some functions to operate our robot. Because two motors are involved, we’ll need four movements:

  • Forward motion
  • Reverse motion
  • Rotate clockwise
  • Rotate counterclockwise

Thus, we’ll need four functions in our sketch to match our four movements: goForward(), goBackward(), rotateLeft(), and rotateRight(). Each accepts a value in milliseconds, which is the length of time required to operate the movement, and a PWM value between 0 and 255. For example, to move forward for 2 seconds at full speed, we’d use goForward(255,2000).

Enter and save the following sketch (but don’t upload it just yet):

// Project 39 - Building and Controlling a Robot Vehicle
#include <AFMotor.h>

1 AF_DCMotor motor1(1); // set up instances of each motor
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

2 void goForward(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(FORWARD);
  motor2.run(FORWARD);
  motor3.run(FORWARD);
  motor4.run(FORWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

2 void goBackward(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

2 void rotateLeft(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(FORWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(FORWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

2 void rotateRight(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(BACKWARD);
  motor2.run(FORWARD);
  motor3.run(FORWARD);
  motor4.run(BACKWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void setup()
{
  delay(5000);
}

void loop()
{
  goForward(127,5000);
  delay(1000);
  rotateLeft(127,2000);
  delay(1000);
  goBackward(127,5000);
  delay(1000);
  rotateRight(127,5000);
  delay(5000);
}

Controlling the robot is easy thanks to the four custom functions in the sketch. Each custom function makes use of the library functions used to control a motor. Before you can use these functions, you need to create an instance for each motor, as shown at 1.

The direction of travel for each motor is set using:

Motor.run(direction)

The value of direction is either FORWARD, REVERSE, or RELEASE, to set the motor’s rotational direction forward or backward or cut power to the motor, respectively.

To set the speed of the motor, we use:

Motor.setSpeed(speed)

The value of speed is between 0 and 255; it is the range of PWM used to control the rotational speed of the motor.

Therefore, in each of our four custom functions at 2, we use the combination of the motor speed and directional controls to control all four motors at once. Each of the custom functions accepts two parameters: speed (our PWM value) and duration (the amount of time to run the motor).

Upload the sketch, remove the USB cable, and connect the battery cable to the Arduino power socket. Then place the robot on carpet or a clean surface and let it drive about. Experiment with the movement functions in the sketch to control your robot; this will help you become familiar with the time delays and how they relate to distance traveled.

Connecting Extra Hardware to the Robot

Some motor drive shields for Arduino may not have stacking header sockets to enable you to put another shield on top, and they might not allow easy connection of wires from sensors, etc. In this case, you should use a terminal shield for Arduino, an example of which is shown in Figure 14-21.

f14021

Figure 14-21: A terminal shield for Arduino

Terminal shields allow for easy wiring of hardware or sensors to the Arduino’s input and output pins without any soldering, and they can also be used to build your own circuitry for more permanent uses later.

Sensing Collisions

Now that our robot can move, we can start to add sensors. These will tell the robot when it has bumped into something, or they will measure the distance between the robot and an object in its path so that it can avoid a crash. We’ll use three methods of collision avoidance: microswitches, infrared, and ultrasonic.

Project #40: Detecting Robot Vehicle Collisions with a Microswitch

A microswitch can act like the simple push button we used in Chapter 4, but the microswitch component is physically larger and includes a large metal bar that serves as the actuator (see Figure 14-22).

f14022

Figure 14-22: A microswitch

When using a microswitch, you connect one wire to the bottom contact and the other to the contact labeled NO (normally open) to ensure that current flows only when the bar is pressed. We’ll mount the microswitch on the front of our robot so that when the robot hits an object, the bar will be pressed, causing current to flow and making the robot reverse direction or take another action.

The Schematic

The microswitch hardware is wired like a single push button, as shown in Figure 14-23.

f14023

Figure 14-23: Schematic for Project 40

The Sketch

We connect the microswitch to an interrupt port (digital pin 2). Although you might think we should have a function called by the interrupt to make the robot reverse for a few moments, that’s not possible, because the delay() function doesn’t operate inside functions called by interrupts. We must think a little differently in this case.

Instead, the function goForward() will turn on the motors if two conditions are met for the variables crash and the Boolean move. If crash is true, the motors will reverse at a slower speed for 2 seconds to back away from a collision situation.

We can’t use delay() because of the interrupt, so we measure the amount of time that the motors run by reading millis() at the start and comparing that against the current value of millis(). When the difference is greater than or equal to the required duration, move is set to false and the motors stop.

Enter and upload the following sketch:

// Project 40 – Detecting Robot Vehicle Collisions with a Microswitch
#include <AFMotor.h>

AF_DCMotor motor1(1); // set up instances of each motor
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

boolean crash = false;

void goBackward(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

1 void backOut()
{
  crash = true;
}

void goForward(int duration, int speed)
{
  long a, b;
  boolean move = true;
2   a = millis();
  do
  {
    if (crash == false)
    {
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
      motor3.setSpeed(speed);
      motor4.setSpeed(speed);
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      motor3.run(FORWARD);
      motor4.run(FORWARD);
    }
    if (crash == true)
    {
3       goBackward(200, 2000);
      crash = false;
    }
4     b = millis() - a;
    if (b >= duration)
    {
      move = false;
    }
  }
  while (move != false);
  // stop motors
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void setup()
{
  attachInterrupt(0, backOut, RISING);
  delay(5000);
}

void loop()
{
  goForward(5000, 127);
  delay(2000);
} 

This sketch uses an advanced method of moving forward, in that two variables are used to monitor movement while the robot is in motion. The first is the Boolean variable crash. If the robot bumps into something and activates the microswitch, then an interrupt is called, which runs the function backOut() at 1. It is here that the variable crash is changed from false to true. The second variable that is monitored is the Boolean variable move. In the function goForward(), we use millis() at 2 to calculate constantly whether the robot has finished moving for the required period of time (set by the parameter duration).

At 4, the function calculates whether the elapsed time is less than the required time, and if so, the variable move is set to true. Therefore, the robot is allowed to move forward only if it has not crashed and not run out of time. If a crash has been detected, the function goBackward() at 3 is called, at which point the robot will reverse slowly for 2 seconds and then resume as normal.

Infrared Distance Sensors

Our next method of collision avoidance uses an infrared (IR) distance sensor. This sensor bounces an infrared light signal off a surface in front of it and returns a voltage that is relative to the distance between the sensor and the surface. Infrared sensors are useful for collision detection because they are inexpensive, but they’re not ideal for exact distance measuring. We’ll use the Sharp GP2Y0A21YK0F analog sensor, shown in Figure 14-24, for our project.

f14024

Figure 14-24: The Sharp IR sensor

Wiring It Up

To wire the sensor, connect the red and black wires on the sensor to 5 V and GND, respectively, with the white wire connecting to an analog input pin on your Arduino. We’ll use analogRead() to measure the voltage returned from the sensor. The graph in Figure 14-25 shows the relationship between the distance measured and the output voltage.

f14025

Figure 14-25: Graph of IR sensor distance versus output voltage

Testing the IR Distance Sensor

Because the relationship between distance and output is not easily represented with an equation, we’ll categorize the readings into 5 cm stages. To demonstrate this, we’ll use a simple example. Connect your infrared sensor’s white lead to analog pin 0, the red lead to 5 V, and the black lead to GND. Then enter and upload the sketch shown in Listing 14-3.

// Listing 14-3

float sensor = 0;
int cm = 0;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
1   sensor = analogRead(0); 
2   if (sensor<=90)
  {
    Serial.println("Infinite distance!");
  } else if (sensor<100) // 80 cm
  {
    cm = 80;
  } else if (sensor<110) // 70 cm
  {
    cm = 70;
  } else if (sensor<118) // 60 cm
  {
    cm = 60;
  } else if (sensor<147) // 50 cm
  {
    cm = 50;
  } else if (sensor<188) // 40 cm
  {
    cm = 40;
  } else if (sensor<230) // 30 cm
  {
    cm = 30;
  } else if (sensor<302) // 25 cm
  {
    cm = 25;
  } else if (sensor<360) // 20 cm
  {
    cm = 20;
  } else if (sensor<505) // 15 cm
  {
    cm = 15;
  } else if (sensor<510) // 10 cm
  {
    cm = 10;
  } else if (sensor>=510) // too close!
  {
     Serial.println("Too close!");
  } 
  Serial.print("Distance: ");
  Serial.print(cm);
  Serial.println(" cm");
  delay(250);  
}

Listing 14-3: IR sensor demonstration sketch

The sketch reads the voltage from the IR sensor at 1 and then uses a series of if statements at 2 to choose which approximate distance is being returned. We determine the distance from the voltage returned by the sensor using two parameters. The first is the voltage-to-distance relationship, as displayed in Figure 14-25. Then, using the knowledge (from Project 6 in Chapter 4) that analogRead() returns a value between 0 and 1,023 relative to a voltage between 0 V and around 5 V, we can calculate the approximate distance returned by the sensor.

After uploading the sketch, open the Serial Monitor and experiment by moving your hand or a piece of paper at various distances from the sensor. The Serial Monitor should return the approximate distance, as shown in Figure 14-26.

f14026

Figure 14-26: Results of Listing 14-3

Project #41: Detecting Robot Vehicle Collisions with an IR Distance Sensor

Now let’s use the IR sensor with our robot vehicle instead of the microswitch. We’ll use a slightly modified version of Project 40. Instead of using an interrupt, we’ll create the function checkDistance(), which changes the variable crash to true if the distance measured by the IR sensor is around 20 cm or less. We’ll use this in the goForward() forward motion do-while loop.

The Sketch

Connect the IR sensor to your robot and then enter and upload this sketch:

// Project 41 - Detecting Robot Vehicle Collisions with an IR Distance Sensor
#include <AFMotor.h>

AF_DCMotor motor1(1); // set up instances of each motor
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);
boolean crash = false;

void goBackward(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void checkDistance()
{
1   if (analogRead(0) > 460)
  {
    crash = true;
  }
}

void goForward(int duration, int speed)
{
  long a, b;
  boolean move = true;
  a = millis();
  do
  {
    checkDistance();
    if (crash == false)
    {
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
      motor3.setSpeed(speed);
      motor4.setSpeed(speed);
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      motor3.run(FORWARD);
      motor4.run(FORWARD);
    }
    if (crash == true)
    {
      goBackward(200, 2000);
      crash = false;
    }
    b = millis() - a;
    if (b >= duration)
    {
      move = false;
    }
  }
  while (move != false);
  // stop motors
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void setup()
{
  delay(5000);
}

void loop()
{
  goForward(5000, 255);
  delay(2000);
}

This sketch operates using the same methods used in Project 40, except this version constantly takes distance measurements at 1 and sets the crash variable to true if the distance between the IR sensor and an object is less than about 20 cm.

Modifying the Sketch: Adding More Sensors

After running the robot and using this sensor, you should see the benefits of using a non-contact collision sensor. It’s simple to add more sensors to the same robot, such as sensors at the front and rear or at each corner. You should be able to add code to check each sensor in turn and make a decision based on the returned distance value.

Ultrasonic Distance Sensors

Our final method of collision avoidance uses an ultrasonic distance sensor. This sensor bounces a sound wave of an ultra-high frequency (that cannot be heard by the human ear) off a surface and measures the amount of time it takes for the sound to return to the sensor. We’ll use the common HC-SR04-type ultrasonic distance sensor, shown in Figure 14-27, for this project, because it’s inexpensive and accurate to around 2 cm.

f14027

Figure 14-27: The HC-SR04 ultrasonic distance sensor

An ultrasonic sensor’s accuracy and range mean it can measure distances between about 2 and 450 cm. However, because the sound wave needs to be reflected back to the sensor, the sensor must be angled less than 15 degrees away from the direction of travel.

Connecting the Ultrasonic Sensor

To connect the sensor, attach the Vcc (5 V) and GND leads to their connectors on the motor drive shield, attach the Trig pin to digital pin D2, and attach the Echo pin to digital pin D13. We use D2 and D13 as they are not used by the motor drive shield. However, if you’re just testing or experimenting with the sensor without the robot, you can connect the wires directly to your Arduino board.

To simplify operation of the sensor, download the Arduino library from https://github.com/Martinsos/arduino-lib-hc-sr04/archive/master.zip and install it as explained in Chapter 7. Once the library is installed, you can run the test sketch in Listing 14-4 to see how the sensor works.

// Listing 14-4
#include <HCSR04.h>
1 UltraSonicDistanceSensor HCSR04(2, 13); // trig - D2, echo - D13
2 float distance;

void setup () 
{
  Serial.begin(9600);
}

void loop () 
{
3   distance = HCSR04.measureDistanceCm();
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
  delay(500);
}

Listing 14-4: Ultrasonic sensor demonstration sketch

Retrieving the distance from the sensor is quite simple thanks to the library. At 1, we create an instance and declare which digital pins are connected to the sensor. Then at 2, we have a floating-point variable used to store the distance returned from the sensor’s library function. Finally, the distance is generated at 3 for display in the Serial Monitor.

Testing the Ultrasonic Sensor

After uploading the sketch, open the Serial Monitor and move an object toward and away from the sensor. The distance to the object should be returned in centimeters. See how it works in Figure 14-28.

f14028

Figure 14-28: Results from Listing 14-4

Project #42: Detecting Collisions with an Ultrasonic Distance Sensor

Now that you understand how the sensor works, let’s use it with our robot.

The Sketch

In the following sketch, we check for distances between the robot and an object of 5 cm or less, which will give the robot a reason to back up. Enter and upload the following sketch to see for yourself:

// Project 42 - Detecting Collisions with an Ultrasonic Distance Sensor
#include <AFMotor.h>
#include <HCSR04.h>

// set up instances of each motor
AF_DCMotor motor1(1); 
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

// set up ultrasonic sensor
UltraSonicDistanceSensor HCSR04(2, 13); // trig - D2, echo - D13

boolean crash=false;

void checkDistance()
{
  float distance;
  distance = HCSR04.measureDistanceCm();
1   if (distance < 5) // crash distance is 5 cm or less
  {
    crash = true;
  }
}

void goBackward(int speed, int duration)
{
  motor1.setSpeed(speed);
  motor2.setSpeed(speed);
  motor3.setSpeed(speed);
  motor4.setSpeed(speed);
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(duration);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void goForward(int duration, int speed)
{
  long a, b;
  boolean move = true;
  a = millis();
  do
  {
    checkDistance();
    if (crash == false)
    {
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
      motor3.setSpeed(speed);
      motor4.setSpeed(speed);
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      motor3.run(FORWARD);
      motor4.run(FORWARD);
    }
    if (crash == true)
    {
      goBackward(200, 2000);
      crash = false;
    }
    b = millis() - a;
    if (b >= duration)
    {
      move = false;
    }
  }
  while (move != false);
  // stop motors
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

void setup()
{
  delay(5000);
}

void loop()
{
  goForward(1000, 255);
}

The operation of this sketch should be quite familiar by now. Once again, we constantly measure the distance at 1 and then change the variable crash to true if the distance between the ultrasonic sensor and an object in its path is less than 5 cm. Watching the robot magically avoid colliding with things or having a battle of wits with a pet can be quite amazing.

Looking Ahead

In this chapter, you learned how to introduce your Arduino-based projects to the world of movement. Using simple motors, or pairs of motors, with a motor shield, you can create projects that can move on their own and even avoid obstacles. We used three types of sensors to demonstrate a range of accuracies and sensor costs, so you can now make decisions based on your requirements and project budget.

By now, I hope you are experiencing and enjoying the ability to design and construct such things. But it doesn’t stop here. In the next chapter, we move outdoors and harness the power of satellite navigation.

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

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