Eric Drucker
Tony Snodgrass
Darren Earl
Dragon Bot: A Reactive Search and Capture Robot
Abstract
The purpose of this project was to design a robot that would autonomously search a limited field looking for small, orange cubes which it would then pick up and deposit in a green bin located in the center of the field. A Lego Mindstorms kit was used to build the robot and its prototypes. Our robot was designed to move on two treads, detect the orange blocks and the green bin with light sensors and touch sensors, and to pick up the orange blocks with a claw mechanism attached to an arm that could be lowered and raised. The initial concept of our robot stayed consistent throughout all prototype inceptions. No drastic redesigns were required. Only small adjustments and design addendums were needed to surmount problems as they arose.
Introduction/Background
The purpose of this project was to construct a robot to perform a given task completely autonomously in a given field space. That task was to search the field space for small orange blocks. Once the blocks are located, the robot picks them up and deposits them in a green bin located in the center of the field. The field itself was was a large piece of vinyl, rectangular in shape, placed on a large dark-brown conference table. It had yellowish masking tape boarders, a white surface, and blue cross-hairs dividing the field into four quadrants. The green bin was located in the center of the field. The original challenge was to find three orange blocks, no more, no less. There was at most one block in any given quadrant, which meant one quadrant was empty. The blocks were placed at random in their respective quadrants. Here is a rough depiction of the field:

The orange blocks were small cubes, roughly two inches on each edge. The green bin, as pictured, was rectangular and measured approximately four inches high and roughly 6” by 8” in length and width. The green bin was weighted down with dead AA batteries to secure it in the center of the field.
A Lego Mindstorms version 1.0 was used to build the robot. Three motors, two light sensors, one touch sensor, two tank treads, wires, the RCX Brick, and various connecting pieces were the Mindstorms kit components used for this project. The sensors available on this task were simple light sensors that operate on a raw data basis, measuring not the color, but the light intensity of an object roughly one inch in front of it. Also, the touch sensor used operates on a binary touched-untouched basis, insensitive to pressure. The Mindstorms kit is controlled entirely by the RCX brick, which is powered by a Renesas H8/300 microcontroller (WI2006). The RCX has three output connections and three input connections. To write, compile, and send code to the RCX, Bricx Command Center (BCC) 3.3 was used. BCC is an IDE for the RCX and uses the programming language Not Quite C (NQC). The motors can only be controlled by time intervals by the RCX, causing them to be very inconsistent. Also, because the light sensors measure the intensity of the light they perceive and give a raw score of it, the accuracy of the light sensors depended on the lighting conditions of the room staying as consistent as possible.
Approach
The Basics

The way in which the robot would accomplish the goal fed the basics for the design of the robot. We envisioned a robot that would use a claw to grasp the orange blocks attached to an arm responsible for lifting the claw up and down. Light sensors would be used to detect the goals and obstacles in the field as well as keep track of field position. The use of tank treads seemed optimal because of the sheer mass of the conceived robot. Stability of motion for the chassis was optimized through use of the tank treads instead of two or more simple wheels.
Once an orange block has been detected by the light sensor, the robot would back up a little, open its claw, lower the claw, grasp the block, and raise the claw. With an orange block “in-hand”, the robot would seek out the green bin and deposit the orange block. Once that is accomplished, it would repeat this process of seeking out the blocks and depositing them in the green bin until all three blocks were found.
Design Initials
Early on, it we wanted to use the tank treads for this robot. We observed the stability of motion of having tank treads, albeit not all that consistent. By consistent, turns were not always constant and straight lines were not always perfectly straight.

Also, as with previous work, we opted to use a v1.0 brick because of the advantage of a 12v power connection as pictured. This gave us the advantage of not rapidly depleting battery power during both development and testing. Also as with previous work, we used the Bricx Command Center to compile, upload, and run our programs in NQC (Not Quite C). A new tool used in the development was an IR remote control which could be used to run the motors in any desired direction.
Three Motors, Four Jobs
The very first problem addressed was discussed by the team at the very start of the design phase. The robot had four distinct kinetic tasks: operation of the left-side tank tread, operation of the right-side tank tread, the lowering and raising of the robotic arm, and the clasping and release of the robotic claw. The RCX brick only allows for the control of three motors. With four tasks and only three motors, we had to be creative in our design.
By our reasoning, indeed there were four tasks, but only two types of task: the motion of the robot itself and the grab/release of an orange block. We decided that a single motor could share its power with each type of task. One motor would control a tank tread and the lowering/raising of the robotic arm. Another motor would control the other tank tread and the opening/closing of the robotic claw. The third motor would be responsible for shifting between the two types of task: motion and grab/release.
Shifting Gears
This design requires that the two motors responsible for the two types of tasks cannot be stationary in the robot: they themselves must move between two separate sets of gears. The two motors are referred to as the kinetic motors, and the third motor is the shifting motor. Here are two pictures of the motors being shifted between the two different gear meshing of each task:


