1. Conditional execution
  2. Boolean values and operators
  3. Making use of analog sensor readings: comparison operators
  4. Repetition
  5. Counting

Conditional execution

So far, we have said that the statements of an IC program are executed sequentially. But this need not be the case. What if we want to say "choose to either go forward or backward, depending on whether the robot is blocked." That is, default to forward unless the robot is hitting up against something.

Say that we have a robot with right and left motors in ports 1 and 3, respectively, and a touch sensor plugged into port 11. We know that digital(11) will tell us the state of that sensor (i.e., whether it is pressed or not). The following construct, then, says that if the sensor is pressed, the robot should go in reverse; otherwise (else) go forward.

...
if (digital(11)) {
   backward();
} else {
   forward();
}
Note that the above assumes that we have defined the functions forward and backward.

To see this in the context of a full program, consider the following:

/* A. Danyluk
   October 2008 */

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

void main() {
    start_press();
    if ( digital(11) ) {
        backward();
    } else {
        forward(); 
    }
    stop_press();
    ao();
}

/* starts the motors at full power in the forward direction */
void forward() {
    fd(RIGHT_MOTOR);
    fd(LEFT_MOTOR);
}

/* starts the motors at full power in the backward direction */
void backward() {
    bk(RIGHT_MOTOR);
    bk(LEFT_MOTOR);
}
What does this program do? When someone presses the start button, the robot checks the status of the sensor in port 11. If it is pressed, the robot goes backward. Otherwise, it goes forward.

We call the construct above an if-else statement. The general syntax of an if-else statement is as follows:

if ( condition-to-check ) {
   statements to execute if condition true
} else {
   statements to execute if condition false
}
(Note the parentheses and curly braces.)

Now consider a robot that looks more like the kind we've built -- with two touch sensors (the right in port 11 and the left in port 14). If either one is hitting against something at the start (or if both are), the robot should go backward. We can express "if digital sensor 11 is pressed or digital sensor 14 is pressesd" as:

if (digital(11) || digital(14))
so our program becomes:
void main( ) {
   start_press();
   if (digital(11) || digital(14)) {
      backward();
   } else {
      forward();
   }
   stop_press();
   ao();
}
Similarly, we can use &&, which means "and" as well as !, which means "not." So if we want to say "if digital sensor 11 is not pressed and neither is digital 14, then go forward; otherwise (else) go backward":
if (!digital(11) && !digital(14)) {
   forward();
} else {
   backward();
}

Boolean values and operators

The function digital(n) produces a value - either 0 or 1 - indicating the state of a sensor. We know that 0 and 1 are integers, but in certain contexts (like the condition in an if statement), Interactive C treats them as boolean values. That is, it treats 0 as having the meaning "false" and 1 as "true."

||, &&, and ! are called boolean (or logical) operators. While arithmetic operators are applied to numbers, these operate on and produce boolean values.

For example, if the value of digital(11) is 0 (false), then

!digital(11)
has the value 1 (i.e., true).

If digital(11) has the value 0 (false) and digital(14) has the value 0 (false), then

digital(11) && digital(14)
has the value 0 (false).

In general, if b1 and b2 are Boolean values,


Making use of analog sensor readings: comparison operators

We frequently want our light sensor readings to affect the operation of our robots. But light sensors are not simply on-off switches. They produce values along a continuum.

Say we want our robot to go forward only in a brightly lit room -- i.e., when the light sensor values are low. The only way we have to describe "low" in Interactive C is to check whether the readings are, say, less than 100. That is, by using a comparison operator like <.

/* A. Danyluk
   October 2008 */

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

int RIGHT_LIGHT = 3;   /* the right light sensor port */
int LEFT_LIGHT = 5;    /* the left light sensor port */

int BRIGHTNESS_THRESHOLD = 100;

/* Goes forward once someone has pressed the start button, but only
if light detected upon start is relatively bright. */

void main() {
    start_press();
    if ( (analog(LEFT_LIGHT) < BRIGHTNESS_THRESHOLD) && 
        (analog(RIGHT_LIGHT) < BRIGHTNESS_THRESHOLD) ) {
        forward();
    } 
    stop_press();
    ao();
}

/* starts the motors at full power in the forward direction */
void forward() {
    fd(RIGHT_MOTOR);
    fd(LEFT_MOTOR);
}
Note that it is perfectly fine to have an if without an else. We call such a statement an if statement.

As another example, consider the following:

if (analog(5) > analog(3)) {
   ...
}
This compares the readings from two analog sensors and performs some action if the reading from sensor 5 is greater than the reading from sensor 3. The comparison operators that are available to us are: Say that RIGHT_LIGHT and LEFT_LIGHT have the values 3 and 5, respectively. And that RIGHT_MOTOR and LEFT_MOTOR have values 1 and 3. Then if we want our robot to turn toward light we might write:
    if ( analog(LEFT_LIGHT) > analog(RIGHT_LIGHT) ) {
        motor(LEFT_MOTOR, 100);
        motor(RIGHT_MOTOR, 20); /* turn right */
    } else {
        motor(RIGHT_MOTOR, 100);
        motor(LEFT_MOTOR, 20);  /* turn left */
    }

Repetition

The examples of if statements above allow us to react to the status of the touch sensors or light sensors at a single point in time - i.e., at the moment that the if statements are executed.

But say that we want to continuously monitor the light sensors, repeatedly adjusting the speed and direction of the robot as we do so. To do this, we simply place the code we want to repeat inside of a while statement as follows:

    while(1) {
        if ( analog(LEFT_LIGHT) > analog(RIGHT_LIGHT) ) {
            motor(LEFT_MOTOR, 100);
            motor(RIGHT_MOTOR, 20); /* turn right */
        } else {
            motor(RIGHT_MOTOR, 100);
            motor(LEFT_MOTOR, 20);  /* turn left */
        }
    }
while(1) means "do this forever" - i.e., until the robot is switched off.

The complete program is as follows:

/* A. Danyluk
   October 2008 */

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

int RIGHT_LIGHT = 3;   /* the right light sensor port */
int LEFT_LIGHT = 5;    /* the left light sensor port */

/* Follows light once the start button is pressed.
   Stops when the robot is turned off. */

void main() {
    start_press();
    while(1) {
        if ( analog(LEFT_LIGHT) > analog(RIGHT_LIGHT) ) {
            motor(LEFT_MOTOR, 100);
            motor(RIGHT_MOTOR, 20); /* turn right */
        } else {
            motor(RIGHT_MOTOR, 100);
            motor(LEFT_MOTOR, 20);  /* turn left */
        }
    }
}

Counting

Say we want to write a program that makes the robot move forward. But every time it detects very bright light, it stops for five seconds and says (i.e., prints) "ouch".
/* A. Danyluk
   October 2008 */

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

int RIGHT_LIGHT = 3;   /* the right light sensor port */
int LEFT_LIGHT = 5;    /* the left light sensor port */

int BRIGHT = 20;       /* light sensor value considered to be very bright */

/* Goes forward, stopping for five seconds whenever the light
detected is too bright.  Says "ouch" whenever it stops. */

void main() {
    start_press();
    forward();
    while(1) {
        if ( analog(LEFT_LIGHT) < BRIGHT || analog(RIGHT_LIGHT) < BRIGHT ) {
            ao();
            printf("Ouch\n");
            sleep(5.0);
            printf("\n");
            forward();
        }
    }
}

/* starts the motors at full power in the forward direction */
void forward() {
    fd(RIGHT_MOTOR);
    fd(LEFT_MOTOR);
}
Now say that every third time the robot encounters bright light, we want it to say "I need sunglasses", rather than "ouch". To accomplish this, we need a way to count.
/* A. Danyluk
   October 2008 */

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

int RIGHT_LIGHT = 3;   /* the right light sensor port */
int LEFT_LIGHT = 5;    /* the left light sensor port */

int BRIGHT = 20;       /* light sensor value considered to be very bright */

int count = 0;         /* number of times light was bright since it last said "I need sunglasses" */

int COUNT_THRESHOLD;    /* number of brightness detected before sunglasses message */

/* Goes forward, stopping for five seconds whenever the light
detected is too bright.  Says "I need sunglasses" every third time it stops.
Otherwise says "ouch" whenever it stops. */

void main() {
    start_press();
    forward();
    while(1) {
        if ( analog(LEFT_LIGHT) < BRIGHT || analog(RIGHT_LIGHT) < BRIGHT ) {
            count++;
            ao();
            if ( count == COUNT_THRESHOLD ) {
                printf( "I really need some sunglasses.\n");
                count = 0;   /* reset to 0 so can count up to three again */
            }else {
                printf("Ouch\n");
            }
            sleep(5.0);
            printf("\n");
            forward();
        }
    }
}

/* starts the motors at full power in the forward direction */
void forward() {
    fd(RIGHT_MOTOR);
    fd(LEFT_MOTOR);
}
In order to count, we need to: We can then compare count to another value in an if statement, for example.

Note that in the above sample program we used an if statement inside of another if statement!