Todays goals:

Are as described in the lesson 7 exercises notes:

  • Exercise 1 – Building a Base Vehicle
  • Exercise 2 – LEGO vehicle that exhibits a single behavior
  • Exercise 3 – Behaviors as concurrent threads
  • Exercise 4 – Add an Escape behavior
  • Exercise 5 – Add a third motor to turn the light sensor
  • Exercise 6 – Describe and Compare the classes SharedCar and Arbiter

Additional “Optional” Goals

  • No additional goals

The Plan

Because of the thorough guide described in the lesson 7 exercises notes, no further planning was necessary.

Then we did the exercises as explained.

Exercise 1 – Building the Vehicle

Plan

In this exercise we will build Max as described in Lesson 7 exercise notes.

Experiment

None needed.

Programming

None needed.

Results

We have rebuilt Max with one ultrasonic sensor, one light sensor, and two touch sensors (working as a bumper), as seen in Figure 1.

Max prepped for the new tasks at hand. Figure 1: Max prepped for the new tasks at hand.

Exercise 2 – LEGO vehicle that exhibits a single behavior

Plan

In this exercise, we will implement an avoid behavior with a single ultrasonic sensor, as shown in Figure 2:

A block diagram of a simple behaviour program Figure 2: A block diagram of a simple behaviour program

First we will see how Max will behave with the program provided by the course (which can be found here). Once this has been observed, we will have make Max drive backwards a bit when all three distances (leftDistance, frontDistance and rightDistance) are less than the stopThreshold, and then have him turn 180 degrees on the spot.

Experiment

In order to get a thorough understand of how Max behaves with the current program, we will let him drive towards several surfaces:

  • Flat surface
  • Concave surface
  • Convex surface
  • Fabric (because of it’s uneven surface and fabric can absorb sound)
  • Two unaligned obstacles
  • Left corner
  • Right corner

Once we have observed this, we will implement the “backing-up-and-turning-180-degrees” function.

Programming

The second part of this exercise requires us to add the following code to the code provided.