The kinetic motors were mounted on a small platform which was fixed in place inside the robot in such a way that it would be allowed to shift back and forth with one and only one dimension of freedom between the two gear meshing points for each task. The platform had four smaller-sized gears acting like wheels atop of a track comprised of two rows of flat Lego pieces, measuring one dot by four dots, fixed with gear-meshing teeth on their tops. This allowed for the motor platform to move smoothly and consistently with no twisting.
The top of the platform had to be specially designed to prevent any movement of the platform in any other direction than the one desired. This was accomplished by using some of the two-dot by two-dot L pieces from the Mindstorms Kit, which are flat on the inner faces of the L. Long Lego pieces, two dots in width, were used as upper support beams to secure the platform in place by sitting atop on the inside of the flat-faces of the L pieces, which were arranged to hug these support beams.
The top portion also had to be designed to incorporate the shifting of the platform powered by the shifting motor. Initially, the design was to have lego worm gears protruding from the engine on a rotating spindle and another set of worm gears fixed into place on one end of the platform. Once the worm gears were meshed and one set began to rotate, the other set and all things attached to it (the motor platform) would move in one direction or the other depending on the rotation of the worm gears. This design proved unstable and unreliable as an overturning of the shifting motor would cause the axles to which the worm gears were attached to twist, un-mesh, and pry up entire sections of the robot chassis. Several attempts to stabilize the dual-axle worm gear apparatus never proved to be 100% reliable.
A new approach taken was to ensure that any axle used never got twisted and that the platform could not help but to go only where it was intended to go, lest the shifting motor stall out (which never happened, of course). Instead of a fixed axle protruding from one side of the platform rigged with non-rotating worm gears, a track of the flat Lego pieces, measuring one dot by four dots, fixed with gear-meshing teeth on their tops was fixed on top of the kinetic motors of the platform. The axle of worm gears that rotated with the shifting motor, which was once only secured on end of the axle (the rest hanging out in space unsecured because one end inevitably collided with the platform it was shifting) was secured at both ends of the axle, ensuring that it didn’t hop around on top of the track atop the motors. This is pictured below:

The stable shifting of the platform from one gear mesh point to the other was essential for operation. If the platform were allowed to hop the track or otherwise travel outside that single dimension of desired motion, the gears would not mesh up correctly for the two tasks and the integrity of the whole robot chassis would be compromised as a result of a botched gear meshing.
The One-Armed Robot
It was first decided that we would be using a claw-type grasping device to grab the blocks. This brought into sharp relief the need for a way to lower and raise the claw before and after a block is picked up. Through a working knowledge of geometry, we knew something special about how we could have a sturdy, stable arm device. We knew that two objects of equal length will maintain a space between their end points consistently when their orientation changes, provided that the objects of equal length are set parallel to each other, offset by a certain distance at each end, that distance being measured as a line between the two ends, and that line being measured by a 45-degree angle from the horizontal. In English, this means that we were able to make it so that the claw could be lowered and raised without rotating with respect to the ground. The figure below illustrates this geometric principle.

As you can see, the two points at the ends of the beams are separated by a 45-degree angle, equidistant from each other. The result is that the arm can rotate downward without either the base or the rotated object losing its horizontal orientation. This was crucial if we were to construct a claw mechanism that will be able to seize a block accurately and consistently. A claw that rigidly descended at a fixed angle would need to grab the claw in its teeth and hopefully not drop it or fling it backward and the arm retracted. With a stable, consistent angle to the horizontal, the orange blocks could be grabbed as a hand would hold a black in its palm, instead of its finger tips.
The issue arose that a block could be raised and lowered using a pull system and string, but a problem about keeping the arm upwards once the gears had been disengaged from the grabbing task gears and re-engaged to the motion gears had surfaced. We figured that we would use rubber bands to hold the arm up in place while the motion gears were engaged and the robot was either searching for blocks or searching for the bin. That way, the pulley system would not lift the arm, but rather pull it downwards to the ground when attempting to seize a block. Photos of the arm performing this task are pictured below:


Notice that the claw remained perfectly parallel to the ground in both pictures. Also take note that the ends of long pieces serving as the pivot points on the claw remain at a perfect 45-degree angle to each other.
Santa Claws

