Wednesday, February 13, 2013

Firebot Day 3

This day was mostly spent on that flame sensor. The line sensor and sonar were pretty reliable.

I noticed that the bot was going after reflections of the flame on the walls of the maze, so I decided to make the flame finding code a bit less primitive.
This scanning code looks for the brightest light values and lowest light values. It also records the encoder values each time it finds a new brightest value. This way, it knows exactly where to turn to in order to face the brightest point found.


bool scanRightForFlame(){ // turn right 180 degrees.
//Initialize variables
int dimmestLight = SensorValue[flameSensor];
int brightestLight = dimmestLight;
int brightestLightAngle = 0;
resetEncoders();

         // TURN_SCAN is a constant for how much the bot turns while it scans
while(SensorValue[leftEncoder]<TURN_SCAN || SensorValue[rightEncoder]<TURN_SCAN){
//keep turning right
if(SensorValue[leftEncoder]<TURN_SCAN){
motor[leftMotor] = MED_LEFT_SPEED;
}else{motor[leftMotor] = 0;}
if(SensorValue[rightEncoder]<TURN_SCAN){
motor[rightMotor] = -MED_RIGHT_SPEED;
}else{motor[rightMotor] = 0;}
  //record values while turning
int currentLight = SensorValue[flameSensor];
if(currentLight < dimmestLight){
dimmestLight = currentLight;
}
if(currentLight > brightestLight){
brightestLight = currentLight;
brightestLightAngle = (SensorValue[leftEncoder]+SensorValue[rightEncoder])/2; //Average of two encoders
}
}
stopMotors(80);
if((brightestLight-dimmestLight) > FLAME_TOLERANCE){ 
// Significant difference between light values
// turn back to face flame
int turnBack = TURN_SCAN-brightestLightAngle+7;
resetEncoders();
while(SensorValue[leftEncoder]<turnBack || SensorValue[rightEncoder]<turnBack){
if(SensorValue[leftEncoder]<turnBack){
motor[leftMotor] = -MED_LEFT_SPEED;
}else{motor[leftMotor] = 0;}
if(SensorValue[rightEncoder]<turnBack){
motor[rightMotor] = MED_RIGHT_SPEED;
}else{motor[rightMotor] = 0;}
  }
  stopMotors(300);
return true;
}
else{ // Flame not found
  turnRight(TURN_90/3);
  return false;}
    stopMotors(500);
}

Firebot Day 2

Continuing work on this firefighting bot, Everette and I wanted some device installed that could potentially snuff the flame.


The "fan" we created was practically a rush job, but I didn't mind having a weak prototype. It gave me something to code.

// Swing fan left and right
void fanFlame(int angle, int iterations){
  for(int i=0; i<iterations; i++){
    motor[fanServo] = FAN_CENTER - angle;
    wait1Millisecond(300);

    motor[fanServo] = FAN_CENTER + angle;
    wait1Millisecond(300);

  }
}

The video shows the bot failing to find the flame. Oh well.

Friday, February 1, 2013

FireBot: It Begins

Today, we had few guidelines. Basically, it was a free day to finish up whatever we were behind on. But ultimately, we were preparing for the FireBot competition.
With four rooms separated by 14 inch walls, the idea is to extinguish a candle that has been placed randomly in one of the rooms.
The field was built just today, so we got some time to test on the real deal.


Everette and I added a platform on our bot for an extinguishing device, and hastily built a fan using a servo and whatever parts we had to emulate a fan. (we used big gears)

Apparently no video of that fan fanning. It was adorable.

The fan didn't seem very effective. We'll probably go with a thing that pats out the flame instead. More worrying is the fact that our flame sensing function wasn't working out this time. I'm just glad the line sensing seems reliable.
Everette said he wanted to know the code better, so I plan to explain it online to him. He also took the bot home with him so he could make whatever improvements he wanted. That's good. I'm glad he feels confident enough to do so.



Walls, Lines, and Fire

Today went way better than the last ones! I got there early and jump-started our transition from Everette's bot to mine. We moved the encoders, flame sensor, and line sensor over, but were given a new sensor - the ultra-sonic sensor, which is basically a sonar device. It reads the distance to whatever is ahead of it.


Everette made a cool suggestion that we mount the line sensor using the sonar sensor like so:
Fewer parts to worry about.

Next, we needed a good spot to place the flame sensor. Since the candle is going to hold the flame several inches from the floor, we needed a raised platform of some kind on the bot.
I came up with a little something for that:
Kind of ridiculous looking, but quick and easy.

