The Atlanta Hobby Robot Club hosts an annual robotic competition. The premiere event is undoubtedly the Polyathlon, in which a single robot competes in 6 different challenges. The robot with the highest combined score out of all 6 events is the winner. You can check out the rules on the AHRC website.
This was the first robot I planned on building after joining the club in 2013, and I decided to build it from scratch. A lot of other club members use infrared sensors heavily in their robots, so I had a lot to learn in that area. I eventually created a pulsed IR obstacle sensor, two pulsed IR edge detector sensors, a 16 channel IR line following sensor, a 360 degree polarized light sensor, a two channel quadrature decoder, and power and logic distribution boards.
Processing was handled using an Arduino Mega 2560, and special care was taken during the design to push almost all of the robot I/O out to the Mega's "extra" pins, leaving the other I/O pins free to accept standard Arduino shields for future expansion.
With a lot of long nights writing code and testing, Bot-Choy was ready to compete in all 6 events. As always, a robot that works great at home isn't quite the same in competition. A last-minute code change caused Bot-Choy to flop in the beacon finding event, which it is very good at. Bot-Choy didn't come in first place in any individual challenge, but it turned out to be a decent all-around competitor, taking 3rd place behind Dale and Ted.
You can see the competition results, pictures and videos here.
The design and build of Bot-Choy was a series of mini-projects. Every sensor package had an initial prototype build followed by design refinements and a second build before being placed on the robot. There were a number of guiding principles I had for the general design:
My focus for the project was to learn how to design and build sensors and to turn that raw data into useful information.
Designing the drive system is one of the most fun parts for me. I had recently discovered Pololu.com and was very impressed with the range of motors, drivers, wheels, and adapters available. But before I could choose motors and wheels for Bot-Choy, I needed to figure out how fast I wanted it to go. The small yet hugely popular 3pi robot from Pololu claims speeds of 3 feet per second. I watched a number of YouTube videos of past competitions, and saw that Dale's Polymax 9000 robot can travel 10 ft to find a beacon in 3 seconds, which included 1/2 second to turn around. That's an average of 1.2 m/s, and part of that was acceleration. I decided my robot should be designed for a speed of 1.5 to 2 m/s.
Next I needed to determine how much pushing force, or acceleration, the robot should have. I made a rough estimate that the robot would weigh around 5 pounds when completed. I made a rougher estimate that the drag of the robot's wheels and bearings at top speed would be 20% of its weight, or 1 pound. This is a ridiculously conservative estimate, but I had to start somewhere (imagine needing 600 lbs of force to push your 3000 lb sedan on flat ground!)
Now that I had an idea of the speed of the robot and the pushing force of the robot, I made a small calculator in a spreadsheet where I could plug in various wheel diameters and it would calculate the required RPM and torque of the motors. I compared these numbers to the range of available motors on Pololu.com, and found that the 37D metal gear motor with a 30:1 gearbox and 70mm to 80mm tires running at 12 volts would be more than enough. The smaller 25D motors may have worked well too, but by going with the larger motors, I could have the option to upgrade to 90mm or 100mm wheels in the future if there is a new and faster competitor.
The 37D Pololu motors pull 5A each when stalled. Since the main focus of this project for me was sensors and automation, I decided to buy a motor controller instead of trying to make one. The Pololu Dual VHN5019 motor controller can handle a continuous 12A per motor, which should be plenty.
Several people in the club had mentioned that for these kinds of competitions, the capacity of the battery is generally of less concern than the ability of the battery to provide the max current that the robot might pull. For me, I figured it would be around 12 Amps max - 10 amps for stalled motors, and 2 amps for the processor and sensors. LiPo packs have great energy density, but they are more picky about temperatures and over-discharging, so I decided to go with NiMH cells. I found the K710F battery pack from www.onlybatterypacks.com. The 10 cell 2/3AA pack is rated for 10 amps max and weighs 6 ounces. This isn't quite the 12A max current that the robot could potential draw, but larger 16 Amp packs would have significantly greater size, weight, and cost, so I figured it would be good enough.
I used Pololu aluminum mounting brackets for the motors and their aluminum mounting hubs for the wheels. I replaced one of the set screws on the mounting hubs with a 4-40 pan head screw so I could torque it down a bit harder without stripping the head. The pololu ball casters I ordered weren't very impressive, but I suppose its still better than a regular caster pulling the robot side to side. I'll eventually need to upgrade to a real ball transfer.
I made another tab in my spreadsheet and started writing down all the different consumers of power. All of the motor current would go from the battery to the motor controller without any voltage regulation. The Arduino and most of the sensors would operate off 5V, but some of the sensors can be quite noisy, so perhaps they would want a separate power rail. Also I wanted to be able to adjust the voltage going to the pulsed IR obstacle detector LEDs. I decided to have 3 voltage regulators - one clean 5V rail for processors and friendly sensors, one dirty 5V rail for high current or pulsed sensors, and one independently adjustable and dirty rail for the obstacle sensor LEDs.
There are some really cheap non-isolated switching regulators available on eBay provided you don't mind waiting a few weeks for them to arrive. For Bot-Choy, I purchased 3 of the "LM2596" type regulators with multi-turn adjustable potentiometers (although they do not appear to be genuine TI LM2596 chips on the board). They are purportedly capable of providing 3A each, and I didn't need any more than 1A max for each of the regulated rails. I threw in reverse polarity protection for the regulators using some random TO-220 package diodes I harvested from an old VCR power supply.
I created a voltage divider so the Arduino could check the battery voltage and stop the robot if the batteries were running low. I put in an extra connection on the battery side in case I needed to measure the battery voltage with a meter. Some folks in the robot club recommended putting at least 300 uf of capacitance between the battery and the motor controller to reduce voltage dips and noise. I may have gone overboard, but its worth the peace of mind knowing that Bot-Choy isn't going to have problems with power.
When all the parts arrived from Hong Kong, I made footprints in Eagle and laid out a carrier board. I used single-sided strip board, cutting and jumpering where necessary to make all the connections.
To protect the battery and wiring, I used a 15 A automotive fuse. I had a few 6A DPDT toggle switches laying around and used one as a main power switch with both sets of contacts wired in parallel. The battery is wired directly into the fuse and the switch without any connector in between. There is a charging port which connects to the battery when the robot is turned off.
The general idea of the obstacle detector and method of operation are explained fairly well on Dale's website, from which we all steal shamelessly. The general idea is to pulse high current, perhaps 0.5 to 1 amp, into an IR LED that is rated for maybe only 50 ma continuous current. This is OK as long as the duty cycle is kept fairly low, usually <1% (read the datasheet). A photo detector is used to take ambient IR readings - one before the LED pulse, and another during the pulse. By subtracting the difference between the two readings, the amount of IR light which bounced off a nearby object can be determined. This method does not make a very good range finder, since a large white wall 1 meter away may reflect more IR as a small black cube just a few centimeters away. The benefit over an ultrasonic sensor is that the data can be collected much faster - 80 microseconds instead of 30 milliseconds - so the processor doesn't waste a lot of time. Compared to Sharp IR sensors, the beam angle can be made as wide or narrow as necessary depending on the application and availability of IR LEDs. With this sensor, an array of LEDs can be setup and actuated in sequence, with IR measurements taken once for each LED. The array can be designed to be significantly smaller and cheaper than a similar array of Ultrasonic or Sharp IR sensors.
Given my rudimentary programming skills, I was quite anxious about a software bug or ISR accidentally burning out an LED. I began investigating using a dedicated Arduino Nano for the obstacle detector and have it communicate with the Arduino Mega over I2C. This is something I had never tried before, and I watched a lot of YouTube videos before I had it working. I timed the communication between the two arduinos, and it took about 240 microseconds to send the first byte, and each additional byte took an additional 100 microseconds. Using the centroid algorithm, I could compress all the sensor data into a single byte to be transferred to the Arduino Mega, regardless of how many LEDs I decided to use. Most importantly, the Arduino Mega wouldn't have to choose between disabling interrupts and burning out LEDs.
Again I planned to use stripboard cut-and-jumper methods to make the PCB. With only 4 LEDs, I found out I could mount the Arduino Nano on its side and only interface with a single header row. The Nano was located so that the USB port would barely stick out for programming access. The clean 5V power rail was used to power the Nano, while the adjustable power rail was brought in for the LEDs. 2N7000 mosfets were used to switch the TSFH5410 LEDs on and off, and 10 ohm resistors were placed in series on the high side of the LED. The SFH314FA phototransistors were mounted on the opposite side of the PCB to help prevent light from the LEDs from bleeding through internally. A status indicator LED was brought out on top for future use.
The stripboard was cut into a hexagon and all cuts and jumpers were put into place, followed by soldering all the components. 5mm holes were drilled into a 2" piece of PVC at 45 degree angles to hold the LEDs equally spaced around the perimeter. The LEDs were press fit into the holes, and the populated circuit board was dropped on top of the LEDs leads and soldered into place. The phototransistors were similarly mounted within a 1" piece of PVC, 80 degrees apart.
The sensor is able to detect 3" tall cylinders of 3" PVC at up to 10 inches away before the signal becomes too noisy. A considerable delay of 2 milliseconds was required to let each LED fully ramp down before turning on the next LED, otherwise the light would cross-over and give poor readings. Light bleed through the holes in the PCB was also an issue, which I fixed by carefully cutting a piece of card stock, covering with black tape and sliding it under the phototransistors. When used on long residential carpet, there is a lot of IR light which reflects off the carpet strands and back to the sensor. On shorter business style carpet and smooth flooring, the sensor works well.
If I ever build another one, I may go with narrower LEDs, such as SFH4550. These should increase the usable range up to 15-18 inches, although many more LEDs would be required to fill in a 180 degree field of view.
When this project started, I ordered a bunch random IR LEDs and Phototransistors from eBay. Turns out none of them were powerful or sensitive enough for the obstacle detector, but I had one package of 20 which were decent at close range so I decided to try them for the line detector. The big question is how many sensors will I need in order to find the line and follow it? Looking at other top robots, Dale uses 8 sensors, Ted uses 32, and the 3pi robot only 5 sensors, but the 3pi is only 3.7" in diameter. I decided that having 16 sensors spaced 1/2" apart would ensure that at least one sensor would always be able to see the line, and provide an 8" wide strip of view across the front of Bot-Choy.
With 16 sensors to read, I was again worried about the speed with which this information could be read by the Arduino. I didn't have 16 analog channels to spare, and I didn't want to put a second Arduino Mega on the robot. I found that it is possible to read 8 arduino pins simultaneously if the input is digital instead of analog. Fortunately, I wasn't worried about how black the line was or how far away the line was, I just wanted to know if it was there or not.
I decided to make a 16 channel comparator circuit - one for each of the 16 phototransistors of the line detector. By comparing the analog voltage from the phototransistors with a threshold voltage, the comparator would output either 0 volts or 5 volts, depending on whether the line was there. Then I could read all 16 sensors with only 2 lines of code, by wiring the comparator outputs into two of the Arduino ports. The trick is to make sure all of the phototransistors are similar enough to use a single threshold voltage for the comparison.
I wanted the threshold voltage to be adjustable, since the lighting conditions at the competition are unpredictable. To do this I fed the PWM channel of the arduino into a low-pass RC filter to generate an analog and variable threshold voltage. IR LEDs typically run at lower voltages and higher current, and with 16 of them running the power consumption can add up quickly. I set up the LEDs in a series-parallel circuit to minimize power draw. I also placed a MOSFET transistor in the circuit so that all of the LEDs could be turned off when they weren't in use.
My first opportunity to test the line detector away from the kitchen linoleum was at the Atlanta Mini Maker Faire. I plopped Bot-Choy down on the line follower boards early in the morning and it ran well for several hours before needing a recharge. Later when a few other club members showed up I realized it was not common for line sensors to work well in direct sunlight. Looks like I got pretty lucky and came up with something we can demo at the club's outdoor events!
In the beacon finding competition, the robot starts in a random orientation 10 ft away from a beacon source. The robot must locate the beacon source, drive towards it and touch it as fast as possible. In another variation, the robot must find the beacon while navigating around obstacles. There is a penalty for each obstacle which is moved. Because my robot was already using IR light for detecting obstacles, I needed to find a different method of locating a beacon.
A lot of people in the club use either Pololu's 38 kHz pulsed IR beacons or some variation of Dale's 10GHz microwave beacon. At one of the club meetings we were talking about beacon finding sensors and someone brought up polarized light as a potential beacon source. Dale mentioned that he had tried that in the past, but the primary challenge was how to make a light source that was strong enough to give a good signal at 10 feet away without melting the polarizing film in front of the light source. He happened to mentioned that maybe some of today's high power LEDs could work. I had just completed my LED Aquarium light project, with its 6x 30W RGB LEDs and I had been eyeing the 100W LEDs on eBay as the prices were starting to drop below $30. When Dale gave me an excuse to buy a 100W LED I had to jump on it!
In general, beacon sensors with good angular resolution tend to have a narrow angle of view, while beacon sensors with a 360 degree field of view generally have poor angular resolution. As a result, some robots spin around in circles at the start looking for the beacons exact location, while others drive around in circles at the end because they can't locate exactly where the beacon is.
I wanted a sensor with a 360 degree field of view and good angular resolution. For the sensor I decided to use matched pairs of photoresistors connected as a voltage dividers. One resistor would have a vertically polarized film covering it, and the other would have horizontally polarized film. With 6 pairs of photoresistors spaced 60 degrees apart, I could achieve a 360 degree field of view on the sensor. I looked up a number of different photoresistor types on digikey and mouser but they were over a dollar each. My sensor would need 12 of them and because I wanted matched pairs, I would need to purchase significantly more than 12. I decided to check eBay and picked up a bag of 30 photoresistors for a few dollars.
Matching the photoresistors took quite some time. I labeled all of them and tested the resistance in two different light conditions. In nearly identical lighting, the resistances sometimes differed by 4x-5x from one piece to another. The linearity wasn't quite as bad, but out of 30 of them I just barely came up with 6 pairs that I was happy with.
I grabbed a piece of 1" PVC and drilled two rings of 6 holes for each of the photoresistors. I had to carefully bend and arrange all 24 leads so they wouldn't interfere with each other inside of the pipe. All of the leads connecting to positive and negative supplies were soldered together inside the pipe. Connections at the mid-points of the voltage divider are made inside the pipe as well, so that only 8 leads protrude from the bottom. I colored the pipe black with a sharpie to help eliminate light bleeding through the middle. In retrospect, I should have spray painted the inside black too.
I didn't want to take up 6 A/D channels of the Arduino Mega to read all 6 voltage divider pairs, so I decided to use another Arduino Nano and have it dedicated to the beacon sensor. All I really want to know is the angle to the beacon, which can be converted into a single byte of information and transferred to the Mega quickly over I2C. The Nano has 8 A/D channels, and two of them are internally multiplexed with the I2C driver, so it works out perfectly. Once again I was able to mount the Nano on its side to save space on the PCB. Since there are no LEDs or other high power or pulsed sensors here, there is no need to route separate power rails into the sensor package. Instead of drawing up all the photoresistors pairs in Eagle, I was lazy and just drew a box with 8 wires coming out.
Converting the 6 analog readings into an angle took a bit of head scratching. The centroid algorithm is well suited to handling sensors arranged in a line, but it doesn't wrap-around the way you want it to for a 360 degree sensor. To make it work, I implemented the centroid algorithm in 2 dimensions. Each sensor pair had a different weight in each dimension, depending on how far away the sensor was from the origin. By multiplying the weight of each sensor by its reading, the "torque" can be calculated for each dimension. The centroid then becomes the torque divided by the sum of the weights. Based upon the two centroids, the code determines which quadrant the beacon is in, then uses the arctan function to combine the two centroids into an angle within that quadrant. Instead of using 0-360 degrees for the angle, I've mapped it to a byte so that 127 is straight ahead, 63 is left, 191 is right, and 0 or 255 is right behind. This is convenient because although 0 minus 359 does not equal 1, 0 minus 255 does.
According to the datasheets I saw on digikey and mouser, photoresistors seem to be most sensitive to green wavelengths. The 100W Green LEDs weren't any more expensive than any other color, so I went with a green LED. The down side to this is the human eye is also most sensitive to green, so I would have to be careful to not hurt my eyes when testing. When the LED arrived from Hong Kong, I mounted it to an old Pentium 4 heatsink which still had a fan attached. The fan was 12V and the LED was ~35V at 3A. I found an old 12V power brick in a box and strapped it to the 3A LED driver. Some old 4-conductor telephone cable became the power cord for the bricks and the beacon.
I bought a couple 12x12" polarized film sheets off eBay and started playing with them. At first I thought I got ripped off, but soon realized that they work a lot better if you peel off the clear protective film. I cut a 3x3" piece of film and used standoffs to hold it an inch away from the surface of the green LED. I held up a few other pieces of polarizing film and plugged the LED in. Everything seemed to be going great for about 30 seconds, then the film in front of the LED turned yellow and was quite hot. I guess this is what Dale had warned us about.
Not giving up too easily, I modified a granola bar box to capture the air coming out from the sides of the heat sink and routed it over the back side of the film. A bit more tape to seal all the corners and edges and I tried it again. This time it worked for ten minutes and the film didn't feel warm at all. Woohoo! Another successful high power LED project.
I played around a bit with pill-box style shielding for the photoresistors, but it actually made things worse since sometimes only one of the sensors was shaded from ambient light while the other wasn't. The beacon sensor worked very well at home and Bot-Choy would consistently find the green LED within a few seconds. With its granola box duct work, the beacon was taking a beating every time Bot-Choy slammed into it at around 1.6 m/s, so I tried using the line sensor to detect the beacon's base plate and brake the motors a fraction of a second earlier. This worked well at home, but the carpet at the competition was as reflective as the beacon's base plate, so the calibration didn't work right and Bot-Choy thought it was finished before it ever started. This was quite disappointing because I suspected Bot-Choy had a good chance to win the beacon finder event. I soon figured out what was happening and was able to fix it before the beacon finder with obstacles event, during which the beacon sensor worked well.
The edge detector sensors are mounted on the front corners just outside the Line detector, and were intended to be used in the bulldozer event. They look for the edge of the table so that Bot-Choy can stop before it falls off. The edge detectors are very similar to the obstacle detector, except with much lower current so there is little risk of burning up the LEDs. The MOSFETs for turning the LEDs on and off were controlled directly from the Arduino Mega.
The library where we held the competition didn't have any white or otherwise highly reflective tables for the bulldozer event. Dale found some disposable white table cloth film, but it seemed to be more transparent to IR that it was reflective. Also, the carpet on the stage was a very dark red, which happened to be highly reflective of IR. When I tried to calibrate Bot-Choy for the Bulldozer event, I found that the edge detect sensors couldn't tell the difference between being on the table or off. I tried changing the LED voltages and on/off timing of pulses but it didn't help much. In the end I went with slightly conservative thresholds to prevent Bot-Choy from falling off, but that didn't work to well either as the robot constantly thought it was at the table edge even when it wasn't. During one round it managed to jitter its way over to one obstacle and push it off, but that was all it could manage in the 90 seconds allowed.
Turns out Dale's Polymax 9000 robot was the only robot that finished the event. We all learned the value of angling our emitters and detectors, so that even if the ground below the table is reflective, the light from the LED wouldn't reflect back into the phototransistor because of the differences in angles and distances. This is one area where I'll need to fix the design for next year.
As mentioned above, considerable effort went into avoiding the use of the regular Arduino pins, so that only the extra Arduino Mega pins were used. I didn't add any shields this year, but will probably add a Bluefruit shield and an LCD Key Shield in the future. This would allow me to more quickly change and test various sensor thresholds or PID tuning values while collecting valuable telemetry data.
For this project I spent a lot more time developing low-level sensor driver code than I spent working on the application code for each event. I ended up not using PID control for any of the events, so there is a lot of room for improvement. Thankfully most of the improvement can come from better software and more practice, so other than the edge detectors, I shouldn't need to change much else for quite some time.
If you like this project or have any suggestions, send me a note, I'd be glad to hear from you.