1. Review of Interactive C so far
  2. Simple command sequences
  3. Other useful Interactive C functions
  4. Writing your own useful functions
  5. Rules for naming functions
  6. Case-sensitivity
  7. User-defined functions in Interactive C programs
  8. Ordering of functions and statements
  9. Giving names to values
  10. Rules for naming variables
  11. Comments
  12. Writing IC functions that depend on information from the outside
  13. Printing

Review of Interactive C so far

Motor commands: digital(d) gives you the value (state) of the digital sensor in port d.

analog(a) gives you the value (state) of the analog sensor in port a.

start_button() gives the value (state) of the start button.

stop_button() gives the value (state) of the stop button.


Simple command sequences

Now that we have some basic vocabulary (primitive functions and entities on which they operate), we can put together simple programs.

For instance, the following Interactive C program will turn motor 3 on and then turn it off.

void main( ) {
   fd(3); 
   off(3);
}

Note the semicolons. Each semicolon marks the end of a statement.

Also note the curly braces. They mark these two statements as a single block (i.e., single unit) of code.

Don't worry about the meaning of "void main()" -- we'll go over that soon. For now, all you need to know is that it signals the beginning of a program.

The commands are executed sequentially. First, motor 3 is turned on at full power in the forward direction. Then motor 3 is turned off.

What will the actual result of these statements be? Nothing noticeable! There's no delay between turning the motor on and turning it off!

We can modify our short program as follows:

void main( ) {
   fd(3); 
   sleep(3.5);
   off(3);
}

sleep(3.5); tells the system to wait for an amount of time equal to or slightly greater than 3.5 seconds.

In general sleep(n) tells the system to wait for an amount of time equal to or slightly greater than n seconds.

n must be a real number. Trying an integer value, for example, will give an error. So


Other useful Interactive C functions

start_press(); waits for the start button to be pressed and then released.

stop_press(); waits for the stop button to be pressed and then released.

If there are two motors on your robotic vehicle such that

then the following program will wait for the start button to be pressed, will then set the robot moving forward, and will stop it when the stop button is pressed:
void main( ) {
   start_press();
   fd(1);
   fd(3);
   stop_press();
   ao();
}

Writing your own useful functions

As above, say that there are two motors on your robotic vehicle: How would you make the robot spin to the right for a bit (say, 5 seconds)?
void spin_a_bit( ) {
   fd(3);
   bk(1);
   sleep(5.0);
   off(3);
   off(1);
}
This is just a block of code in curly braces to which we've assigned a name ("spin_a_bit"). Note that, with the exception of the name, it looks very much like an Interactive C program. "main" is a special function name that designates the main instructions of a program. As a second example, consider the following function, which will make the robot move forward at full power:
void forward( ) {
   fd(1);
   fd(3);
}
And yet another useful function that slows the vehicle to a stop (rather than stopping it abruptly):
void slow_stop( ) {
   motor(1, 20);
   motor(3, 20);
   sleep(5.0);
   off(1);
   off(3);
}

Rules for naming functions


Case-sensitivity

Interactive C is case-sensitive. You cannot, for example, write main with anything but lowercase letters. You should be careful when typing all function names.

User-defined functions in Interactive C programs

When writing programs, you can use the handy functions of Interactive C, or you can use your own:
void main( ) {
   start_press();
   forward();
   sleep(3.0);
   spin_a_bit();
   forward();
   stop_press();
   slow_stop();
}

void forward( ) {
   fd(1);
   fd(3);
}

void spin_a_bit( ) {
   fd(3);
   bk(1);
   sleep(5.0);
   off(3);
   off(1);
}

void slow_stop( ) {
   motor(1, 20);
   motor(3, 20);
   sleep(5.0);
   off(1);
   off(3);
}


Ordering of functions and statements

Within a block of code (i.e., within a set of curly braces), the order of statements matters!

The order of functions within a program, on the other hand, does not matter. Execution will always begin with "main". My personal preference is to have "main" appear first, since it gives the reader of the program a sense of its high level design.


Giving names to values

