You are on page 1of 116

Team E3 Robot Project Report

Engineering 1282.01H

Spring 2022

Keenan Darkins

Ayham Huq

Declan O’Brien

Leo Zhang

Instructor: Paul Clingan MWF 12:40PM


Table of Contents

List of Figures 1

List of Tables 3

Executive Summary 4
1. Introduction 5
1.1 The Problem 5
1.2 Outline 5

2. Preliminary Concepts & Ideas 6


2.1 Project Requirements and Constraints 6
2.2 Initial Brainstorming 7
2.2.1 Chassis 8
2.2.2 Drivetrain 9
2.2.3 Mechanisms for Accomplishing Tasks 10
2.2.4 Path 12
2.2.5 Coding Ideas 14

3. Analysis, Testing, and Refinements 14


3.1 Performance Test 1 14
3.1.1 Building the First Model 15
3.1.2 Testing and Refinements 18
3.1.3 Results 19
3.2 Performance Test 2 19
3.2.1 Building the Second Model 20
3.2.2 Testing and Refinements 21
3.2.3 Results 22
3.3 Performance Test 3 22
3.3.1 Building the Third Model 22
3.3.2 Testing and Refinements 23
3.3.3 Results 24
3.4 Performance Test 4 24
3.4.1 Building the Fourth Model 25
3.4.2 Testing and Refinements 25
3.4.3 Results 26

4. Individual Competition 26
4.1 Testing and Refinements 26
4.2 Structure and Strategy 28
4.3 Results 29
4.4 Analysis 29

5. Final Design 31
5.1 Strengths and Weaknesses 32
5.2 Budget 36
5.3 Final Schedule and Times 38
5.4 Final Code 39
5.5 Electrical Representation 41

6. Final Competition 42
6.1 Testing and Refinements 42
6.2 Structure and Strategy 43
6.3 Results 44
6.4 Analysis 46

7. Summary and Conclusions 46


7.1 Errors 48
7.2 Possible Improvements 50

References 52

APPENDIX A - SolidWorks Models A1

APPENDIX B - Decision Matrices B1

APPENDIX C - Equations C1

APPENDIX D - Additional Pictures of Robot D1

APPENDIX E - Testing Logs E1

APPENDIX F - Budget F1

APPENDIX G - Design Schedule G1

APPENDIX H - Code H1

APPENDIX I - Code Representation I1

APPENDIX J - Symbols J1
List of Figures

Figure Number Figure Description Page

1 Sketch of the initial design concept the team 6


chose.

2 Hollow Box for Chassis 8

3 AWD drivetrain from mock-up 9

4 Contracting arm with squares to represent 10


servos.

5 Preliminary Solid Works Model 11

6 The preferred order in which to accomplish the 12


tasks

7 The alternative order in which to accomplish 12


the tasks

8 Speed-torque graph for drivetrain analysis 16

9 Model that Completed Performance Test 1 17

10 Model that completed Performance Test 2 20

11 Model that completed Performance Test 3 22

12 Model that completed Performance Test 4 24

13 Model that completed Individual Competition 27

14 Pennies used as balance were placed on the 31


inside

15 Final Design of the Robot 32

16 The bottom of the Final Design 32

17 Skid that was used on the robot 33

18 Upright positioning of the proteus 34

19 Biggest flaw of having a single mechanism 35


design.

1
20 Inconsistent shaft encoding and RPS checks led 36
to task failures

21 SolidWorks drawing of the chassis 37

22 Budget Allocation to different parts of the robot 38

23 Remaining budget over time 38

24 move_straight method with time failsafe 40

25 Block diagram of electrical system 42

26 The crevice that caught the lever 43

27 Round Robin run 3 45

28 The arm of the robot 49

2
List of Tables

Table Number Figure Description Page

1 Chassis decision matrix 8

2 Drivetrain decision matrix 10

3 Total Time by Member 39

3
Executive Summary

Due to a recent increase in customers, Carmen’s Diner is looking for an automated way to

do simple tasks so human employers can focus on maintaining a friendly atmosphere. They

tasked the OSU Research and Development team to create automated robots that can return used

trays, slide order tickets, flip burgers, fill ice-cream cones, and turn on music. This report details

the process, final product, and results of competition of one said prototype.

On this specific prototype, the chassis, skid, and arm were all made of aluminum. The

only parts that were not aluminum were the QR code holder, which was made of erector set

pieces, the popsicle stick bumper in the front, and the wheels that were part of the two-wheel

drivetrain with IGWAN motors.

This model only had one arm, and this arm was able to complete most of the tasks by

raising the arm up and down. The popsicle stick bumper did the task that the arm wasn’t able to

do, namely pressing the correct jukebox button. This prototype prioritized versatility over

anything else in an effort to save money for Carmen’s Diner; ⅓ of the allotted budget was saved.

Although the multifunctional arm did save money, the efficacy and consistency of the

model was compromised. The robot was capable of doing every task, as determined through

testing, but it struggled with doing a few tasks consistently, namely flipping the burger and filling

the ice-cream cones. This prototype was able to secure a few perfect runs during testing, but it

did not perform as well during the official competitions.

Some improvements that could be made include using a different material such that the

robot is lighter and can maneuver around better. The arm could be redesigned to face the

opposite direction as that would greatly improve the consistency of the burger flip task. Finally,

specific mechanisms can be created for each task to make sure each can be done consistently.

4
1. Introduction

1.1 The Problem

The recent influx of customers into Carmen’s Diner required management to implement

robots to execute simple, repeatable tasks, such as turning on a jukebox, dropping off dirty trays

in the sink, moving order tickets, flipping burgers, and filling ice cream cones [1]. This

automation would allow the human staff to perform tasks that require more customer interaction

to maintain the “Friends Eat Here” atmosphere upon which the diner prides itself. Management

has contracted the OSU Research and Development (OSURED) team to design, build, and test

various prototypes to fulfill these requirements. The following report outlines one such prototype

designed, built, and tested by a sub-team of OSURED, Team E3, which consists of Keenan

Darkins, Ayham Huq, Declan O’Brien, and Leo Zhang, from February 4th to April 25th, 2022.

Some key dates within this two and a half month time frame include the four

performance tests and the two competition dates. Performance Test 1 was on February 25th,

Performance Test 2 was on March 4th, Performance Test 3 was on March 11th and Performance

Test 4 was on March 25th. The Individual Competition took place on April 1st, and the Final

Competition took place about a week later on April 9th.

1.2 Outline

The Preliminary Concepts & Ideas section following this introduction outlines the project

requirements and restraints. It also contains the decisions the team made regarding the chassis,

drivetrain, and path taken along the course. The Analysis, Testing, and Refinements section

details how the team used the mockup and the drivetrain analysis to determine the best choices

for the initial design. It also addresses the challenges, testing, and results of each performance

5
test. The Individual Competition section discusses some basic logistics of the Individual

Competition including the date and time. It talks about the team’s strategy, the results, and the

changes made to improve the robot following the competition.

The Final Design section explains the final model of the prototype made by the team. It

talks about the chassis, mechanisms, drivetrain, final budget, final schedule, and final code. The

Final Competition section resembles the Individual Competition section; it starts by giving some

basic logistics about the competition and follows with an analysis of the team’s strategy and

results. Finally, the Summary and Conclusions section gives a brief overview of the entire report,

discusses errors that the team made throughout the project, and offers improvements that could

be made with more time.

2. Preliminary Concepts & Ideas

2.1 Project Requirements and Constraints

While brainstorming ideas for the initial robot design, the team had to keep a few

requirements and restraints in mind. One of the most important constraints was the size

constraint. The robot, in its starting configuration, had to fit within a 9” by 9” box and could not

be taller than 12” [1]. It was important for the team to consider this size restraint as they

considered various ideas as the robot would not be able to compete if it was too big. Another

constraint was the time constraint; the self-propelled robot had to be able to complete the course

within two minutes. Therefore, the team had to consider the speed of the robot while

brainstorming different ideas for the drivetrain. The budget was also a restraint that had to be

kept in mind while brainstorming different mechanisms and drivetrains. The team was allotted

6
$160 to spend in the FEH Store. Spending more than this budget would result in a point

deduction, and spending less than this threshold meant earning bonus points. Thus, while

brainstorming ideas, the team wanted to save as much money as possible. Finally, the team had

to consider where the required QR code would be mounted onto the robot. The QR code had to

be mounted on the robot such that it was around 9” above the rest of course. On the mockup, the

team failed to consider this requirement, but the team was able to correct this error on the initial

design.

2.2 Initial Brainstorming

The initial idea for the robot design included a hollow box with a grabbing arm to

complete every task and four wheel drive, shown in the sketch in Figure 1.

Figure 1: Sketch of the initial design concept the team chose.

However, the design needed further refinements throughout the building process.

7
2.2.1 Chassis

The chassis options included a solid box with an indentation in which to place the

Proteus, a hollow box to reduce weight and increase the overall volume of the chassis, and a

ladder shaped chassis to accommodate for the various mechanisms to complete the tasks.

Selection for the chassis was made based on the following criterion: shape, stability, weight, and

area. Weight and area were given the highest preference.

Given this criteria, a hollow box was chosen due to its low weight and high

stability/weight distribution. The hollow box was to have a shell to allow the Proteus to sit and a

flat platform for the arm mechanism. Table 1 shows the decision matrix used to select this

hollow box chassis. The chassis is shown below in Figure 2. See Appendix A for the SolidWorks

model of not only the chassis, but the whole prototype.

Table 1: Chassis decision matrix


CHASSIS Weight Solid box Ladder-shaped idea Hollow Hollow Triangle
box
Shape 1 3 2 2 1
Stability 3 3 2 3 2
Weight 3 1 3 2 3
Size/Area 2 2 2 3 2
Total 19 19 23 20

8
Figure 2: Hollow box for chassis

2.2.2 Drivetrain

The initial design concepts for the drivetrain included four wheels with rear wheel drive,

four wheels with all wheel drive, treads, and 3 wheels with rear wheel drive. The most important

criteria for selecting a drive train mechanism were traction, cost, turning, replaceability of parts,

and balance.

After applying decision matrices based on these concepts and selection criteria, the team

determined that treads were the weakest mechanism due to their low ability to turn and difficulty

of replacement. While the three wheel-based concepts all resulted in similar scores in the

decision matrix, the team determined that the best overall drive train mechanism was four wheels

with all wheel drive because, while it did increase the cost, it also increased the robot’s turning

ability, and the turning ability weighed more in the decision matrix than the cost. The drivetrain

is represented below in Figure 3, and Table 2 shows the decision matrix used to come to this

decision.

9
Table 2: Drivetrain decision matrix
DRIVETRAIN Weight Four wheels: RWD Four wheels: AWD Treads 3 wheels RWD
Traction 3 3 3 2 2
Cost 1 2 1 1 3
Turning 3 2 3 1 3
Replaceability 2 2 2 1 3
Balance 3 3 3 3 2
Total 30 32 21 30

Figure 3: AWD drivetrain from mock-up

2.2.3 Mechanisms for Accomplishing Tasks

Various mechanisms for completing the tasks were considered. Primarily, thought was

given to the versatility of the mechanisms: how well they could perform each of the tasks

individually and how well they could perform other tasks as well. The majority of mechanisms

thought of were initially brainstormed to apply to nearly every single task. The selection was

chosen based on versatility, accuracy, and complexity with versatility and accuracy given the

highest weight.

10
Ultimately, the most prominent mechanisms chosen included a forklift and a contracting

arm. The forklift would complete the tasks with a servo moving it up and down with a stationary

forklift portion. This would be able to place the tray in the desired location by sliding it off the

forklift, the ice cream lever and the burger by vertical movement, the buttons by pushing, and the

ticket by robot movement. The forklift would have an easier application but was considered to

lack accuracy and consistency.

The omnidirectional contracting arm was chosen for the mock up as it excelled in

versatility and had a high skill gap regarding the potential to complete tasks. The arm included a

servo for vertical movement, another servo for horizontal movement, and another servo for

contracting hand movement. Although this design was deemed fairly complex, it was still chosen

based on the selected criteria. Namely, it could easily grab the ice cream lever, lift the hot plate,