// stop and turn 180 degrees
if(leftDistance < stopThreshold && rightDistance < stopThreshold
&& frontDistance < stopThreshold{
  car.backward(power, power);
  Delay.msDelay(ms*4);
  car.rotate(power, power);
  Delay.msDelay(ms*4);
}

The car.rotate() rotates the car by applying forward power to the right motor and backwards power to the left. The delay has been extended which results in Max driving backwards a longer distance and then makes a full 180 degrees turn.

Results

Observing Max’ simple avoidance behaviour

As seen in the videos for flat, concave, convex and fabric surface, when Max gets close enough to an object he turns left and right to detect if there is any where else to move. If both right and left gives equal value of distance from objects, Max moves turns left, and repeats the process until no objects are detected in front of him. The only notable difference of his behavior according to these surfaces is that he lightly grazes the fabric surface, while this does not occur with the other surfaces. We are not sure why this happened, but we speculate it could be caused by Max’ position or perhaps the width of the fabric.

As seen in the videos for the two unaligned obstacles, found here and here, Max will to turn to the side of the farthest of the two unaligned objects.

As seen in the videos for the corners (left corner and right corner), Max can repeatedly and easily move and turn to move away from a corner if the corner is on the right side. If the corner is on the left side, Max will first turn left and then afterwards repeatedly switch between turning right and left, while moving a little forward, until he is so far in the corner and can no longer move. This may be caused by behavior of moving to the left when the distance of objects on both sides are equal.

Max’s implementation with the “move-backward-and-turn-180-degrees” function

As seen in this video (shown in the first 15 seconds), Max reacts similar to before, but when the distance in the front, right and left are lower than the stop threshold, Max drives backwards for a short while, followed by a 180 degrees turn.

Exercise 3 – Behaviors as concurrent threads

Plan

In this exercise we will get to know the framework supplied. The framework uses a behavior control network to prioritize Max’ actions. We will through different experiments investigate how the different behaviors react and how they are prioritized.

Experiment

We will make the experiments shown in Table 1 in order to get a better understanding of the framework.

Max´ behaviour table
Avoid Follow Cruise
Experiment 1 ON ON ON
Experiment 2 ON OFF ON
Experiment 3 OFF OFF ON

Table 1: List of experiments

Experiment 1 will investigate how Max will react with all three behaviours turned on. Experiment 2 will investigate how Max will react with only Follow and Cruise behaviour turned on. Experiment 3 will investigate how Max will react with only Cruise behaviour turned on.

Programming

The code used was based on the folder provided by the course (as linked earlier), and the specific class to run can be found here. The only changes we made was out commenting some parts.

Max’ behavior control network Figure 3: Max’ behavior control network

The way it works is shown in Figure 3. As standard behavior, Max will Cruise ahead. The code will then loop through the input from the sensors and flag any suspicious behaviour. The code for the sensors work like this:

  • For the ultrasound sensor, suspicious behaviour is if the input values are below a set threshold, which in our case is set to 30 cm (standard from the code provided).
  • For the light sensor, when the program starts it will set a threshold value based on the current reading. In every loop, a new measured value will be compared to the set threshold value, and in case of a change Max will change direction towards a value higher than the current set value, and then drive in that direction for a set time in milliseconds which is 500ms (standard from the code provided). The speed at which Max drives towards the light depends relatively on the two light measurements at either side, with a high difference causing a high power to the motors.

When the suspicious behaviour happens, Max will look to either side and determine which side is the way to go, depending on the priority of the input (Avoid or Follow).

Results

The results is presented here following the table from the experiment section.

Experiment 1: Max has 3 actions: Avoid, Follow, and Cruise. Avoid uses the ultrasonic sensor to avoid obstacles, which is the highest priority. Follow uses the light sensor to drive towards light, and is prioritized as less important than Avoid, but more important than Cruise. Cruise has the lowest priority, and its purpose is simply to make Max drive forward. The experiment 1 results can be seen here. This priority of behaviors ensures that Max is not likely to get stuck when trying to get to the light.

Experiment 2: In this experiment we have turned off the Avoid behavior. This makes Max drive towards light, and when there is not enough light he will search for it. However, we found that if the light is too bright, he will search for other values, as seen in this video. We can also clearly see how the light intensity increases the power at which Max accelerates.

Experiment 3: In this experiment, Max is just driving forwards, not caring about anything in the world – which can be seen in this video.

Exercise 4 – Add an Escape behavior

Plan

The plan for this exercise is to implement the Escape behaviour as described here on page 305, and then use the code provided from exercise 3 and give the Escape behaviour top priority over the other behaviours. This means that if the right side of the bumper is hit, then Max should turn left, and if the left side of the bumper is he hit he should turn right. In case both sides of the bumper are hit, then Max should back up and do a left turn.

Experiment

In this experiment we will see how Max behaves with the newly implemented Escape behavior. We will experiment by drive forward and press on Max’s bumper on the right, left and front, while not affecting the other sensor. We will be filming during the whole experiment.

Programming

The escape function consists of a simple if case checking for the conditions mentioned above as shown here:

if (touchLeft.isPressed() && touchRight.isPressed()){
  car.backward(power, power);
  Delay.msDelay(ms);
  car.backward(power, 0);
  Delay.msDelay(ms);
  car.stop();  
}else if (touchLeft.isPressed()){
  car.backward(0, power);
  Delay.msDelay(ms);
  car.stop();
}else if (touchRight.isPressed()){
  car.backward(power, 0);
  Delay.msDelay(ms);
  car.stop();
}else{
  car.noCommand();
}

Then adding the escape function at position 0 giving it highest priority was all the additional programming that was needed.

The final code can be downloaded here

Results As seen in this video, Max starts by searching for the light source in the distance, but once his left bumper hits the wheels, he then immediately react to it, making it possible to navigate through the obstacles towards the light.

Exercise 5 – Add a third motor to turn the light sensor

Plan

First we will start by mounting the motor horizontally on Max, making it possible to move the light sensor from the front to this, as seen in Figure 4.

Max with newly mounted motor and light sensor rig. Figure 4: Max with newly mounted motor and light sensor rig.

What we need to do now, is take the segment of the code that makes Max turn left or right when scanning for the correct direction, and make the new motor turn 45 degrees left and right instead. The 45 degrees were chosen because we thought that a complete 90 degree cone would give a satisfactory result, which we then would adjust according to the results from our experiments.

An issue that might arise is backlash from the motor, which in time could turn the light sensor off-center, but this will be something we will observe in the experiment and assess if we need to take action against.

Experiment

We will be using the search motor to find the brightest light source and drive towards it. However, during our initial experiments, we concluded that the 90 degrees cone was insufficient in getting a clear difference between the two sides, meaning that we adjusted the cone to a 120 degrees cone, resulting in 60 degrees to the left and to the right (instead of 45).

After running Max for some while, the backlash from the search motor did not show any significant offset of the light sensor, therefore no further action was taken to correct for this.

Programming

As seen in the following code segment, the only needed action was to replace the commands moving Max to the left and the right with rotateTo commands, that rotate the search motor a specified amount of degrees.

searchMotor.rotateTo(60, false);
leftLight = light.getLightValue();
Delay.msDelay(ms);

searchMotor.rotateTo(-60, false);
rightLight = light.getLightValue();
Delay.msDelay(ms);

Results

Max reacts as expected as shown in [this video][18] by searching for the light and driving towards it.

Exercise 6 – Describe and Compare the classes SharedCar and Arbiter

Plan

First we will describe how the classes SharedCar and Arbiter implements the arbitration suggested on page 306 in Mobile Robots, Inspiration to Implementation. Afterwards we will compare this arbitration with the arbiter of Fred G. Martin, Robotic Explorations: A Hands-on Introduction to Engineering, page 214-218.

Experiment

None needed.

Programming

None needed.

Results

[Jones, Flynn and Seiger’s][19] solution (page 306) works this way: The IC’s main() method starts by starting the motor driver, followed by the behaviours that they want implemented and finally starts they arbiter: arbitrate().

An example of one of these behaviors is shown below:

Jones, Flynn and Seiger’s Cruise

int cruise_command;
int cruise_output_flag;void cruise()
  { while(1) {
    cruise_output = FORWARD;
    cruise_output_falg = 1;
  }
}

Our Cruise Behaviour

private SharedCar car;
private int power = 70;

public Cruise(SharedCar car){
  this.car = car;
}

public void run(){
  while (true) {
    car.forward(power, power);
  }
}

These two behaviors are the same in function but written for different programming styles and languages, and they both set a command to make the car drive forwards.

In the Arbiters shown below, the behaviors are prioritized and the winning behaviour is executed:

Jones, Flynn and Seiger’s Arbiter

void arbitrate()
  {while (1){
    if (cruise_output_flag ==1)
  {motor_input = cruise_output;}
    if (follow_output_flag == 1)
  {motor_input = follow_output;}
    if (avoid_output_flag == 1)
  {motor_input = avoid_output;}
    if (escape_output_flag == 1)
  {motor_input = escape_output;}
    sleep(tick);
  }
}

Our Arbiter

public Arbiter(SharedCar [] car,
CarDriver cd){
  this.car = car;
  this.cd = cd;
}

public void run(){
  while ( true ){
    for (int i=0; i < car.length; i++){
      CarCommand carCommand =
      car[i].getCommand();
      if ( carCommand != null){
        cd.perform(carCommand);
        winner = i;
        break;
      }
    }
  }
}

public int winner(){
  return winner;
}

In Fred Martin’s solution behaviours are different from our own and Jones, Flynn and Seiger’s in the way that behaviours are added to a central list of commands instead of containing the behavior inside itself as seen below in Figure 5:

Data Structures of the Prioritization Algorithm Figure 5: Data Structures of the Prioritization Algorithm

The results of the two Arbiters are again the same, but with a few non-function specific differences. First a sleep is implemented in the version made by Jones, Flynn and Seiger which defines the rate these behaviors are checked and executed, whereas no sleep or delay is implemented in ours. This means we just check as much as the system allows where, in the other arbiter, they can define a delay between checks. Another difference is that in our Arbiter we stop looking for more commands when we have one, because this will be the most prioritized – whereas the other Arbiter starts by assigning the lowest prioritized command and overriding that with any command higher than that one, searching through all commands every time. This means that the essential difference is that they use a parametric design and we have used a compositional design. Finally, because the prioritization in our solution is based on how the list containing the behaviours is sorted, it is possible to change the priorities of behaviours at run time, which would not be possible with their solution.

Fred G. Martin’s Wander Behaviour ~~~ void wander (int pid) { enable(pid); forward(pid); } ~~~

Fred G. Martin’s Arbiter ~~~ void prioritize () { int max, i;while (1) { max= 0; for(i=0; i< num_processes; i++) if(process_enable[i] > max) max= process_enable[i];

if(max == 0) {
  motor(LEFT_MOTOR_PORT, 0);
  motor(RIGHT_MOTOR_PORT, 0);
  printf(“No tasks enabled\n”);
}else{
  for (i=0; i< num_processes; i++)
    if (process_enabled[i] == max) break;
    active_process = i;
    motor(LEFT_MOTOR_PORT,
    left_motor[active_process]); ~~~

The Arbiter created by Fred Martin functions as the other two; by finding the most prioritized behavior and executing it. The thing that is different here is that it’s all decided from the central list instead of having prioritizing and behaviour execution spread out between functions and methods. Also, Fred Martin goes through the entire list of behaviours once to determine the most prioritized command and then again – at least partially – to find and execute that behaviour, taking time.

So to sum up: All get the same behavior, but in slightly different ways.

General

Problems

An error occurred when during exercise 5, when Max was searching for the light to the right, he kept reading 0 as the light value (meaning complete darkness), so after using a lot of time seeing if it could be a Thread issue or a variable initialization issue etc. the culprit was found as seen in Figure 6:

A faulty NXT sensor cable Figure 6: A faulty NXT sensor cable

Conclusion

The conclusion to this lesson would be that there are a lot of ways to solve the same problem, not only in the form of different ways of writing the software, but also by solving a problem mechanically. This was seen in exercise 5, where the problem of finding the direction with most light was done by adding a motor to turn the light sensor, instead of turning Max, which in some cases might be favourable.