Rather than always referring to "port 1" and "port 3" as we did above, it would be nice if we could refer to "the left motor" and "the right motor". Interactive C allows us to do so as follows:
int LEFT_MOTOR = 3;
int RIGHT_MOTOR = 1;

void main( ) {
   start_press();
   forward();
   sleep(3.0);
   spin_a_bit();
   forward();
   stop_press();
   slow_stop();
}

void forward( ) {
   fd(RIGHT_MOTOR);
   fd(LEFT_MOTOR);
}

void spin_a_bit( ) {
   fd(LEFT_MOTOR);
   bk(RIGHT_MOTOR);
   sleep(5.0);
   off(LEFT_MOTOR);
   off(RIGHT_MOTOR);
}

void slow_stop( ) {
   motor(RIGHT_MOTOR, 20);
   motor(LEFT_MOTOR, 20);
   sleep(5.0);
   off(RIGHT_MOTOR);
   off(LEFT_MOTOR);
}
Let's look at the first two lines a bit more carefully:
int LEFT_MOTOR = 3;
int RIGHT_MOTOR = 1;
They tell IC that we would like the name LEFT_MOTOR to refer to the value 3 and RIGHT_MOTOR to refer to the value 1. Once this is done, we can use LEFT_MOTOR and RIGHT_MOTOR in place of 3 and 1, respectively, in the rest of the program.

There are a couple of important things to note about each of these lines:

We must precede the name (e.g., LEFT_MOTOR) with information about the type of the value to which the name will refer. In our example, the names refer to integers (i.e., "int"). The names we use can also refer to real values. The type name for real values is "float":

float LONG_PAUSE = 5.0;
Each of these lines is referred to as a declaration and initialization.

Rules for naming variables

As with function names: LEFT_MOTOR and RIGHT_MOTOR are variable names. That is, in the program in which we're using them, we can choose to change the values to which they refer. In this program, however, we have no plan to change them. The convention we follow is to use all upper case for names of constants and lower case for names of variables.

Comments

You may add your own descriptive comments to your programs. To do so, enclose the text you want to include in a block that begins with /* and ends with */. For example:
/* A. Danyluk */
/* October 2008 */

int LEFT_MOTOR = 3;     /* the left motor port */
int RIGHT_MOTOR = 1;    /* the right motor port */

/* Move forward, spin a bit, straighten out, then slow to a stop */
/* when the stop button is pressed. */
void main( ) {
   start_press();
   forward();
   sleep(3.0);
   spin_a_bit();
   forward();
   stop_press();
   slow_stop();
}

/* Move forward */
void forward( ) {
   fd(RIGHT_MOTOR);
   fd(LEFT_MOTOR);
}

/* Spin right for 5 seconds */
void spin_a_bit( ) {
   fd(LEFT_MOTOR);
   bk(RIGHT_MOTOR);
   sleep(5.0);
   off(LEFT_MOTOR);
   off(RIGHT_MOTOR);
}

/* Slow to a stop */
void slow_stop( ) {
   motor(RIGHT_MOTOR, 20);
   motor(LEFT_MOTOR, 20);
   sleep(5.0);
   off(RIGHT_MOTOR);
   off(LEFT_MOTOR);
}
Interactive C ignores comments. Comments are there to make the code easier to read and understand.

Writing IC functions that depend on information from the outside

You have seen how to write simple functions in Interactive C. Now say that someone asks you to do the following: write a function that will make the robot move forward for n seconds. You can assume that LEFT_MOTOR and RIGHT_MOTOR refer to the left and right motor ports, respectively. You can accomplish your task as follows:
void forward_for_n(float n) {
   forward(); /* note that you can call any function from within another */
   sleep(n);
   ao();
}

void forward( ) {
   fd(LEFT_MOTOR);
   fd(RIGHT_MOTOR);
}
In the function forward_for_n, "n" is a placeholder for a specific value that we expect someone to supply when the function is actually needed. Note the function header:
void forward_for_n(float n)
Inside of the parentheses we include the declaration
float n
This tells Interactive C that when the function is called, the caller will supply a value and the value is expected to be a real number.