move the ticket, and push any buttons without moving the robot to adjust. The contracting arm

with the servos is presented below in Figure 4.

Figure 4: Contracting arm with squares to represent servos.

11
See Tables B1 through B5 in Appendix B for the decision matrices that helped the team

select the arm.

The Solid Works model of the mock-up is shown in Figure 5. This included the chassis,

the omnidirectional arm with the servos, the AWD drivetrain and the QR code holder.

Figure 5: Preliminary Solid Works Model

2.2.4 Path

When it comes to the path to take on the course, the team came up with two preliminary

ideas for the order in which to accomplish the tasks. These ideas are shown in Figures 6 and 7

below.

12
Figure 6: The preferred order in which to accomplish the tasks

Figure 7: The alternative order in which to accomplish the tasks

The first idea, shown in Figure 6, was to deposit the tray in the sink, and then do all tasks

on the upper level, including sliding the ticket, before coming to the bottom level to do the

jukebox task and press the final button. The second idea, shown in Figure 7, was to deposit the

tray in the trash and do all the tasks on the lower level before going to the upper level to do the

tasks there. The team ultimately decided that doing the upper level tasks first would be most

efficient and safe because it would be easier to place the tray in the sink because the sink was

deeper and wider.

13
2.2.5 Coding Ideas

Prior to creating the program in VSCode that would eventually store all of the code, the

team discussed the best ways to organize the code. For example, the team decided to first make

three main functions that would be used throughout the rest of the code: a function that moves

the robot straight, a function that turns the robot left, and a function that turns the robot right.

Having these functions would prove to be crucial as almost all other methods that were

developed required these three functions.

Additionally, the team emphasized making the code as modular as possible. Thus, the

team decided that it would be best to split up each task into two methods: one method for

navigating to said task and one method for accomplishing said task once the robot got there. In

theory, this would make the code much more modular as there would not be any extremely long

methods, and the main method of the code would only consist of calls to these methods.

In terms of code organization, the team decided to try to use GitHub as a way to share

and collaborate on the code. A repository was created for the project, and the team experimented

with pushing onto Github and pulling from GitHub for a couple of weeks. However, due to a

complication with GitHub and compiling the code, the team abandoned using GitHub and

switched to Google Drive, which is less advanced, but also simpler to use.

3. Analysis, Testing, and Refinements

3.1 Performance Test 1

Performance Test 1 consisted of pressing the correct jukebox button and navigating up

the ramp.

14
3.1.1 Building the First Model

The biggest challenge the team encountered while preparing for this performance test was

constructing the physical robot. Building the chassis, wiring the sensors and the motors, and

attaching the CdS to the robot all in one week was challenging.

Using the cardboard mockup that was constructed the week before, the team replicated

the chassis by cutting and bending an aluminum sheet. There were, however, a few differences

between the first model and the mockup. Namely, the chassis in the mockup was a 7” by 7” box

whereas the chassis in the model was a 5” by 7” hollow box. The team realized that the DuBro

wheels were both about 1” thick, so the chassis shape was altered to make space for these

wheels. Additionally, the team realized that making an arm would not be feasible for this

Performance Test due to a lack of time. Thus, there was no need for adding a surface to the top of

the box just yet.

Upon further analyzing the possible choices for the drivetrain, the team decided to only

use two wheels as the team found that four wheels would not be necessary. Also, using the

mockup, the team found that having a drivetrain with four wheels might add more friction

compared to just simply using a skid.

To determine which motors to use, the team conducted a drivetrain analysis. The

following outlines the steps taken. First, the team determined the total distance traveled by the

robot if it were to follow the course laid out by the team: around 217 inches. Then, after

estimating that it would take about 38 seconds to complete all the tasks and allotting a buffer of

20 seconds, the team found that the minimum linear speed the robot would need to complete the

course in two minutes was 3.5 inches per second; the team decided to round up to 4 inches per

15
second to overestimate the speed. The calculation to find this value is shown in Equation 1

below.

𝑚𝑖𝑛 𝑙𝑖𝑛𝑒𝑎𝑟 𝑠𝑝𝑒𝑒𝑑 =


𝑡𝑜𝑡𝑎𝑙 𝑑𝑖𝑠𝑡𝑎𝑛𝑐𝑒 (1)
𝑡𝑜𝑡𝑎𝑙 𝑡𝑖𝑚𝑒 − 𝑡𝑎𝑠𝑘𝑠 𝑡𝑖𝑚𝑒

Four inches/second was then changed to 25.46 revolutions/minute using dimensional

analysis, detailed in Equation C1 in Appendix C.

The angle of the ramp was calculated to be around 18.4º using Equation C2 in Appendix

C. Using this angle, the team found the force that is needed from the motors to get up the ramp is

around 8.97N or 32.25 ounces using Equation 2 below.

𝐹𝑚𝑜𝑡𝑜𝑟 = 𝑊𝑠𝑖𝑛θ + 𝐹𝑖𝑛𝑡𝑒𝑟𝑛𝑎𝑙 𝑓𝑟𝑖𝑐𝑡𝑖𝑜𝑛 (2)

This force was then converted to torque required per motor: around 24.19 oz-in. This was

done by using Equation C2 in Appendix C and then dividing the answer received from said

equation by two–the number of motors in the drivetrain.

Using the speed-torque graph found in Figure 8, the team found that the following motors

satisfy the speed and torque requirements calculated above: IGWAN, FUTABA SERVO,

ACRONAME, VEX 393, GMH-34, and FITEC SERVO.

16
Figure 8: Speed-torque graph for drivetrain analysis

Using a decision matrix, found in Table B6 in Appendix B, the team initially decided on

using the VEX motors. Later on, the team discovered that the VEX motors would be more

inconvenient to use as the encoder was not part of the motor while the IGWAN encoders were

built into the motor. Additionally, the price of the two motors were the same since the encoders

for the VEX had to be purchased separately. Thus, the team decided to switch to the IGWAN

motors before making the first purchase from the store.

Furthermore, instead of making an arm for this performance test, the team decided to add

a bumper to the front of the robot to use for pressing the jukebox button. Figure 9 below shows

the model that the team constructed for this performance test.

17
Figure 9: Model that Completed Performance Test 1

3.1.2 Testing and Refinements

Writing the code for the robot and calculating the counts per inch for our wheels for this

performance test was relatively simple. The team determined that the robot would use around

33.7 counts per inch, shown in Equation 3 below.

𝑛=
𝐸𝑛𝑐𝑜𝑑𝑒𝑟 𝐶𝑜𝑢𝑛𝑡𝑠/𝑅𝑜𝑡𝑎𝑡𝑖𝑜𝑛 (3)
2π𝑟

Through trial and error, the team was able to determine the correct distance to travel to

get to the jukebox light and the correct distance to travel to get to the ramp from the jukebox.

Using shaft encoding, the robot was able to travel to the jukebox light very consistently so that

the CdS cell would get accurate readings on which button needed to be pressed.

While testing if the robot could make it up the ramp, the team found the following issues

with the robot. One problem was that it was backheavy but not backheavy enough to get up the

18
ramp. The team was able to fix this problem by adding a wrench to the back of the chassis. This

addition changed the weight distribution of the robot and made it possible for the robot to drive

up the ramp backwards. Another problem that the robot encountered was with the faulty IGWAN

wheel adapters. The adapters would constantly crack, making it so that the robot struggled to

move up the ramp or move straight consistently. Eventually, the team was able to get

replacements and the issue was resolved.

While testing the functionality of the robot at the jukebox, the team found that the robot

would sometimes topple over backwards if it hit the jukebox button and kept driving forward. To

fix this, the team lowered the driving distance from the jukebox light to the jukebox buttons in

the code so that it would consistently press the jukebox button perfectly.

3.1.3 Results

Although it was challenging to build the physical robot within a week, the robot was able

to complete this performance test very successfully, earning the team a 26/20. See Appendix A

for the SolidWorks models of the robot at this point and Appendix D for more pictures of the

model. Additionally, see Appendix E for the testing logs for this performance test and all

following performance tests.

3.2 Performance Test 2

Performance Test 2 consisted of placing the tray above the trash can or the sink and

sliding the ticket.

19
3.2.1 Building the Second Model

The team needed to add an arm to the model of the robot shown above. The team

considered a few options for the arm, including making the arm out of wood or erector set

pieces; the following are the options that were ultimately chosen by the team.

First, the team decided to use the FITEC Servo motor instead of the FUTABA Servo

motor because the FITEC offered higher torque.

Then, the team decided that they still liked the idea of putting the arm on a flat surface,

much like how it was built on the mockup. Thus, using the mockup as an example, the team

placed a piece of aluminum on the front of the robot so that the servo motor could be set on the

robot in a convenient location.

Upon reconsidering the arm that was originally on the mockup, the team decided that a

contracting, omnidirectional arm with three servo motors would be too costly and complex.

Thus, the team decided to build the arm such that only one servo would be needed. Initially, the

team wanted to make the arm out of erector set pieces, but upon further consideration and

testing, the team found that the erector set pieces were inconvenient to use and flimsy.

Furthermore, the aluminum could be modified into any shape so it was more convenient to use;

the arm was cut such that the tray could slide onto the arm through the slit in the tray.

The team also decided to keep the skid instead of adding an omnidirectional wheel

because the skid worked well enough in the first performance test, so there was no justification

to remove it. Figure 10 below shows the model that was used for Performance Test 2. See

Appendix D for more images of this model.

20
Figure 10: Model that completed Performance Test 2

3.2.2 Testing and Refinements

After adding the arm to the robot, the robot could no longer make it up the ramp going

backwards due to the change in weight distribution from adding the arm. Upon testing the robot’s

capability to go up the ramp, the team found that the robot was able to move up the ramp going

forward without the wrench. The wrench is attached to the front of the robot in the image above,

but it was not there during the official performance test.

The code for this performance test was more tedious to write. Since the robot did not

have bump switches, line following capabilities or RPS capabilities, the code had to be extremely

precise. Through lots of testing and trial and error, the team was able to determine the best, most

accurate shaft encoding values for both the tray task and the ticket task. By adding these values

to the code, the robot was able to consistently accomplish both tasks. Additionally, since the code

had to be very precise, the team made a template to help with placing the robot at the same spot

on the course every time.

21
3.2.3 Results

Getting the stretch bonuses was simple. After coding the robot such that it would place

the arm in the same spot every run, it was easy to turn the robot left so that it would slide the

ticket the whole way. Furthermore, coding the robot to move up the ramp and turn slightly to hit

the hotplate was simple since the robot did not need to flip the burger. Thus, the team earned a

26/20 on Performance Test 2.

Upon successfully completing Performance Test 2 with the stretch bonuses, the team

updated the SolidWorks model, which can be seen in Appendix A.

3.3 Performance Test 3

Performance Test 3 consisted of flipping the burger using the hotplate with stretch

bonuses of pressing down any of the three ice-cream levers and returning the hotplate to its

original position.

3.3.1 Building the Third Model

Before any coding was done, the team decided to trim down the arm and readjust its

positioning on the servo motor because the arm made it so that it wouldn’t fit within the required

dimensions addressed in the Preliminary Concepts and Ideas section of this report. After

adjusting the arm, the team needed to recalibrate it.

Additionally, the team decided to 3D print the QR code holder so that it would be exact,

consistent, and easy to use. The printed part was added to the robot by placing it on top of two

erector set pieces, shown in Figure 11 below. The SolidWorks representation of the mockup was

used as a guide for building the QR code holder.

22
Figure 11: Model that completed Performance Test 3

3.3.2 Testing and Refinements

Writing the code for this performance test was even more tedious than for Performance

Test 2. Due to the shape of the arm, the robot had to navigate to a very specific spot in order to

successfully flip the hotplate the entire way. To navigate to said spot consistently, the team used

both shaft encoding and RPS checks.

While testing, the team realized that the weight distribution of the robot was altered due

to the adjustment of the arm and the addition of the QR code component. To counteract this

change, the wrench had to be added to the front of the robot so that it could still drive forward up

the ramp.

Furthermore, the team realized that the RPS readings were different on each course since