The claw was by-far the most challenging part of the design. Coming up with an adequate way to grasp an orange block in such a way that it can be lifted and transported without dropping it was very challenging. Fortunately for us, the Lego Mindstorms Kit comes equipped with specially curved parts which look as if they were intended to be part of a robotic claw. These pieces are pictured above and are yellow or dark grey in color.
The same issue faced with the arm was faced with the claw: how do we keep hold of a black that has been grasped once the motion gears are re-engaged? We solved this issue with the same solution employed with the arm. Rubber bands were used to hold the claw shut at all times, and the grasping motor was only used (via a pulley system) to open the claw. The pull from the rubber bands pulled it shut again once the pulley system released its tension.
Opening the claw as wide as possible without breaking it was an incredible challenge for the design. The respective ‘sides’ of the claw open in sync with each other because they are both oriented on two gears meshed together. This forces all motion of the claw to be perfectly symmetrical. This is pictured below:

The rubber bands provide the negative force to clasp the claw shut on a block. This has to be strong enough so that the block will not be dropped during transport. The clasp of an orange block is only about “mid-range” for the claw with respect to fully open and completely shut. Therefore, the mid-range tension has to be strong enough to hold onto a block.
The resistance of rubber bands gets stronger as they are stretched. Therefore, it stands to reason that the force required to get the claw to mid-range must be quite strong if mid-range is the claw state at which a block is held. However, this also means that the force needed to get the claw state to fully open must be even greater. Striking the proper balance between the force exerted by the pulley system responsible for the claw’s opening and the tension of the rubber bands providing the negative force took a lot of trial and error.
The original design had the portion of the pulley system oriented on the claw itself as a lever which was pulled inwards by the string attached to a pulley at the base of the robot’s chassis. The range of motion of the lever with respect to the actual range of opening of the claw was insufficient. The lever mechanism and its respective claw gearing were replaced with a wheel that had the string rapped around it, having the string pulled out of it and thus rotating it, almost like a fishing reel with reversed kinetics. When the line was pulled in at the base of the robot’s chassis, the wheel on the claw would unwind forcing open the claw. This apparatus is pictured below:

When tension was released, the rubber bands would snap the claw shut again. The pictures of the claw’s full range of motion are below:


The full range of motion from completely closed to completely open is vital. We could never be sure that an orange block, once detected, would be perfectly centered in front of the robot. Also, as illustrated in the first picture above, the yellow rubber bands that provided some of the negative force responsible for clasping the claw served a dual purpose. When the claw is completely shut, the yellow rubber bands in tandem with a pair of black rubber bands assist in holding onto a captured block. As you can see, the yellow and black rubber bands form a web-like pattern. The friction of the rubber bands is enough to prevent the block from slipping once the claw has closed around it.
It was also discovered that the distance at which we detect a block was not always constant either. We observed through our testing that, occasionally, an orange block would be seized in the “fingertips” of the claw where there were no rubber bands to prevent the block from slipping as the web did. To deal with this eventuality, we wrapped the “fingertips” in green rubber bands to provide the same non-slip effect as the rubber bands which formed the web inside the claw. It proved most effective. The wrapped rubber bands are pictured below:

The overall performance of the claw was nominal for our design. We were very pleased with all tests once we had finalized its construction.
Sense and Sensibility: Up-high and Down-low
The first use of a sensor we considered was the detection of the orange blocks and, potentially, the green bin. We positioned a light sensor on the front of the robot chassis at the perfect height to detect the orange blocks, pictured below:

The light sensors of the Lego Mindstorms Kit only measure the intensity of the light (how bright or how dark a color is) and not the color itself. So the light sensor mounted on the front of the chassis was never looking for an orange block, but rather a block that emits a given light intensity under the given lighting conditions. The light sensor perceives everything it can within a short range, taking a histogram of the readings from the area it scans. This means that if the light sensor is detecting an area that is half white and half black, it will average the two scores together evenly. Semi-consistent readings only occur when the light sensor is only perceiving a solid color before it, and even then, only at a limited range.
Testing revealed that the light sensor’s readings were only consistent when it was very close to the object it perceived. The reason for this is that, from a distance, the light sensor is averaging the histogram of the scene in its field of ‘vision’ into a raw score. So, with varying backgrounds behind an orange block being incorporated into the scene with the block itself, long-range detection of a block proved almost impossible.
We attempted to affix a small roll of construction paper around the front of the sensor in hopes of giving it a sort of tunnel vision, acting almost like blinders on a stagecoach horse. However, all attempts to cut the background from the total histogram proved futile. We eventually gave in to the reality that accurate and consistent perception was only possible at a distance of about one inch, at which the only color being seen is the orange block.
The second use of a light sensor we considered was the use of a light sensor to maintain position on the field via the boarder of the field and the blue cross-hairs. As mentioned briefly above, the lighting conditions must remain as consistent as possible, even if those conditions aren’t extremely bright. In this case, the light sensor responsible for position while the robot was in motion was built into the interior of the robot’s chassis pointing down onto the field through a hole just wide enough to perceive color changes, and high enough from the surface of the field for accurate readings. After all, there is such a thing as too close with light sensors. If an object is too close to a light sensor, then it is too close to reflect the signals back, and nothing will be read by the sensor. The light sensor oriented downwards is close the very front of the chassis, directly behind the forward light sensor, and about ¾ of an inch up from the surface of the field. The sensor and the hole through which it perceives are pictured below:

Keeping the downward sensor centered on the chassis was a wise decision because the symmetry of the design didn’t require us to adhere to any particular course of action when searching for the blocks. Also, the hole through which the sensor sees was perfect for maintaining a consistent amount of ambient light so as not to interfere with the sensor’s readings.
The downward sensor was responsible for detecting the blue cross-hairs as well as the surface of the table. The yellow masking tape boarder on the field was not distinct enough to effectively differentiate it from the white vinyl surface of the field. Detecting the edge of the field by watching for a reading from the table was very effective. However, a slight complication arose (again) from the histogram nature of the light sensors. It seems that when the sensor perceived the very edge of a blue line, i.e., a field of vision made up of half blue-line and half white-vinyl, the histogram is identical to the histogram reading of the table surface. This issue was surmounted in the implementation and testing of the software by taking a first reading as a maybe. Upon the initial detection, the robot knows it found something, either the table surface or a blue line. The robot takes an abrupt second reading to either confirm or deny the detection of a table or a blue line.
Clean Sweep
As stated before, the robot has to be approximately one inch from an orange block to accurately and consistently detect it. The trick is getting the orange block in front of the light sensor. The odds of running into an orange block dead-on while searching randomly are slim, and repetitious exhaustive searches take forever. So the robot needed a way to gently guide the blocks that are sort of in the path of the robot’s search patterns into the view of the forward light sensor. We employed a pair of small, scraping antennae that skim the surface of the field protruding from the front of the robot’s chassis. If a block is caught between the two scraping antennae, the forward motion of the robot inevitably guides the block in front of the light sensor.
The width of the scrapers was an issue of great consideration for us when we decided to use them. If they were too wide, they risk hitting the green bin and snapping off. Furthermore, the scrapers could push blocks out of the way or out of the field completely while the robot is turning. We decided to keep the range of the scrapers limited to the width of the robot chassis. As long as we catch a block between the scrapers, the light sensor will detect it. And if the light sensor can see it, then it is in a position to be grabbed by the claw. The scraping antennae are pictured below:

The Robot, the Bin, and the Touch Sensor
One of our biggest challenges was dealing with the green bin in which we were to deposit the orange blocks. As our robot traverses the field looking for the orange blocks, the bin is sitting in the dead center of the area. The imprecision of our motors made the possibility of a simple, clean, and methodical search pattern in which we could avoid the bin with a little geometry almost impossible. And the height of the bin and the arrangement of our light sensors made the detection/avoidance of the bin virtually impossible.
The detection of the bin by touch sensor was our last and perhaps greatest contribution to the design. Given the design of our arm mechanism, there was space to incorporate something small within the arm, itself. If properly fitted with joints, it would rise up and go down with an invariant horizontal orientation, just as the claw does. The advantage of putting the touch sensor inside the arm was that it required no major redesign. The arm was able to lower and raise with no difficulty with the touch sensor lowering and raising with the claw. Also, the touch sensor is put inside the arm such that it is at just the right height to clear the blocks, but low enough to be triggered by the bin which is considerably taller than an orange block.
In order to make sure that the single touch sensor would be triggered upon contact with the bin, a barbell was built across the front of the touch sensor on a hinge. Any contact with the bar will push down on the hinged trigger and hit the touch sensor. The barbell is the width of the robot to ensure that the chance of slamming into the bin and not detecting it is minimal. The apparatus is pictured below:

As previously stated, the entire touch sensor/barbell combination fits neatly inside the arm of the robot. It is high up enough as to not obstruct a block from being detected by the forward light sensor, but low enough that it will impact with the green bin. Furthermore, when the arm lowers, the touch sensor and barbell do not interfere with the grasping and raising of an orange block. The neat incorporation of the touch sensor when the arm is lowered is pictured below:

There are only two eventualities in which we would impact with the green bin. Either we’re searching for an orange block, in which case the robot, once the touch sensor is tripped, knows to stop moving forward, back up, and turn away on a different heading. That way, the robot isn’t pushing the bin all over the field. The second circumstance in which we run into the bin is when we are looking for it. We’re either looking for it to deposit an orange block, or as a frame of reference to move into the next quadrant to begin searching for blocks there. This will be discussed further in the software specifications.
Another Dragon Bot Gets Its Wings
From the beginning of the design phase when the first chassis was mounted with the arm and claw mechanisms, the robot’s resemblance to a fat little dragon with a long neck was undeniable. Our robot was affectionately deemed Dragon Bot almost from the first day onward. We even attached small, orange Lego dragon wings for style.
Methodology and Code Development
Code was divided up and written in small, easy to manage pieces. Each function only provided specific functionality, and more complex actions were a composition of simpler functions. For example, capturing a block was separated into the different functions of search, movement, alignment, actual capture, and then release. Due to the lack of physical feedback (no distance sensors, no internal mapping, no hardwired system status) much of the movements relied upon timing (tuned by trial and error). Since these timings were needed in many places, they were implemented as constant variables. Thus a change of timing only necessitated a change in one line of code.
The code was developed in small steps. The first to be implemented was the change of the status motors (from wheels to the arm and back again). The second was the opening of the claw. The third was the opening of the claw, the lowering of the arm, the closing of the claw, and the raising of the claw. Fourthly was line following. The search method was the final implementation made.
The hardware presented some interesting problems in the line following procedure. Since the sensors were not very exacting, they would falsely register the table as a blue line at a certain point in the approach. The solution was to simply continue forward for a small amount of time and recheck the sensor. The second sensor check determined the type of line with complete accuracy.
Only the search method lent itself to different approaches. From the onset, since the search area was already divided into quadrants, we decided to constrain ourselves to one quadrant at a time. Do to a lack of physical input, a randomized search method was deemed both the easiest to implement and the best for the design. The robot was to bounce around the quadrant until it found a block or until after a number of side hits was reached, signifying that a block probably wasn’t in the quadrant. Through some trial and error and some mathematical experimentations, it was determined that if the robot bounced at acute angles, then it would traverse the middle section of the quadrant. If the robot bounced at larger angles, the robot would hug the sides. Thus an acute angle was deemed favorable. After bouncing around, the robot would seek to access the next quadrant. The first implementation was just to tell the robot to ignore the blue lines until it crossed one (and thereby entered a new quadrant). The problem with this implementation was that the robot would alternate between two quadrants and thus waste time in quadrants already searched. A more systematic search of the quadrants was needed. In order to traverse the quadrants in counter-clockwise order, we decided to end each quadrant search at the rightmost blue line and then enter the quadrant to the right. Thus all the quadrants would be entered and searched in a systematic procedure.
During testing, some errors occurred. If a block was captured too close to the bin, the robot would ram the bin during a turn directly after the capture. A simple right turn fixed this problem. If a block was captured too close to the blue line, due to backing up the robot ended up in a different quadrant. The solution to this problem was to move forward to where the robot initially detected the block.
Trials and Experiments
Let There Be Light
As mentioned above, many experiments were ran to determine how, exactly, the light sensors performed. We experimented with different lighting conditions and attempted to augment the light sensors to get accurate readings from a distance. We measured the ambient room lighting, the intensity of the vinyl surface, and the various readings we would get for all objects of importance at different distances. After the tests were finished, we knew we wouldn’t be able to use the light sensors to detect anything unless it was right up against the object of interest. We determined the measurements for the objects of interest in the field, and proceeded with the design.
Pick Up And Go
Once a block was detected, the procedure was simple:
The robot would stop moving immediately.
The robot would back up a set distance to position the robot to grab the block.
The shifting motor moves the motor platform to mesh with the gears responsible for the operation of the claw and arm.
The first kinetic motor opens the claw.
The second kinetic motor lowers the arm.
The first kinetic motor releases tension on the pulley for the claw, and the rubber bands close the claw around the block, holding it in place.
The second kinetic motor releases tension on the pulley for the arm, and the rubber bands pull the claw back up, block in-hand.
The shifting motor shifts the motor platform back to mesh with the gears responsible for motion.
The robot seeks out the green bin and deposits the block.
The robot resumes its search in the next quadrant by backing up and turning right.
The amount of time it took us to program this portion of the behavior was relatively short because we had been anticipating writing the code for this behavior all throughout the design phase.
Looking For Blocks in All the Wrong Places
The quadrant by quadrant bouncing search pattern with acutely angled turns was the most effective search strategy, but several other strategies were first considered. Initially, we wanted to do a spiral search pattern that started at the boarder of the field and slowly spiraled inward, moving counter-clockwise around the field exhaustively searching every square inch for the orange blocks. However, this was not possible seeing as how straight lines and accurate turns are naïve dreams, and a lack of internal representation made resuming the search after finding an orange block impossible.
Our next search aspiration was a step in the right direction. We implemented a completely random search pattern using bouncing off the sides of the field and the bin, regardless of blue lines or quadrants. This proved ineffective and tedious. It also proved problematic because the robot would frequently get stuck in corners bouncing back and forth with no hope of escape.
The third search method was a bouncing quadrant search, but we still had trouble with getting stuck in corners. Acute angle turns solved this problem for the most part. After a set number of bounces, the robot would leave the quadrant by crossing a blue line indiscriminately. This created the aforementioned problem of searching the same two quadrants over and over, one after the other.
The final search method was the most successful by far. Once the number of bounces has been reached or an orange block has been found, the robot seeks out either the edge of the field or a blue line. If it finds the edge of the field, the robot takes an obtuse angled turn to its left carrying it to the quadrant’s right-most blue line. Once the blue line is found, it follows the blue line to the bin to either deposit the orange block or to use it as a reference point to move into the next quadrant for searching non-redundantly. If by chance the robot collides with the blue line on the left, it will follow the blue line to the left until it reaches the table edge. If it reaches the table edge, the robot will not find the bin and will have to make a very length rotation in place to line itself back up with the blue line. This reaction is timed, and if the maximum time is exceeded, the robot ‘knows’ it is at the wrong blue line, turns around, and resumes its search for the correct blue line, the one right-most to it in the quadrant.
Results
The results of Dragon Bot were very good. The robot was able to traverse the entire field, searching all quadrants one after the other (including one quadrant left intentionally empty), find all three blocks, and deposit them in the green bin in the center of the field in an average time of about six minutes. Once in a while, one of the scraping antennae would catch a block in the wrong way and push it out of the field, but other than that infrequent event, the autonomous operation of Dragon Bot went quite smoothly. A video of a successful test run of Dragon Bot can be found on our team’s robotics webpage here: http://www.ai.uga.edu/tonysnod/robots.html
Conclusions
An autonomous robot that had a working internal representation of its environment would have been ideal. However, for the task at hand, a purely reactive (albeit sophisticated) approach without an internal representation was more than sufficient. The advantages of a solid design, innovative concepts and solutions, and a sturdy construction saved us a lot of problems that would have otherwise arisen for us during the programming stages.
Future Directions
Dragon Bot will not be dismantled immediately. The robot will be available for AI demonstrations of purely reactive autonomous robotics.

