Subject:
|
RoboTag version 0.8 -- explaination & NQC source
|
Newsgroups:
|
lugnet.robotics
|
Date:
|
Tue, 6 Oct 1998 17:46:46 GMT
|
Reply-To:
|
MATTDM@MATTDMspamless.ORG
|
Viewed:
|
2645 times
|
| |
| |
/* Matthew's RoboTag 0.8 for Lego Mindstorms.
*
* written in NQC version 0.5b1 -- http://www.enteract.com/~dbaum/lego/nqc/
*
* Copyright (c) 1998 Matthew Miller. You're free to use and modify this as
* you wish. You can also redistribute it, but please give me credit and
* don't make any changes you haven't told me about. Thanks!
*
* mattdm@mattdm.org -- http://www.mattdm.org/mindstorms/
*
* The basic game:
*
* Two robots run around a playing field. When one tags another, the
* "victim" must sit still for a few seconds.
*
* The playing field:
*
* A big piece of paper, with a think black line for a border. There can
* also be other lines on the paper for interest, although too many
* doesn't work very well -- these aren't very smart robots. I find that a
* simple partial line in the middle works well, like this:
*
* -------------------------------------------------------
* | |
* | |
* | | |
* | | |
* | | |
* | | |
* | | |
* | |
* | |
* -------------------------------------------------------
*
* The line is the border -- if the robot senses it, it must turn around.
*
* The only actual objects allowed on the field are the robots, so if one
* hits something, it's safe to assume it was the other robot.
*
* The robots:
*
* Very simple. Treaded bulldozer-like robots, except that the 'blade' is
* connected to a touch sensor, so that if it's bumped, the sensor is
* triggered. (Shock absorbers, either large or small, are invaluable for
* making this work. I'm really surprised Mindstorms doesn't come with any,
* since it's such a useful construction. How do other people make their
* bump sensors broad enough to be useful?) The light sensor is mounted
* front-center and looks for the black line.
*
* Light sensor is on input 2, touch sensor on 1. Motors on A and C. No
* particular reason -- that's just the Way It Is.
*
* The treads, by the way, have a 24t gear on attached directly to their
* axles, and that meshes with an 8t gear attached to the motor shaft. This
* gearing works well and is nice and compact. I wouldn't recommend it on
* shag carpet or a dirty floor though, as the 24t gears are large enough
* and close enough to the ground that they can gather junk. Works fine on
* a paper play surface though.
*
* (I'll post pictures and a movie of these sometime soon.)
*
* The protocol:
*
* A lot of trust involved here. The RCXs are too dumb^H^H^H^H simple to do
* otherwise. So, each robot believes what the other one says, and in fact
* relies on the other to know if _it_ has been hit.
*
* If robot A hits robot B, A sends out a "Bang" signal. When robot B hears
* this, it responds with "Ow" and goes into "punishment" mode -- sits
* still beeping mournfully for a few seconds. If robot A hears this Ow, it
* goes about its business. (Namely, meandering meaninglessly.) But if it
* doesn't get the response after a few seconds, it starts spinning and
* yelling "Ditto Ditto Ditto" until a response is heard. (Spinning 'cause
* that has a good chance of making the IR ports line up, the lack of which
* being the usual cause of lost messages.) If robot B hears a Ditto, it
* responds with an Ow, and if it isn't in punishment mode already, starts
* being punished. If already is being punished, it doesn't add to the
* punishment (but still says Ow, just to get robot A to shut up).
*
* This may sound confusing, but it works beautifully.
*
*
* Notes:
*
* Right now both robots run the same code. Maybe someday they'll each have
* their own independent devious schemes....
*
* For some reason, one light sensor gives readings about 10 lower than the
* other. Which is sort of a pain. Originally, I just used a #define and
* changed it before compiling/downloading, but that's annoying. So now the
* robot reads 'normal' at startup, and assumes the dark line is going to
* be about (at least) 7 darker than that. This is good for other reasons
* too -- you could play on different colored paper without recompiling.
* It also means you have to press "Run" while the robot is on the ground
* on the playing field -- for some reason some of my friends' natural
* instinct is to pick up the robot, press Run, and set it down. That won't
* work. Future (fairly easy) adjustment -- make it so it also triggers on
* 7 (or so) brighter than normal, for use with tape on carpets.
*
* Also, we used the Mindstorms/GUI to set the IR port into long-range
* mode. This seemed like a good idea. We haven't tested it in
* short-range. And I couldn't find any documentation on this anywhere --
* has anybody looked into this? Can any alternative tools set/read what
* mode it's in?
*
* When I say "we", I mean Paul Stauffer, who owns the other RCX. I wish I
* were that wealthy.
*
* When we first built the robots, my bump-sensor kinda sucked and was
* breaking all the time and stuff. So I re-built it, and now it's really
* good (I'm proud of myself; can you tell?). It's especially good at
* making Paul whine, because in a head-on collision, my robot always
* triggers first, and therefore wins. Hahahahahahaha.
*
*/
int randnum;
int bumpcount;
int needackflag;
int gotackflag;
int blackvalue;
task main
{
//set up sensors properly
Sensor(IN_1,IN_SWITCH);
Sensor(IN_2,IN_LIGHT);
initlight(); //set trigger-value for border lines, since apparently
//different sensors give different readings, and
//because different surfaces obviously are different.
//clear all flags
bumpcount=0;
needackflag=0;
gotackflag=0;
//start message-watching service
start postoffice;
//start black-line-watching service
start checkline;
//start bumper-watching service
start checkbump;
//full forward (um, the motors are connected backwards, so
// Rev=Forward. sorry)
Rev(OUT_A + OUT_C,OUT_FULL);
while(true) //loop forever
{
if (bumpcount>0) // if we got hit
{
punishment(); // sit still for a while
bumpcount -=1; // and then decrement hit counter
}
if (needackflag>1 && gotackflag==0) // if we need to hear ack of
{ // our bump signal and we haven't yet
startspinning(); //start turning a random dir
ClearTimer(0); //count how long we've spun
while(gotackflag==0) //wait until we get the ack signal
{
SendMessage(34); //yell ditto
PlaySound(0); //and beep nicely
Sleep(10); // if we yell too fast, we can't listen.
// so we have to pause for a while. 5 was
// too little -- 10 works. haven't bothered
// to find the exact value
if (Timer(0)>100)
{ // it's been a long time
gotackflag=1; //pretend we got an ack
needackflag=0; //and stop caring.
}
}
//ok done spinning now go.
Rev(OUT_A + OUT_C,OUT_FULL);
}
}
}
// this task watches for incoming messages.
task postoffice
{
ClearMessage(); //start by erasing whatever's in the air
while(true)
{
if (Message()==33) //bang! we've been hit!
{
SendMessage(6); //send ack
bumpcount +=1; //increase our damage. ow.
ClearMessage(); //and of course clear the message now that
// we've dealt with it.
}
if (Message()==34) //we've been hit but didn't respond. bad us.
{
SendMessage(6); //ack
if (bumpcount==0) // but only do anything if we're
{ // supposed to be paying attention. if we're
// down already, we ignore " signals.
bumpcount +=1;
}
ClearMessage();
}
if (Message()==6) //an ack
{
if (needackflag>0) //we only care if we're listening.
{
needackflag=0; //ok, so we don't care anymore
gotackflag=1; //and we have what we're lookin' for
}
ClearMessage();
}
}
}
task checkline
{
while(true)
{
if (IN_2 < blackvalue) //if the sensor detects dark
{
PlayNote(442,10);
revturn(); //back up and turn
Rev(OUT_A + OUT_C,OUT_FULL); //then go forward again
}
}
}
task checkbump
{
while(true)
{
if (IN_1 == 1) //if the bump sensor is pressed
{
SendMessage(33); //yell bang
PlaySound(0);
gotackflag=0; //clear old acks -- they're not relevant anymore
needackflag=1; //we need an ack now
revturn(); //back up and turn
Rev(OUT_A + OUT_C,OUT_FULL); //the forward again
if (needackflag==1) //if we haven't gotten an ack yet...
{
needackflag=2; //then advance to spinning around yelling
}
}
}
}
sub revturn //back up and turn a random direction
{
Fwd(OUT_A + OUT_C, OUT_FULL); //back up
Sleep(100); //for one second
Off(OUT_A + OUT_C); // stop motors -- is this needed? probly not.
randnum=Random(2); //kludge 'cause Random(x) doesn't work in an "if"
if (randnum == 1) // 50/50 chance.
{
Rev(OUT_A,OUT_FULL); //turn uh, left or right. whichever this is.
Fwd(OUT_C,OUT_FULL);
}
else
{
Rev(OUT_C,OUT_FULL); //turn uh, right or left.
Fwd(OUT_A,OUT_FULL);
}
Sleep(50); //keep turning for .5+Random(3) seconds
Sleep(Random(300));
Off(OUT_A + OUT_C); //stop motors
}
sub startspinning // start spinning a random direction.
{ // if we could nest subs, we would. (same code above)
Off(OUT_A + OUT_C);
randnum=Random(2);
if (randnum == 1)
{
Rev(OUT_A,OUT_FULL);
Fwd(OUT_C,OUT_FULL);
}
else
{
Rev(OUT_C,OUT_FULL);
Fwd(OUT_A,OUT_FULL);
}
}
sub punishment //bad robot. must sit still for 8 seconds.
{
stop checkline; // ignore everything else. we're DEAD. for now at least
stop checkbump; // note that we still process messages.
Off(OUT_A + OUT_C);
repeat(4)
{
PlaySound(4); //cry
Sleep(200);
}
Rev(OUT_A + OUT_C,OUT_FULL); // ok go forward again.
start checkline; //and pay attention to stuff
start checkbump;
}
sub initlight //reads the value of 'normal', and assumes that the
{ // black-line border is about 7 darker. no real reason to
// put this in a sub, except for neatness.
blackvalue=IN_2;
blackvalue-=7; //may have to adjust this.
//also -- what about white lines?
}
--
Matthew Miller ---> mattdm@mattdm.org
Quotes 'R' Us ---> http://quotes-r-us.org/
|
|
1 Message in This Thread:
- Entire Thread on One Page:
- Nested:
All | Brief | Compact | Dots
Linear:
All | Brief | Compact
|
|
|
Active threads in Robotics
|
|
|
|