the robot behaved differently based on which course it was on. The team discovered this issue on

the day before the performance test and was not able to make drastic changes. Thus, the code

that was written for this specific performance test was written for one specific course: course F.

23
Additionally, upon testing the ice cream flipping mechanism, the team realized that the

robot’s arm would miss the lever more often than not. The code was then adjusted such that the

robot would swing the arm down, then turn left a little, then swing the arm down again, and

repeat this four more times. This essentially eliminated the possibility of missing the lever, but it

introduced a new problem of the arm getting caught under the lever, rendering the arm immobile.

However, since the arm getting stuck rarely occurred, the team accepted the risk.

3.3.3 Results

On the first four official performance test runs, the robot did not travel to the correct

location; it traveled too far forward. Upon noticing this, the team changed the code so that the

robot would not travel as far forward. Then, on the fifth attempt, the robot was able to flip the

burger and return the hotplate to its original position. However, the team did not get all stretch

bonus points because the arm got stuck under an ice-cream lever, something that did not happen

in the previous four official runs.

After getting a 23 out of 20 on this performance test, the team updated the SolidWorks

model, which can be found in Appendix A. Appendix D contains more pictures of the model.

3.4 Performance Test 4

The goal of Performance Test 4 was to navigate to the upper half of the course, flip an ice

cream lever, move it back to its original position, and navigate back to the final button. Bonuses

were awarded for flipping the correct ice cream lever and for leaving an ice cream lever down

for at least seven seconds.

24
3.4.1 Building the Fourth Model

The team initially added team designation signs on two sides of the robot labeled “E3”,

shown below in Figure 12. No other changes were deemed necessary for this performance test.

See Appendix D for more pictures of the model.

Figure 12: Model that completed Performance Test 4

3.4.2 Testing and Refinements

The beginning of this coding process originally led to some difficulties. The team found

that RPS was very inconsistent across the different courses and it made it very difficult to get

successful runs. Eventually, the robot was coded to find the starting position based on RPS and

use that to determine the calibration of the course. This helped the robot to be more consistent

with its x and y RPS positions but did not fully fix our issues.

The team attempted three of the five allowed official attempts for this run on Wednesday.

During these attempts, only one was successful in navigating back to the final button and none of

them were able to bring the lever back to its original position. This resulted in a score of 16/20

for the runs that had been completed Wednesday. The team worked on the robot more on Friday

25
to try to make it more consistent and noticed another team had put the tray on their robot's arm

which made it wider and therefore more consistent with moving the lever. This aspect was then

applied to the robot to add some extra consistency.

One issue that adding the tray caused was that there were times when it would fall off the

arm. This was counteracted by moving the arm slower and also changing some of the angles that

it would go to so the tray would stay attached to the arm.

3.4.3 Results

After adding the tray to the arm, two of the ice cream levers, twist and chocolate, were

working consistently. The vanilla lever caused many issues and the team chose to code the robot

to always go to the twist lever. This change made it so the robot would always get at least 23/20

points and with two runs left there was a possibility of getting 26 points if twist was randomized

on one of the attempts.

Twist was the randomized lever on the fourth attempt and the run was executed correctly

so the score for this performance test was 26/20. The SolidWorks model of the robot was then

updated to include the team designation signs which can be found in Appendix A.

Testing logs can be found in Appendix E.

4. Individual Competition

4.1 Testing and Refinements

No major changes were made to the physical model between PT4 and the Individual

Competition. The only changes made included updated team designation signs and rubber bands

26
added around the circumference of the DuBro wheels. The rubber bands gave the wheels more

traction and made the robot more stable and consistent when driving straight. Figure 13 below

shows the model of the robot used for the Individual Competition. More pictures can be found in

Appendix D, and a SolidWorks rendering of this model can be found in Appendix A.

Figure 13: Model that completed Individual Competition

The team made a few major changes in the code between the fourth performance test and

the Individual Competition. Specifically, the team had to increase the motor power in order to

complete all the tasks within two minutes; the power was increased from 25 to 33 for when the

robot was driving straight. The team was wary of the possibility of encoder miscounts with high

motor speeds, so the increase in speed was kept at a minimum. Additionally, the team did not

want to risk having any encoder miscounts for the turns because having a correct heading was a

very big factor of the robot’s success. Thus, the motor power for the turns was kept at 25.

The second major change in the code was introducing RPS data logging to get specific

RPS values for each run. The team found that the RPS coordinates were different for each

course, i.e., if the y-coordinate of a location on course H was 64.0, the y-coordinate of the same

27
location on course E might be 63.0. Thus, by logging some points before each run, the team

would be able to get the exact RPS coordinates it needed for each run, no matter what course was

chosen. This eliminated a lot of the inconsistencies the team was facing with RPS. More details

on this modification to the code can be found in Section 5.4.

The first major issue the team encountered was the differences in performance of the

robot due to differences in power level of the proteus. The team addressed this issue by charging

the proteus between each run and removing the charger once the green light came on indicating it

was fully charged so as to not overcharge the proteus. The only other issues encountered had to

do with slight RPS differences especially with heading checks which the team addressed by

testing and modifying the code.

4.2 Structure and Strategy

The team completed the Individual Competition on Friday, April 1 in Hitchcock 208. It

consisted of three runs of the full course: one instructor chosen, one random, one chosen by the

team. The grade the team received was the amount of primary points achieved in the best of

those three runs.

The team knew that courses E and F were the courses on which the robot performed the

worst, and courses C, G, and H were the courses on which the robot performed the best overall.

The team’s strategy for the competition was to first drop the tray off in the trash to free up the

arm for the other tasks. The robot then completed the ticket and moved up the ramp to the upper

level, at which point it completed the burger and ice cream tasks. Finally, it moved back down

the ramp to complete the jukebox task and hit the final button. The instructor-chosen course was

course F, and both the random and team-chosen courses were course C.

28
4.3 Results

On the instructor chosen course, the robot did not perform well; it scored only 33 total

points with 23 primary points. The only tasks that were completed successfully before running

out of time were sliding the ticket completely, initiating the burger flip, and putting the tray in the

trash. As stated above, going into the competition, the team knew that courses E and F were not

great for our robot as the robot did not perform consistently on these courses. Thus, this low

score did not come as a surprise to the team

On the random course, the team got course C. Due to long lines during open hours, the

team was never able to test on course C. Thus, the team did not really know what to expect going

into the competition. Ultimately, the robot performed surprisingly well. The robot earned 85 total

points with 68 primary points. It was able to complete all tasks except fully flipping the hotplate,

returning the hotplate to its original position, and waiting seven seconds at the ice-cream lever.

Finally, the team was able to choose a course for the last run. Since the team found that

the robot performs well on course C, course C was chosen for run three. The robot performed

well, but not as well as the second run, earning 77 total points and 67 primary points. It missed

the ticket task completely and also did not wait for seven seconds at the ice-cream lever.

However, it was able to accomplish all the other tasks perfectly.

4.4 Analysis

Upon evaluating the results of the competition, the team noticed a few strengths and

weaknesses of the robot. One of the main strengths of the robot was its stability. During testing

and the official runs, the robot never really deviated from what it was supposed to do. None of

the parts of the robot came off, and the robot was able to drive almost perfectly straight as it was

29
well balanced. Being able to drive straight was a very important factor for many of the tasks. If

the robot was unstable, the alignment for tasks like the burger task would be thrown off

completely.

One of the biggest weaknesses of the robot was its weight. Although adding weight to the

front of the robot helped with the robot’s balance, it made the robot too heavy. Paired with using

a drivetrain with only two wheels and two motors, the robot was inevitably slow. Due to the lack

of time between the Individual Competition and the Final Competition, the team decided that it

was not feasible to make any major changes to the drivetrain or the chassis in an effort to make

the robot lighter. Thus, the team had to accept the slow and low-maneuverability design of the

robot. While increasing the motor speeds would have made the robot move faster, the shaft

encoding, which the team used as its main manner of navigation, would have become more

inaccurate. Therefore, the team decided to air on the safer side and kept the lower motor powers.

The second weakness of the robot was that the wrench placed on the front of the robot to

counteract the back-heaviness of the model was interfering with the jukebox task in that it would

sometimes press both buttons. Figure 13 above shows the wrench on the front of the robot. To fix

this issue in preparation for the Final Competition, the team removed the wrench from the front

of the robot and replaced it with a roll of 50 pennies on the inside of the robot. The roll of

pennies was only one gram heavier than the wrench, so the weight distribution was not altered

much. Furthermore, since the pennies were on the inside, they did not interfere with the jukebox

buttons. Figure 14 below shows the placement of the pennies.

30
Figure 14: Pennies used as balance were placed on the inside

5. Final Design

The chassis of the final design was made of aluminum. The aluminum was folded to

make a box-like shape. The final design of the robot included one arm that was able to

accomplish all the tasks. The drivetrain included two 3” DuBro wheels with rubber bands along

the circumference of the wheels for additional traction and a skid in the front of the robot.

Popsicle sticks were glued onto the front of the robot for the sole purpose of pushing the jukebox

buttons. The wrench was replaced with pennies which were taped to the front of the robot on the

inside to counteract the back-heaviness of the robot due to the Proteus. The CdS sensor was

placed at the front of the robot, just behind the skid. Figure 15 below shows the final design of

the robot. Figure 16 shows the bottom of the robot, displaying the motors and the CdS sensor.

31
See Appendix A for the SolidWorks rendering of the final design and Appendix D for more

pictures of the final robot.

Figure 15: Final Design of the Robot

Figure 16: The bottom of the final design.

32
5.1 Strengths and Weaknesses

The model had a few strengths and weaknesses. Some strengths include the versatility of

the mechanism on the robot as this single arm was able to accomplish all the tasks rather

efficiently and effectively. Using only one arm saved a lot of money in terms of the final budget

since it only required one servo motor to be purchased.

Additionally, a strength that was unexpected but welcomed was the use of a skid that was

long in the horizontal direction, shown in Figure 17 below. This skid made it so that whenever

the robot traveled up the ramp, the robot would be perfectly facing 90º since the skid helped

realign the robot using the uneven surface between the ramp and the lower level. Having a

consistent heading every run regardless of which course was chosen helped tremendously as it

saved time and made the upper level tasks far more consistent.

Figure 17: Skid that was used on the robot

Another strength of this model was the placement of the Proteus in the back in an upright

position. Although this placement made the robot more back-heavy, it saved a lot of space,

giving the arm more range of motion. It also made it so that it was easy to connect all necessary

ports. Additionally, placing the Proteus in an upright position made it so that there was much

more space for the wires so none of them got tangled up amongst themselves. Finally, it also

made it so the Proteus was extremely secure as it fit perfectly into the slot that the team created.

A close up image of the vertical placement of the proteus is shown in Figure 18 below.

33
Figure 18: Upright positioning of the proteus.

As previously mentioned, the simplicity of the robot and its single mechanism resulted in

some weaknesses as well. For example, one prominent weakness was the fact that the robot had

to navigate to specific locations and face specific directions to give itself the best chance to

complete the task successfully. This meant that the robot had to make extra turns that cost time

during the official runs.

Although the single arm mechanism that was utilized on this robot could theoretically do

all the tasks, having a specialized mechanism for each of the tasks would have been more

consistent and effective. For example, the arm that was used on this model could slide the ticket

and flip the burger, but it was not very consistent in doing either task due to the fact that the team

had to make it so that it could do both tasks. Figure 19 below shows one of the biggest flaws of

the robot’s single mechanism: missing the ticket to the right. If the robot had a mechanism

specifically built for the ticket task, it would not have had to be so accurate in its positioning.

34
Figure 19: Biggest flaw of having a single mechanism design.

Additionally, the back-heaviness of the robot made it so that the robot struggled with

going up the ramp. To fix this issue, the team added weight to the front of the robot, making the

robot much heavier. This meant that the Proteus had to be fully charged at all times because if it

was not, the pulses for the RPS checks could not move the robot due to its weight. Adding extra

weight to the front of the robot also put more strain on the motors. Although this did not hurt the

team during this project, having such a heavy robot might cause issues with the motors in the

long run.

Finally, the only navigation technique that was utilized on this robot up to the third