To use the function (say, to make a robot go forward for 3 seconds), all you need to do is supply the value 3.0 in parentheses:

forward_for_n(3.0);
We call "n" in the example above a formal parameter. We say that 3.0 is an actual parameter.

The syntax for supplying an actual parameter to a function should seem familiar, as you've used it in the fd, bk, motor, and sleep functions, among others.


Printing

Many of the programs we use print information on the computer screen: email programs print actual email messages; spreadsheet programs print results of computations; many programs print error messages when we try to use them incorrectly. IC allows us to print messages from within our programs.

All messages are printed to the LCD on the Handy Board. We can print cute messages like "I am a happy handy board" (recall Lab 2). We can also print status information that might be useful in debugging our programs.

To print a message such as "I'm printing...":

printf("I'm printing...\n");

This will print I'm printing... with a newline (i.e., return) at the end.

Recall our program from last time (with a minor modification so that we make use of "forward_for_n"):

/* A. Danyluk */
/* October 2008 */

int LEFT_MOTOR = 3;     /* the left motor port */
int RIGHT_MOTOR = 1;    /* the right motor port */

/* Move forward, spin a bit, straighten out, then slow to a stop */
/* when the stop button is pressed. */
void main( ) {
   start_press();
   forward_for_n(3.0);
   spin_a_bit();
   forward();
   stop_press();
   slow_stop();
}

/* Move forward for n seconds */
void forward_for_n(float n) {
   forward();
   sleep(n);
   ao();
}

/* Move forward */
void forward( ) {
   fd(RIGHT_MOTOR);
   fd(LEFT_MOTOR);
}

/* Spin right for 5 seconds */
void spin_a_bit( ) {
   fd(LEFT_MOTOR);
   bk(RIGHT_MOTOR);
   sleep(5.0);
   off(LEFT_MOTOR);
   off(RIGHT_MOTOR);
}

/* Slow to a stop */
void slow_stop( ) {
   motor(RIGHT_MOTOR, 20);
   motor(LEFT_MOTOR, 20);
   sleep(5.0);
   off(RIGHT_MOTOR);
   off(LEFT_MOTOR);
}

Let's modify it by adding a printf at the beginning of each function:
/* A. Danyluk */
/* October 2008 */

int LEFT_MOTOR = 3;     /* the left motor port */
int RIGHT_MOTOR = 1;    /* the right motor port */

/* Move forward, spin a bit, straighten out, then slow to a stop */
/* when the stop button is pressed. */
void main( ) {
   printf("Starting main\n");
   start_press();
   forward_for_n(3.0);
   spin_a_bit();
   forward();
   stop_press();
   slow_stop();
}

/* Move forward for n seconds */
void forward_for_n(float n) {
   printf("in forward for n\n");
   forward();
   sleep(n);
   ao();
}

/* Move forward */
void forward( ) {
   printf("In forward\n");
   fd(RIGHT_MOTOR);
   fd(LEFT_MOTOR);
}

/* Spin right for 5 seconds */
void spin_a_bit( ) {
   printf("In spin\n");
   fd(LEFT_MOTOR);
   bk(RIGHT_MOTOR);
   sleep(5.0);
   off(LEFT_MOTOR);
   off(RIGHT_MOTOR);
}

/* Slow to a stop */
void slow_stop( ) {
   printf("in slow stop\n");
   motor(RIGHT_MOTOR, 20);
   motor(LEFT_MOTOR, 20);
   sleep(5.0);
   off(RIGHT_MOTOR);
   off(LEFT_MOTOR);
}
Now as the program runs, the LCD will display where we are in the execution of the program. This is generally not necessary in short programs, but can be very useful when we're trying to debug a large, complex program and want to pinpoint where the program fails.

In addition to printing messages, we can print values -- for example, sensor readings, results of computations, etc.

To print a sensor reading - for instance, the value of the digital sensor in port 8:

printf("%d\n", digital(8));

To print a message and a value:

printf("Digital %d is %d\n", 10, digital(10));

prints Digital 10 is 0

if the value of digital sensor 10 is 0

In summary: