// commands as transmitted from the
// desktop to the tanks
#define FWD 0
#define REV 1
#define LEFT 2
#define RIGHT 3
#define STOP 4
#define FIRE 5
// broadcast message sent from the
// desktop, inviting tanks to sign
// up with the desktop
#define HELLO 0x10
// define threshold for the light sensor.
// If the readings of the sensor go above
// that value, we have probably been hit
// by the laser of another tank. Note: the
// light sensor gets confused by flashlight
// photography
#define LASER_THRESHOLD 70
// the three different status messages that
// we can sent back to the desktop.
#define STATUS_OK 0x40
#define STATUS_BUMPED 0x41
#define STATUS_KILLED 0x42
// The ID of a particular tank. At the moment,
// we have to change this value for each tank,
// and recompile and download. This will be
// changed ASAP.
#define MY_ID 0x61
#define SEND_ID (MY_ID + 0x20)
int alive; // are we still alive?
int fire_sem; // is a fire cmd currently in process
int id; // ID associated with current cmd
int status; // current status
int cmd; // current cmd
// the main tank task. This initially
// waits for an invitation to sign up
// from the host (the HELLO message).
// The tank responds by sending its ID.
// After that, the task sits in a loop
// waiting for commands that are addressed
// to this tank. The host will prepend
// each cmd with a tank ID, so the tanks
// will know which cmd is meant for which
// tank. The directional cmds (fwd, bwd,
// left, right, stop) just manipulate the
// direction of the motors driving the
// tank treads, and complte almost
// immediately. The fire cmd is more time-
// consuming, and hence is spun off in
// its own task (see below).
task main {
fire_sem = 0;
status = STATUS_OK;
cmd = 0;
start bump_task;
start hit_task;
while (true) {
alive = 1;
while (cmd != HELLO) {
ClearMessage();
wait (Message() != 0);
cmd = Message();
}
SendMessage(SEND_ID);
// supply audio confirm
// to user
repeat (2) {
PlaySound(1);
Sleep(100);
}
while (true) {
ClearMessage();
wait (Message() != 0 || alive == 0);
if (alive == 0) break;
// ignore all messages
// not meant for us
id = Message();
if (id != MY_ID) continue;
ClearMessage();
wait (Message() != 0 || alive == 0);
if (alive == 0) break;
cmd = Message() - 0x20;
SendMessage(SEND_ID);
SendMessage(status);
status = STATUS_OK;
if (cmd == FWD) {
Fwd(OUT_A + OUT_C, 4);
}
if (cmd == REV) {
Rev(OUT_A + OUT_C, 4);
}
if (cmd == LEFT) {
Fwd(OUT_C, 4);
Rev(OUT_A, 4);
}
if (cmd == RIGHT) {
Fwd(OUT_A, 4);
Rev(OUT_C, 4);
}
if (cmd == STOP) {
Off(OUT_A + OUT_C);
}
if (cmd == FIRE && fire_sem == 0) {
fire_sem = 1;
start fire_task;
}
}
}
stop bump_task;
stop hit_task;
Off(OUT_A + OUT_C);
}
// This task waits for either the
// front bumper or the back bumper
// to activate. It will then briefly
// switch direction for both treads,
// and finally stop. The brief switch
// is needed to ensure that the bumper
// will unblock. A blocked bumper will
// keep the tank from operating (because
// the bumper behavior just described
// will execute over and over).
task bump_task {
Sensor(IN_1, IN_SWITCH);
Sensor(IN_3, IN_SWITCH);
while (true) {
ClearSensor(IN_1);
ClearSensor(IN_3);
wait (IN_1 == 1 || IN_3 == 1);
OutputDir(OUT_A + OUT_C, OUT_FLIP);
Sleep(30);
Off(OUT_A + OUT_C);
if (status == STATUS_OK) status = STATUS_BUMPED;
}
}
// This task waits for the light
// sensor to report input that lies
// above the specified threshold.
// When that condition is met, it
// gives audio confirmation of the fact
// and clears the 'alive' flag.
task hit_task {
Sensor(IN_2, IN_LIGHT);
while (true) {
ClearSensor(IN_2);
wait (IN_2 > LASER_THRESHOLD);
status = STATUS_KILLED;
Off(OUT_A + OUT_C);
repeat (3) {
PlaySound(2);
Sleep(100);
}
alive = 0;
}
}
// this task drives the motor that
// operates the cam, which activates
// the laser gun, in one direction
// for 1500 milliseconds. It then
// briefly reverses the direction
// to make sure the laser will turn off.
task fire_task {
Fwd(OUT_B, 1);
repeat(3) {
PlaySound(5);
Sleep(50);
}
Rev(OUT_B, 1);
Sleep(20);
Off(OUT_B);
fire_sem = 0;
}