performance test was shaft encoding. Afterwards, the team added the use of RPS as a check to

see if the shaft encoding did what it was supposed to do. Only having one navigation technique

made the robot extremely inconsistent. Even after adding RPS checks, the robot continued to be

inefficient due to the inconsistencies with RPS between the courses. To counteract these

inconsistencies, the team used data logging to log the critical points prior to the start of each run.

While this fixed most of the issues, using more navigation techniques such as bump switches

35
would have made the robot even more consistent and probably saved time as the RPS checks

during the runs take a long time. Figure 20 shows the consequences of using only shaft encoding

and RPS checks.

Figure 20: Inconsistent shaft encoding and RPS checks led to task failures.

5.2 Budget

As mentioned in the section above, the simplicity of the model, i.e., having only one arm

and using two-wheel drive, made it so that the team could save a lot of money. The team used a

minimal number of parts while constructing the chassis as well, demonstrated in the CAD

drawing in Figure 21 below. More CAD drawings can be found in Appendix A.

36
Figure 21: SolidWorks drawing of the chassis

Only having to buy two IGWAN motors and one servo motor paired with doing a good

job of maintaining these motors helped the team conserve a lot of the budget; the team saved

$50.64 by the end of the project. The bonus points associated with the remaining budget will

greatly improve the team’s score. Figure 22 below shows the budget allocation, and Figure 23

shows the remaining budget over time. See Appendix F for a full breakdown of how the money

was spent.

37
Figure 22: Budget allocation to different parts of the robot

Figure 23: Remaining budget over time

5.3 Final Schedule and Times

While the design of the robot left a large amount of money in the budget, construction

and coding of the robot took additional time that a more costly design may have fixed. The time

spent by each member in each category is shown below in Table 3. Each category shows how

much time was spent by each member on that aspect of the project. The team originally budgeted

38
400 hours total which is very close to the time spent so far. Currently the team has spent a total

of 345 man hours. The schedule of when each task was to be completed and when they were

fully completed is shown in Appendix G.

The time spent by each member was divided into seven categories. These categories

show the time that each member spent doing certain aspects of the project. The largest category

of time for everyone was testing on the course since all team members made an effort to be at

open lab as much as possible. Once the team finished constructing the robot, testing was done to

try to decrease the variability in the robot. The total time testing the robot (so far) has been 104.5

man hours.

Table 3: Total Time by Member

5.4 Final Code

While the team was coding throughout the project, the team stuck to its preliminary ideas

for the code and worked to make the code as modular as possible. Functions were written for

traveling straight and turning left and right. Using these user-written functions, the team wrote

functions for traveling to the required location to accomplish each task and functions for doing

the task once the robot got to the desired location. After Performance Test 2, the team added

functions for RPS checks including functions to pulse forward, backward, left and right.

While testing the code, the team modified the functions such that more arguments could

be passed into the functions, making them more specialized. For example, for the function that

moves the robot straight, the team added a time parameter. This time parameter was used as a

39
time-out failsafe; the robot would sometimes get caught on a part of the course while trying to

drive forward or backward, and this time parameter told the robot that if the amount of time

elapsed was greater than the argument the function received, break out of the move straight

function and move on. Figure 24 shows the move_straight function.

Figure 24: move_straight method with time failsafe

Another example is the power parameter that gets passed into the RPS check functions.

For the functions that check the x and y positions of the robot, the team sometimes needed

different pulse powers such that the checks took less time. To solve this issue, the team edited the

RPS check functions so that a power argument could be passed into each call.

As stated in Section 4.1, the team also wrote a function that logs five RPS points into a

text file and a function that reads these values from the text file. The five points are the x and y

coordinates of the hotplate, the x and y coordinates of the jukebox light, and the x coordinate of

the chocolate ice-cream lever. These functions made the robot much more consistent as they

eliminated the RPS variance between courses; the team just had to log the correct locations prior

to the run and the robot would do the rest.

40
Unfortunately, since the robot uses shaft encoding as its primary navigation technique,

the code has a lot of random values for distances to travel. These values were determined

through testing, but they might not make sense to someone who is trying to decipher the code.

Thus, the team added comments to the code to make it more readable and to clear up some

confusion.

See Appendix H for the final code along with the code representation.

5.5 Electrical Representation

Due to the simplicity of the design, the team only needed to make six connections to the

Proteus. These six connections included two encoders, two motors, one servo, and one CdS cell.

All six of these connections were made by the second performance test, and the team did not find

a need to change them, so they have been constant since passing Performance Test 2. Figure 25

below provides a visual representation of the connections made to the Proteus.

41
Figure 25: Block diagram of electrical system

6. Final Competition

6.1 Testing and Refinements

Throughout the week leading up to the Final Competition, the team spent many hours

trying to refine the code such that the robot would behave more consistently. One of the changes

the team decided to make during testing was pulsing left once before lifting ice-cream lever back

up. Pulsing left would ensure that the arm was under the lever so that lifting the arm would also

lift the lever.

The team found that by pulsing left, the lever would sometimes get caught in the crevice

between the flat portion of the arm and the upright portion of the arm. Then, since the team

coded it so that the arm would move up and then back down after flipping the lever up, the robot

42
would sometimes flip the arm up then back down immediately. The team found that by doing

this, the robot would receive points for both flipping the lever back up and waiting seven

seconds. While this manner of earning points does not have a practical application in Carmen’s

Diner, the team found that they could save seven seconds by doing this, which was important

since time was a major issue for the performance of the team. Figure 26 below shows the crevice

of the arm that the lever was getting caught in.

Figure 26: The crevice that caught the lever

6.2 Structure and Strategy

The final competition took place at The Ohio State University’s RPAC in the Tom W.

Davis special events gym at 12:00 P.M. on April 9 2022. The competition consisted of a

minimum of four runs total. The initial three runs were constructed as a ‘Round Robin’ in which

teams were assigned a random course and given a minute to set up and two minutes to run; these

three runs were not competition based. At approximately 4:00 P.M., the elimination tournament

began. Each of the 57 teams was assigned a course and exactly one run to begin. Four teams

competed against each other and the highest score advanced to the Sweet 16. This process was

repeated to reach the Final Four where a winner was finally selected..

43
The strategy used for the final competition in regards to task order was exactly the same

as the individual competition: tray, ticket, burger, ice cream lever, jukebox, and final button. A

few variables affected the initial setup of the robot. During preliminary testing in the RPAC,

CDS cell values for both lights were different compared to previous testing, so the constants

were altered. Furthermore, RPS values from SD card data logging showed different values for

the burger flip. As a result, the burger placement was slightly to the left during the one minute

setup.

6.3 Results

The first run was on course E, and it yielded 66 total points with 59 of those points being

primary points. The robot missed the ticket completely, i.e., it did not slide the ticket at all. This

was a surprise to the team as the team had increased the consistency of the ticket task to about

90% during testing in the week leading up to the final competition. The robot also missed the

final button as it ran out of time. The RPS check at the jukebox light for the y coordinate was

longer than usual, meaning a lot of time was wasted.

The second run was on course D. This run earned 33 total points and 23 primary points.

The robot successfully completed the tray task and the ticket task, earning full points for both

tasks. However, upon reaching the top of the ramp, the robot flipped over and was rendered

immobile. Since the robot could not move, it was unable to complete any other tasks. During

testing throughout the entire project, the robot did not do this once, so this result came as a

surprise to the team.

The third run was on course B; this run earned 76 total points and 54 primary points. The

robot failed the following tasks: returning the tray, initiating the burger flip, finishing the burger

flip, and returning the hotplate to its original position. While the robot was able to complete the

44
burger task pretty often during testing, it did miss the hotplate at times because of faulty

calibration of the robot during the setup period. Thus, the team was not as surprised about this

error as the robot’s flip at the top of the ramp.

The team conducted its only tournament run on course A. The team earned 70 total points

and 60 primary points. It completely missed the tray return task and the ticket slide task. It also

did not wait for the full seven seconds at the ice-cream lever task. This result was not the result

the team was hoping for, but, at the same time, it was not necessarily unexpected since the team

knew that course A was not the best course for the robot.

Figure 27 below shows the robot during the third run of the Round Robin portion of the

Final Competition.

Figure 27: Round Robin run 3

45
6.4 Analysis

Although the robot had previously encountered continuous success on the tray task, this

was not the case during the final competition. The navigation during this task relied solely on

shaft encoding, and as a result, it required low degrees of error which was not apparent during

competition day.

Furthermore, RPS values were not consistent among courses. The previously most tested

courses included course C, H, and G; these courses were where the robot performed best on.

None of the four final runs were on these courses, a 15% possibility. RPS values on the courses

required preliminary placement to change, altering the possibility of course consistency. For

example, during the two practice runs granted to each team, the team found that the data logging

position for the burger task on course B needed to be left of the usual position. However, due to

the heat of competition, the team forgot about this discovery on the third round robin run, leading

to the robot missing the hotplate by a significant margin.

Another issue during competition day was that for nearly every run, the proteus was

brought to full charge which had not been done previously. The full charge caused the robot to

unexpectedly flip after traversing the ramp, an outcome that had never happened before. Overall,

there were a number of variables that had changed when moving to the RPAC as well as team

errors that caused the robot to perform worse than it had previously.

7. Summary and Conclusions

Through the iterative process of designing, building, and testing, the team built a robot

that was able to successfully complete the tasks required of it by Carmen’s Diner. The team first

46
started by brainstorming possible solutions and different models including an omnidirectional

grabbing arm and a solid-box chassis. A drivetrain analysis was conducted to help with choosing

the motor that was best suited for the robot. Upon deciding on a model and a motor, the team

built the chassis and drivetrain. Then, throughout the rest of the project, the team added parts and

mechanisms to the chassis, such as the arm and the QR code holder, in an effort to complete the

required performance tests. While the team mainly added onto the robot, some parts had to be

changed or removed as they proved to be hindering the performance of the robot. At the end of

the project, the team had a robot that was a culmination of all the edits and additions made

during the iterative engineering design process.

The model that the team decided on included one multifunctional aluminum arm and a

two-wheel drivetrain that used IGWAN motors with a skid for stability and reduced friction. Due

to the simplicity of the model, the team was able to save a lot of money when it came to the final

budget. On the other hand, the simplicity of the model made the code more tedious to test and

made doing the tasks more time consuming because the robot had to get to a very specific

location to do each task.

At the Individual Competition, the robot performed well but not as well as the team

would have hoped. The robot scored a 68/75 on its best run, failing to flip the hotplate the entire

way such that the burger patty flipped over. On the second best run, the robot scored a 67/75,

failing to move the ticket at all. Evidently, the robot struggled with consistency and the team had

to work to fix that.

At the Final Competition, the robot did not perform as well as it did in the Individual

Competition. The best run earned 76 total points, which is nine points less than the best run from

Individual Competition. Despite the testing and the changes made to the robot in an effort to

47
make it more consistent, the aforementioned discrepancies in RPS and proteus charge at the Final

Competition caused the robot to perform poorly.

Overall, this project helped the team learn more about the engineering design process as

the team had to fully immerse themselves in said process to make a working robot. The team had

to work together to build, code, and test the robot repeatedly. By working together and making

sure to make time to meet with each other, the team was able to get lots of work done in a short

period of time. This project also taught the team about what it takes to be an engineer; the team

learned about the perseverance and problem solving required in making a working product.

7.1 Errors

The team made a few minor errors throughout the course of the project. For example, the

team forgot to keep a meeting agenda for some out of class meetings and forgot to keep a test log

for some test sessions. Later on, the team tried their best to recall what was discussed during the

meetings in order to make the meeting agendas, but information was lost despite the efforts of

the team. Another minor error that the team made was leaving the USB adapter in the computer

after class. This happened three or four times and cost the team a dollar to buy it back. Although

a dollar is not a lot in the long run, wasting money is never a good thing.

The team also forgot to charge the proteus a few times. Not having a Proteus on full

charge made it hard to test the code because the robot acted differently on full charge than on

half charge. For example, the robot traveled further and pulsed further on full charge. Testing the

robot on half to quarter charge meant that the code was written for a Proteus on half charge.

