Rich's Hints & Kinks is a collection of useful information gleaned from many years of experience in running Autonomous Robotics at CWRU (LEGO 375/475 and its predecessor, LEGO 479). Rich's Hints & Kinks is not intended to replace student experimentation or stifle student creativity; rather, it is a helpful guide to some of the known pitfalls that have needlessly ambushed students in the past. Your mileage, of course, may vary.
Rich's Hints & Kinks is an evolving document. Perhaps you will discover some novel bit of wisdom which will be enshrined in these hallowed pages. Keep your eyes open!
The single biggest problem with batteries results when people forget to turn the computer boards OFF when they're done with them, and they go dead. This wastes batteries and causes headaches for the staff because there aren't always fully-charged extras lying around to hand out. Whenever possible, use the bench power supply instead of the battery pack. There's enough capacitance on the computer board to keep the static RAM powered when switching between batteries and the bench supply, so you don't have to worry about losing any program stored in memory during the switch. However, don't leave the bench power supply plugged in when not in use; being a linear power supply, it draws current even with no load, and can overheat.
Another sure-fire way to drain the computer batteries quickly is to try to run motors without the motor battery pack plugged in (or with the 10 A fuse in the motor battery pack blown). The computer batteries can supply 100 mA maximum, and the motors will draw 1 A each (3 A or more when stalled). Even if you're not using the motors, it's a good idea to keep the motor battery pack plugged in when running off of the computer batteries-the motor batteries can supply some of the current, sparing the computer batteries.
If motors don't work but the motor driver chip status LEDs turn on correctly, the 10 A fuse is probably blown. Use a voltmeter to make sure you're getting +6 V or more at the connector (remember, the center of the plug is ground).
When motor or logic batteries become drained, give them to the staff for recharging. A freshly-charged motor battery pack will read about +7.0 V when warm right off of the charger, about +6.45 V after it cools to room temperature, and about +5.5 V when discharged to the point that it is unable to power a typical LEGO robot drive train. A freshly-charged computer battery pack is about +6.0 V, and about +5.5 V when too weak to power the board.
If you should happen to recharge your own motor batteries, never use the FAST setting, only the SLOW, and let the batteries charge overnight. Never leave the batteries on FAST charge overnight! The batteries will overheat and possibly rupture, spewing sulfuric acid all over. (This actually happened once; someone mistakenly thought the charger was on SLOW. Fortunately, no other equipment was harmed.)
Batteries are a limited resource which must be utilized with care. Don't waste them. You cannot replace them at the first sign of performance degradation. You will have to design your robots to function adequately over a wide range of battery voltages. A friction-free geartrain with adequate gear reduction will drain the motor batteries less than a binding geartrain with more speed than power. Also be sure to keep incandescent lamps turned off when not in active use.
The bend sensors are potentially very useful to measure how close you are to another object (such as a wall or another robot). They are relatively fragile and should not be used as naked "whiskers", or in other situations where they are required to withstand large forces. Moreover, they are only sensitive to bending which occurs along the entire length of the sensor--a small overall bend and a sharp bend at only one point will give the same values. Consequently, bend sensors should always be protectively encased in some kind of LEGO structural element which bears the brunt of impacts, and which causes the sensor to bend uniformly along its length.
The breakbeam sensors are just an IR LED/phototransistor pair encased in a slotted plastic housing. When something gets into the slot, it breaks the IR beam and the signal from the phototransistor changes. They're used in floppy disk drives to sense disk presence, write-protect notches, etc. You can use them as motion limit detectors by having part of your mechanism move into the slot when it's in the correct position. This is especially useful for emulating a servo motor: a shaft rotates until a cam breaks the beam, at which point the motor is turned off.
The most common attempted use of the monolithic breakbeam sensors, however, is as a wheel stall sensor. Positioned over a non-drive pulley wheel, the sensor will send alternating on/off pulses as the spokes of the wheel pass through the slot. If the robot has stalled (i.e., the robot platform isn't moving; the drive wheels may or may not still be turning), the sensor will be constantly either on or off. Thus, changing signal means movement, constant signal means the robot is stuck.
While simple in principle, breakbeam stall sensors generally have been major headaches in practice. The geometry of the sensor mount has to be just right, and the software has to be very robust. I've seen teams invest tens of hours into stall sensors without success, after half a semester, when their time would have been better spent on nest detection or egg discrimination. Think very carefully before you embark on a motion control strategy which requires a breakbeam stall sensor.
A common oversight in the use of breakbeam sensors is that the emitter side has to be turned on before the value returned by the detector side has any meaning. Make sure that you have issued the appropriate led_out0(1) or led_out1(1) command to turn on the IR LED before concluding that the sensor is broken. This caveat also applies to wide-area breakbeams constructed with the discrete IR LEDs and IR phototransistors.
The breakbeam sensors are particularly sensitive to electromagnetic interference generated by both DC and servo motors. Both sensors and the sensor wires must be kept at least 6.0 cm away from any motors. Rotating motors generate pulses which cause the breakbeam to register inputs even if nothing is repeatedly breaking the beam, wreaking havoc with stall detection. Aluminum foil shielding may also be used for added protection to the lead wires, but no effective shielding has yet been found for the breakbeam sensor itself. Keep breakbeam sensors away from motors!
The computer boards often flake out, for a variety of reasons. Since the boards cost $300 each and we've drummed it into you that "you break it, you bought it", this inevitably inspires panic. Fortunately, every case so far has eventually been resolved successfully, without the need to scrap the board. Here are some common conditions:
Board won't go into Download Mode. Usually this means you're not doing it right :-) Remember, it's push the Choose and Reset buttons simultaneously, release the Reset button while still holding down the Choose button, wait for the yellow LED at the serial port to go out, and then let go of the Choose button. If you release the Choose button too soon, the yellow LED won't go out. Note that the green LED should be lit at all times; if not, that means the serial cable isn't plugged into the Mac, or else the Mac serial port isn't working right. The only known "real" failure to go into Download Mode was a blown reset delay chip on one board.
Board goes into Download Mode okay but IC won't load. This usually means (1) you forgot to hit the Reset switch after InitBoard was finished and told you to hit it, or (2) the Reset switch is sticky and probably needs to be replaced. The latter has been observed 3 times, so be nice to the Reset switch!
LCD screen is really dim. Try adjusting the Brightness knob on the main board (next to the Choose and Escape buttons). If that doesn't help, your AA batteries are low.
LCD screen has black rectangles instead of readable characters. The Brightness knob is turned down too low. Probably you just changed to freshly-charged batteries, and the extra voltage is affecting the display.
Heartbeat doesn't blink. The onboard software has been corrupted (either due to low voltage or your own buggy software). Put the board back into Download Mode, run InitBoard, remember to hit the Reset switch, and then reload IC. Any on-board program/data will be lost.
MEMORY FAULT error message at Reset or Power-On. Most likely you have an infinitely-recursive function in your software; the stack has overflowed and overwritten the system software. This fatal error occurs when you least want it to--such as at the start of an Egg Hunt round, right after you made a last-minute "simple tweak" to your code.
Blinky LEDs with motors going crazy, often with clicky sounds. This one takes 10 years off your life if you haven't seen it before. The software is badly corrupted and just executing garbage at random (the instruction pointer is off in Never-Never-Land). Eventually it falls into routines to turn on the motors or the LED outputs, and the status LEDs associated with these turn on. Put the board back into Download Mode and reinstall everything.
Motors work intermittently; batteries are good. This is due to the motor driver chips coming unseated from their sockets. A hack to increase the allowable current drain is the use of piggybacked motor driver chips (soldering one on top of another, then plugging the pair into a single socket). The soldering process leaves the legs of the bottom chip too short to plug deeply into the socket. Add a big heatsink on top, and you have something that can easily get pulled out (especially since the motor connector ports are right next to the drivers). The solution is to push the chips back in, but you have to make sure that the pins aren't bent! If you have any doubts, ask one of the staff for assistance.
The lab computers and printer may not be the current top-of-the-line, but they are perfectly adequate for all course requirements. Fortunately, this tends to discourage people from installing games or other unauthorized software, or wasting time web-surfing or chatting on IRC :-)
Don't install unauthorized software. If there is a system software upgrade or other technical issue, discuss it with the instructors before doing anything. Well-intentioned students have caused problems in the past by making "improvements".
Don't change the hardware configurations without express permission from the instructors! This includes changing the network configuration. Don't change the AppleTalk zone, IP address, machine name, etc. Again, if there is a legitimate technical issue, discuss it with the instructors first.
The lab computers may not be used as file servers or FTP sites. If you want to work on some code when you're at home, bring it home on a floppy disk, or (while in the lab) transfer it to some other machine that you otherwise have net.access to.
Pirate copies of software ("warez") are forbidden. If you didn't buy it yourself, or if the University didn't buy a license for you to use it, you can't have it on any of the computers. This includes .MP3 audio files of commercial music recordings. Violations are subject to severe disciplinary action at the University level, per the Computing Ethics Policy.
Don't disturb other groups' workstations. Anyone found tampering with another group's code will be subject to severe disciplinary action at the University level --this is considered cheating.
Use only the designated lab computers. There are 10 clearly-marked workstations and one laser printer available in the primary robot lab for student use. Any other equipment that you may see in adjoining rooms is for staff or research use only and is off-limits to students without explicit authorization from the instructors.
Check all system and operating system advocacy at the door. The lab computers are tools, nothing more. Griping that they aren't your computing platform of choice is not helpful. Neither is over-trumpeting their virtues if they are your computing platform of choice. Be they UNIX, MacOS, DOS, Windows, OS/2, or Coleco ADAM, you should be able to use whatever computing resources happen to be at hand. This is an important survival skill in The Real WorldTM.
Keeping your code modular is helpful, but being anal about structured programming is not. Remember, the most elegantly-designed and -written code is useless if it doesn't work. Similarly, code which does what it's supposed to can be as ugly as it wants to be. Do whatever works for you; this isn't ENGR 131.
This being said, here are some practical hints with proven success. Students with little programming experience are advised to take these "hints" as "well-nigh-obligatory", but even programming gurus can benefit from them.
Make frequent backups! This is Cardinal Rule #1. Too many times I have observed code "improvements" which broke an existing program, and which could not then be undone, because the "improvements" had been saved with the same name as the original, and there was only one copy of the original. Each kit is provided with a 1.44 MB floppy disk; use it and use it frequently!
Use lots of comments. This is Cardinal Rule #2. You'd be surprised how much you forget from one class session to the next, let alone from one week to the next! Remember, too, that the other members of your team may have to deal with your code when you're not there, and if they have no way to figure out what you did, they're (and ultimately you're) stuck.
Use meaningful variable and function names. There is no executable code penalty for using multi-character variable and function names, so pick names that help you "read" the code. Don't go overboard, however, into the AnnoyinglyLongAndUnreadableSentence. I find names which use underscores as separators to be somewhat more readable (e.g., go_forward(), right_rear_bumper), but your mileage may vary.
Make global variable names visually distinctive from local variable names. My own preference is to use all capitals for global variables (e.g., EGG_COUNT versus egg_count). Some people like to use a g or G prefix (e.g., g_egg_count versus egg_count). Whatever you do, just be consistent.
Use global variables for all I/O port numbers. This way, if you have to redesign what's plugged into what port, you need change only one line of code (instead of hunting through the entire program for every absolute reference to a port number).
Use indenting to show hierarchy. This greatly improves readability of code. I know that particular C indenting styles are a holy-war topic for some, but my personal favorite goes like:
int MYPORT=20;
void main()
{
int x;
while(1)
{
x=analog(MYPORT);
printf("%d\n",x);
}
}
Use modular, reusable code. The preliminary exercises are designed to help you build functional pieces of the overall design project. What a waste to throw it away and start over "once the real Egg Hunt project starts"! Rewriting a working but spaghetti routine to be modular is a good way to accidentally break the code. Try to make it modular from the start.
Use a combination of daemons and global variables to monitor sensory inputs. Have a separate daemon (process) for each input port (or class of input ports). The job of the daemon is to read the port, optionally filter/transform the raw data, and write the result to a global variable. This way, any other process need not concern itself with how the data was acquired or filtered/transformed; it only sees the final, useful value. This is a great way to create a well-behaved, "idealized" sensor from one whose raw input is noisy, non-linear, etc. Global variables are by definition accessible from all processes and functions at all times, so you can avoid the stack overhead of parameter passing.
Keep the software hierarchical. Try to build your control software in layers. The bottom layer should be all the daemons which talk directly to the hardware:
int mystall_sensor() /* returns 1 if robot is moving, 0 if stalled */
/* samples sensor 10 times, looks for changes */
void mymotor_on(int motor, int speed, int direction) /* turns on a motor */
/* has fudges for */
/* performance diffs */
/* of each motor */
The next layer above that might be simple behaviors:
int turn_right(int degrees) /* drives motors for duration proportional */
/* to the amount of turning desired (uses */
/* internal calibration curve). Returns 1 */
/* if completed successfully, 0 if error. */
int go_forward(float seconds) /* drives forward for specified time. */
/* Returns 1 if successful, 0 if error. */
A final, top layer would be what we more typically think of as "behavior":
void avoid() /* keep me from getting stuck; only 2 bumpers */
{
/* it's too bad there aren't switch statements in IC, eh? */
if (FRONT_BUMPER == HIT) /* front impact? */
{
go_backward(BACKWARD_TIME); /* yes, so back up */
turn_random(); /* try to turn away */
}
else
{
if (REAR_BUMPER == HIT) /* rear impact? */
{
go_forward(FORWARD_TIME); /* yes, so move forward */
turn_random(); /* try to turn away */
}
else
{
if (STALL_SENSOR == STALLED) /* am I stalled? */
{
turn_random(); /* try to wiggle out of it */
}
else
{
/* I'm not stuck, so don't do anything *
}
}
}
}
int check_egg() /* find out if the egg in the funnel is a keeper */
{
if (egg_color() == PASTEL) /* determine the egg color */
{
open_gate(); /* we want it, so open wide */
go_forward(SNARF_TIME); /* drive over it so it goes in */
return(GOT_EGG); /* say we got it */
}
else
{
go_backward(BARF_TIME); /* yecch, back up so it comes out */
turn_right(AVOID_TIME); /* turn so we won't find it again */
return(BAD_EGG); /* say we avoided it */
}
}
This kind of hierarchical separation greatly simplifies debugging, and is the only sure way to get complex behaviors working in a real-world environment in a practicable amount of time.
Lock shared resources in a multi-process environment. Make sure that, at any one time, only one process has access to shared output devices like motors (especially the drive motors). The driver code for such devices should have an "in use" or "locked" flag (a global variable) that gets set when they're being used, and which other processes must check (and heed) before trying to use them. This will prevent such disasters as go_forward() and go_backward() running simultaneously (actually, alternately in 5 ms timeslices, to the great dismay of your geartrain).
Prioritize control behaviors. You may find it useful to design your top-level control software with multiple parallel behavior daemons, each capable of interrupting the other, as the need arises. For instance, any time your robot runs into an obstacle, it should execute an avoidance routine, and then return to whatever it was doing. Of course, when the avoidance routine starts, the drive motors are already running. Obstacle avoidance, however, is more important than the current process (if you're stuck, you can't do anything but spin your wheels), so the avoidance routine should be able to seize control of the motors (despite any "locked" flag which might be set) long enough to get you unstuck, and then relinquish control to the prior routine. The interrupting process also must prevent the current process from continuing to try to use the motors; this can be accomplished by a system of status message passing (through global variables), or even by killing the current process and restarting it when the interrupting process has completed. Arbitrating resource conflicts among multiple processes and across priority hierarchies can be tricky and difficult. A process hierarchy diagram is invaluable for structuring your thinking; you should create such a diagram and carefully work out its logic and implications before ever writing a line of code. In general, for a given "locked" shared resource, processes at the same or lower priority as the process which "locked" the resource should wait until the "locked" flag has cleared; processes at higher priority are free to interrupt lower-priority processes, but must insure that resource contention does not occur, and that the pre-interrupt status quo is restored upon exit.
The most important mechanical part of your robot is its drive train. It's the very first thing you have to build. Its controlling software is the very first thing you have to write and debug. Everything else is built around it. If it breaks, or if you get it wrong and have to change it late in the game, you'll have to tear your robot completely apart in order to get at it. Drive motor and geartrain problems are responsible for more robot performance failures than any other cause. It is disheartening to see a robot, with otherwise clever design and control software, sit twitching helplessly because its motors have popped loose, or creeping with screeches because high friction is grinding its gears into grey dust-- especially with the world watching at the Egg Hunt.
Here are some important design considerations:
Find a good compromise between speed and torque. Your robot needs to move with some quickness, but it also needs to be able to transport itself and a heavy load of batteries and computer board. The arena surface is carpet, which provides additional friction to overcome. Since speed and torque vary inversely to one another, your geartrain needs to be in the middle of the continuum. A speedy but weak robot won't be able to move; a powerful but plodding robot won't cover enough ground in the limited competition time available.
Minimize the number of gears. The more gears, the more friction. Especially avoid "idler" 1:1 ratio gears whose only purpose is to get around some LEGOmetric difficulty. The power losses due to friction in such arrangements are almost never acceptable. You're better off in the long run redesigning your robot frame to avoid the LEGOmetric difficulty.
Don't use differentials in high-torque situations. The current LEGO differentials have such weakly-constructed ring gears that they can't handle a heavy load without stripping or breaking. This means that your main drive train shouldn't use these differentials (nice as it would be to be able to do so). Hopefully, some day LEGO will make a more robust differential set, suitable for a real drive train.
Keep axles as short as possible. The more beams an axle passes through, the more friction and the greater the power loss. Also, as the robot frame gets loaded, inevitably the frame will sag. Long axles can get bent, resulting in higher friction and power loss. Note: expect that the axles of the drive wheels will sag. The weight is just too great.
Use bushings and half-bushings to lock gears and axles in place. One on each side of a gear, where possible, will keep the gear from slipping along the axle. Bushings and half-bushings can also be used to keep an entire axle from sliding in and out, if placed just next to (but not touching) the beams they pass through.
Anchor the motors securely in the robot frame. The motors have dorsal and ventral LEGO plates, appropriately shimmed so that the entire assembly fits the plate thickness LEGOmetrics. Use these to hold the motors in place from top and bottom.
Expect that drilled axles will have a non-zero coning angle and may slip. It's impossible to drill axles to be perfectly perpendicular, so all of them will have a slight wobble or eccentricity. This means that there is guaranteed to be friction, instability, and power loss at this point, especially if two motors are joined shaft-to-shaft with an axle union. Also, there is a chance that, eventually, the Super Glue holding the axles onto the shafts will break loose, and the axles will start to slip. A high-friction or otherwise overloaded gear train greatly accelerates this wearout. The only remedy in case of slippage is to disassemble the geartrain and replace/reglue the drilled axles. Should this become necessary on the day of the Egg Hunt, your chances of success are quite remote.
Allow suitable ground clearance. Don't make your robot so low to the ground that it can't deal with minor sags in the carpet, or can't get over the low barrier in front of the nests.
Store your robot on frame jacks. Since the LEGO axles are plastic, they will bend rather easily. The lead-acid storage batteries used to drive the motors are extremely heavy, and a robot stored on its wheels will sag as the axles bend under the weight. This greatly increases the friction of the gear train. Thus, store your robot such that the wheels are off the ground, and the weight is borne by the frame. This is easily accomplished by building a frame jack.
As supplied, there are 4 bi-directional motor ports (0-3) on the main computer board, plus 4 additional uni-directional motor ports (4-5, in pairs of two, left and right) on the expansion board. A neat, non-destructive hack has been devised to convert the pairs of uni-directional ports into single bi-directional ports: Plug the 3-pin motor across the back 2 pins of the uni-directional ports in the pair. Then you can use motor(4,speed) and motor(5,speed) for -100 <= speed <= 100 to get bi-directional mode, just like motor ports 0-3.
DC motors emit electromagnetic interference which can be picked up as pulses by analog sensors, causing false sensor inputs. Keep sensors and sensor wires away from the motor casings. Aluminum foil may or may not work for shielding.
Another common cause of DC motor misbehavior is the piggybacked motor driver chips becoming unseated from their sockets. A check for this condition should be a standard part of motor debugging before you call for assistance from the instructor. Gently push a chip back in if it has worked loose.
Excessive current draw (due to poor geartrain design), in addition to causing the motor driver chips to overheat and enter emergency thermal shutdown, will blow the fuse link connecting the logic and motor battery supply busses. When this happens, the motor controlpulses (which are powered by the logic batteries) and the motor outputs no longer have the same electrical ground, so behavior of the motor driver chips becomes unpredictable. A command such as motor(0,100) might actually end up working like motor(0,50) or even motor(1,-25) depending upon other electrical loads on the computer board; the ground potential will float with load. The direction LEDs may flicker and both directions be lit at the same time. If the fuse link is blown, the servo motor will also be jittery and unpredictable (see SERVO MOTORS below). Your computer board must be repaired by the instructor, and you must redesign your geartrain to eliminate the excessive load.
The required Design Notebooks are not mere busywork. They don't necessarily have to be pretty (neatness is highly desirable, though; if the instructors can't read it, they can't grade it), but they should be a complete record of everything you've done throughout the semester. Design ideas, experiments, sketches of prototypes, sensor calibrations, algorithms, behavior diagrams-- everything should be documented, and in a way that someone else could figure out what you'd done just by what was in the Notebook. Even though you may not have had a formal course in Engineering Drawing or Drafting, as future engineers and scientists, you are expected to be able to make clear sketches that are neatly and informatively labelled. Unless you have the necessary experience, don't waste your time trying for brownie points with laser printer pictures from AutoCAD or Adobe Illustrator.
The Design Notebooks are also supposed to be working documents, not something thrown together post hoc for the express purpose of having something to hand in at the end of the semester. Make entries as you go, and summarize your progress at the end of every class. Remember, your course grade does not depend in any way upon the performance of your robot in the Egg Hunt. Your Design Notebook is an important basis for the grade you receive in LEGO 375/475.
All illustrations (drawings or photographs) and graphs in your design notebook must be labelled. There must be appropriate discussion text accompanying each figure. A bunch of unlabelled, badly-focussed digital camera photos and garish Excel plots (with illogical axis tick spacing and huge fonts) is not a substitute for a design notebook, and will be graded accordingly. Digital graphics can be a convenience, but over-use comes at the expense of content. The instructors will not be fooled by webpage-style glitz.
It is also very bad form for one member of your group to spend an hour of class time shooting pictures and then print out 3 sets for each of you to stick into your design notebook. The person who took the pictures knows what they are supposed to show, but it's very likely that the rest of you won't, and this will be reflected in the quality of the labelling and discussion.
The Notebook itself should be 8.5 x 11 inch format. If you are keeping a traditional handwritten notebook, the standard graph-paper-paged chemlab-style notebook is by far the best. (Don't use carbon pages, though.) Spiral-bound composition notebooks (college-ruled pages) are not as sturdy for heavy use, but are still acceptable. If you are keeping a typewritten or "electronic" notebook, use a 3-ring binder and hole punch to organize printed pages. Pocket folders are undesirable because it's too easy to lose pages and get them out of order; also, the pockets aren't big enough for the number of papers you'll have by the end of the semester. Historically, students who have kept loose-leaf design notebooks have tended to fall behind in them quicker and have poorer information content than students who have kept traditional bound laboratory-style notebooks; so beware!
Design Notebooks will be returned to you at the end of the semester (after we've had a chance to read them carefully). During the course of the semester, your Design Notebooks will be periodically examined to insure that they're actually being kept up; those whose Notebooks are in arrears will be cajoled, then warned, and finally threatened with bad grades if they don't shape up :-) You should be proud of your Design Notebook, because by semester's end it will be a testament to lots of hard but hopefully satisfying work.
The lab's digital camera can simplify the task of documenting your mechanical designs, if used properly. Photos should be in focus, of suitable size to show what you're trying to show, and cropped of extraneous background. In addition, once firmly taped/glued/stapled into your design notebook, they should be suitably labelled. Scientific and engineering photos serve a different purpose than snapshots you take on vacation--the object is to convey mechanical design information clearly and concisely. Uncritical tourist-style photos are not an asset to your design notebook.
The digital camera currently in use in the lab has a number of limitations. It can hold only 90-odd photos maximum, and these must be transferred to a computer using a USB-based external flash memory card reader. Only half the computers in the lab currently have USB ports, so if you don't have USB at your workstation, you'll have to use the staff computer and then copy the files over the network back to your workstation for editing and printing.
These limitations conspire to make the digital camera a scarce resource in the lab, one that must be shared fairly with everyone. Don't spend too much class time waiting around for the digital camera. Even if you don't consider yourself a competent draftsman, you will find that, for most illustration purposes, clear hand sketches with good labelling are perfectly adequate to document most mechanical designs. Remember, the object of the illustrations is to convey information, not to be eye candy. If you want to do an extensive photo shoot, consider coming to an extra lab session, at which there will be far less demand for the camera.
To take photos, take off the lens cap and turn on the camera. After a brief warm-up, the lens will extend and the LCD status display on the top will appear. The back of the camera has a mode selector ring; turn this to CAPTURE. Look through the viewfinder and press the shutter. After a brief auto-focus pause, the camera will flash, and a preview of the photo will appear on the color LCD screen on the back. You'll also get a prompt to press a button under the color LCD screen to delete the photo if you don't like it. To save battery life, if you press the shutter only partway down, it will blank the color LCD screen; that screen takes a lot of power. The estimated remaining photo capacity appears on the top LCD status display; it will say FULL when you're at the limit. Note that a green LED next to the viewfinder will blink while the flash is recharging. As the batteries drain, it will take longer and longer to recharge the flash.
To review photos in the camera, turn the mode selector ring to REVIEW, and use the 4-way arrow disk to move around. You can delete unwanted photos by following the appropriate prompts.
To transfer photos to your desktop computer, a stand-alone USB reader for the camera's internal flash memory card must be used. First, make sure that the camera is turned off. Open the memory card compartment at the right front of the camera, lift the white card latch lever, and depress to eject the memory card. Insert the card into the card reader. It only goes in one way; don't force it! An icon for the memory card will appear on the Desktop. Double-click on the icon, then open the folder named DC220_01; photos will appear as files with the extension .JPG. Drag the photo files to the desired destination on the computer; they will be copied. When you're done, drag the files out of the DC220_01 folder into the Trash, then select Empty Trash from the Special menu. This removes the files from the flash memory card. Finally, drag the icon of the card itself into the Trash to unmount its filesystem. At this point, it's safe to remove the card from the reader. Re-insert the card into the camera (again, don't force it!), fold down the white latch lever, and close the door to the memory card compartment. Turn on the camera, and you're ready to take more pictures.
The "live viewfinder" mode using the LCD screen uses enormous amounts of battery power. Don't take photos this way unless you are using the external AC adapter.
It's a trap to design/test your robot in isolation--remember, there will be 3 other robots out there with you in the arena. You'll run into them; they'll run into you; they'll move back and forth in front of the polarizing beacons and block your view; they'll knock eggs out of the open and up against the walls. While it's encouraging to see your robot work as designed in an uncluttered arena, this is no guarantee that it will do the same with 3 other robots around. Similarly, desktop tests of isolated nest detectors and egg discriminators are no guarantee that they will work when integrated with the rest of your robot. Simplicity and robustness of design are your best insurance policies against interference by other robots.
Ultimately, the only truly valid test of your robot is under actual game conditions--in the arena, with 3 other robots, black and pastel eggs, 2 polarizing beacons, and 10-minute rounds. Previously, in an attempt to prevent teams from wasting most of the semester on side-issues and then trying to complete their robots at the last minute, we instituted benchmark performance criteria, to be met by specified dates before the actual Egg Hunt. The idea was that, if all robots were required to show competence in key behaviors (nest-homing, egg collection and discrimination) well in advance of the Egg Hunt, the early maturity of the designs would insure better performance in the competition. Contrary to expectations, this did not happen. The reason is probably that something as complex as an Egg Hunt robot is not simply the sum of its parts. Additional features have costs, because they interact in unexpected ways with the existing design. For example, nest detection is not just the polarizing detector array; it's the drive train, the movement and obstacle avoidance software, the frame construction. A sensor head stuck on at the last moment is likely to be poorly-anchored and liable to fall off, or else require disassembly of already-working structures to make it fit (which runs the risk of not being able to get them working again). In short, it takes an entire robot to find a nest, and if the entire robot isn't designed with that in mind, it won't be able to do so robustly.
Teams have many choices of Egg Hunt strategy. The following list, in order of increasing risk and unreliability, is not exhaustive, but it's pretty representative. Students are, of course, free to invent and explore strategies not listed here.
Two independent pastel egg collectors. Neither robot depends upon the other in any way. This approach maximizes offense and is the most robust, because it is functionally redundant: if one robot breaks down for any reason, the other still can collect eggs for a positive team score. Note: the strategy of constructing 2 identical "clone" robots is expressly forbidden.
One pastel egg collector, one black egg collector. One robot increases the team's positive score, the other "poisons" the opponent. The robots can be completely independent, but there is a potential danger: if the pastel egg collector breaks down, there is no way to generate additional positive scores for the team (unless the black egg collector can somehow learn of its teammate's predicament and switch strategies).
One pastel egg collector, one opponent-nest blocker. This strategy combines offense (increasing your own positive score) with defense (preventing your opponent from increasing his positive score by blocking his nest). It is risky in that a failure of the egg collector means that your team can win only through luck (e.g., you already got some pastel eggs in your nest before the collector failed) or through your opponent's stupidity (e.g., he accidentally puts some pastel eggs into your nest). Two competing teams which employ this strategy, assuming each deploys it successfully against the other, generate a dull 10-minute standoff.
One black egg collector, one home-nest blocker. This is the strategy for those who like trenches and wars of attrition. You put black eggs into your opponent's nest while preventing him from doing the same thing to you. The only way you can win is with a score of You: zero, Opponent: minus-something. The reason this is riskier than the pastel-collector/opponent-nest-blocker strategy is that black eggs are far less numerous than pastel eggs. Again, it's brutal to watch if two teams use this strategy against each another. You're totally at the mercy of your opponent if the black egg collector breaks down--you can win only if your opponent makes a mistake.
The key to a successful Egg Hunt strategy is reliability. I repeat, the key to a successful Egg Hunt strategy is reliability. I can't say it enough! Whatever your robots are supposed to do, they'd better do it 90% of the time, and do it well. Historically, however, the average reliability of individual robots (all strategies) has been about 50-70%. This translates into team reliabilities of 25-50%, meaning that, in the best-case scenario, your team has only a 50% chance that both your robots will function as designed for an entire 10-minute round. This is the strongest argument in favor of the dual independent pastel egg collector strategy. Other strategies which require robot specialization and/or cooperation have intrinsically lower reliabilities (they're more complex, harder to implement and debug), and leave the team without options if one of the robots malfunctions. With the hardware currently available in the course, there are no simple means of communication between robots (though we hope to change this soon); so planning strategies which require robots to reliably communicate is, for now, a waste of time.
My strong advice is to pick a simple strategy, one which you may find quite boring and uninteresting at first, and do it really well. In many of the past Egg Hunt rounds, a robot which could collect a single pastel egg and bring it home would have won that round for its team.
Ties and sudden-death overtime. Make sure that at least one of your team's robots is capable of grabbing a pastel egg and making a dash home in less than 3 minutes. This "overtime" behavior should be selectable by DIP switches and not require the loading of separate, special software at the last minute. Amazingly, we have had teams forget to plan for the eventuality of a tie, and end up in one! Nothing, however, is more ignominious than having a 0-0 tie after the round, a 0-0 tie after the tiebreaker, and finally having to decide the contest by a coin toss...
Since LEGO 375/475 has no formal prerequisites, it potentially attracts students from a wide variety of backgrounds and experience. Historically, the majority have been computer engineering and computer science majors; but there have also been other engineering students (electrical, biomedical, mechanical), as well as physics, biology, mathematics, and even philosophy majors. No single student will have a pre-existing mastery of all the skills necessary to build a successful robot; thus, groups are selected by the instructors so that there is a balance of skills. At some point, you will have to learn skills that you didn't have before. The structured exercises during the first half of the semester are intended to make this learning process easier. By mid-semester, you and your groupmates should be ready to integrate everything into building a complete Egg Hunt robot.
Specialization is necessary in order to complete all the complex tasks within the limited time available; but over-specialization to the point that there is only one person who can do a particular task should be avoided. Whining that "we can't do anything because Susan is the only one who knows how the egg detector is supposed to work and she's not here tonight" will not be regarded with any sympathy by the staff. One of the best reasons for keeping well-documented code is that every group member (or team member) may have to work with it in your absence. Having a narrow focus leads to a great responsibility being placed upon individuals, which can be stressful and destructive if problems are encountered or the task is not progressing as well as hoped (or needed).
Every member of the group (or team) should have a say in what is done; but once a decision is made, everybody needs to abide by it. There is nothing more destructive to morale than second-guessing, whining, or even taking substantive contrary actions when nobody else is around (rewriting code, scrapping a constructed LEGO element without permission). You have to trust your colleagues if you want them to trust you. Make sure that you obtain consent from your groupmates (or, once Egg Hunt teams are formed, from your teammates) before making any alterations to code or mechanical design.
Respect the workspace of other groups, but remember, this isn't a top-secret Manhattan Project. Every student in the course is a colleague; you should learn from others and be willing to teach others what you've learned. This doesn't mean that you do all the hard work and give it away for the lazy to exploit. Be sporting about it--after all, your course grade does not depend upon your robot's performance. In the past, some groups (and teams) have been overly nosy and have engaged in intense "industrial espionage", scouting out the competition (during extra lab hours, when the competition isn't present). In retaliation, other groups have tried to be extremely secretive about their work, hiding their robots in opaque plastic bags, refusing to talk with other students, or even spreading disinformation about their strategies, capabilities, or progress. This behavior adds an "edge" to the course that I find uncomfortable and actually quite revolting. If it's allowed to continue, it only tempts someone to actually tamper with another robot (an action which gets you flunked from the course and in danger of expulsion from the University). Please, let us compete to win as best we can, but let us not become cut-throat about it.
In extreme cases of internal group or team dysfunction, the instructors reserve the right to reassign students in an attempt to solve the problem. We hope never to have to assert this right.
The computer board provides several output ports which can be used to drive incandescent lamps and LEDs. With the proper adapters, lamps can be plugged into either a motor port or one of the two led_outx ports on the expansion board. If plugged into a motor port, the intensity of the lamp can be varied by varying speed in the motor(n,speed) command. LEDs cannot run off of more than about 2.5 V without an additional load resistor.
Don't drive a breakbeam LED from a motor port! Even at the maximum speed of 100, the motor output is still pulsed, and the time constant of the LED is small enough that it can flicker on and off with these pulses. The response time of the phototransistor is also very fast, and it can detect the flickers. (They can even detect the 60 Hz flicker of fluorescent room lights.) Thus, you will get random false-positive detections of the breakbeam, and your Egg Hunt robot will keep thinking it has just gotten an egg, and drive you to distraction with its misbehavior. This caveat applies to both the discrete and monolithic breakbeam sensors.
Don't attempt to drive an incandescent lamp from the +5 V bus (middle pin) of an analog port! This +5 V bus is powered by the AA logic batteries, not the motor batteries, and the current draw is too great. This results in rapid (< 5 minutes) depletion of AA batteries. Don't be fooled by the fact that it seems to work just fine when the board is powered by the bench supply; this is only because the bench supply can supply 350 mA indefinitely.
Make sure that LEDs are plugged in with the correct polarity! Diodes conduct current in only one direction, so if you get + and - backwards, no light will come out. Please check polarity before complaining to the instructors that your LED doesn't work.
Besides their obvious use as indicators, the most common use of incandescent lamps and LEDs is for illumination sources involved in egg detection and color discrimination.
IC has some annoying kinks, but it's free and totally open and documented so we run with it. The most annoying feature of IC is that any C program you want to load has to either be in the same folder as IC itself, or inside the IC library folder. It will accept a fully-qualified pathname, but not use it :-( This means that every lab computer has to run its own copy of IC and that there's no way to set up a networked home directory for everybody in the course.
For those new to C programming, the most frustrating thing is forgetting to put a semicolon at the end of every immediate statement you enter at the command line. For C gurus, however, the most frustrating thing is that IC is a stripped-down, non-ANSI version of C, lacking such advanced features as struct and union, and such convenience features as switch, enum, string handling functions, and a preprocessor with #include, #define, and conditional compilation. It is our experience, however, that if-else, for, and while are sufficient for implementing useful and quite complex robot control software.
Comments cannot be nested in IC. Also, the C++ comment style // this is a comment cannot be used.
IC does not allow function prototypes, which means that all functions must be declared before they are used (as in Pascal), and main() is at the end.
IC requires that all local variables defined by a function be defined in a block before any executable code (K&R style). Inline declaration of temporary variables is not supported.
It is important that variable typing be consistently observed in math calculations. For example, if you have an int variable, and need to multiply it by a float variable to produce a float result, you must explicitly cast the int to float. Also, when setting float variables to immediate numeric values, remember that a trailing decimal point is required if the value is an "integer". Similarly, immediate long int values are specified with a trailing L. Failure to observe consistent typing leads to compiler errors at load time. Consult the IC Quick Reference for all library function parameter type requirements.
int i=5; /* int doesn't need decimal point */ float x=25.; /* float requires decimal point */ x=(float)(i)*x; /* must cast int to float for correct result */ msleep(1000L); /* msleep() library function requires a long int */
IC prohibits pointer arithmetic. You cannot use a pointer as an integer representation of a base memory address and access other memory addresses as offsets from the base. If you want to implement a pseudo-struct, you must use arrays and explicit indexing. This is a safety feature to prevent the common confusion between int and *int, which can lead to obscure program bugs.
IC does not support function pointers. Functions must be called explicitly by name (i.e., hard-coded into the program).
The default stack size is only 256 bytes per process, so be careful not to create too many local variables. Allocate extra stack space during start_process() if a process has lots of recursion or deeply-nested function calls to avoid stack overflow errors.
IC seems to dislike local char arrays which have an odd number of elements (probably because the parameter stack is accessed only on word boundaries), so don't be afraid to "waste" a byte and keep the size an even number.
There are a number of important limitations to the main() function. main() has a default stack size of 256 bytes and a default timeslice of 5 msec. These values cannot be changed. Thus, if you need your "main" program to have more than 256 bytes of temporary variable data, or you want a longer timeslice, you must use start_process() to create a main2() with the desired STACK_SIZE and TICKS options. The empty main() will continue to run; main() cannot be killed with kill_process(). However, you can place the following code to run at the end of main() to minimize its execution overhead:
while(1)
{
swap(); /* we aren't doing anything, so go to the next process */
}
Remember the difference between = (assignment of equality) and == (test of equality). Some computer languages (like BASIC) use = for both assignment and test of equality. The following for loop will never execute in IC, skipping to the "All done!" message:
int i;
for (i=1;i=10;i++)
{
printf("%d\n",i);
}
printf("All done!\n");
The i=10 immediately evaluates as true, and the for loop exits to the next statement. You must have i==10 to get the behavior you expect (i.e., that the loop go from 1 to 10 and then stop).
IC supports only 1-dimensional arrays.
The return() statement can only appear as the last logical item of a statement block. You will get bizarre compiler errors if return() appears elsewhere. (In debugging, for instance, you can't just throw in an arbitrary return() to get a function to abort early; you will have to comment out what you don't want executed. And then watch out for nested comments...)
There is a limit to the number of nested if-else statements. If you reach this limit (which is about 16), you will get a bizarre yacc stack overflow error message from IC. You must restructure your code to avoid nesting this deeply. One solution is to make the just-before-the-overflow if statement be a call to another function that finishes out the rest of your if-else cascade. Ugly, but it works.
No assumptions whatsoever should be made about the values of process IDs returned by start_process(). For instance, if process B is started after process A, you cannot assume that process B's ID will have a numerically greater value than the ID of process A. Process IDs are guaranteed only to be unique handles for particular processes.
The >> operator (logical shift right, integer divide-by-2 for each shift) does not work correctly; it returns 0 for any combination of operands. The << operator (logical shift left, integer multiply-by-2 for each shift), does work correctly.
Make sure that your Favorite Text EditorTM is saving your code file in TEXT format, or IC won't be able to read it. SimpleText would be the obvious choice for Mac-based editor, except that it doesn't expand tab characters! (It treats them as spaces! So much for nested indenting C style.)
Consider organizing your code as separate .c files and loading a given project with a .lis file (which lists all the constituent .c files). Put one important or basic functionality in each .c file. This will help with debugging and prevent accidental changes to working code which are often hard to detect and recover from. It also saves typing a bunch of separate load commands.
More than one bug has been found in the IC library code; there may be more. If you find a function which doesn't behave like its description, please let the staff know, and we'll try to fix it. Remember, though, as Kernighan and Ritchie (the inventors of the C programming language) have said, C is what your C compiler lets you get away with :-)
The robot lab is a shared environment. The following points will help everyone to get along with a minimum of friction:
Keep your workstation neat between classes. Keep as much of the contents of your robot kit inside the box. Promptly throw away waste paper, bits of tape, food wrappers, pop cans, etc. Push in the chairs at your desk before you leave.
Shut down all open applications at the end of class. Close (and save, if necessary) all open documents, quit all applications. Don't leave unsaved code sitting in an open window; if the power goes off, your program is lost!
Play music quietly. Some of the workstations have CD players; you may listen to the music of your choice as long as it is not a nuisance to other students. Headphones are best, but open-air music is permitted as long as nobody else objects. If there is wide disagreement, work it out intelligently amongst yourselves.
Don't change the room thermostat setting. By default, the robot lab is kept on the cool side. Otherwise, when filled with 30 students and when all 10 computers are turned on, the lab would get quite warm and sticky. Bring a sweater or sweatshirt if you are persistently chilly.
In snowy or muddy weather, take off your shoes/boots. Don't track muck all over the room and arena carpeting.
Don't walk unnecessarily in the arena. Yes, you must test your robots in the arena; but no more than one member of a group at a time should be in the arena during such tests. The others can watch from outside; that way, they won't be in the way of some other group which also needs arena time. Be courteous with regards to obstructing nest beacons; someone else may be testing nest-homing.
Don't step on the nest floors. The cardboard floor won't support adult weights, and the white painted floor will get dirty.
It is very important to learn how to exploit LEGO dimensions and form factors to build sturdy mechanical structures. Width and length (x-y plane) are specified in peg units (e.g. a 2 x 4 plate), while height (z-axis) is given in either plates or beams (3 plates = 1 beam in height). Unfortunately, the x-y and z units are not exactly the same (the distance between 2 adjacent pegs is not equal to the height of a beam). This means that a rectangular frame made by pinning 4 beams together (through the axle holes, using grey standard pins) cannot be exactly traversed by a column of plates. Also, LEGOmetrics are such that it isn't easy to use triangular braces to reinforce corners, except inexactly, by pinning beams across other beams. This is also unfortunate, because the triangle is the only shape which cannot change the angles between adjoining sides without changing the lengths of the sides; this is the source of the triangle's structural stability, and why it is used in bridges, etc.
Here are some basic LEGO construction tips:
Stagger and overlap layers. You don't want long continuous vertical seams; a whole section can fall out because it's anchored only at the top and bottom.
Use crossbeams pinned at right angles when possible. Even though the bracing is rectangular, multiple pins along the length will prevent movement and sagging.
Try to keep weight uniformly distributed. If you make an unbalanced robot frame, you'll have to compensate with a counterweight somewhere (the heavy battery packs, the computer board, or even ballast LEGOs). Make sure, though, that you do account for the weight of the batteries and the computer board. The lighter your robot, the less hard your motors have to work, and the longer your batteries will last.
Keep it streamlined. Don't have lots of things sticking out that can get snagged on obstacles or other robots.
Avoid long, thin structures. These are hard to make structurally sound, will sag badly, and are also likely to break off easily.
When you get your kit, the parts are sorted into clear Zip-Loc bags and screw-top tubes. Keeping the parts sorted in their appropriate containers when not in use is a really good idea, especially for the little grey parts. It makes it easy to find the parts and easy to keep track of inventory. Remember, you have to return the kit in the same condition you received it.
The beams and bricks are distributed with like sizes stacked together in a stagger. Not only is it easier to count the pieces that way, it's easier to get them apart. For instance, trying to get a 1 x 2 plate off a stack with no stagger is difficult without strong fingernails or a jeweler's screwdriver.
After DC motors and geartrains, light sensors are the second-biggest source of student headaches. Virtually all the difficulties are due to shielding problems and failure to take into account the wide variation between individual sensors of the same type. Consider the two functionally-relevant cases:
Nest homing. The arena design is intended to help you with this task; but you have to take some steps of your own. The walls are 1 foot high, and the polarizing beacons are 6 inches off the floor. The walls screen out a majority of the possible direct light interference. For a light sensor 6 inches high, aimed parallel to the ground, given the current arena dimensions, elementary trigonometry shows that, at the entrance to your own nest, the walls screen out direct external light at angles below 14.0°; at mid-court, below 2.8°; and at the entrance to your opponent's nest, 1.5°. Room lights from overhead and outside light from windows, however, will be at a variety of much steeper angles. By putting your light sensors underneath an awning, or at the base of a horizontal tube, or recessed into some LEGO alcove, you should be able to restrict the angles of incoming light to only those originating from the polarizing beacon (0°). The dimensions of the shielding required for different direct illumination angle cutoffs are left as an exercise for the reader.
The polarizing film provided has 23-25% transmittance per sheet; since 2 sheets are required to detect polarization, this means that only 5-6% of the total light with the desired polarization will reach the light sensor. Thus, what seems like blinding light to an external observer is really only a very weak signal to the polarization detector (which is why adequate shielding from confounding ambient light is so important). Given the large size of the arena, it is therefore likely that there are regions in which nests at the opposite end cannot be reliably detected by a single polarization detector. Remember that light intensity is inversely proportional to the square of the distance from the beacon. Distance from one nest, however, implies proximity to another; hence, you should have polarization detectors for both nests. If you want to go to nest A, get no signal from the nest A detector, but get a strong signal from the nest B detector, then driving away from nest B should eventually bring you closer to nest A. You should also consider the case in which neither nest A or nest B are detected; you need some way to maneuver until you can detect at least one of the nests, and thus find out where you are.
"Home" nest assignments are made on the fly at the start of each competition round. You must be able to accept either nest A or nest B as your home nest. It is extremely advantageous to have this selection made by a simple DIP switch setting. Some students have attempted to have separate A/B and B/A sensor heads which are plugged in at game time, or even a single head requiring manual swapping of analog input leads. Too many times with this "strategy", in the excitement of the moment, the wrong sensor head is picked up, or the leads are improperly swapped, or the wrong lead is pulled out entirely--leading to most unfortunate results. Needless to say, it's not recommended!
Egg detection and color discrimination. There are 2 questions your robot must answer: Is there an egg present? If so, what color is it? The color of egg you're trying to detect has a great impact on the design and construction of your egg detector/discriminator. The basic strategy is to measure the reflectance of the egg surface. Black eggs reflect little light, while pastel eggs reflect lots of light. However, depending upon the ambient lighting conditions, no egg may read the same as either a black egg or a pastel egg.
A relatively foolproof egg detector is to position an IR LED/phototransistor pair on opposite sides of a collection chamber. In an empty chamber, the LED emits a beam of IR light (heat, you can feel it) which is detected at the phototransistor. If an egg of any color enters the chamber, the beam is obstructed, and the phototransistor signal changes abruptly. This method requires precise alignment of the emitter/detector pair, and sufficient shielding so that ambient light does not activate the detector even when the IR beam is blocked by an egg.
To determine the egg color, additional light sensors are needed. While ambient light may be adequate under many conditions as a reflectance source, a more robust discriminator would use a well-shielded chamber and an independent illumination source (such as an incandescent lamp). If ambient light alone is used, a separate reference sensor for ambient light alone might be useful as a correction for values recorded by the color sensor, in an attempt to prevent false discrimination (e.g., false-pastel due to bright ambient light, false-black due to dim ambient light).
The computer board has a rudimentary motor current sensor for each of the bi-directional motors, motor_force(n). This can give a vague indication of a stalled motor (stalled motors draw high current). It has not proved especially accurate, since unstalled but heavily-loaded motors can also draw high current. Use it with caution.
Push-button switches used for selection or software control (e.g., you want to wait for a keypress before starting some action) require debouncing software. A completed keypress consists of three consecutive states:
Your software has to wait for these 3 consecutive states, especially (1) and (3). If you simply check for (2), you run the risk that, before you lift up your finger, the program will have run into code which is waiting for the next keypress, and misread the first as the second. Imagine typing on a keyboard with "instant typematic": a character is read repeatedly for as long as a key is pressed. Depending upon your typing speed, you'd get stuff that looked llliiikkeee tthhhhiiisss.... Debouncing the keys (waiting for complete press/release cycles) will do the trick.
Every semester, some teams are tempted to construct grandiose "secret" strategies, in the hopes that (1) they can surprise everyone else with something that they have no defense against, and (2) they can prevent anyone else from devising countermeasures against their robots. Inevitably, "secret" strategies fail because of the lack of field testing--if it's tested in public, it's not a secret any more. However, such under-tested robots are prone to catastrophic failure in the Egg Hunt.
The choice is yours. Personally, I think it's bad sportsmanship to keep secrets in this course--after all, your grade does not depend upon robot performance. Also, you're required to field contest-ready robots in two mock Egg Hunts, so you can't keep them secret anyway. However, "secret" strategies are not expressly prohibited. They are their own punishment...
While the sensors we give you are pre-assembled, plug-and-play, and often nicely packaged into convenient LEGO bricks, proper use of sensors is not trivial. In our experience, students tend to greatly underestimate the complexities inherent in sensors. Here are some pitfalls:
Sensors are noisy. Instead of a simple, idealized y = f(x) stimulus/response curve, real-world sensors are more like y = f(x) � error(a,b,c,...). In other words, there is a trendline function with a superimposed error component which depends on an unknown number of other variables, most of which you couldn't control even if you knew what they were. Since what you care about is the trendline function, in most cases, a single reading from the sensor will not give you an accurate reading--it will be off by some error amount. This deviation from the trendline is called noise; the greater the amplitude of this deviation, the noisier the sensor is. Filtering is the process of getting rid of noise, so you can see what the trendline is. Filtering can be done electrically for some sensors, but also in software. A simple software filtering mechanism is to sample the sensor repeatedly for some time interval, then average the values (sum of all values divided by the number of samples). The sampling interval should be several times greater than the period of the noise element, to ensure that a valid range of responses is captured.
Sensors vary in response time. Some sensors change their response quickly as the stimulus changes; others may lag, so that the current value read from the sensor doesn't necessarily reflect the current state of the environment. Averaging the sensor input over a time interval longer than the lag is necessary to get a value representative of the environment over that interval. However, if a particular sensor's response time is too slow compared to the frequency of the stimulus you wish to detect, you need to find a faster sensor, because averaging will give you a mid-range value that isn't representative of either the highs or the lows of the stimulus.
Sensor values vary with battery voltage. When plugged into your computer board, analog sensors are sampled by an analog-to-digital (A/D) converter circuit which requires a reference voltage signal. The reference signal used is the supply voltage from the computer battery pack, nominally +6 V. As the batteries discharge, this voltage slowly falls to +5.5 V and below. This affects the digital value of the sensor reading returned by the A/D converter for a constant input signal. The implication of this is that the entire response curve drifts in a battery-dependent fashion, and thus calibration values obtained under one set of battery conditions will not be valid under other battery conditions, without some form of correction for the drift. Also be aware that the bench power supplies may have a slightly different voltage than even a freshly-charged battery pack.
Sensors can respond to a wide range of stimuli, many of them undesirable. A mercury "tilt" switch in a door assembly might momentarily close due to the shock of an impact elsewhere on the robot. Photosensors with wide frequency response could mistake bright room light for a polarizing beacon. One way to avoid spurious (false positive) sensor detection is by proper shielding. The sensor is protected or encased in such a way that only the desired kind of stimulus can reach it, and undesirable stimuli can't (even though the sensor itself would respond if the undesirable stimuli did). Shielding can greatly improve the apparent selectivity and sensitivity of a sensor.
"Identical" sensors don't exist. There is considerable variation in the responsiveness of nominally "identical" sensors, even those purchased as part of the same lot. Thus, it is not sufficient to characterize a single representative and expect that others will respond in exactly the same way. You may get lucky; it is more likely, however, that you will be frustrated and disappointed. You should characterize every sensor individually, and be prepared for variations. One of the great advantages to a software design in which separate daemons perform all the low-level sensor input is that the daemon can filter the raw input to create an "ideal" sensor. For instance, if two photoresistors have different response characteristics, the daemon can adjust the response of one to be of the same form as the other, so that all other processes accessing the sensors via global variables would see them as behaving identically.
The servo motors come in a custom-modified package that gives you LEGO plates along 2 axes (for anchoring) and a LEGO gear (to plug directly into a LEGO geartrain). There are only a few sticky points about servo motors:
Don't plug the servo motor into a regular DC motor port! If power is applied, you will fry it and damage (perhaps permanently) the computer board (both of which are your financial responsibility). Look at the board diagram to find the servo port, or ask one of the staff for assistance.
Don't plug the servo motor in backwards! If you plug the servo motor in backwards with the power turned on, you will also fry it. Make sure the servo motor is plugged in with the correct polarity (white or yellow lead to the right) before you turn on the board.
If the servo motor doesn't work: Make sure the servo motor libraries have been loaded by IC at startup. Make sure that your code issues a servo_on() command before trying to turn the motor to a particular angle. Make sure that the motor batteries are plugged in and charged. If you did all these things and it still doesn't work, then either (a) the cable is broken (often at the strain relief), or (b) you plugged it in backwards and fried it. Give it to the staff for dissection. The hot smell of phenol and formaldehyde is pathognomonic, as the doctors say, of (b)...and that'll cost ya $20.
If the servo motor is jittery: You may have a computer board grounding problem. The motor and logic batteries share a common ground bus, joined by a fuse trace on the underside of the board (which will blow if there is a dead short circuit in the motor supply; this protects the logic circuitry). Servo motor power comes from the motor batteries, but the control signal pulse is a digital output from the 68HC11 CPU, in the logic battery circuit. If the motor and logic grounds are not connected, the control pulses float with regard to the motor ground, and may not be high enough to be detected. Float level is dependent upon current load, so the servo motor might work fine until some other motors or LED outputs are turned on. Give your board to the staff for analysis.
Don't overload the servo motor shaft radially. You're likely to break off the LEGO gear. It can be reglued, but it's a hassle. Axial (compression) loads, however, don't cause any difficulties.
Remember to set the global variable SERVO_TYPE to match your servo motor. The default value is 0 (defined in servo.c), which may or may not match the servo motor in your kit. If you don't set SERVO_TYPE correctly, you won't get 180° of travel, and you may run the servo motor past its physical stop, thereby damaging it and resulting in a $20 replacement fine for your group.
Allow enough time for the servo motor to move into position. It takes more than 1 second for the servo motor to turn through 180°. If you issue too many servo commands too quickly (especially if followed immediately by servo_off()), the servo motor can't catch up, and may not move at all. Put some sleep() commands after each servo movement.
The various contact switch sensors come pre-mounted into suitable LEGO bricks. Additional configurations can easily be made upon request, with the help of some hot glue; but the "standard" arrangements are suitable for most purposes. The switches are pretty sound mechanically and don't seem to be noisy. The spring action of the lever switches can't recoil hard enough to move a large LEGO bumper; you'll need a separate spring assembly in parallel.
Wherever possible, switches should be protected by other LEGO structural elements. A bumper made of LEGO beams can detect impacts over a greater area than a naked switch, and also diffuse the (often considerable) force of impact. Bare lever switches are particularly undesirable, as the lever can get snagged on other robots and ripped right off, destroying the switch and costing you some $$$.
Switches used in bumpers for collision detection may also require debouncing. Since it's not impossible for a switch to get stuck in the ON position, a debounce routine which returned an error condition if the switch didn't turn OFF after a certain period of time might be worth considering. Without this, a simple-minded collision daemon might put the robot into an infinite loop of avoidance, for as long as the switch was ON.
Although it is sometimes tempting, never plug in or swap components while the computer board is turned on! Some items (like servo motors) will fry immediately if you plug them in backwards with the board energized. Turn off the power before plugging anything in, and double-check the polarities before you turn the power back on. Remember, you and your group are financially liable for damaged electrical equipment.
If you forget to turn off your computer board, it will run until the AA batteries fail. When the AA battery voltage falls too low, but not quite to the dead state, the board will spontaneously reset over and over (you'll hear it beeping). This reset is the same as pushing the Reset button, which means that main() will begin executing with each reset. Thus, if your main() code immediately runs go_forward() or some other movement routine, this routine will execute, and the robot will move. In this case, if you have left your robot out on the table, it will quite likely lurch itself right onto the floor, with catastrophic results.
As fail-safe insurance against forgetting to turn off the computer board, always make the first executable code in main() be a check for a keypress before beginning any movement. This way, if you do forget to turn off the computer board, and main() begins to execute with each power failure reset, the robot won't be able to move, because it will hang waiting for a keypress which it's not going to get.
Yes, one group actually did have its robot drive off the table and self-destruct due to leaving the power on after an extra session. The corpse was not discovered until the next day, but autopsy clearly showed the main power switch in the ON position, and the last main() code loaded did not wait for a user keypress before starting to move forward. This group was lucky in that the computer board was undamaged in the fall; the robot, however, was totally destroyed.