Harvey Mudd College
Computer Science 154 - Robotics
Assignment A

Building Keanu

Lab #1 write-up
Z. Dodds
1/25/01



Part 1 - Stateless reactive control -- Survivor!

As mentioned in the introduction, the first test we'll be putting the simulator to is building Keanu-level intelligence. In particular, you should write a function

int computeRotationalVelocity()
that maps the sonar values (the input) to a rotational velocity (the output), so that the robot (whose speed is fixed) survives as long as possible without hitting the walls or obstacles in various environments. The return value of computeRotationalVelocity is an integer, because that is the type expected by the velocity-setting call, vm. (A prototype function is provided in the test file, /cs/cs154/as/A/survivor.cc .

You may use the current rotational and translational velocities of the robot in your computeRotationalVelocity function -- they are accessible as State[39] and State[38], respectively.

Test Worlds

Two worlds in which to test your robot are included in /cs/cs154/as/A. They are shown here. Note that not all angles need be right angles



Survivor Map 1





Survivor Map 2

In the write up, below, explain your approach and include the text of your code either in the HTML or as a link from it. Also, include the results of your algorithm run at a variety of different speeds on the above two worlds and at least one world of your own devising.



Results



My approach to this assignment was to let the sonar readings to the forward right and the forward left of the robot "push" it in one direction or the other. In particular, the smallest sonar reading among sonars 1, 2, and 3 is compared to the smallest reading of sonars 13, 14, and 15. Whichever is smaller "pushes" the robot in the opposite direction by setting its velocity appropriately. Here is the code for the computeRotationalVelocity function, commented to highlight the decisions the algorithm makes:
int
computeRotationalVelocity()
{
  int oldrv = State[39];
  double rv = 0.0;

  /* Here we determine how imminent a collision is        */
  /* by finding the closest sonar reading among the front */ 
  /* three sonars, 15, 0, and 1                           */

  int frontShortestI = getShortestSonarIndex(-2,2);
  int frontShortest  = State[frontShortestI];

  /********************************************************/
  /*                                                      */
  /* The shortest sonar is compared to a threshhold that  */
  /* depends on the translational velocity of the robot   */ 
  /* In this case, it is read in from a file so that we   */
  /* could tune the parameter more easily.                */
  /*                                                      */
  /* the value for trans. velocities 50 and 100  is  40   */
  /* the value for trans. velocities 150 and 200  is 70   */
  /*                                                      */
  /********************************************************/

  if (frontShortest < FORWARD_THRESH)         
  { 
    /* find side that pulls harder */
    int  leftSidePushI = getShortestSonarIndex(1,4);
    int rightSidePushI = getShortestSonarIndex(-4,-1);

    if (State[leftSidePushI] > State[rightSidePushI])
    {
      rv = (oldrv < -10) ? -MAX_SPEED :  MAX_SPEED;
    }
    else
    {
      rv = (oldrv > 10) ? MAX_SPEED : -MAX_SPEED;
    }

  /********************************************************/
  /*                                                      */
  /* MAX_SPEED is another global parameter that depends   */
  /* on the trans. velocity. It indicates the angular     */
  /* speed commanded when the robot needs to turn.        */
  /*                                                      */
  /* its value for trans. velocities 50 and 100  is  300  */
  /* its value for trans. velocities 150 and 200  is 450  */
  /*                                                      */
  /********************************************************/

  /********************************************************/
  /*                                                      */
  /* Note that the new rotational velocity depends on the */
  /* old velocity. This is so that when heading into a    */
  /* corner, for example, the balanced readings on either */
  /* side of the robot do not keep it headed in a         */
  /* line.                                                */
  /*                                                      */
  /* You can see an example of this happening in world 2, */
  /* at speed 150 and world 1, at speed 100, below.       */
  /*                                                      */
  /********************************************************/

  }
  else
  {
    rv = 0;
  }

  return (int)rv;
}


Considerable tuning of the parameters MAX_SPEED and FORWARD_THRESH was done at a speed of 50 in world 2. Unfortunately, not all environments interacted with the system in as benign a way... .

Speeds of 50 and 100 in test world 2:
   


Speeds of 150 and 200 in test world 2:
   


Speeds of 50 and 100 in test world 1:
   


Speeds of 150 and 200 in test world 1:
   

I place the blame for the performance of the robot in the last few examples squarely on the shoulders of the simulator. Given my carefully constructed (and beautifully working) code (see world 2, speed 50), there seems to be no explanation for the other results. I suspect that another lab group was connecting to my simulator (through port #7042) and so the results of the lower runs actually indicate the performance of their algorithm. Similarly, the results they present should actually be credited to me.