RoboCatz.com
About FLL | Navigation | Playbook | Strategy | Models | Techniques | RobotC | Programming | Robot News |

Playbook: Function Overloading -- The Exercise

Definition: The ability to define multiple functions with the same name but with different implementations.

driveForward();   // Just start driving forward
driveForward(12); // Just drive for 12 inches
driveForward(12,25); // Drive for 12 inches at 25% power
The types of function overloading we use are classified as a form of static polymorphism in which a function call is resolved using the 'best match technique', i.e., the function is resolved depending upon the argument list.

Function overloading is usually associated with statically-typed programming languages which enforce type checking in function calls. When overloading a function, you are really just making a number of different functions that happen to have the same name. When the program is "compiled", the compiler determines which of the functions are used in each instance.

Requirements

This exercise requires you to be in front of a computer with RobotC and a Mindstorms robot. You will write a program according to the instructions below. Try not to just jump to the end of the lesson and copy the whole program. You won't learn much by doing that. Follow the individual steps shown below. Follow them in order--so that you'll know what to do when you have to write your own programs some day.

Start RobotC and access a New program

Start RobotC then click on the New File button from the button bar. The new program should appear as:

task main()
{


}
Insert a function to draw a circle as shown below.

task main()
{

  drawCircle(100, 50, 20);

}
Did you see it? Probably not. The robot drew the circle and ended the program probably faster than you could see it. Let's make the robot wait a little bit.

task main()
{
  drawCircle(100, 50, 20);
  wait(2);
}
Ok. There it is. 100 on the x axis, and 50 on the y axis. From this, you can see that the origin point is the lower left corner of the display.

Now let's draw the circle at random positions on the display.

task main()
{
  drawCircle(random(100), random(100), random(20));
  wait(2);
}
Run it several times.

Do you see circles?

The reason is NOT intuitive and is probably just a bug in the RobotC compiler. There is a simple work around: just make sure you pass integers to the drawCircle function as shown below:

task main()
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
  wait(2);
}
Reading the program above, we declare an integer x and assign (=) it a random number between 0 and 100. We declare a y integer to also contain a random number. Then we pass the two integers to the drawCircle() function.

Now Create Your Own Function

Sometimes you may want to use a function in multiple places within your program. ALL C LANGUAGES ALLOW YOU TO CREATE YOUR OWN FUNCTIONS!!! This is very important. C is powerful because you can customize it to meet your needs. And there are almost no limitations to the degree to which you can customize it.

Let's try something new. You'll create your own function called randomCircle(). Type the following before the main task as shown below:

void randomCircle() 
{

}

task main()
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
  wait(2);
}
Now block and move the statements which drew the circle into the newly created function as shown below:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  drawCircle(x, y, 20);
}

task main()
{

  wait(2);
}
Now we just need our program to use the new function we created. So we will add a randomCircle(); within the task main() as shown below:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}

task main()
{
  randomCircle();
  wait(2);  
}
We can "call" our function as many times as we want as in:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}

task main()
{
  randomCircle();
  randomCircle();
  randomCircle();
  randomCircle();
  randomCircle();
  wait(2);  
}

Animation

The robot will do what you tell it to do. So, let's tell it to draw circles for a long while as in:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}

task main()
{
   while(true)
  {
    randomCircle();
    randomCircle();
    randomCircle();
    randomCircle();
    randomCircle();
    wait(2);  
  }
}
Adding the while(true) loop allow the robot to continue executing the functions forever.

You can speed up the drawing by reducing the wait time. Try changing the wait parameter to 0.2 which will make it 10 times faster.

Overloading Functions

I can have multiple forms of the same function where each form may do something different depending on the number and types of parameters passed to it.

For example:

All 3 forms of the randomCircle function will draw circles. Each form specifies different combination of location and size. Try adding the functions below to your program:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}
void randomCircle(int r) {
  int x = random(100);
  int y = random(100);
  drawCircle(x, y, r);
}
void randomCircle(int x, int y) {
  int r = random(100);
  drawCircle(x, y, r);
}
task main()
{
  while(true)
  {
    //randomCircle(50, 50);
    randomCircle(100);
    wait(0.2);  
  }
}

Multi Tasking ( Multi Threaded Programs )

Your robot can perform multiple tasks simultaneously. Let's create a separate task that will clear the screen after a few seconds. Add the following to your program right BEFORE the task main()

task clearScreen()
{
  wait(5);
  eraseDisplay();
}
Then include the startTask() function in the main task as shown below. Notice how we give the startTask function the parameter that is the name of the new task we created above.

task clearScreen()
{
  wait(5);
  eraseDisplay();
}
task main()
{
  startTask(clearScreen);
  while(true)
  {
    //randomCircle(50, 50);
    randomCircle(100);
    wait(0.2);  
  }
}
As you can see, the screen is cleared after the first 5 seconds. How can you get it to clear every 5 seconds?

Try using a while(true) loop in the new task as follows:

task clearScreen()
{
  while(true) {
    wait(5);
    eraseDisplay();
  }
}
Now the complete program should look like:

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}
void randomCircle(int r) {
  int x = random(100);
  int y = random(100);
  drawCircle(x, y, r);
}
void randomCircle(int x, int y) {
  int r = random(100);
  drawCircle(x, y, r);
}
task clearScreen()
{
  while(true)
  {
    wait(5);
    eraseDisplay();
  }
}
task main()
{
  startTask(clearScreen);
  while(true)
  {
    //randomCircle(50, 50);
    randomCircle(100);
    wait(0.2);  
  }
}

Responsiveness and Human-Robot Interaction

Ok. Let's make the robot more responsive to our input. Let's make the robot erase the scree only when we press a certain button. We will modify the clearScreen task to replace the wait(5) with something that says: if a button is pressed.

Try replacing the clearScreen() task with the one shown below. The "enter" button is the dark gray square button on the EV3.

task clearScreen()
{
  while(true) {
    if (getButtonPress(buttonEnter))
      eraseDisplay();
  }
}
Let's make it even more responsive by adjusting the size of the circles based on whether the Up or Down buttons were pressed on the EV3. We'll use an Integer variable to keep track of the size of the circle and create a new task to handle the button presses.

int circleSize=50;
task resizeCircle()
{
  while(true) {
    if (getButtonPress(buttonUp))
      circleSize+=10;
    if (getButtonPress(buttonDown))
      circleSize-=10;
    wait(.5);
  }
}
Don't forget. You will need to start this task from within the task main() like below:

task main()
{
  startTask(resizeCircle);
  startTask(clearScreen);
  while(true)
  {
    //randomCircle(50, 50);
    randomCircle(circleSize);
    wait(0.2);  
  }
}
Now you can press the Up and Down buttons to change the size of the circles and the Enter button to clear the screen.

The complete program is shown below.

void randomCircle() 
{
  int x = random(100);
  int y = random(100);
  int r = random(20);
  drawCircle(x, y, r);
}
void randomCircle(int r) {
  int x = random(100);
  int y = random(100);
  drawCircle(x, y, r);
}
void randomCircle(int x, int y) {
  int r = random(100);
  drawCircle(x, y, r);
}
int circleSize=50;
task resizeCircle()
{
  while(true) {
    if (getButtonPress(buttonUp))
      circleSize+=10;
    if (getButtonPress(buttonDown))
      circleSize-=10;
    wait(.5);
  }
}
task clearScreen()
{
  while(true) 
  {
    if (getButtonPress(buttonEnter))
      eraseDisplay();
  }
}
task main()
{
  startTask(resizeCircle);
  startTask(clearScreen);
  while(true)
  {
    //randomCircle(50, 50);
    randomCircle(circleSize);
    wait(0.2);  
  }
}

Bonus Exercise

Just as you can draw circles, you can also draw squares. Squares are rectangles that have the same lengths for their width and height. The drawRect() function takes four parameters: x1, y1, and x2, y2.

A square with size (s) is shown as:

drawRect(x, y, x+s, y+s);

A randomSquare function would be defined as follows:

void randomSquare(int s) {
  int x = random(100);
  int y = random(100);
  drawRect(x, y, x+s, y+s);
}
Your task main() could use the function as:

task main()
{
  startTask(resizeCircle);
  startTask(clearScreen);
  while(true)
  {
    randomSquare(circleSize);
    wait(0.2);  
  }
}
In the above program, we are passing the "circleSize" variable to the "randomSquare" function. I know this is a little confusing. Part of the Art of programming is trying to write programs that are easy to read and understand. The Integrated Development Environment has a few built-in tools to help with this. One of them is the "search-and-replace" feature to replace the names of variables and functions with something more relevant.

For example, press CTRL-H to open the search-and-replace box. Type: "circleSize" in the "Find What" box that appears at the top of the PopUp. Then type: "size" in the "Replace with" box that appears below. Then click on the "Replace All" button.

Then block the "resizeCircle" parameter from the first startTask function and press CTRL-H. Put the cursor in the "Replace with" box and type: "resizeObject" and press the "Replace All" button.

There. That's better.