References
(WI2006) Lego Mindstorms. (2006, September 6). In Wikipedia, The Free Encyclopedia. Retrieved September 6, 2006, from http://en.wikipedia.org/wiki/Lego_Mindstorms
Code Appendix
#ifndef MRROBOTO
#define MRROBOTO
/// sensors
#define FWD_SENSOR SENSOR_1
#define DOWN_SENSOR SENSOR_3
#define TOUCH_SENSOR SENSOR_2
// motors
#define LEFT_MOTOR OUT_A
#define RIGHT_MOTOR OUT_C
#define CTRL_MOTOR OUT_B
#define ARM_MOTOR OUT_A
#define CLAW_MOTOR OUT_C
// directions
#define RIGHT_FWD OUT_REV
#define RIGHT_REV OUT_FWD
#define LEFT_FWD OUT_REV
#define LEFT_REV OUT_FWD
#define CTRL_TO_MOTOR OUT_FWD
#define CTRL_TO_GRIP OUT_REV
#define CLAW_OPEN OUT_REV
#define CLAW_CLOSE OUT_FWD
#define ARM_DOWN OUT_REV
#define ARM_UP OUT_FWD
#define CTRL_SWITCH_TIME 160
#define CLAW_OPEN_T 460
#define CLAW_CLOSE_T 345
#define ARM_TIME_DOWN 460
#define ARM_TIME_UP 265
#define BLUE_LINE (bottom-DOWN_SENSOR>9)
#define TABLE (bottom-DOWN_SENSOR>2 && bottom-DOWN_SENSOR<8)
#define BOUNCE 13
#define TURN 250
#define TURN360 320
#define BACKUP 86
#endif
int ambient;
int atWheels;
int bottom;
int blocks;
int captured;
task main(){ //assumes that the motors start at wheels
atWheels=1;
captured=0;
SetSensor(FWD_SENSOR,SENSOR_LIGHT); //initialize
SetSensor(DOWN_SENSOR,SENSOR_LIGHT);
SetSensor(TOUCH_SENSOR,SENSOR_TOUCH);
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
SetDirection(LEFT_MOTOR,LEFT_FWD);
SetDirection(CTRL_MOTOR,CTRL_TO_GRIP);
blocks = 0;
ambient=FWD_SENSOR;
bottom=DOWN_SENSOR;
/*
On(RIGHT_MOTOR + LEFT_MOTOR);//previous test code
Wait(100);
Toggle(RIGHT_MOTOR);
Wait(300);
Toggle(RIGHT_MOTOR);
Wait(100);
*/
while(blocks<3){ //main loop, find three blocks
move(); //move around until found a block of give up
findBin(); //go to the right bin
if(captured){ //if a block was captured, release and record
release();
captured=0;
blocks++;
}
back(120); //back up to get room
Toggle(RIGHT_MOTOR); //turn right and then move foward (goes to next quadrant)
On(RIGHT_MOTOR + LEFT_MOTOR);
Wait(150); //get past blue line
Toggle(RIGHT_MOTOR); // go straight
Wait(100);
Off(RIGHT_MOTOR + LEFT_MOTOR);
}
spinMeRightRound(); //for shits and giggles, unwind the cord
/*
//celebration
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
Toggle(LEFT_MOTOR);
int count = 0;
while(count < 20)
{
PlayTone(440, 50);
Wait(50);
PlayTone(440, 50);
Wait(50);
count = count + 1;
} */
Off(RIGHT_MOTOR + LEFT_MOTOR);
}
void spinMeRightRound(){//funtion that unwinds the cord, not relavent to block finding
SetDirection(RIGHT_MOTOR,RIGHT_REV);
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
Wait(TURN360 * 5);
Off(RIGHT_MOTOR + LEFT_MOTOR);
Toggle(LEFT_MOTOR);
}
void back(int x){ //go backwards a specified amount
SetDirection(RIGHT_MOTOR,RIGHT_REV);
SetDirection(LEFT_MOTOR,LEFT_REV);
On(RIGHT_MOTOR + LEFT_MOTOR);
Wait(x);
Off(RIGHT_MOTOR + LEFT_MOTOR);
Toggle(RIGHT_MOTOR + LEFT_MOTOR);
}
void fwd(int x){ //go fwd a specified amount
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
Wait(x);
Off(RIGHT_MOTOR + LEFT_MOTOR);
}
/*
void fwdtouch(){ //go forward until touch, this is test code
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
while(1){
if(TOUCH_SENSOR)
break;
}
Off(RIGHT_MOTOR + LEFT_MOTOR);
release();
}
*/
void release(){ //let go of the block
if(atWheels)
changemode();
SetDirection(CLAW_MOTOR,CLAW_OPEN);
On(CLAW_MOTOR);
Wait(CLAW_OPEN_T);
Off(CLAW_MOTOR);
Toggle(CLAW_MOTOR);
On(CLAW_MOTOR);
Wait(CLAW_CLOSE_T);
Off(CLAW_MOTOR);
changemode();
}
void move(){
if(!atWheels)
changemode();
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
int count = 0;
int bounce=0;
while(1)
{
moveBeg:
///contained
if(TOUCH_SENSOR)//bin hit, bounce off
{
Toggle(LEFT_MOTOR);
Toggle(RIGHT_MOTOR);
Wait(70);
Toggle(RIGHT_MOTOR);
Wait(TURN);
Toggle(LEFT_MOTOR);
}//contained if(touch)
if(FWD_SENSOR-ambient>10){ //found box
back(BACKUP);
capture();
fwd(BACKUP);
SetDirection(RIGHT_MOTOR,RIGHT_REV); //turn right so that we don't get a very specific error (goes to next quadrant)
SetDirection(LEFT_MOTOR,LEFT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
Wait(100);
Toggle(RIGHT_MOTOR); //go straight
Off(RIGHT_MOTOR + LEFT_MOTOR);
break;
}else if(TABLE || BLUE_LINE) //boundry found
{
PlaySound(SOUND_CLICK);
bounce++; //bounce in a new direction
Toggle(LEFT_MOTOR);
Toggle(RIGHT_MOTOR);
Wait(70);
Toggle(RIGHT_MOTOR);
Wait(TURN);
Toggle(LEFT_MOTOR);
if(bounce>BOUNCE) //if bounced enough times, give up and more to new quadrant
break;
}
}///end of while(1)
Off(RIGHT_MOTOR + LEFT_MOTOR);
} //end of move
void changemode(){ //change the mode of the drive wheels
if(atWheels)
SetDirection(CTRL_MOTOR,CTRL_TO_GRIP);
else
SetDirection(CTRL_MOTOR,CTRL_TO_MOTOR);
On(CTRL_MOTOR);
Wait(CTRL_SWITCH_TIME);
Off(CTRL_MOTOR);
Toggle(CTRL_MOTOR);
if(atWheels)
atWheels=0;
else
atWheels=1;
}
void capture(){ //block should be lined up and at the specified distance away
//this only opens the claw, lowers the arm, closes the claw, and then raises the arm again
////////////claw open
captured=1;
if(atWheels)
changemode();
SetDirection(CLAW_MOTOR,CLAW_OPEN);
On(CLAW_MOTOR);
Wait(CLAW_OPEN_T);
Off(CLAW_MOTOR);
SetDirection(ARM_MOTOR,ARM_DOWN);
On(ARM_MOTOR);
Wait(ARM_TIME_DOWN);
Off(ARM_MOTOR);
Toggle(CLAW_MOTOR);
On(CLAW_MOTOR);
Wait(CLAW_CLOSE_T);
Off(CLAW_MOTOR);
Wait(100);
Toggle(ARM_MOTOR);
On(ARM_MOTOR);
Wait(ARM_TIME_UP);
Off(ARM_MOTOR);
changemode();
}
/*
void toBin(){ //outdated code, use findBin instead
if(!atWheels)
changemode();
SetDirection(LEFT_MOTOR,LEFT_FWD);
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
On(LEFT_MOTOR + RIGHT_MOTOR);
while(!BLUE_LINE){}//go till hit blue line
while(!TOUCH_SENSOR){
while(BLUE_LINE && !TOUCH_SENSOR){}//go till miss blue line
Toggle(LEFT_MOTOR); //turn
while(!BLUE_LINE && !TOUCH_SENSOR){}//till blue line is found
Toggle(LEFT_MOTOR); //stop turning
PlaySound(SOUND_CLICK);
}
Off(LEFT_MOTOR + RIGHT_MOTOR);
}
*/
void findBin(){ //goes to a blueline, follows it until it hits the bin
int timer;
if(!atWheels)
changemode();
SetDirection(LEFT_MOTOR,LEFT_FWD);
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
On(LEFT_MOTOR + RIGHT_MOTOR);
findBin_restart:
while(1)
{
if(TOUCH_SENSOR){ //hit bin but not lined up, bounce off and try again
Toggle(LEFT_MOTOR+RIGHT_MOTOR);
Wait(50);
Toggle(LEFT_MOTOR);
Wait(100);
Toggle(RIGHT_MOTOR);
continue;
}
if(FWD_SENSOR-ambient>10 && !captured){ //found box and we still don't have a box
back(BACKUP);
capture();
fwd(BACKUP);
SetDirection(LEFT_MOTOR,LEFT_FWD);
SetDirection(RIGHT_MOTOR,RIGHT_FWD);
On(RIGHT_MOTOR + LEFT_MOTOR);
}
if(TABLE || BLUE_LINE) //boundry found
{
PlaySound(SOUND_CLICK);
Wait(3);
if(TABLE) //really a table, bounce off table to look for blue line
{
Toggle(LEFT_MOTOR); //backward
Toggle(RIGHT_MOTOR);
Wait(50);
Toggle(RIGHT_MOTOR); //turn
Wait(100);
Toggle(LEFT_MOTOR); //go straight again
continue; //restart
}
else //this is a blue line--not a table
{
while(!TOUCH_SENSOR) //if you haven't hit the bin
{
while(BLUE_LINE && !TOUCH_SENSOR){}//go till miss blue line
Toggle(LEFT_MOTOR); //turn
ClearTimer(0);
while(!BLUE_LINE && !TOUCH_SENSOR){}//till blue line is found
Toggle(LEFT_MOTOR); //stop turning
timer=Timer(0);
if(timer>37) //wrong blue line (taken too long for a turn, means 360 turn)
{
PlaySound(SOUND_UP); //head to the right blue line
Toggle(RIGHT_MOTOR);
Wait(100);
Toggle(RIGHT_MOTOR);
Wait(100);
goto findBin_restart;
}
PlaySound(SOUND_CLICK);
}
Off(LEFT_MOTOR + RIGHT_MOTOR);
break;
}
}
}
Off(LEFT_MOTOR + RIGHT_MOTOR);
}