Thus, once the Proteus was fully charged, the robot acted completely differently. This error

ended up costing the team many points in the Final Competition, as previously mentioned.

48
Fortunately, the team really only made one major error while working on the robot. This

error came from not thinking about all aspects of the project before building the arm. Figure 28

below shows the arm that the team built. The arm was built this way because the servo motor

was placed on the right hand side of the robot. The fact that the vertical portion of the arm is on

the right hand side ended up causing many issues. First, the vertical portion of the arm would

often get caught in the hotplate handle, preventing the robot from completing the hotplate flip

task. If the vertical portion was on the left, the robot likely would not have had this problem.

Furthermore, since the vertical portion was on the right, the robot could not slide the ticket from

the upper level, which is what the team had originally planned on doing. Thus, the team had to

rethink the order in which the robot completed the tasks.

Figure 28: The arm of the robot

If the team considered these possible issues prior to mounting the servo and bending the

arm, these problems and headaches could have been avoided, resulting in a much more

successful and possibly more consistent robot.

49
7.2 Possible Improvements

There are definitely a few ways in which the model built by the team could be improved

had there been more time or if the team were to do the project again. For one, the model could

have taken advantage of bump switches. The team realized how useful bump switches are too

late into the project cycle. Bump switches are extremely good at resetting the robot’s heading and

position, meaning that the robot would not have to rely on accurate encoder counts.

Secondly, the robot could have been made to be lighter. Since our robot was so heavy, the

wheels would stop spinning if the robot ran into a wall or some other obstacle. If the robot was

lighter, the wheels would have kept spinning. This is important because if the wheels stop

spinning, the encoder counts will stop increasing, meaning that the robot will get stuck and stop

moving. The team solved this issue by introducing a time-out failsafe into the method, but

having a lighter robot will put less strain on the motors in general.

Thirdly, the robot could have used a different drivetrain in order to travel around the

course faster. For example, a three wheel drivetrain where each wheel is omnidirectional would

have allowed for quick RPS checks and diagonal movement. The two-wheel drivetrain that the

team used only allowed for forward and backward movement, restricting it from moving

diagonally.

Finally, the team could have built specialized mechanisms for each of the tasks. Having

specialized mechanisms for each task would have made it much easier to travel around the

course as the team would not have to be as worried about taking a certain path to each task. With

a single arm, the team had to think about which path was best since the arm had to be in a

specific location to maximize utility for each task. Furthermore, having a specialized mechanism

50
for each task probably would have made the robot much more consistent as each task had a

mechanism built specifically for it.

51
References

[1] FEH Program, “Robot_Scenario_SP_22” Ohio State University Department of

Engineering Education, Columbus, OH, United States, 2020. Accessed: February 2022 [Online]

[2] FEH Program, “Final Reports” Ohio State University Department of Engineering

Education, Columbus, OH, United States, 2022. Accessed: March 2022 [Online]

[3] FEH Program, “Exploration 01: Introduction to Sensors and Motors” Ohio State

University Department of Engineering Education, Columbus, OH, United States, 2022.

Accessed: March 2022 [Online]

[4] FEH Program, “Exploration 02: Line Following and Shaft Encoding” Ohio State

University Department of Engineering Education, Columbus, OH, United States, 2022.

Accessed: March 2022 [Online]

[5] FEH Program, “Exploration 03: RPS & Data Logging” Ohio State University Department

of Engineering Education, Columbus, OH, United States, 2022. Accessed: March 2022 [Online]

52
APPENDIX A

SolidWorks Models
Figure A1: SolidWorks model that completed Performance Test 1

Figure A2: SolidWorks model that completed Performance Test 2

A2
Figure A3: SolidWorks model that passed Performance Test 3

Figure A4: SolidWorks model that passed Performance Test 4.

A3
Figure A5: SolidWorks model of design used for Individual Competition

Figure A6: SolidWorks model of final design.

A4
Figure A7: Second CAD drawing of the final robot design

A5
APPENDIX B

Decision Matrices
Table B1: Ticket task decision matrix.
TICKET Weight Grabbing arm Stationary arm Arm with arm Wheel
Complexity 2 2 3 2 2
Potential damage 1 3 3 1 1
Versatility 3 3 1 3 1
Total 16 12 14 8

Table B2: Jukebox task decision matrix


JUKEBOX Weight Extending Arm Extension Back up Contracting Arm
Accuracy 3 3 2 1 3
Complexity 2 2 3 3 1
Versatility 3 1 2 1 3
Potential Dmg 1 3 2 1 3
Total 19 20 13 23

Table B3: Ice-cream task decision matrix


ICE CREAM Weight Contracting arm Robot w/ hole Height change Forklift
Accuracy 3 1 1 2 3
Reversibility 3 2 2 1 3
Versatility 2 3 1 1 1
Complexity 1 1 1 1 3
Total 16 12 12 23

B2
Table B4: Burger task decision matrix
BURGER Weight Contracting arm Spinning wheel Forklift Stick arm in wheel
Grip Strength 3 2 1 2 1
Versatility 2 3 1 2 2
Complexity 2 2 3 3 3
Range of Motion 2 3 1 2 2
Accuracy 2 3 1 3 1
Total 28 15 26 19

Table B5: Tray task decision matrix


TRASH/SINK Weight Contracting arm Tilting Platform Ramming Forklift
Platform
Can it carry tray 3 2 3 3 3
Placement 2 3 3 1 2
Versatility 2 3 1 1 2
Repeatability 1 3 2 1 2
Total 21 19 14 19

Table B6: Motor selection decision matrix

B3
APPENDIX C

Equations
𝑟𝑒𝑣/𝑚𝑖𝑛 =
𝑖𝑛𝑐ℎ𝑒𝑠
·
𝑟𝑒𝑣
·
𝑠𝑒𝑐 (C1)
𝑠𝑒𝑐𝑜𝑛𝑑 𝑖𝑛𝑐ℎ𝑒𝑠 𝑚𝑖𝑛

τ𝑚𝑜𝑡𝑜𝑟𝑠 = 𝐹𝑚𝑜𝑡𝑜𝑟𝑠 × 𝑟𝑤ℎ𝑒𝑒𝑙 (C2)

Sample Calculation for Equation 1 (appeared in body)


𝑡𝑜𝑡𝑎𝑙 𝑑𝑖𝑠𝑡𝑎𝑛𝑐𝑒 217 𝑖𝑛
𝑚𝑖𝑛 𝑙𝑖𝑛𝑒𝑎𝑟 𝑠𝑝𝑒𝑒𝑑 = 𝑡𝑜𝑡𝑎𝑙 𝑡𝑖𝑚𝑒 − 𝑡𝑎𝑠𝑘𝑠 𝑡𝑖𝑚𝑒
= 120 𝑠 − 58 𝑠
= 3. 5 𝑖𝑛/𝑠

Sample Calculation for Equation 2 (appeared in body)

𝐹𝑚𝑜𝑡𝑜𝑟 = 𝑊𝑠𝑖𝑛θ + 𝐹𝑖𝑛𝑡𝑒𝑟𝑛𝑎𝑙 𝑓𝑟𝑖𝑐𝑡𝑖𝑜𝑛 = 21. 3504𝑁(𝑠𝑖𝑛(18. 41º)) + 2. 2241𝑁 = 8. 97𝑁 = 32. 253 𝑜𝑧.

Sample Calculation for Equation 3 (appeared in body)

𝐸𝑛𝑐𝑜𝑑𝑒𝑟 𝐶𝑜𝑢𝑛𝑡𝑠/𝑅𝑜𝑡𝑎𝑡𝑖𝑜𝑛 318


𝑛= 2π𝑟
= 3π
≈ 33. 74 𝐶𝑜𝑢𝑛𝑡𝑠/𝐼𝑛𝑐ℎ

Sample Calculation for Equation C1

𝑖𝑛𝑐ℎ𝑒𝑠 𝑟𝑒𝑣 𝑠𝑒𝑐 4 𝑖𝑛𝑐ℎ𝑒𝑠 𝑟𝑒𝑣 60 𝑠𝑒𝑐


𝑟𝑒𝑣/𝑚𝑖𝑛 = 𝑠𝑒𝑐𝑜𝑛𝑑
· 𝑖𝑛𝑐ℎ𝑒𝑠
· 𝑚𝑖𝑛
= 𝑠𝑒𝑐𝑜𝑛𝑑
· 3π 𝑖𝑛𝑐ℎ𝑒𝑠
· 𝑚𝑖𝑛
= 25. 46 𝑟𝑒𝑣/𝑚𝑖𝑛

Sample Calculation for Equation C2

τ𝑚𝑜𝑡𝑜𝑟𝑠 = 𝐹𝑚𝑜𝑡𝑜𝑟𝑠 × 𝑟𝑤ℎ𝑒𝑒𝑙 = 32. 253 𝑜𝑧. × 1. 5 𝑖𝑛 = 48. 28 𝑜𝑧. 𝑖𝑛.

C2
APPENDIX D

Additional Pictures of Robot


Figure D1: Robot that completed Performance Test 1

Figure D2: Underside of robot that completed Performance Test 1

D2
Figure D3: Front view of robot that completed Performance Test 2

Figure D4: Side view of robot that completed Performance Test 2

D3
Figure D5: Back right view of robot that completed Performance Test 3

Figure D6: Front view of robot that completed Performance Test 3

D4
Figure D7: Top view of robot that completed Performance Test 3

Figure D8: Front view of model that completed Performance Test 4

D5
Figure D9: Drivetrain and sensors of model that completed Performance Test 4

Figure D10: Rear-view of the model that completed the Individual Competition.

D6
Figure D11: Top view of the model that completed the Individual Competition.

Figure D12: Front view of final design

D7
Figure D13: Back view of the robot

Figure D14: Pennies that replaced the wrench for counteracting back-heaviness

D8
APPENDIX E

Testing Logs
Table E1: Testing Logs from Performance Test 1

Table E2: Testing logs for Performance Test 2

E2
Table E3: Testing Logs for Performance Test 3

E3
Table E4: Testing Logs for Performance Test 4

E4
Table E5: Testing Log for Individual Competition

E5
Table E6: Testing log for final competition

E6
APPENDIX F

Budget
Table F1: List of Parts Bought
Date Bought Parts Bought Individual Price Total Price
2/17/22 DuBro 300T 3.0" Wheel (x2) $2.85 $5.70
2/17/22 IG-22 (IGWAN) Motor (x2) $25.00 $50.00
2/17/22 Aluminum Sheet, 16 Gauge (12" x 12" ) $5.75 $5.75
2/17/22 Aluminum Sheet, 12 Gauge (12" x 6") $2.87 $2.87
2/18/22 Chassis Mount for IGWAN motors (x2) $2.50 $5
2/18/22 DuBro Wheel Adapter for 3.0" Wheel (x2) $1.00 $2
2/21/22 Angle Bracket, 0.5x0.5" 1x1 hole (x8) $0.31 $2.48
2/21/22 8.5" x 11" Cardboard Sheet $0.04 $0.04
2/21/22 Terminal Block for continuous rotation motors (x2) $1 $2
2/21/22 3/32" Dia Shrink Tubing (P/Ft.) $0.20 $0.20
2/22/22 Red Plastic Filter (3" x 3") $0.10 $0.10
2/22/22 Length of Solder (2ft, lead-based) $1.00 $1.00
2/25/22 SD to USB Adapter $1.00 $1.00
2/25/22 High-Torque Fitec Servo Motor $12.00 $12.00
2/25/22 Microswitch, roller blade (medium) $1.20 $1.20
2/25/22 Axle Rod, 1" $0.44 $0.44
2/25/22 Angle girder, 7.5" 15 hole $2.06 $4.12
2/25/22 3/32" Dia Shrink Tubing (P/Ft.) $0.20 $0.20
2/28/22 Male Header Strip (36 Pin) $0.60 $0.60
2/28/22 Angle Bracket, 1x0.5" 2x1 hole $0.58 $1.16
2/28/22 3/32" Dia Shrink Tubing (P/Ft.) $0.20 $0.20
2/28/22 Slotted Strip, 2" $0.79 $0.79
2/28/22 10 Pack, #6 Screws (0.25"), Nuts, Washers $0.20 $0.20
2/28/22 Reversed Angle Bracket, 1" (x2) $0.96 $1.92
3/2/22 XL Rubber Band x4 $0.04 $0.16
3/8/22 Replacement QR Code Acrylic Mount (3" x 3") $1.00 $1.00
3/8/22 3D Printed QR Code Holder $5.87 $5.87
3/9/22 Popsicle Sticks (x2) $0.01 $0.02
3/9/22 6 Pack, #6 Screws (0.75"), Nuts, Washers $0.20 $0.20
3/9/22 10 Pack, #8 Screws (0.25"), Nuts, Washers $0.20 $0.20
3/21/22 10 Pack, #6 Screws (0.5"), Nuts, Washers $0.20 $0.20
3/29/22 Large Rubber Band x4 $0.03 $0.12

F2
Table F2: Money Spent vs Remaining Budget over Time
Date Money Spent Remaining Budget
2/16/22 $0 $160
2/17/22 $64.32 $95.68
2/18/22 $7 $88.68
2/21/22 $4.72 $83.96
2/22/22 $1.10 $82.86
2/25/2022 $18.96 $63.90
2/28/22 $4.87 $59.03
3/2/22 $0.16 $58.87
3/8/22 $6.87 $52.00
3/9/22 $0.42 $51.58
3/21/22 $0.20 $51.38

F3
APPENDIX G

Robot Design Schedule


Figure G1: Robot Design Schedule

G2
APPENDIX H

Code
//Standard Proteus Libraries
#include <FEHLCD.h>
#include <FEHIO.h>
#include <FEHUtility.h>
#include <FEHMotor.h>
#include <FEHRPS.h>
#include <FEHServo.h>
#include <FEHRPS.h>
#include <FEHSD.h>
#include <string.h>
#include <stdlib.h>

// #define CDS_THRESHOLD *put value here*


#define CDS_BLUE_THRESHOLD 1.015
#define CDS_RED_THRESHOLD .75
#define CDS_UPPER_THRESHOLD 2.0
#define COUNTS_PER_INCH 34.0
#define NINETY_DEG_TWENTYSPEED 5.2
#define SERVO_MIN 726
#define SERVO_MAX 1427
#define RPS_WAIT_TIME_IN_SEC 0.35
#define PULSE_TIME 0.3
#define PULSE_POWER 20
#define PLUS 0
#define MINUS 1
#define STD_POWER 33

/* Declarations for encoders, motors, and input pins (all subject to


change) */
DigitalEncoder right_encoder(FEHIO::P2_0);
DigitalEncoder left_encoder(FEHIO::P3_0); // Left stupid
FEHMotor right_motor(FEHMotor::Motor0, 9.0);
FEHMotor left_motor(FEHMotor::Motor3, 9.0); // left taped
AnalogInputPin cds(FEHIO::P1_0);
FEHServo arm_servo(FEHServo::Servo0);

/* function for pulsing forward using encoders */


void pulse_forward(int percent, float seconds)
{
// Set both motors to desired percent

H2
right_motor.SetPercent(percent);
left_motor.SetPercent(percent);

// Wait for the correct number of seconds


Sleep(seconds);

// Turn off motors


right_motor.Stop();
left_motor.Stop();
}
//Function for pulsing left using encoders
void pulse_counterclockwise(int percent, float seconds)
{
// Set both motors to desired percent
right_motor.SetPercent(percent);
left_motor.SetPercent(-percent);

// Wait for the correct number of seconds


Sleep(seconds);

// Turn off motors


right_motor.Stop();
left_motor.Stop();
}

//Function to check RPS X values and have the robot correct itself to
those values
void check_x(float x_coordinate, int orientation, int power)
{
// Determine the direction of the motors based on the orientation of
the QR code
if (orientation == MINUS)
{
power = -PULSE_POWER;
}

// Check if receiving proper RPS coordinates and whether the robot is


within an acceptable range
while (RPS.X() > 0.0 && RPS.Y() > 0.0 && RPS.Heading() > 0.0 &&
(RPS.X() < x_coordinate - 0.25 || RPS.X() > x_coordinate + 0.25))

H3
{
LCD.WriteLine(RPS.X());
// Forward
if (RPS.X() < x_coordinate - 0.25)
{
// Pulse the motors for a short duration in the correct
direction
pulse_forward(power, .25);
LCD.WriteLine("Correction = Forward");

} // Backward
else if (RPS.X() > x_coordinate + 0.25)
{
// Pulse the motors for a short duration in the correct
direction
pulse_forward(-power, .25);
LCD.WriteLine("Correction = Backward");
}
Sleep(RPS_WAIT_TIME_IN_SEC);
}
}

//Function to check RPS Y values and have the robot correct itself to
those values
void check_y(float y_coordinate, int orientation, int power)
{
// Determine the direction of the motors based on the orientation of
the QR code
if (orientation == MINUS)
{
power = -PULSE_POWER;
}

// Check if receiving proper RPS coordinates and whether the robot is


within an acceptable range
while (RPS.X() > 0.0 && RPS.Y() > 0.0 && RPS.Heading() > 0.0 &&
(RPS.Y() < y_coordinate - 0.25 || RPS.Y() > y_coordinate + 0.25))
{
// Forward

H4
if (RPS.Y() < y_coordinate - 0.25)
{
// Pulse the motors for a short duration in the correct
direction
pulse_forward(power, PULSE_TIME);

} // Backward
else if (RPS.Y() > y_coordinate + 0.25)
{
// Pulse the motors for a short duration in the correct
direction
pulse_forward(-power, PULSE_TIME);
}
Sleep(RPS_WAIT_TIME_IN_SEC);
}
}

//Function to check RPS Heading values and have the robot correct itself
to those values
void check_heading(float heading)
{

float currentHeading = RPS.Heading();

while (currentHeading > heading + 1 || currentHeading < heading - 1)


{

float pulseTime = PULSE_TIME * 0.2;

if (heading == 0)
{
if(currentHeading < 359.9 - currentHeading) {
pulse_counterclockwise(-PULSE_POWER, pulseTime);
} else {
pulse_counterclockwise(PULSE_POWER, pulseTime);
}
} else {
// Pulse longer if the heading is off by more than 5 to
decrease time spent pulsing
if (abs(currentHeading - heading) > 6){

H5
pulseTime = PULSE_TIME * 0.5;
}
if (currentHeading < heading - 1)
{
pulse_counterclockwise(PULSE_POWER, pulseTime);
} else if (currentHeading > heading + 1)
{
pulse_counterclockwise(-PULSE_POWER, pulseTime);
}
}

currentHeading = RPS.Heading();
Sleep(RPS_WAIT_TIME_IN_SEC);
}
}
//Function to set RPS values before run
//Creates Consistency between courses and locations
void logPoints(){
FEHFile *RPS_Points = SD.FOpen("RPS.txt", "w");
float x, y;
Sleep(.6);
LCD.WriteLine("X & Y for Burger:"); //Check X & Y Value for Burger
while (!LCD.Touch(&x, &y)){
LCD.WriteLine(RPS.X());
LCD.WriteLine(RPS.Y());
Sleep(.25);
}
float tmpBurgerX = RPS.X();
float tmpBurgerY = RPS.Y();
SD.FPrintf(RPS_Points, "%s\t%f\t%f\t%f", "BX", tmpBurgerX, 0., 0.);
SD.FPrintf(RPS_Points, "\n%s\t%f\t%f\t%f", "BY", 0., tmpBurgerY, 0.);
LCD.Clear();
Sleep(.6);
LCD.WriteLine("X for chocolate ice cream:");
while (!LCD.Touch(&x, &y)){
LCD.WriteLine(RPS.X());
Sleep(.25);
}
float tmpChocolate = RPS.X();

H6
SD.FPrintf(RPS_Points, "\n%s\t%f\t%f\t%f", "CH", tmpChocolate, 0.,
0.);
Sleep(.6);
LCD.Clear();
LCD.WriteLine("X & Y for Juke:");
while (!LCD.Touch(&x, &y)){
LCD.WriteLine(RPS.X());
LCD.WriteLine(RPS.Y());
Sleep(.25);
}
float tmpJukeX = RPS.X();
float tmpJukeY = RPS.Y();
SD.FPrintf(RPS_Points, "\n%s\t%f\t%f\t%f", "JX", tmpJukeX, 0., 0.);
SD.FPrintf(RPS_Points, "\n%s\t%f\t%f\t%f", "JY", 0., tmpJukeY, 0.);
LCD.Clear();
SD.FClose(RPS_Points);
}

//Function to Read Logged RPS Data Files


float readRPSFile(const char *location, const char *whichRPSVal){
FEHFile *RPS_Points = SD.FOpen("RPS.txt", "r");
float RPS_DesiredPoint = -1;
char name[20];
if (strcmp(whichRPSVal, "X") == 0){
for (int i = 0; i < 5; i++){
SD.FScanf(RPS_Points, "%s%f%*s%*s", name, &RPS_DesiredPoint);
if(strcmp(location, name) == 0)
break;
}
}
if (strcmp(whichRPSVal, "Y") == 0){
for (int i = 0; i < 5; i++){
SD.FScanf(RPS_Points, "%s%*s%f%*s", name, &RPS_DesiredPoint);
if(strcmp(location, name) == 0)
break;
}
}
if (strcmp(whichRPSVal, "Heading") == 0){
for (int i = 0; i < 5; i++){
SD.FScanf(RPS_Points, "%s%*s%*s%f", name, &RPS_DesiredPoint);

H7
if(strcmp(location, name) == 0)
break;
}
}
SD.FClose(RPS_Points);
return RPS_DesiredPoint;
}

//Function To Turn Right using encoders


void turn_right(int percentage, int encoder_counts)
{
// Reset encoder counts
right_encoder.ResetCounts();
left_encoder.ResetCounts();

// Set both motors to desired percent


left_motor.SetPercent(percentage);
right_motor.SetPercent(-percentage);

// Keep running motors while average of left and right encoder is less
// than encoderCounts
double startTime = TimeNow();
while ((left_encoder.Counts() + right_encoder.Counts()) / 2.0 <
encoder_counts && TimeNow() - startTime < 2.75);

// turn off motors


right_motor.Stop();
left_motor.Stop();
}

/* function for turning left. use encoders */


void turn_left(int percentage, int encoder_counts)
{
// Reset encoder counts
right_encoder.ResetCounts();
left_encoder.ResetCounts();

// Set both motors to desired percent


left_motor.SetPercent(-percentage);
right_motor.SetPercent(percentage);

H8
// Keep running motors while average of left and right encoder is less
// than encoderCounts
double startTime = TimeNow();
while ((left_encoder.Counts() + right_encoder.Counts()) / 2.0 <
encoder_counts && TimeNow() - startTime < 2.75);

// turn off motors


right_motor.Stop();
left_motor.Stop();
}

/* function for moving forward. use encoders */


void move_straight(int percentage, int encoder_counts, float time)
{
// Reset encoder counts
right_encoder.ResetCounts();
left_encoder.ResetCounts();

// Set both motors to desired percent


left_motor.SetPercent(percentage);
right_motor.SetPercent(percentage);

// Keep running motors while average of left and right encoder is less
// than encoderCounts
double startTime = TimeNow();
while ((left_encoder.Counts() + right_encoder.Counts()) / 2.0 <
encoder_counts && TimeNow() - startTime < time);

// turn off motors


right_motor.Stop();
left_motor.Stop();
}

/* function for moving at an angle


direction is based off of quadrants (1 is forward right, 2 forward
left, etc.)
percentage is motor percentage
angle is the desired angle of turning as a decimal
encoder counts for how much to go*/

