Team Eight/Final Paper
From Maslab 2007
Matt Farrell
Matt Robertson
Alex Sanchez
Daniel Torres
Contents |
Abstract
The design of “Jolly Roger” was not without difficulty. After several days and a long meeting one night within the first week of MASLAB of thinking of design ideas, we settled on our most ambitious one, partly as a challenge as well as the opportunity to showcase our insanity for even trying it. We made sure that everyone was aware of how many ways it could fail, while keeping in mind how great it would be if the whole machine worked as planned. Weighing out the risk, we decided to take the chance and go for our ‘dream machine’.
The final design called for an entirely omnidirectional robot, not just in terms of its locomotive capabilities, but for its ball collection capability as well. Since we were limited by sensor points, and hence motors, we chose a three wheel robot that would utilize three “omniwheels” (or “Swedish wheels”) spaced out sixty degrees apart around the center to form an equilateral triangular base. Each side of the robot between adjacent wheels was built to pick up balls.
Mechanical Design
The first mechanical problem we ran into was figuring out a way to use only one servo to drive all three rollers to collect balls, and then somehow reverse the rollers to eject the balls, but only out one of the rollers, instead of out whichever roller the ball was picked up by. To do this we designated one roller as the scoring roller, or the “front”, and designed a ball feeding system that would passively deliver balls from the two “back” secondary rollers to the front primary. For this to work though, the ball collecting rollers in the back would have to lift the balls higher than the front roller lifted balls (so they could roll down a set of rails by gravity to the front). This could have been done by using a larger radius roller, but since we were limited by size restrictions, we had to use a belt to lift the balls at the back rollers.
The first iteration did not work as planned. Using a system of 90 degree beveled gears and rubber cord belts, we were able to make all three rollers move with just one servo – barely. Not only that, this was without the belts for the back two rollers. The servo would not be powerful enough we decided – there was just too much friction in the system, and what would turn, ended up slipping at the rubber belts anyways.
To fix the rollers we took two measures: we ordered small timing belts and pulleys to replace the rubber cord belts, and traded our servomotor for a gearmotor, the same kind we used for our drive system. This set us back from our schedule some. We were set back furthermore after it turned out that the belt delivering power from the motor to the gear-train was not strong enough to transmit the necessary power, and broke. Luckily, through some good fortune we found some #25 chain and some small sprockets that fit perfectly onto the motor and gear-train. We were almost in business – the rollers now turned and nothing was at risk of breaking, but it was all still too slow. After another sleepless night, the root of the problem was discovered. The gear being driven by the chain, being driven by the motor, was not properly supported and was wedging itself in the small space that it had been turning in. Once the shaft through the gear was extended and supported from above with a simple aluminum plate, everything started to turn smoothly and quickly. The mechanics of the roller power distribution was thereby solved (at least it would prove good enough for the competition, though hardly suitable for real world application).
Once the rollers were working, it was time to actually get them “working”, meaning, they all turned, but still could not pick up balls. The belts needed to be put on the back rollers, and rubber bands were needed on the front roller to “grab” balls. Once this was done though, the roller system was bogged down. It seems that the tension caused by the rubber belts on the back rollers was forcing the roller shafts to bend slightly and bind, slowing down the whole system. We fixed this by replacing the rubber belts with a flat, non-elastic strip of carpet grip material. This however only worked when the balls were being lifted off a high friction surface, such as another strip of the carpet grip material. On carpet, the balls would just roll in front of the rollers, instead of being drawn in. This was finally fixed by a seemingly obvious though actually very clever idea to use reversed duct tape for the belts. It worked on the first try, on a surface even more slippery than carpet. The rollers worked. It did not take long then to mount the ball distribution system of rails and back plates on the robot before we were finally done with the ball collector.
A second minor mechanical aspect of our robot that had to be addressed was building a turret to mount the camera on that would give it 360 degree vision. We geared a servomoter 2:1 so it would have the proper range of motion, and then mounted it above the ball collector base of the robot, inside a clear plastic tube, so as to minimize obstruction from supports for the platform above it where we mounted the computer and electronics.
Electrical/Hardware
It may seem trivial, but malfunctions due to faulty soldering are a pain to find. It seemed like we had to replace wires due to faulty connections everyday. The motor connections were proved to be the most difficult as they kept breaking the most. Soldering SMDs is fun once you get the hang of it. We looked into the technical specifications of the OrcBoard to see what voltages and currents came out of what so we could control LEDs using the DigitalOutput class that came with the OrcBoard. We used three LEDs (red, yellow, blue) to determine the status of our robot. We used glue sticks to provide light diffusion for the LEDs which worked pretty well. Our computer was running hot, and we were told to plug the fan into a port in the motherboard, but that port was weak (like five volts), so we brought in an extra Molex connector to steal 12v from the power supply, and the fan blew nicely.
There was a mass of zip ties and rubber bands on our robot, but it was still missing one crucial element - duct tape. We found an excellent use for this MacGyver-like tape: making the rollers sticky. The rollers were originally covered with a rubber mat-like material, but that wasn’t providing enough friction to pick the balls up off the ground reliably. By creating a roller belt out of “inside-out” duct tape, the balls were picked up with no problem at all.
Software
Sensors
We used 3 IR sensors and 3 quad phase encoders. In order to get constant feedback from these sensors we had two separate threads running that were constantly sampling the sensors. One thread was responsible for sampling each of the IR sensors and the other was for the quad phase encoders. Since the IR sensors turned out to be unreliable and sporadically give random errors, we decided to try and minimize the error. In order to do this we had a running squared average of the last ten readings from the IR sensors. Then we abstracted the sensors readings away from the rest of the system by creating an enumeration representing different sensor readings. There were enumerations for High, Medium, Low, and No alerts. Thresholds were created for each alert enumeration so that when the averaged reading from an IR sensor was within a threshold the appropriate enumeration would be made available to any objects listening the IR sensor thread. This allowed other classes and objects to easily interface with the IR sensors.
Due to the structure of the omni-wheels we had to mount the quad phase encoders further from the black and white pattern than we had desired. Fortunately we were able to get consistent readings, however, the resolution of the readings was greatly decreased which made getting accurate odometer information much harder. The quad phase encoders were used in the PID Controller as well as for turning as the Gyro turned out to be too noisy to accurately make any turn less than 15 degrees and our strategy called for a lot of small turns.
Movement
Using 3 omni wheels presented some difficulties in getting the robot to move, but the software was actually easier to implement than expected. The strategy we used was to solve a kinematic equation that would give the desired velocities for each wheel that could then be convert into motor commands. To achieve this we first created a few classes that essentially did a bunch of math. One class would convert a velocity vector with respect to a global map to a velocity vector with respect to the robot. The second class would convert a velocity vector with respect to the robot into the components that each wheel contributed and then into motor commands. It turns out that we ended up giving these classes more robustness and functionality than was needed as we ended up not using a global math. This decision actually made the code run faster as it did not have to do all of the linear algebra involved with converting a global velocity vector to a robot velocity vector.
After these number crunching classes were created we wrapped them in a motion controller class to provide a simple interface to the rest of the code base. To use the motion controller you first give it the velocity vector that you wanted to robot to move in. Then you simply tell the motion controller to go and stop as desired and it will move in the desired direction. This allowed to robot to easily translate in any direction. The motion controller class also abstracted the thread that was reading the quad phase encoders since only the motion controller needed access to these sensors. This allowed the sensor reading and responding to be fully automated within the PID Controller.
The PID Controller was abstracted away within the Motion Controller. The PID Controller was a thread that would get data from the quad phase encoder thread (which it abstracted away) and make adjustments to the wheel speeds in order to keep the robot moving in the desired direction and with the desired velocity.
Strategy
Overview
When deciding upon a high level strategy for the control of the robot, we tried to take full advantage of the unique abilities made possible through the use of omniwheels and a pivoting camera. The resulting control system was a network of finite state machines. The highest level finite state machine could be in one of four primary states or two secondary states. Each of the primary states did one of the following: locate a ball; capture a ball; locate a goal; and score a goal. The secondary states served two auxiliary functions: fleeing from being stuck against the wall and mapping.
Finding Balls and Goals
The strategy when searching for a target, either a ball or a goal, was to separate control of the camera and that of the motion of the robot. In this way, the robot could move around, using the sensors to avoid walls, and explore new areas of the map. Meanwhile, the camera would sweep around scanning for balls. For this phase, the two actions would be completely unconnected.
The motion of the robot in this phase was essentially a random wander. The only sensor input going into the wander was from the ir range finders. Since the robot was able to translate in any direction, an initial heading was arbitrarily chosen for the robot. The robot would begin moving in that direction until it began to receive ir sensor input indicating it was approaching a wall. At that point, the heading of the robot would be adjusted toward 180 degrees away from the sensor indicating a wall. Furthermore, the rate at which the heading was shifted was inversely proportional to the distance reported by the ir sensor. This way, when a wall was reported by multiple ir sensors, the closest wall would dominate the motion. After correcting a major, if subtle, bug, we found this to be a very effective random walk, capable of traversing both narrow openings and corridors.
The motion of the camera was even more simple. The servo simply drove the camera to oscillate back and forth around the circle in a series of 25 degree steps. At each step, the camera snapped a picture and processed it, looking for the desired features. Once the target was found, either a ball or a goal depending on the state, a signal was sent to to the primary finite state machine, telling it to switch states.
Capture Balls and Score Goals
Entry into the high level states of 'capture ball' and 'score goal' both triggered similar low level finite state machines. On the initialization of these state machines, the drive motors were halted so the target was not lost. Then, the camera was turned such that the target was in the center of the image, ensuring that the current angle of the servo was the current angle to the target. Once the target was locked, the robot uses its omnidrive to move in the direction of the target with out turning, which could cause the target to be lost. As soon as the robot was close enough to the target ('close enough' being estimated by the location of the target in the camera frame) the behavior diverges slightly in the two cases. For ball capture, the robot spun so the closest roller was facing the ball. Then the robot moved in the direction of that roller, capturing the ball when it contacted the roller. For scoring, the robot oriented itself so the primary roller was facing toward the goal. Then, the direction of the roller was reversed, so balls would be ejected. At the same time, the robot charged the goal, pushing the ejected balls through. Finally the roller was switched back to capture so more balls could be found. At this point, with the objective completed, the state machine would terminate and the primary state machine would change states, to find goal if a ball was just captured and find ball if a ball was just scored. If at any time during the capture or scoring the target was lost, the robot returned to its wandering-search state.
Flee
Prior to the correction of a major bug in the wander routine, the robot frequently found itself stuck against walls, so a 'flee' state was created to help it escape. Although it was not used in the final design, it was used for most of the development so I will explain it. At the beginning of each iteration of the primary finite state machine, if any of the ir sensors reported that the distance was less than a threshold we set, the robot switched to the flee state. Then, for as long as it was in the flee state, it would attempt to move in the direction diametrically opposite to that sensor. When the sensor eventually read an acceptable distance, the robot would return to whatever state it had been in before the alert was triggered. Although this seems like a simple enough escape mechanism, it a had several major problem that made it nearly useless in practice. First, in the case of narrow corridors, the robot panicked, attempting to flee and just bouncing off both sides. Second, once the wall was close enough to the ir sensor, the sensor would fail and report that the wall was very far away. Hence, if the wall got sufficiently close before the robot could switch to flee it would never make it to the flee state and just stay stuck against the wall. These unexpected difficulties were extremely frustrating and lead to our brief attempts at mapping.
Mapping
When we discovered how frequently and catastrophically flee failed, we decided to attempt some basic mapping that would allow the robot to know it was stuck and which way to go to escape. The map was based entirely on data from the camera. The map was made as follows. The camera was stepped the full 360 degrees around the circle. At each step, several sample points were chosen. At each sample, the distance to the wall was determined by finding the row in the image where the ground met the wall. Then, given the image resolution, the field of view of the camera, the elevation of the camera, the angle of the camera with the ground, and some math, the distance to the wall could be calculated. Then, using the angle of the camera known from the servo, the distances were ploted on a map as walls and the space between the robot and the wall were colored as ground. This was found to be extremely effective, and was very close to becoming the primary navigation system when it had to be abandoned due to time constraints. The only remaining difficulty, occasional problems differentiating wall and ground, could have been overcome with basic edge detection, as opposed to color thresholds to blindly catagorize each individual pixel as wall or ground that we used. As it was, there were to many errors for the mapping to be used for the full navigation system, so in the final code a map was generated once per minute as a demonstration.
Contest Evaluation
Ultimately, the results of the contest were mixed. While we did not experience any catastrophic failures resulting in a complete inability to score points, problems did prevent us from performing as well as we anticipated. Although it is difficult to be sure what failed, the behavior of the robot and the indicator LEDs that lit up suggest that the robot saw balls and goals that did not exist. While the robot was looking for a ball, it would see non-existent balls. Each time it saw one of these phantom balls, it would switch states and the drive engines would stop. Then it would lose the ball, which was never there to begin with, and switch back to looking for a ball and wandering. This resulted in a jerking motion that didn't allow the robot to move far enough to capture many balls. The only explanation we can think of is that for some unknown reason, the thresholds we had set, which worked for all test cases including pictures from mock contests, failed at the competition. We don't know why this would happen.
Aside from this one color balance problem, we were very happy with the final robot. The mechanical systems of the robot worked flawlessly in spite of their complexity. Furthermore, although it had problems at the competition, the robot worked very well immediately before and after.
