Given the limited availability of the Mindstorms kits, I set out the first weekend of class to learn as much as I could about what I might be able to build.
Russell Nelson's Lego Mindstorms Internals page [RNLMI] provides an abundance of information that couldn't be found at Lego's Mindstorms web site. [LGLM] Another extremely helpful resource are the newsgroups available at lugnet.com [LUGNET]. That's where you will find most of the people listed in the bibliography of this project discussing future directions in Lego RCX programming. It is also a great place to go for information, as I found when I wanted to overcome the problem with the IR tower falling asleep (which is covered below).
Once I had an overview of what the RCX was capable of, I then set down to try some basic communication between the RCX and PC. I originally planned to make a page scanner that could scan a page of arbitrary (very large) size. The idea was to have the robot use the light sensor to do the scan and then report back what it found to the PC. I had seen at Lego's web site a project that someone had done that could scan something the size of a sheet of paper. I wanted to develop a bot that would be put on a very large piece of paper, have it find a corner and align itself to the edge, and then proceed to scan line by line while sending the results back to the PC. However, I abandoned this idea when I realized a single Mindstorms kit didn't provide all that I needed to do it right (I needed more light sensors at least).
So, I then changed the plan to a basic room explorer bot. Have the bot walk around the room bumping into things and making course corrections. Additionally, have it report back to the PC the contacts it had made so the PC could provide better instructions for those parts of the room that needed more exploration.
Having not searched the lugnet.com discussion groups at that point, I assumed the range of the IR tower was rather limited. Therefore, I planned to build an explorer bot that could carry my Compaq laptop around so that it would always be in range of the PC.
So, with that in mind, I sat down with just the RCX, a couple of motors, a couple of touch sensors, my laptop and the IR tower to figure out how to get a dialog going.
I originally considered three approaches:
Kekoa's tools include a simple program named send.c which provides for basic communication with the RCX. Dave's NQC provides an easy way to send messages and raw commands (much like Kekoa's). Scott's RCXPort is a Java interface to the RCX.
Given the time constraints imposed, I quickly discarded Scott's RCXPort since he had only tested it with JDK 1.2 and I was only familiar with JDK 1.1 (and that familiarity has waned in the year since I last used it). Kekoa and Dave's tools were available as C source which I am much more comfortable with when under deadline.
I experimented with the two remaining approaches. At first, I thought I'd try using the RCX's ``message'' routines. This had a couple of problems. First off, there were timing/coordination issues that would have to be resolved in order to keep the RCX and PC from talking at the same time (and taking corrective action when they realized that they had). However, the second problem of limited communication bandwidth made me abandon this approach altogether. I found that Dave's NQC took about 350ms per message while Kekoa's took about 450ms. This meant that only two to three messages per second could be sent. I managed to get Kekoa's send() to go a little faster by lowering some of the timeout values, but I know that he probably picked the values that he did for good reason and I was possibly affecting the reliability of his code by modifying it. I also noted that most of the time spent in Kekoa's code was waiting for the last byte of a message that never came. I thought it might be easy figure out how many bytes to expect on the reply, and thus forego the final byte, but, again, making such a change would have affected the robustness of his code. In the end, since it was unknown at what rate the RCX would generate data, and since there were the coordination issues to overcome, I decided to toss this approach.
I then focused on using the RCX ``get value'' command in conjunction with the RCX's Datalog to provide polling and data exchange between the PC and RCX. This had two advantages and one major disadvantage. The first good point was that coordination was no longer an issue since the PC was responsible for initiating all communications. The other benefit was the communication ``burst'' used to transfer the Datalog that allowed for more effective use of the bandwidth available. The downside to this approach is that it only works between the PC and one RCX. A multi-RCX implementation can not use this method since all RCX's would attempt to respond to the PC's polls. In the future, I think that the Lego Network Protocol being discussed in the newsgroup lugnet.robotics.rcx.legos for incorporation into the LegOS (Lego Operating System) might be the best way to go. However, they are still working out the details on how to implement it (and, of course, looking for volunteers to contribute code).
Although Kekoa's send.c seems to be a bit more powerful in terms of message handling, Dave's NQC provided all the functionality I needed. Since I had already decided to use NQC to write the RCX code, I decided to go with a ``single-vendor'' solution and use NQC exclusively.
I should mention the development environment at this point. I generally run a Win95 desktop with the laptop on the local net running RedHat 5.2 Linux. I used Mark Overmars RCX Command Center[MORCC] on the Win95 side to develop the RCX code (in particular, because he has a great tutorial[MONT] on NQC). Once it compiled clean, I would FTP it over to the laptop where it would be compiled again (using the Linux NQC) and then downloaded to the bot. In theory, the code developed should work under Win95 or Linux. The ``testing grounds'' was the kitchen floor which is adjacent to my study. With the IR tower facing out the doorway of my study, I was able to communicate with the RCX in most parts of the kitchen.
I should also note that I was easily able to port NQC to HP-UX (Hewlett-Packard's Unix). The actual communications didn't work (I didn't see any point in trying to make them work), but it does provide a way to at least check the NQC code for compile-time errors. I imagine it would be very simple to port NQC to other Unix variants (e.g., Solaris).
Once I had some preliminary success with polling the RCX and retrieving the Datalog, I then investigated how to build the laptop carrying bot.
After several failed attempts, I finally managed to develop a bot that was big enough and had enough torque to carry a book [CLRIA] that was the same size and about half the weight of the laptop. However, the gear ratio required to move the weight made for very slow progress across a room. Since I wanted to be able to demonstrate the project in a reasonable period of time, and since I did not think I could build a sturdy enough platform that I would trust to hold a $2500 laptop as it roamed around the room ramming into things, I abandoned the laptop explorer bot.
It was at this point that I went to the RCX group at lugnet.com to research the range of the IR tower. I found out there that I could reasonably expect a 20 foot range in a room like HRBB 104, and so decided to change my tack and develop the bot I ended up with.
So, again I ripped apart the bot I had (for about the sixth time at this point [the calluses that I developed on my fingertips have just peeled off this last week... my fingers were very tender at this point in the development due to prying apart bricks]).
I concentrated this time on making a rock-solid drivetrain. Previous designs had suffered over time due to loosening of bricks and the different forces placed on different axles. After some experimenting, I came up with a very economical package that clamped the motors, gear and wheel axles very tightly so that their wouldn't be room for the bricks to move. With the drivetrain I developed, I was able to run for extended periods of time without gears slipping (in fact, they never did in the tests I did... only time would tell if they would eventually work themselves loose).
I then worked on a feeler array that would be responsive to obstacles encountered. My first approach to this was a dismal failure, but the lessons learned in the experience allowed me to improve upon my design.
I experimented with different free-wheels at the front of the bot for support. After failing to find one I found satisfactory, and noticing in the Mindstorms Constructopedia that the round, smooth, black thing was designed to be a skid plate, I decided to take that approach. Since the demo was to take place on a well-waxed Texas A&M University classroom floor, I figured the coefficient of friction would be sufficiently low for this to work.
Once I had the bot, it was time to go back to developing the software.
I needed a way to keep the IR tower ``awake''. I had read in the lugnet.com discussion groups that it had a tendency to go to sleep when idle in order to conserve batteries. Furthermore, the RCX could do nothing about the situation, only the PC could wake up the tower. That lead to the decision to poll the RCX constantly in order to keep the tower awake. Since the polling was taking place anyway, I decided to put it to some use.
The first, rather minor, use I found for the RCX's responses to the polls was the use of a proximity detector. I had read that the light sensor could catch the reflection of IR messages off of objects and that this could be used to build a proximity detector of varying ranges. When I had first played with this, I had set up a task in the RCX to constantly send out a message from its IR port and then check the light sensor for the reflection. However, this had the disadvantage that when the PC needed to talk to the RCX, the RCX never heard it because RCX's constant sending would collide with the incoming messages from the PC. However, now I had the RCX providing a constant message stream in cooperation with the PC. Since this was rather ideal, I decided to slap a light sensor on the RCX facing upwards to detect any overhead items (like a desk or chair).
The second, more important, use I found for the RCX polls was to keep the RCX informed as to its range to the PC. I wanted the bot to maintain a constant dialog with the PC so that it could notify the PC when its Datalog was full and needed to be collected. If contact was lost, the bot would have simply stopped (as programmed) because the Datalog was full but nothing was retrieving it. To this end, I came up with a simple little protocol which has the PC and RCX constantly updating variable 0 in the RCX to let each other know what's going on. Originally, I was just going to use variable 0 to notify the PC that the Datalog of recorded observations was available. However, this new ping protocol also allowed for the bot to quickly determine when it had just gone out of range so that it could spin around until facing the RCX (and hopefully, regaining communication) before continuing in its explorations. Figure 1 provides a state diagram of the protocol developed.