The Lebanon Evangelical School for Boys and Girls is celebrating its 150th anniversary, and, today, as part of the festivities, we had an exhibition of our students’ work, followed by a “Lebanese Night” (which still seems to be going strong, judging by the music blasting through my living room windows).
Our robot club had robots playing “Robot Tag” on the stage. The idea of “Robot Tag” is that you have two robots inside of an arena that chase each other, while being careful not to cross the white lines that mark the border of the arena. A robot “tags” the other robot when it uses the ultrasonic sensor to detect that it’s within 20cm of it (though, given the small size of the robots, it normally gets closer than that before the ultrasonic sensor says that it’s within range).
It was quite a hit with both students and parents, and I was very pleased with how well the robots did, especially given the problems I ran into getting everything set up. But that’s a LONG story…
The LONG story
At the beginning of the year, our principal bought three LEGO Mindstorms Golfbots, and I started a robotics club with a few of my students. It started out with a couple of older students, and then expanded when a few of my eighth-graders got interested, and then one of my seventh-graders.
About six weeks ago, the principal asked me to put together something for the exhibition using the robots. I brainstormed with my students, and we came up with the idea of “Robot Tag”.
The only reasonable way to make something like this work is to have multiple threads (called tasks in NXC), and, since my students are still very much beginners when it comes to programming, I decided to put together a library to do the heavy lifting, while letting them write the procedures that would determine the robot’s strategy.
I decided to go with a four-thread design:
- A bluetooth thread in which the two robots communicate which is “it” and which isn’t.
- A light sensor thread, which determines when the robot has crossed the white line, and does the necessary work to get the robot back into the arena.
- A “check it” thread that checks whether the robot has tagged the other robot or been tagged by the other robot and starts and stops the appropriate student threads.
- One of four control threads.
The control threads are:
- it – the thread run while the robot is “it”.
- notit – the thread run while the robot is not “it”.
- run – the thread run when the robot has just tagged the other robot, before notit is run. It’s only purpose is to turn the robot around.
- wait – the thread run after a robot has been tagged. This thread should only spin the robot around or flash its lights or the like. It will automatically be stopped after 10 seconds, and it will be run.
The beauty of this design is that my students don’t have to understand the concept of semaphores, mutexes (mutexi?), or even threads. They get to write four separate procedures, only one of which will be running at any time. Their threads will be automatically stopped whenever the robot crosses the white line, tags the other robot, or gets tagged itself. I thought it sounded very elegant. Unfortunately, reality got in the way.
You see, this whole design is dependent on the ability to start and stop threads at will. And, though NXC does have StartTask() and StopTask() functions (the latter only works if you’re running the NXC Enhanced firmware on your robots), I ran into a couple of rather… strange… problems. First, StopTask() doesn’t work at all with the Enhanced NXC 2.0 firmware (v1.28), which I later found out is because of a change in how NXC deals with the Wait() function.
When I figured this out, I thought, “No problem, I’ll just install the latest enhanced 1.0x firmware.” And, sure enough, StopTask() did work fine under the 1.05 firmware… most of the time. And therein lies the problem. It’s very difficult to work with a function that only works “most” of the time, especially when there’s no way to see whether a thread is running or not. It was very interesting to watch two robots playing tag when one would suddenly decide to ignore little niceties like staying in the arena. You could almost hear the other robot saying, “Wait, that’s not how you’re supposed to play!”
In the end, I had to write my own solution, which sledgehammered the problem. I decided that each thread would be running all the time (bypassing StopTask() completely), but that the motors would only respond to the tasks that were supposed to be “on”. I wrote a wrapper for every motor and sound function that would ensure that the motor would ignore any commands from any tasks that were officially “stopped”.
So, after weeks of working on something that should have only taken a few days, I finally got the library finished and the students were able to write their procedures. They did an excellent job and came up with very creative ways of getting their robot in close enough to the other robot to tag it.
The code for my library is available here. You must create
user.h which will contain the four user tasks. See
user.h.example for help. To compile, all you should need to do is write
nbc -S=usb -d -safecall tag.nxc. You will need two NXT robots connected via bluetooth to make it work.