Now to the program.

goForwardUntilCloseToWall();
turnRight(TURN_90);
goForwardUntilLine(); // pretty self-explanatory
scanForFlame(); // this function has the bot turn right 90 degrees, turn back 180 until flame is detected
goForwardUntilLine(); // go up to the candle
scanForFlame(); // correct direction if not facing candle

With three independent sensors, the testing process would take quite a while, though we did have some really promising results early on. I was only concerned that the bot wasn't facing directly toward the candle when it detected it.
The sonar worked pretty well, but the flame and line sensor's tolerance needed quite a bit of tweaking in the program.
By the end of class, our bot's performance was hit and miss, but the final presentation was successful.

Seemed the flame sensor needed a bigger flame than that tiny candle produces.

Lines and Fire

Our upcoming big challenge is to create a lean, mean, firefighting robot.
...Or a little guy that'll put out a candle for you.

For this challenge, we need not only to detect the flame, but to get our bearings inside a four-room building. For this, we need an flame sensor to find the flame, and a line sensor to  find the "doors" to each room.
An infrared light sensor can be used to find the flame since fire emits so much infrared light.
Little infrared? - no flame.
Lots of infrared? - flame detected.

Just an infrared LDR working with a 10K resistor like in my Hexbug.

The line sensor also uses an infrared sensor, but it also needs an infrared light emitter working with it.  The emitter constantly shoots infrared at the floor, and depending on whether or not there's black electrical tape below, the sensor will receive varying reflection from it.
Lots of infrared? - no line.
Little infrared? - line found.

I added electrical tape around the sides so they emit and receive to and from the floor only.

We were supposed to have this bot up and running, so we can see it stop at a line, then point to the flame when it sees it, but we spent quite a bit of time being confused about the construction and testing of these new sensors. On top of that, the bot that Everette built seemed unwilling to give us a strong drive-train, as we observed during the maze-run last week.
Tomorrow, we plan to start fresh, and transfer everything to my bot.



Running a Maze

This time, we got to do something with our VEX bots. The aim was to navigate a maze using no sensors besides the bot's internal clock. This means we had to calculate how much time it takes for the bot to travel a certain distance, then hard-code a set of instructions that allows it to follow the path all on its own.

Start in the lower right, and get to the X.

I was partnered with Everette, who's deaf and mute, but he was one of the people I wanted to work with, since he showed interest in the Robotics team earlier. (Plus, I always wanted to learn some sign language.) We have interpreters to facilitate communication too.
Everette seemed to think I should be be leading our efforts, which is cool, since I have some experience in this stuff, and love messing with robots and programming.

He took a picture of the maze on his iPad for us to reference while we prepare the robot and develop the program. I found that the bot needed about 400 milliseconds to travel one floor tile, and using that number as a unit (TILE_TIME), I quickly calculated some approximations of the steps that the robot had to take to complete the maze. I used functions like goForward(int milliseconds) that runs the motors for some milliseconds.

goForward(3500); // The goForward function multiplies 3500 it by TILE_TIME, then divides by 1000.
turnLeft(TURN_90); // TURN_90 is a constant that I recorded for how long it takes to turn exactly 90 degrees
goForward(3000);
turnRight(TURN_90); // etc...

It looked like this would turn out to be pretty easy, but we soon learned that the varying power given by the quickly draining battery made it much trickier. I figured something like this would happened, so I tried adjusting my constants like TILE_TIME to work for our current battery level. (e.g. increase TILE_TIME so a sluggish bot with a low-level battery could go the correct distance)
In the end, we didn't get quite enough time to perfect it, so our bot didn't quite succeed, but it did wind up pretty close to the end of the maze.

The battery was a bit lower than anticipated.

The next challenge was to use encoders to measure how far the robots have traveled. This solves the battery issue, since encoders measure how many rotations of the wheels have occurred, which gives us actual data, and accounts for any friction in the drive-train.

The big problem Everette and I ran into was purely mechanical. The encoders didn't seem to fit quite right on my bot, so we hastily switched over to Everette's. This turned out to be a bad decision, since his drive-train was problematic for ambiguous reasons. Its output was downright feeble on one side. We spent all the rest of class time trying to fix it, but never succeeded, so we went out to present without any prior testing.

The thing that I found hilarious was that even without any testing, my program's encoder counter was dead-on for the distances we wanted the bot to go. it attempted its first turn at just the right spot, but failed to complete it.