1. Autonomous Hazmat Cleanup Robot
ECET 4640 – Intro to System Engineering and Robotics
SPRING 2015
Professor:
Scott Tippens
Project Engineers:
Daniel Gavora
Christopher Hilger
Logan Isler
Submitted: April 29, 2015
2. 2 | P a g e
Table of contents
Section Title Page
1. ABSTRACT............................................................................................ 4
2. INTRODUCTION.................................................................................. 5
3. REQUIREMENT ANALYSIS.............................................................. 6
4. MATERIAL TRANSFER..................................................................... 7
5. SCHEDULING....................................................................................... 8
6. OPERATING INSTRUCTIONS.......................................................... 9
7. HARDWARE/SOFTWARE SENSORS.............................................. 10
7.1 ELECTROMAGNET…………………………………………………... 10
7.2 INFRARED SENSOR…………………………………………………. 10
7.3 COLOR SENSOR……………………………………………………… 11
8. PARTS LIST .......................................................................................... 12
9. CONCLUSION ...................................................................................... 13
10. APPENDIX............................................................................................. 14
10.1 FINAL PRODUCT .................................................................................. 14
10.2 SCHEMATIC .......................................................................................... 16
10.3 CODE....................................................................................................... 17
10.4 DATA SHEETS....................................................................................... 32
3. 3 | P a g e
Table of Figures
Figure 1. Black and red starting positions………………………………………………. 4
Table 1. Requirement’s Part Description…….……………………………………………. 5
Table 2. Requirement Analysis………………………………………………….……. 6
Figure 2. XBee S1 …………………………………………………………………... 7
Figure 3. Communication commands ……………………………………………….. 7
Figure 4. Gantt Chart…………………………………………………………………..….. 8
Figure 5. PERT chart ……………………………………………….…………………… 8
Figure 6. Power Supply………………………………………………………………….. 9
Graph 1. Magnet Strength vs Voltage……………………………………………….. 10
Figure 7. Robot Arm ………………………………………………….…………….. 10
Figure 8. Serial Monitor of the infrared sensor………………….………………………. 10
Graph 2. Distance vs voltage..….……………………………………….………….. 11
Table 3. Bills of Materials………………………………………………………….. 12
4. 4 | P a g e
1. Abstract
The purpose of the Autonomous Hazmat Cleanup Robot was to survey an industrial building’s floor to
look for hazardous material and parts by shape and color. The robot would use it’s sensors to get a grasp
of a field using the walls and looking for parts on the ground by swaying the arm in a 60 degree angle.
The pickup method has two ways by either using a robot gripper or an electromagnet. The following
components were used in the design of the product.
Arduino Uno R3
Infrared Sensor
Electromagnet
Micro Robot Gripper
Pololu DC Dual Motor Driver
Micro and Continuous Servos
The core of the Autonomous Hazmat Cleanup Robot is the Arduino Uno R3. The microcontroller is used
to control and interface all of the components listed above. The microcontroller is coded using Arduino
Software with libraries associated with each component. Our design system has three levels that is
constructed like a tower. The first levelhouses the microcontroller, battery, robot chassis, Infrared
sensor, and the wiring to connect the sensors and servos. The second level houses the robot arm,
servos, bins, and electromagnet. The third level houses the basic stamp board that contains the motor
driver and DC-DC converter.
Our robot must not exceed a 15x15 cm square, where the robot would start before cleaning the field.
Figure 1. Black and red 15x15 cm starting positions
5. 5 | P a g e
2.Introduction
What applications are hazmat robot used in?
1. Currently there are industrial robot arms that handle large hazardous containers moving and
sorting materials. There are also hazmat robots used by law enforcement to contain dangerous
hazardous used for biochemical weapons.
2. There are numerous applications where a robot is needed to secure or pick up an object that
humans can’t pick up due to sheer weight or too dangerous to touch. Most of the robots used in
such applications are manually controlled through a camera positioned near the top or front of
the robot.
For our spring 2015 Introduction to System Engineering class, we were required to design a product that
met a set of requirements and performed a useful task. The project requirements were as follows:
• Be able to pick up a black and red nut
• Also be able to pick up a black and red rod
• Storing the objects on the robot
• Be able to communicate to another robot within the field
• Transport and drop off objects to another field
As a group on three, we had to decide on a project that met these requirements and go through the
entire design process until we had a built to scale working prototype at the end of the semester. We
were chosen this design by the professor. During our planning phase we decided on the following
features to meet the project requirements:
PART DESCRIPTION
Electromagnet Pick up ferrous objects
2 Infrared Sensors Detect walls
Detect objects in the field
Micro Gripper Kit Pick up non-ferrous objects
Robot Chassis Moving around the field
Micro/Tilt Servos Moving and Tilting the robot
arm
Table 1. Part Description
So our first task was to design our project on paper until we were comfortable and then build and
cardboard model of the entire physical system, both inside and out. In building our first
cardboard prototype we learned a lot of small decisions that would help us later on in our design
phases. Ironically enough some of the things we left off of our cardboard physical model either
because we forgot or because we were not 100% sure how we wanted to implement them are all
things that gave us trouble building our actual physical model. After building our cardboard
model we went into figuring out how to operate each hardware piece of our design. Testing each
piece to make sure we had proper functionality along the way so when the time came to have all
of our moving parts put together we know each part works properly on its own and we would
only have to discover how to make them all work together. All of this took us into our design
project and while in the end our project did not work quite as we had originally planned it to, we
6. 6 | P a g e
did achieve operation of all the hardware components and learned more that we could have
imagined about not only the design process as a whole, but also group dynamics and working
together towards a common goal.
3. Requirement Analysis
We created a specific requirement analysis that meets our needs of the project before
creating our first prototype model shown in the table below.
Operational OR 1: Navigate the factory floor
OR 2: Differentiate between the chemical makeup of the parts
OR 3: Transfer objects across center barrier
OR 4: Drop off objects into bins
Environmental ER 1: Work in a natural light room
ER 2: Work indoors
ER 3: Work in a room temperature climate
User UR 1: Button Push for On/Off Manual
UR 2: Be able to lift the entire robot with ease
UR 3: Place the robot on the ground in 15cm x 15cm START square
Ship/Store SR 1: Packaged correctly for long travels
SR 2: Stored in a safe area
SR 3: Stored in a environmental controlled area
Lifecycle LR 1: Be able to reuse the robot after first use
LR 2: The robot can last for several months
LR 3: Does not break down so easily
Budget BR 1: Stay under $300
BR 2: Drive system cost only 20% of the budget
BR 3: Microcontroller cost under 15% of the budget
Table 2. Requirement Analysis
7. 7 | P a g e
4. Material Transfer
For our group, we wanted to create a list of commands that the other robot on the opposite side could
follow with ease at startup. In order to send any commands we had to decide on a platform that
communicate such commands and we chose the XBee S1 created by Digi International shown below.
Figure 2. XBee S1
The list of commands when sending and receiving would be perceived below with the robots labeled as
numbers assigned to the group number.
Figure 3. Communication commands
8. 8 | P a g e
5. Scheduling
We decided to create a Gantt chart that would illustrate the start and finish dates of the current project
shown below.
Figure 4. Gantt chart
A PERT chart is also shown for a more detailing schedule broken down into parts.
Figure 5. PERT chart
9. 9 | P a g e
6. Operating Instructions
Setup
Power Supply
The entire project is powered by two 9V batteries. The power supply is protected by a
fuse on the main Arduino board with power protection across all the wires. The power
supply must be connected to the Arduino Uno.
Figure 6. Power Supply
Operating the Project
1. Turn on the Autonomous Hazmat Cleanup Robot by plugging in the power supply to
a 9v battery.
2. Make sure to place the robot in the designated 15x15 cm before turning on the robot. The
robot will begin to scan for the objects immediately.Warning. Do not obstruct the robot’s
arm when it is swaying back and forth when scanning or it can result in permanently
damaging the robot.
Figure 7. Robot Arm
Refer to the “Board Interface” for location of the board’s reset button.
10. 10 | P a g e
7.Hardware/Software Sensors
7.1 Electromagnet
We tested the electromagnet by applying voltage. As we increased the voltage, the strength of the
magnet is increased.
Graph 1. Voltage vs strength
7.2 Infrared Sensor
For testing the infrared sensor we measured the distance by looking at the serial monitor of the Arduino
by using a simple code when the signal wire is attached to the analog port A0. We used an infrared
sensor to detect an object and when the number was close to 240, we knew that was an object and for
the ground it was near 260.
Figure 8. Serial monitor of the infrared sensor
11. 11 | P a g e
Graph 2. Distance vs voltage
7.3 Color Sensor
For the color sensor, we used the example code provided by the datasheet and we obtained
values of 0 or 2 for black and 20 to 30 for red.
12. 12 | P a g e
8. Parts List
Description Obtained Part Number Price QTY Total
LynxMotion Pan
Tilt/Servo Kit
RobotShop RB-Lyn-74 29.93 1 29.93
DFRobot Micro
Servo
RobotShop RB-Dfr-124 3.50 2 7.00
Basic Stamp
Homework Board
RadioShack -- 44.99 1 44.99
Arduino UNO R3 RadioShack -- 29.99 1 29.99
PololuDC Dual
Motor Driver
RobotShop RB-Pol-110 4.95 1 4.95
Sharp IR Sensor RobotShop RB-Dem-01 9.95 2 19.90
LynxMotion
Aluminum Bracket
RobotShop RB-Lyn-281 6.45 1 6.45
Pololu Round Robot
Chassis
RobotShop RB-Pol-46 24.40 1 24.40
Micro Gripper Kit SparkFun ROB-13176 5.95 1 5.95
DC-DC Converter Mouser OKR-T/6-W12-C 8.25 1 8.25
16-Channel Servo
Driver
Adafruit PCA-9685 14.95 1 14.95
ColorPal Color
Sensor
RobotShop RB-Plx-200 19.99 1 19.99
Raw Materials -- -- ≈20.00 ≈20.00
Shipping Costs -- -- ≈30.00 ≈30.00
Total Cost 266.75
Table 3. Bills of Materials
13. 13 | P a g e
9. Conclusion
After an entire semester of working on the group design project we came to a close
feeling of being accomplished and successful for our work. Even though in our final
demonstration of our project did not work as we wanted it to, we did have every hardware
components working and only some mechanical features kept us from a complete
operation. We had a better understanding of our Arduino and the C+ language
programming due to the project which could help us when we become proper engineers in
the near future.
The major point of failure for our project was a mechanical issue with our robot
arm component. Our main problem came into play because of the construction of the arm
which made the robot arm jitter a lot. If we had more time, we could have fixed the jitter
problem and try to integrate the XBee into our project.
17. 17 | P a g e
10.3 Code
//***************************************************************************************
// ECET 3640 - System Engineering & Intro to Robotics
// Group 2 - Logan Isler, Chris Hilger, Daniel Gavora
// DUE - April 27, 2015
//
// Description - The purpose of this code is to command the robot to inch foward
// slowly, scanning then stopping, to find an object in its path.
// When an object is determined to be blocking the robot, the arm
// will attempt to use the magnet to pick up the object. The bot will
// again try to detect an object. If no object is seen, the robot
// assumes a nut is against the magnet. If an object is detected, the
// robot will assume an aluminum spacer is under the IR sensor.
// If a nut is determined, the robot will sense the color of the object
// and drop it in its designated spot on the second tier of the bot.
// If a spacer is determined, the robot will lower its arm to pick up
// the spacer, sense it's color, and drop it in its designated
// location on the first tier of the robot.
//=======================================================================================
#include <Wire.h> // Library containing I2C setup
#include <Adafruit_PWMServoDriver.h> // Library obtained from Adafruit
Adafruit_PWMServoDriverpwm = Adafruit_PWMServoDriver();
#define Release 150 // Minimum pulse length to the grab servo
#define Engage 385 // Maximumm pulse given to the grab
#define GrabMidPoint 250
#define TiltHigh 180 // Same for the Tilt servo
18. 18 | P a g e
#define TiltLow 405 // These constants define how far the servo rotates
#define TiltMidPoint 360
#define TiltMagnet 420
#define RotateRight 300
#define RotateLeft 475
#define RotateMidPoint 383
#define BendIn 330
#define BendOut 600
#define BendMidPoint 420
#define BendMagnet 450
#define LookingNut 180
#define NotLookingNut 585
#define LookingSpacer 320
#define NotLookingSpacer 440
intservonum = 0; // This line defines the channel of the servo driver, 0-15
intpulselengrab = Engage; // These 4 integers are the initial conditions
intpulselentilt = TiltHigh; // of the 4 servos. When the Arduino boots
intpulselenrotate = RotateMidPoint; // the code, it assumes the servos are in this
intpulselenbend = BendMidPoint; // position; these are the starting positions.
intcolorPin = 5;
intcolorSwitch = 2;
int magnet = 12;
int color;
19. 19 | P a g e
int red;
intdist;
intwalldist;
intpiecefound = 0;
intpiecedist = 238;
int tracking = 0; // This int is keeping track of the times the sensor determined
// a piece is in front of the robot. This is to prevent false
// positives due to the short-comings of the playing field.
intwalldetected = 0;
intlooptracking = 0;
int motorA1 = 6;
int motorA2 = 9;
int motorB2 = 10;
int motorB1 = 11;
//***************************************************************************************
//=======================================================================================
void setup()
{
pwm.begin(); // Starts the pwm stream (defined by adafruit library)
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
Serial.begin(9600);
pinMode(colorPin, INPUT);
pinMode(colorSwitch, INPUT);
pinMode(magnet, OUTPUT);
20. 20 | P a g e
pinMode(motorA1, OUTPUT);
pinMode(motorA2, OUTPUT);
pinMode(motorB2, OUTPUT);
pinMode(motorB1, OUTPUT);
Bend(BendOut);
Tilt(TiltMidPoint);
Grab(Release);
}
//***************************************************************************************
//=======================================================================================
void loop()
{
RotateScan(RotateLeft);
Forward(400);
RotateScan(RotateRight);
Forward(400);
}
//***************************************************************************************
// Grab - a while-looping structure that either opens or closes the grabber
// Input Parameters - int grab - interger representing a pulse length
// Output Parameters - none
//=======================================================================================
void Grab(int grab)
{
servonum = 0;
while(pulselengrab< grab)
{
pwm.setPWM(servonum, 0, pulselengrab); // These functions (grab, tilt, rotate,
pulselengrab++; // and grab) are based on a looping
21. 21 | P a g e
delay(2); // structure using while loops. Basically,
} // when you pass an integer to the
while(pulselengrab> grab) // function, the servos will increase or
{ // decrease the pulse length from the
pwm.setPWM(servonum, 0, pulselengrab); // previously set pulse to the desired
pulselengrab--; // pulse. In turn, we only require one
delay(2); // function per servo.
}
return;
}
//***************************************************************************************
// Tilt - a while-looping structure that tilts the arm up or down
// Input Parameters - int tilt - interger representing a pulse length
// Output Parameters - none
//=======================================================================================
void Tilt(int tilt)
{
while(pulselentilt> tilt)
{
servonum = 1; // This while loop will take the passed
pwm.setPWM(servonum, 0, pulselentilt); // integer and compare to the currently
pulselentilt--; // set pulse length. If the pulse length
delay(12); // is bigger than the passed integer,
} // decrease the pulse length until the
while(pulselentilt< tilt) // pulse length matches the passed int.
{
servonum = 1; // Similar to the previous, but opposite.
pwm.setPWM(servonum, 0, pulselentilt);
pulselentilt++;
delay(12); // This delay yeilds smooth servo action.
}
22. 22 | P a g e
}
//***************************************************************************************
// Rotate - a while-looping structure that rotates the arm left and right
// Input Parameters - int rotate - interger representing a pulse length
// Output Parameters - none
//=======================================================================================
void Rotate(int rotate)
{
while(pulselenrotate> rotate)
{
servonum = 2;
pwm.setPWM(servonum, 0, pulselenrotate);
pulselenrotate--;
delay(12);
}
while(pulselenrotate< rotate)
{
servonum = 2;
pwm.setPWM(servonum, 0, pulselenrotate);
pulselenrotate++;
delay(12);
}
}
//***************************************************************************************
// RotateScan - a while-looping structure that rotates the arm left and right while
// simultaneously scanning for pieces
// Input Parameters - int rotate - interger representing a pulse length
// Output Parameters - none
//=======================================================================================
void RotateScan(int rotate)
{
23. 23 | P a g e
while(pulselenrotate> rotate)
{
servonum = 2;
pwm.setPWM(servonum, 0, pulselenrotate);
pulselenrotate--;
delay(12);
ObjectDetection();
WallDetection();
}
while(pulselenrotate< rotate)
{
servonum = 2;
pwm.setPWM(servonum, 0, pulselenrotate);
pulselenrotate++;
delay(12);
ObjectDetection();
WallDetection();
}
}
//***************************************************************************************
// Bend - a while-looping structure that bends the outer arm inward and outward
// Input Parameters - int bend - interger representing a pulse length
// Output Parameters - none
//=======================================================================================
void Bend(int bend)
{
while(pulselenbend> bend)
{
servonum = 3;
pwm.setPWM(servonum, 0, pulselenbend);
pulselenbend--;
24. 24 | P a g e
delay(6);
}
while(pulselenbend< bend)
{
servonum = 3;
pwm.setPWM(servonum, 0, pulselenbend);
pulselenbend++;
delay(6);
}
}
//***************************************************************************************
// ObjectDetection - Once a piece is found using RotateScan, this function is
// implemented. This function handles all piece detection and
// handling. To determine the piece, the bot will attempt to pick up
// the object with the magnet. Here, it tries to redetect the piece.
// If a piece is detected, the bot knows it picked nothing up and is
// dealing with a spacer. If nothing is detected, the bot assumes it
// is currently holding a nut with the magnet.
// Input Parameters - none
// Output Parameters - none
//=======================================================================================
void ObjectDetection()
{
dist = analogRead(A0);
if (dist>= piecedist)
{
tracking++;
if (tracking == 4) // Piece definitely found
{
tracking = 0;
Grab(Release);
25. 25 | P a g e
Reverse(1850);
digitalWrite(12, HIGH);
Bend(BendMagnet);
Tilt(TiltMagnet);
delay(1000);
Tilt(TiltMidPoint);
Bend(BendOut);
Forward(1850);
delay(500);
dist = analogRead(A0);
Serial.println(dist);
dist = analogRead(A0);
Serial.println(dist);
dist = analogRead(A0);
Serial.println(dist); // Look for piece again. If found, its a spacer.
// If nothing, a nut is against the magnet.
///////////////////////////////////////////////////////////////////////////////////////////
if (dist>piecedist)
{
digitalWrite(12, LOW); // In this case, a spacer is handled.
Bend(BendMidPoint);
Tilt(TiltLow);
Grab(Engage);
Tilt(TiltMidPoint+20);
Rotate(RotateMidPoint);
Bend(BendIn);
delay(1000);
Bend(BendMidPoint);
red = digitalRead(colorPin);
color = digitalRead(colorSwitch);
if ((red == 0 && color == 0) || (red != 0 && color != 0))
26. 26 | P a g e
{
Tilt(280);
Rotate(LookingSpacer);
Bend(BendIn-20);
Grab(Release);
Rotate(RotateMidPoint);
Tilt(TiltMidPoint);
Bend(BendOut);
}
else
{
Tilt(280);
Rotate(NotLookingSpacer);
Bend(BendIn-20);
Grab(Release);
Rotate(RotateMidPoint);
Tilt(TiltMidPoint);
Bend(BendOut);
}
}
////////////////////////////////////////////////////////////////////////////////////
else // In this case, a nut is handled.
{
Rotate(RotateMidPoint);
Tilt(TiltMidPoint);
Bend(BendIn);
Tilt(TiltMagnet-10);
Bend(BendIn-20);
delay(1000);
red = digitalRead(colorPin);
color = digitalRead(colorSwitch);
27. 27 | P a g e
Bend(BendIn);
Tilt(TiltMidPoint);
Bend(BendMidPoint);
if ((red == 0 && color == 0) || (red != 0 && color != 0))
{
Tilt(TiltHigh);
Bend(BendIn);
Rotate(LookingNut);
digitalWrite(12, LOW);
Rotate(RotateMidPoint);
Tilt(TiltMidPoint);
Bend(BendOut);
}
else
{
Tilt(TiltHigh);
Bend(BendIn);
Rotate(NotLookingNut);
digitalWrite(12, LOW);
Rotate(RotateMidPoint);
Tilt(TiltMidPoint);
Bend(BendOut);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////
else if (dist<piecedist)
{
tracking = 0;
28. 28 | P a g e
looptracking = 0;
}
return;
}
//***************************************************************************************
// WallDetection - This function determines how close we are to a wall while moving
// about the field. If we are too close to the edge, the bot will turn
// away from the wall.
// Input Parameters - none
// Output Parameters - none
//=======================================================================================
void WallDetection()
{
walldist = analogRead(A2);
if (walldist>= 630)
{
TurnLeft(3500);
}
return;
}
//***************************************************************************************
// Forward() - inches the robot forward until turned off with a ShortBreak().
// Input Parameters - int sec - the time given to move forward
// Output Parameters - none
//=======================================================================================
void Forward(int sec)
{
analogWrite(motorA2, 220); // 220 is the LOW duty cycle, meaning a 35% duty cycle
analogWrite(motorB2, 220);
digitalWrite(motorB1, HIGH);
digitalWrite(motorA1, HIGH);
29. 29 | P a g e
delay(sec);
ShortBreak(100);
}
//***************************************************************************************
// Reverse() - inches the robot backward until turned off with a ShortBreak().
// Input Parameters - int sec - the time given to reverse
// Output Parameters - none
//=======================================================================================
void Reverse(int sec)
{
analogWrite(motorA1, 220); // 220 is the LOW duty cycle, meaning a 35% duty cycle
analogWrite(motorB1, 220);
digitalWrite(motorB2, HIGH);
digitalWrite(motorA2, HIGH);
delay(sec);
ShortBreak(100);
}
//***************************************************************************************
// ShortBreak() - forces all inputs to the motor controller to a high state, causing a
// short, accurate break.
// Input Parameters - none
// Output Parameters - none
//=======================================================================================
void ShortBreak(int sec)
{
digitalWrite(motorA2, HIGH);
digitalWrite(motorB2, HIGH);
digitalWrite(motorB1, HIGH);
digitalWrite(motorA1, HIGH);
30. 30 | P a g e
delay(sec);
}
//***************************************************************************************
// TurnRight() - This function drives the right motor low and the left motor high.
// This produces a very tight turn, provding no change in the x or y
// direction.
// Input Parameters - int sec - the time given to turn the bot
// Output Parameters - none
//=======================================================================================
void TurnRight(int sec)
{
analogWrite(motorA1, 220);
analogWrite(motorB2, 220);
digitalWrite(motorA2, HIGH);
digitalWrite(motorB1, HIGH);
delay(sec);
ShortBreak(100);
}
//***************************************************************************************
// TurnLeft() - This function drives the left motor low and the right motor high.
// This produces a very tight turn, provding no change in the x or y
// direction.
// Input Parameters - int sec - the time given to turn the bot
// Output Parameters - none
//=======================================================================================
void TurnLeft(int sec)
{
analogWrite(motorA2, 220);
analogWrite(motorB1, 220);
digitalWrite(motorA1, HIGH);
31. 31 | P a g e
digitalWrite(motorB2, HIGH);
delay(sec);
ShortBreak(100);
}
//***************************************************************************************
//=======================================================================================