H9
void angled_turn(int direction, int percentage, float angle, float inches)
{
// Initializing distance and angle
int encoder_counts = inches * COUNTS_PER_INCH;
float turn_radius = angle / 100.0;
// Reset encoder counts
right_encoder.ResetCounts();
left_encoder.ResetCounts();
// Set both motors to desired percent based on direction
int adjusted_angle = percentage * (1 - turn_radius);
switch (direction)
{
case 1:
left_motor.SetPercent(percentage);
right_motor.SetPercent(adjusted_angle);
break;
case 2:
left_motor.SetPercent(adjusted_angle);
right_motor.SetPercent(percentage);
break;
case 3:
left_motor.SetPercent(-adjusted_angle);
right_motor.SetPercent(-percentage);
break;
case 4:
left_motor.SetPercent(-percentage);
right_motor.SetPercent(-adjusted_angle);
break;
case 5:
left_motor.SetPercent(-percentage / (1 - turn_radius));
right_motor.SetPercent(percentage / (1 - turn_radius));
break;
}

// Keep running motors while average of left and right encoder is less
// than encoderCounts
while ((left_encoder.Counts() + right_encoder.Counts()) / 2.0 <
encoder_counts);

// turn off motors

H10
right_motor.Stop();
left_motor.Stop();
Sleep(.25);
}

/* Function for moving based off sensing the start light */

