Strings & Ints

RobotMC Team Building Day

by elbekko on Sep.24, 2009, under Robots

On the 19th of September 2009, RobotMC organised its second Team Building Day.

In the months before the contest, a few hints are given out, like telling you which sensors you’ll be needing lots of. On the day itself though, you have around 6-7 hours of time to build and program your robot. And in my case an hour or so of that was wasted on reading a tutorial, as it had been a rather long time since I last worked with NXC.

Of course the base of your robot doesn’t have to be built that day, such a rule would just kill off all the non-Lego competitors.

I’d like to believe our team, At Random, didn’t do that badly with a second place, mainly because of a glitch that we still haven’t confirmed (but it is believed to be the afterglow of one of the lamps that gave too high a reading on the light sensor).

And in the name of team spirit and open-source software, have some code.
All of this code is written in NXC using the BricxCC IDE.

The first assignment – Go towards a random light source

The goal of this assignment was to break a beam of light (as done by our legendary pirate flag, it was talk like a pirate day anyway), and then either go left or right towards a light source. Which direction to go in was randomly selected.

/* Motor defs */
#define LMOTOR OUT_B
#define RMOTOR OUT_C
#define MOTORS OUT_BC

/* Motor control defs */
#define Fwd(motor, speed) OnFwdReg(motor, speed, OUT_REGMODE_SYNC)
#define Rev(motor, speed) OnRevReg(motor, speed, OUT_REGMODE_SYNC)
#define TFwd(motor, speed) OnFwd(motor, speed)
#define TRev(motor, speed) OnRev(motor, speed)

/* Sensor defs */
#define LIGHTLEFT IN_2
#define LIGHTRIGHT IN_3

/* Other defs */
#define STOPAT_1 40
#define STOPAT_2 25
#define LIGHTSOURCE 95

#define rotationspeed 60
#define rot90deg 420

int rotcount = 0;
bool side = false; // false = left, true = right

void turnLeft()
{
    RotateMotor(RMOTOR, rotationspeed, rot90deg);
}

void turnRight()
{
    RotateMotor(LMOTOR, rotationspeed, rot90deg);
}

task main()
{
     /* Sensor init */
     SetSensorLowspeed(IN_4);
     SetSensorLight(LIGHTLEFT);
     SetSensorLight(LIGHTRIGHT);

     /* Move to middle */
     Fwd(MOTORS, 65);
     until(SensorUS(IN_4) <= STOPAT_1);
     Off(MOTORS);

     /* Scan light source */
     if(Sensor(LIGHTLEFT) >= LIGHTSOURCE)
     {
         /* Turn left */
         turnLeft();
         Off(MOTORS);

         side = false;
     }
     else if(Sensor(LIGHTRIGHT) >= LIGHTSOURCE)
     {
         /* Turn right */
         turnRight();
         Off(MOTORS);

         side = true;
     }

     ResetAllTachoCounts(MOTORS);
     ResetRotationCount(MOTORS);

     Fwd(MOTORS, 75);
     until(SensorUS(IN_4) <= STOPAT_2);
     Off(MOTORS);

     // Left
     if(side == true)
     {
         turnRight();
         turnRight();
         Off(MOTORS);
     }
     else
     {
         turnLeft();
         turnLeft();
         Off(MOTORS);
     }

     Fwd(MOTORS, 75);
     until(SensorUS(IN_4) <= 180);
     Off(MOTORS);

     if(side == true)
     {
         /* Turn left */
         turnLeft();
         Off(MOTORS);
     }
     else
     {
         /* Turn right */
         turnRight();
         Off(MOTORS);
     }

     Fwd(MOTORS, 75);
     until(SensorUS(IN_4) <= STOPAT_2);
     Off(MOTORS);
}

The second assignment – line following

This is actually the assignment we kept as last, as it seemed to be the hardest one… boy were we wrong. We did it in about half an hour, and had to add an extra sensor to the robot for the sharp turns, and it worked. I proclaim another victory against the laws of physics and logic.
The most special bit about this code is the multithreading, which worked great, even without mutexes, probably because it’s only written once and read many times.
We had to up the light threshold in this bit, because the rear sensor didn’t have the special cardboard magic to stop other light from affecting it, but in the end it didn’t seem to make that much of a difference.

/* Motor defs */
#define LMOTOR OUT_B
#define RMOTOR OUT_C
#define MOTORS OUT_BC

/* Motor control defs */
#define Fwd(motor, speed) OnFwdReg(motor, speed, OUT_REGMODE_SYNC)
#define Rev(motor, speed) OnRevReg(motor, speed, OUT_REGMODE_SYNC)
#define TFwd(motor, speed) OnFwd(motor, speed)
#define TRev(motor, speed) OnRev(motor, speed)

/* Sensor defs */
#define LIGHTLEFT IN_2
#define LIGHTRIGHT IN_3
#define LIGHTBACK IN_1

/* Other defs */
#define SPEED 35
#define TURNSPEED 20

#define LINE_lower 25
#define LINE_upper 50

int leftSpeed = 0;
int rightSpeed = 0;

task leftWheel()
{
    while(true)
    {
        TFwd(LMOTOR, leftSpeed);
    }
}

task rightWheel()
{
    while(true)
    {
        TFwd(RMOTOR, rightSpeed);
    }
}

task checkSensors()
{
    while(true)
    {
        if(Sensor(LIGHTLEFT) > LINE_upper && Sensor(LIGHTRIGHT) > LINE_upper)
        {
            leftSpeed = SPEED;
            rightSpeed = SPEED;
        }
        else if(Sensor(LIGHTLEFT) <= LINE_upper && Sensor(LIGHTRIGHT) > LINE_upper)
        {
            leftSpeed -= TURNSPEED;
            rightSpeed = SPEED;

            if(Sensor(LIGHTBACK) <= LINE_upper)
            {
                leftSpeed = -100;
                PlayTone(500, 250);
            }

            if(leftSpeed < 0)
                leftSpeed = 0;
        }
        else if(Sensor(LIGHTLEFT) > LINE_upper && Sensor(LIGHTRIGHT) <= LINE_upper)
        {
            leftSpeed = SPEED;
            rightSpeed -= TURNSPEED;

            if(Sensor(LIGHTBACK) <= LINE_upper)
            {
                rightSpeed = -100;
                PlayTone(500, 250);
            }

            if(rightSpeed < 0)
                rightSpeed = 0;
        }
    }
}

task main()
{
    SetSensorLight(LIGHTLEFT);
    SetSensorLight(LIGHTRIGHT);
    SetSensorLight(LIGHTBACK);

    Precedes(checkSensors, leftWheel, rightWheel);
}

The third assignment – line detection

This was the simplest and hardest of all. A contradiction you say? Pah!
The premise was dead easy: drive in a straight line and back again, crossing 3 black lines, but not a fourth. At the detection of each black line, but not the gray lines, you had to beep. When going back, you had to detect both lines (to see when to stop), but only beep on the gray lines. This proved tricky for many teams as white + black = gray, and of course there’s this very tiny bit of a black line that the sensor sees as being gray. We solved this by waiting a bit before the final sensor poll that’d have to tell us which colour the line was, to make sure the robot wasn’t in that pesky gray area.

/* Motor defs */
#define LMOTOR OUT_B
#define RMOTOR OUT_C
#define MOTORS OUT_BC

/* Motor control defs */
#define Fwd(motor, speed) OnFwdReg(motor, speed, OUT_REGMODE_SYNC)
#define Rev(motor, speed) OnRevReg(motor, speed, OUT_REGMODE_SYNC)
#define TFwd(motor, speed) OnFwd(motor, speed)
#define TRev(motor, speed) OnRev(motor, speed)

/* Sensor defs */
#define LIGHTLEFT IN_2
#define LIGHTRIGHT IN_3

/* Other defs */
#define SPEED 65
#define WAITTIME 200

/* Line defs */
#define DARKLINE_lower 25
#define DARKLINE_upper 35

#define GRAYLINE_lower 39
#define GRAYLINE_upper 43

int blackcount = 0;
int graycount = 0;
int sensorvalue = 100;

task main()
{
    /* Sensor init */
    SetSensorLowspeed(IN_4);
    SetSensorLight(LIGHTLEFT);
    SetSensorLight(LIGHTRIGHT);

    /* Run 1 */
    while(blackcount < 3)
    {
        Fwd(MOTORS, SPEED);
        until(Sensor(LIGHTLEFT) <= DARKLINE_upper);

        if(blackcount < 2)
            Wait(WAITTIME);
        Off(MOTORS);

        PlayTone(500, 250);
        blackcount++;
    }

    Rev(MOTORS, SPEED);
    Wait(WAITTIME);

    /* Run 2 */
    blackcount = 0;
    while(blackcount < 3)
    {
        Rev(MOTORS, SPEED);
        until(Sensor(LIGHTLEFT) <= GRAYLINE_upper);

        Wait(20);
        sensorvalue = Sensor(LIGHTLEFT);

        NumOut(1, 1, sensorvalue, 0);

        if(blackcount < 2)
            Wait(WAITTIME);
        Off(MOTORS);

        if(sensorvalue >= DARKLINE_lower && sensorvalue <= DARKLINE_upper)
        {
            blackcount++;
            Wait(WAITTIME);
        }
        else if(sensorvalue >= GRAYLINE_lower && sensorvalue <= GRAYLINE_upper)
        {
            PlayTone(800, 250);
            graycount++;
        }
    }

    Rev(MOTORS, SPEED);
    Wait(500);
    Off(MOTORS);
}

I hope the code is of use to you, and it’s as much fun for you figuring out what it does as it was for me figuring out how to make it do it.

Keep an eye on this thread, it’ll have more videos of the action cam on our robot, and probably pictures too.


Leave a Reply