void start()
{
// Display whu function is currently running
LCD.Clear();
float x, y;
while (!LCD.Touch(&x, &y));
LCD.WriteLine("start");
LCD.WriteLine("put the tray on now.");
LCD.WriteLine("");
LCD.WriteLine("press the screen again to begin the 30s time out");
arm_servo.SetMin(SERVO_MIN);
arm_servo.SetMax(SERVO_MAX);
arm_servo.SetDegree(30.0);
Sleep(0.35);

while (!LCD.Touch(&x,&y));
LCD.Clear();
LCD.WriteLine("Final action has been completed");
LCD.WriteLine("30s countdown has begun");
// Starting servo at 0 degrees

// While elapsed time is less than 30 seconds.


float time_now = TimeNow();
bool started = false;
while (TimeNow() - time_now < 30 && !started)
{
// Wait until light goes on
while (cds.Value() > CDS_BLUE_THRESHOLD)
;
if ((cds.Value() > CDS_RED_THRESHOLD) && cds.Value() <
CDS_BLUE_THRESHOLD)

H11
{
LCD.WriteLine("The start line was red"); // Display what color
is read
}
else
{
LCD.WriteLine("The start line was red"); // Display what color
is read
}
started = true;
}
// Once 30 seconds elapsed, start anyway
LCD.WriteLine("Did not read a light within 30 secs. Starting
anyway.");
// Call any function
}

//Original Function to go to Jukebox from Start Button


void toJuke(int lever)
{
arm_servo.SetDegree(150);
move_straight(-STD_POWER, COUNTS_PER_INCH * 5., 6.0);
while (RPS.Heading() < -1.5) {
move_straight(-STD_POWER, COUNTS_PER_INCH * 0.1, 6.0);
Sleep(0.1);
}
arm_servo.SetDegree(10);
Sleep(0.35);
check_heading(90.);
turn_left(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);

switch (lever) {
case 0:
move_straight(-STD_POWER, COUNTS_PER_INCH * 8, 6.0);
break;
case 1:
move_straight(-STD_POWER, COUNTS_PER_INCH * 8, 6.0);
break;
case 2:
move_straight(-STD_POWER, COUNTS_PER_INCH * 5.5, 6.0);

H12
break;
}

turn_left(20, COUNTS_PER_INCH * (NINETY_DEG_TWENTYSPEED + 0.125));


Sleep(0.35);
arm_servo.SetDegree(80.);
check_heading(270.);
move_straight(STD_POWER, COUNTS_PER_INCH * 27., 6.0);
arm_servo.SetDegree(0.);
turn_right(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
move_straight(STD_POWER, COUNTS_PER_INCH * 7., 6.0);
Sleep(.35);
float JukeX = readRPSFile("JX", "X");
check_x(JukeX, MINUS, 12);
turn_left(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
Sleep(0.35);
check_heading(270.);
// move_straight(20, COUNTS_PER_INCH * 0.33, 6.0);
Sleep(0.35);
float JukeY = readRPSFile("JY", "Y");
check_y(JukeY, MINUS, 12);

//Function to push a jukebox button after reading the light


bool atJuke()
{
// Set boolean to know which button was hit. False is red, true is
blue
bool button = false;
// Display what function is currently running
LCD.Clear();
LCD.WriteLine("pushButton");

if (cds.Value() < CDS_RED_THRESHOLD)


{
LCD.Clear(RED); // Display what color is read
LCD.WriteLine("Need to hit RED");
LCD.WriteLine(cds.Value());

H13
turn_right(20, COUNTS_PER_INCH * 5);
move_straight(STD_POWER, COUNTS_PER_INCH * 0.75, 6.0);
turn_left(20, COUNTS_PER_INCH * 5);
move_straight(STD_POWER, COUNTS_PER_INCH * 5.25, 6.0);
}
else
{
LCD.Clear(BLUE); // Display what color is read
LCD.WriteLine("Need to hit BLUE");
LCD.WriteLine(cds.Value());
turn_left(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
move_straight(STD_POWER, COUNTS_PER_INCH * 0.6, 6.0);
turn_right(20, COUNTS_PER_INCH * 5.8);
move_straight(STD_POWER, COUNTS_PER_INCH * 5.45, 6.0);
button = true; // hit blue button
}
return button;//Returns which button was hit so robot knows
approximately where it is
}

//Original function to move from jukebox to ramp


void toRamp(bool redBlue)
{
LCD.Clear();
LCD.WriteLine("toRamp");
if (!redBlue)
{
move_straight(-STD_POWER, COUNTS_PER_INCH * 6, 6.0);
turn_right(20, COUNTS_PER_INCH * 5);
move_straight(-STD_POWER, COUNTS_PER_INCH * 10, 6.0);
turn_left(20, COUNTS_PER_INCH * 5);
move_straight(-STD_POWER, COUNTS_PER_INCH * 4, 6.0);
}
else
{
move_straight(-STD_POWER, COUNTS_PER_INCH * 6, 6.0);
turn_right(20, COUNTS_PER_INCH * 5);
move_straight(-STD_POWER, COUNTS_PER_INCH * 9, 6.0);
turn_left(20, COUNTS_PER_INCH * 5);
move_straight(-STD_POWER, COUNTS_PER_INCH * 4, 6.0);

H14
}
}

//Function used to test servo


void moveArm()
{
// Enter the min and max servo valeus from the .TouchCalibrate() fxn

float x, y;
while (!LCD.Touch(&x, &y))
{
arm_servo.SetDegree(180.0);
}
Sleep(.1);
while (LCD.Touch(&x, &y))
{
arm_servo.SetDegree(1.0 / cds.Value() * 180.0);
}
}

//Function to have robot move to the trash can and set up to deposit tray
void toTray()
{
move_straight(STD_POWER, COUNTS_PER_INCH * 13.7, 6.75);
turn_left(20, COUNTS_PER_INCH * 5.6);
move_straight(STD_POWER, COUNTS_PER_INCH * 18.5, 6.0);
turn_right(20, COUNTS_PER_INCH * 5.0);
check_heading(93.);
move_straight(STD_POWER, COUNTS_PER_INCH * 0.45, 0.2);
Sleep(1.0);
}

//Moves arm down to deposit tray into trash can


void atTray()
{

for (float degree = 30.0; degree < 130.0; degree += 5)


{
arm_servo.SetDegree(degree);
Sleep(.05);

H15
}
Sleep(1.0);
move_straight(-20, COUNTS_PER_INCH * .95, 1.0); //The next few lines
ensure that the arm doesn't keep holding the tray while its moving back
turn_left(STD_POWER, COUNTS_PER_INCH * 0.4);
turn_right(STD_POWER, COUNTS_PER_INCH * 0.4);
arm_servo.SetDegree(125);
move_straight(-20, COUNTS_PER_INCH * 1.5, 1.0);
arm_servo.SetDegree(120);
move_straight(-20, COUNTS_PER_INCH * 2.25, 1.5);
}

//Moves robot to the ticket from the trash can


void toTicket()
{

arm_servo.SetDegree(20.0);
Sleep(.25);
arm_servo.SetDegree(125.);
Sleep(.25);
arm_servo.SetDegree(20.);
turn_right(20, COUNTS_PER_INCH * 5.6);
move_straight(STD_POWER, COUNTS_PER_INCH * 21., 6.0);
// check_heading(0.);
// turn_left(20, COUNTS_PER_INCH * 4.25); // DO NOT CHANGE JUST CHARGE
PROTEUS
turn_left(20, COUNTS_PER_INCH * 5.45);
Sleep(0.35);
check_heading(90.);
turn_right(20, COUNTS_PER_INCH * 0.8);

//places arm in the correct place to quickly rotate and throw the ticket
to the ready side
void atTicket()
{
for (int i = 20.; i < 160; i+=5){
arm_servo.SetDegree(i);

H16
Sleep(.05);
}
move_straight(STD_POWER,COUNTS_PER_INCH * 6.5,2.3);
arm_servo.SetDegree(158);
move_straight(STD_POWER, COUNTS_PER_INCH * .7, .35);
turn_right(20, COUNTS_PER_INCH * .65);
move_straight(STD_POWER, COUNTS_PER_INCH * .75, .35);
Sleep(.5);
angled_turn(5, 20, 50, 2);
}

//Moves back from ticket and approaches the hotplate


void toBurger()
{
turn_right(20, COUNTS_PER_INCH * 1.1); // 15 deg turn
move_straight(-STD_POWER, COUNTS_PER_INCH * 6.5, 6.0);
arm_servo.SetDegree(140);
turn_left(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
move_straight(STD_POWER, COUNTS_PER_INCH * 10.5, 6.0);
turn_right(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
move_straight(50, COUNTS_PER_INCH * 26., 6.0);
Sleep(0.1);
move_straight(STD_POWER, COUNTS_PER_INCH * 6.25, 2.0);
Sleep(.5);
turn_right(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
arm_servo.SetDegree(20);
move_straight(STD_POWER, COUNTS_PER_INCH * 4.75, 6.0);
float burgerX = readRPSFile("BX", "X");
LCD.WriteLine(burgerX);
Sleep(.35);
check_x(burgerX, PLUS,14);
turn_left(20, COUNTS_PER_INCH * 5.13);
Sleep(.35);
check_heading(88.);
arm_servo.SetDegree(180);
}

//Throws the hotplate up and returns the hotplate to original position


void atBurger()
{

H17
move_straight(STD_POWER, COUNTS_PER_INCH * 1.25, 0.75);
float burgerY = readRPSFile("BY", "Y");
Sleep(.35);
check_y(burgerY, PLUS, 14);
arm_servo.SetDegree(170);
Sleep(0.2);
for (int i = 170; i > 130; i = i - 10)
{
arm_servo.SetDegree(i);
Sleep(0.05);
}
// arm_servo.SetDegree(100); // set to 140 in the toHotPlate() fxn.
move_straight(STD_POWER, COUNTS_PER_INCH * .4, 6.0);
arm_servo.SetDegree(65);
// left_motor.SetPercent(20);
turn_right(40, COUNTS_PER_INCH * 2); // 20 degree turn
Sleep(1.0);
arm_servo.SetDegree(90);
move_straight(-25, COUNTS_PER_INCH * 3, 6.0);
turn_left(20, COUNTS_PER_INCH * 2.);
Sleep(0.35);
check_heading(90.);
Sleep(0.35);
}

void toIceCream(int whichIceCream)


{
move_straight(-STD_POWER, COUNTS_PER_INCH * 4, 6.0);
turn_left(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
Sleep(0.35);
check_heading(175.);
move_straight(STD_POWER, COUNTS_PER_INCH * 4.5, 6.0);
float chocolateX = readRPSFile("CH", "X");
Sleep(.35);
check_x(chocolateX, MINUS, 14);
arm_servo.SetDegree(30);
switch(whichIceCream){
case 2:
move_straight(25, COUNTS_PER_INCH * 5.35, 6.0);

H18
turn_right(20, COUNTS_PER_INCH * 5.3);
move_straight(25, COUNTS_PER_INCH * 7.5, 6.0);
break;
case 1:
move_straight(25, COUNTS_PER_INCH * 8.5, 6.0);
turn_right(20, COUNTS_PER_INCH * NINETY_DEG_TWENTYSPEED);
move_straight(25, COUNTS_PER_INCH * 4.75, 6.0);
break;
case 0:
move_straight(25, COUNTS_PER_INCH * 9., 6.0);
turn_right(20, COUNTS_PER_INCH * 4.4);
move_straight(25, COUNTS_PER_INCH * 2.5, 6.0);
break;
}
}

void atIceCream(int lever){


Sleep(.5);
for (int degree = 30; degree < 140; degree+=10)
{
arm_servo.SetDegree(degree);
Sleep(.05);
}
arm_servo.SetDegree(110);
move_straight(-STD_POWER, COUNTS_PER_INCH * 3, 1.0);
Sleep(1.);
arm_servo.SetDegree(160);
move_straight(STD_POWER, COUNTS_PER_INCH * 3, 1.0);
//turn_left(20, COUNTS_PER_INCH * .3); // do we still need to turn
left?
pulse_counterclockwise(PULSE_POWER, PULSE_TIME);
double startTime = TimeNow();
for (int degree = 160; degree > 80 && TimeNow() - startTime < 1.5;
degree-=10)
{
arm_servo.SetDegree(degree);
Sleep(.05);
}
arm_servo.SetDegree(150);
move_straight(-STD_POWER,COUNTS_PER_INCH * 1.0,1.0);

H19
turn_right(20,COUNTS_PER_INCH*.2);

void toFinish(bool button)


{
if(!button) // Red button
{
move_straight(-STD_POWER,COUNTS_PER_INCH*10.5, 6.0);
turn_left(20,NINETY_DEG_TWENTYSPEED+COUNTS_PER_INCH*3);
move_straight(60,COUNTS_PER_INCH*30, 6.0);
} else
{
move_straight(-STD_POWER,COUNTS_PER_INCH*7.5, 6.0);
turn_left(20,NINETY_DEG_TWENTYSPEED+COUNTS_PER_INCH*3);
move_straight(60,COUNTS_PER_INCH*30, 6.0);
}
}

void start0()
{
float x, y;
while (!LCD.Touch(&x, &y))
{
LCD.Clear();
LCD.WriteLine(cds.Value());
Sleep(0.5);
}

int main(void)
{
arm_servo.SetMin(SERVO_MIN);
arm_servo.SetMax(SERVO_MAX);
//start0();
RPS.InitializeTouchMenu();
logPoints();

H20
// float IRPSX = RPS.X();
// float IRPSY = RPS.Y();
start();
int lever = RPS.GetIceCream();
toTray();
atTray();
toTicket();
atTicket();
toBurger();
atBurger();
toIceCream(lever);
atIceCream(lever);

toJuke(lever);
bool button = atJuke();
toFinish(button);
return 0;
}

H21
APPENDIX I

Code Representation
Algorithm for main method
**Disclaimer - move_straight method moves the robot straight a certain number of counts; turn_right
and turn_left turn the robot right and left a certain number of encoder counts, respectively.**
1. Call LogPoints()
a. Open SD File
b.
1. Call the start() method
a. Clear screen and display “start”
b. Move arm to 30º angle so that it is within boundaries
c. Stay still while time elapsed is less than 30 seconds and the start light has not turned on.
d. Display light that was turned on if a light is turned on.
i. Otherwise, display that no light was detected
e. Call the next method.
2. Call toTray() method
a. Call move_straight and move 13 inches forward from starting position.
b. Call turn_left and turn 90º
c. Call move_straight and move 19 inches forward.
d. Call turn_right and turn 90º
e. Call move_straight and move 1 inch forward.
3. Call atTray() method
a. Set the servo’s min and max.
b. Slowly lower the forklift mechanism from 30º to 165º
c. Call move_straight to move backward 2 inches.
d. Raise the arm slightly.
e. Call move_striaght to move backward another 2.25 inches.
4. Call toTicket() method
a. Set servo arm to 20º
b. Turn right 90º
c. Move forward 21.8 inches using move_straight method
d. Turn left 80º
5. Call atTicket() method
a. Set servo arm to 180º
b. Move forward 6.85 inches to lodge the arm in between the ticket and wall.
c. Turn left using the angled_turn method to move the ticket.
6. Call toRampFromLower() method
a. Turn right 15º
b. Move backward 4 inches
c. Set servo arm to 140º
d. Turn left 90º
e. Drive forward 11 inches

I2
f. Turn right 90º
g. Check positioning using RPS
h. Call SServe() method (See #7)
7. Call to toSServe(Correct Lever) method
a. Drive 20 inches forward to go up the ramp
b. Check positioning and ice cream flavor using RPS
c. Move left, right or stay in the same place for vanilla, chocolate, and twist respectively
d. Turn left 30º
e. Drive forward 20 inches
f. Call atSServe() method.
i. Set servo arm to 30º
ii. Gradually lower the servo arm to 180º while the arm is over the correct lever.
g. Call toHotPlate(Correct Lever) method
i. Drive backward 11 inches
ii. Turn right 45º
iii. Check position using RPS
iv. Drive forward certain amount based on RPS data
v. Lodge the arm under the hotplate handle.
h. Call atHotPlate() method
i. Raise arm to 45º gradually
ii. Turn right 45º to flip the hotplate
i. Drive back to the soft serve
i. Move backward certain amount based on RPS reading of which lever was flipped
ii. Turn left 45º
iii. Lower arm to 160º
iv. Drive forward certain amount based on RPS reading
j. Flip lever back up by raising arm gradually from 160º to 45º
8. Call toRampFromUpper(Correct Lever) method
a. Drive backward certain amount based on which lever was hit
b. Turn 135º so front is facing the lower level
c. Check RPS Positioning
d. Drive forward based on robot positioning.
9. Call toJuke() method
a. Move forward 20 inches to drive down the ramp
b. Move to location of the light
i. Turn right, drive forward, turn left, drive forward.
c. Check RPS for position
d. Read light display of jukebox song
10. Call atJuke() method
a. Display color that was read to screen
b. Write boolean for which color was read
c. Turn call turn_left 90º or turn_right 90º for blue or red respectively

I3
d. Call move_straight for 1 inch
e. Call turn_left 90º or turn_right 90º for red or blue respectively
f. Call move_straight for 5 inches
11. Call endRun(Correct Juke Box Button) method
a. Drive backward a certain amount of inches based on parameter.
b. Turn left 80º
c. Drive forward 30 inches to hit the final red button!
Verbal Description:
In an attempt to make the code as modular as possible, we divided each task into two functions.
One function would be for moving the robot to the correct position to accomplish the task and the other
function would be for actually doing or accomplishing the task. The function for moving the robot to the
correct task (often called “toTaskName”) takes into consideration the final position of the robot after
accomplishing each task, and moves accordingly, sometimes with the aid of RPS. Each function for
accomplishing the tasks (often called “atTaskName”) assumes that the robot is in the correct position
and only has to worry about executing the correct sequences of actions to finish the task.
The toSServe() method has function calls within it. This is due to the fact that the robot must
move back to the soft serve machine after completing the hot plate task to move the lever back up to
the up position. Although this is different from most other functions in that most other functions do not
have a call to another method, the performance of the robot and the modularity of the code should not
be affected.

Function for LogPoints() Detailed


List of inputs
N/a

List of Outputs
N/a

Pseudocode
1. Wait for RPS initialization
2. Wait for touch and return coordinates
3. Store coordinates when touched
4. Repeated steps 2 and 3 3 times
5. Wait for final touch to go to start function

Function for Start() Detailed


List of inputs
N/a

List of Outputs
N/a

I4
Pseudocode
1. Start a 30 second timer
2. Check if either the start light has turned on our if the timer has finished
3. Once the start light or timer finishes start the run

Function for Totray() Detailed


List of Inputs
N/a

List of Outputs
N/a

Pseudocode
1. Move forward
2. Turn Left 90 degrees
3. Move forward until robot is in line with trash
4. Turn right 90 degrees
5. Move forward 2 inches

Function for AtTray() Detailed


List of Inputs
N/a

List of Outputs
N/a

Pseudocode
1. Slowly move arm down
2. Move back slightly
3. Move arm up slightly so there is not friction between the arm and tray
4. Turn left slightly
5. Turn right slightly
6. Move back to have tray fall off arm
7. Quickly move arm up and down to ensure the tray is off

Function for ToTicket() Detailed


List of Inputs
N/a

List of Outputs
N/a

I5
Pseudocode
1. Turn right 90 degrees
2. Move straight until robot has almost hit the wall
3. Turn left 90 degrees
4. Check RPS heading for 90 degrees
5. Turn right slightly
6. Drive forward into ticket

Function for AtTicket() Detailed


List of Inputs
N/a

List of Outputs
N/a

Pseudocode
1. Turn right to wedge arm between ticket and wall
2. Turn left to move the ticket with the arm

Function for ToBurger() Detailed


List of Inputs
N/a

List of Outputs
N/a

Pseudocode
1. Turn right 15 degrees
2. Move backward from ticket
3. Move forward to ramp
4. Turn right 90 degrees
5. Move forward up ramp
6. Turn right 90 degrees
7. Move forward until in line with x position of burger
8. Turn left 90 degrees
9. Move forward until in line with y position of burger

Function for AtBurger() Detailed


List of Inputs
N/a

List of Outputs

I6
N/a

Pseudocode
1. Lift arm up slightly
2. Lift arm up high quickly
3. Turn robot right to move hot plate
4. Move backward slightly to release hot plate from arm

Function for ToIceCream(WhichIceCream) Detailed


List of Inputs
1. Integer variable indicating which ice cream lever should be flipped
a. 0 indicates vanilla
b. 1 indicates twist
c. 2 indicates chocolate

List of Outputs
N/a

Pseudocode
1. Move backward away from burger
2. Turn left 90 degrees
3. Move forward 5 inches for chocolate, 8 inches for twist, or 9 inches for vanilla
4. Turn right 90 degrees
5. Move forward 8 inches for chocolate, 5 inches for twist, or 3 inches for vanilla

Function for AtIceCream() Detailed


List of Inputs
N/a

List of Outputs
N/a

Pseudocode
1. Move arm down partially
2. Move backward away from lever
3. Move arm down fully
4. Move forward underneath lever
5. Move arm up
6. Quickly move arm down
7. Move back away from lever

I7
Function for toJuke(IceCreamLever) Detailed
List of Inputs
1. Integer variable indicating which ice cream lever should be flipped
a. 0 indicates vanilla
b. 1 indicates twist
c. 2 indicates chocolate

List of Outputs
N/a

Pseudocode
1. Back up until robot is not in dead zone
2. Turn left 90 degrees
3. Back up until robot is even with ramp
4. Turn left 90 degrees
5. Move forward down the ramp
6. Turn right 90 degrees
7. Check RPS X value with data from log points
8. Turn left 90 degrees
9. Check RPS Y value with data from log points

Function for atJuke() Detailed


List of Inputs
N/A

List of Outputs
1. Boolean variable indicating which jukebox button should be pressed
a. False indicates red
b. True indicates blue

Pseudocode
1. Read value of light using CDS cell
2. Turn right for red or turn left for blue
3. Move forward 0.7 inches
4. Turn left for red or turn right for blue
5. Move forward 5 inches to hit button

Function for toFinish(button) Detailed


List of inputs
1. Boolean variable indicating which button on the JukeBox was pressed
a. False indicates red button

I8
b. True indicates blue button

List of Outputs
N/A

Pseudocode
1. Check which button was pressed using boolean variable
2. Call move_straight() reversed 5 inches for false (red button) and 3 inches for true (blue
button)
3. Call turn_left() 80 degrees
4. Call move_straight() for 30 inches
5. When the final button is pressed, the course and robot will stop

I9
APPENDIX J

Symbols
𝐹𝑚𝑜𝑡𝑜𝑟 Force of Motor (N)

τ𝑚𝑜𝑡𝑜𝑟 Torque of Motor (oz-in)

𝑊 Weight of robot (N)

𝐹𝑖𝑛𝑡𝑒𝑟𝑛𝑎𝑙 𝑓𝑟𝑖𝑐𝑡𝑖𝑜𝑛 Internal friction of robot (N)

J2

You might also like