TUTORIAL 6
                    ROBOT INPUTS
                    by M. Timin

In this document I will attempt to explain as clearly as I am able the meaning of all the items in the version 0.61 situation structure. The situation structure declaration is found in CAR.H, along with the declarations of STAGE and rel_state, which are used in situation.  The reader should refer to CAR.H when appropriate.

You will find the items divided into four groups, with an explanation for each item.  Note that the eight items in group 1 are all you really need to make a robot that performs quite well on most tracks.  (Really only seven, because s.to_rgt = width - s.to_lft.)

There is some other information available to the robot that is not part of the situation structure.  This is the track description arrays, the number of segments and the track width.  There is a function get_track_description()which gets this information if you want your robot to use it, but it is not necessary to use it.  If you are interested it is described in track.h.

With each definition I will make a suggestion as to how the item might be used.  These are just my suggestions; in many cases you might discover other uses that I have not thought of.


Group 1 - Essential Information.

These alone are sufficient for a good  performing robot, and no robot should ignore any of these.  Any robot author should master the use of these first.  There are plenty of examples in the robots supplied with the software package.

cur_rad - If the car is in a curve to the left, then this is the radius of the left, or inner, edge of the track.  If in a curve to the right, then this is the negative of the radius of the right, or inner, edge of the track.  If on a straightaway it is zero.  The most common use for this is to calculate an appropriate cornering speed, and to know if you can apply full throttle because you are on a straight. (all radii are given in feet)

to_end - This tells you (i.e, the robot driver) how far you have to go to the end of the straight or curve you are on.  For a straight it is in feet.  For a curve, which is a circle arc, it is in radians. You use this to decide when to begin a transition to the next segment, either by braking or accelerating, and by steering in an appropriate way.

to_lft, to_rgt - These tell you how close you are to the left and right walls of the track.  If they get too small you need to steer away from the wall.  In a curve you generally want to keep near the inside wall for at least part of the curve.  You do this by steering so as to maintain a small value for one of those.  Finally, if either of those becomes negative, then you are off of the track and accumulating damage and decelerating.  (These are in feet.)

v - How fast you are travelling, feet per second.  Every part of the course has an appropriate speed.  You need to estimate that in some way and compare your speed to it, then speed up or slow down.

vn - The component of v which is perpedicular to the track walls.  This tells you if you are drifting toward a wall, and how fast.  You need to keep this from getting very large or very negative or you will go off the track soon afterward.  Negative means heading toward right wall.

nex_rad - The radius of the next segment, zero for a straight, negative for a right turn.  It is necessary to make some kind of transition as you near the end of the current segment.  nex_rad lets you calculate if you are going to be slowing down or speeding up, and how much.  Also, in which direction you will have to begin heading.

dead_ahead - This warns you that you are pointing toward a nearby car.  It is zero when it's clear ahead.  It gets set when there is another car within 2.5 car lengths ahead (center to center) and within + or - 20 degrees of the direction your nose is pointing. You might want to steer a little to the right or left if this gets set.  That should be no problem on a straight.  On a curve it is not clear what to do - maybe slow down a small amount, maybe steer a small amount toward the inside, which will also slow you down.


Group 2 - Potentially useful information.

These items might be used to improve performance in specific situations.

nex_len - The length of the next segment ahead of you.  This is in  feet if the next segment is a straight, otherwise it's an arc length in radians.  If this is not used then you are assuming that it is long.  Suppose the next segment is a curve.  If it is long, say more than two radians, you will have to slow down to the theoretical speed determined by its radius.  But if it is very short, say less than half a radian, then you could go through it much faster.  You would not know this unless you consider s.nex_len.

after_rad - Like cur_rad and nex_rad, but refers to the segment following those.  If nex_len is short and you want to compute a speed and a path to follow, it will depend on after_rad.  If nex_len is very short the speed with which you can enter the next segment will depend more on after_rad than on nex_rad.

after_len - Like cur_len and nex_len, but refers to the segment following those.  It might be used in determining the speed and path with which to enter the next segment when nex_len and after_len are both short, in which case aftaft_rad will be important.

aftaft_rad - Like cur_rad, nex_rad, and after_rad, but refers to the segment following those.  It would affect the speed at which you could safely enter a corner if both nex_len and after_len are short.

aftaft_len - Probably just overkill.  (like cur_len, nex_len, after_len)

cen_a - Acceleration is a vector.  This is the component perpendicular to your velocity vector.  You could use this to tell if you are cornering fast enough.  If you are cornering at constant speed then this should approach MYU_MAX, the maximum coeficient of friction. This simulates the human driver's sensation of centrifugal force during cornering.   (cen_a is short for centripetal acceleration.)

tan_a - This is the component of the acceleration vector which is parallel to the velocity vector.  It is positive if speed is increasing, negative when braking.  The vector sum of tan_a and cen_a will always be less than MYU_MAX.  (Actually it could exceed it slightly when braking, due to air drag.)  (tan_a = tangential accel.)

damage - This starts at zero and goes up each time you bump another car or it bumps you, or if you are driving off the track.  The damage depends on the relative velocity.  If it hits 30000 your car is out of the race.  The details are in move_car() in CARZ.CPP.  A smart robot would watch this and drive more carefully if it gets dangerously large.  If it is near the end of a race and he is trying to pass then he might delibertely risk some damage.

fuel - This start out at 150 pounds and then decreases at a rate proportional to power.  At full power the rate is .045 pounds per second.  (of simulated time as measured by time_count)  You can accelerate away from a corner a little bit faster when the tank is near empty.  If the fuel goes to zero the car will refuel automatically and you will only lose about 15 to 20 seconds.  If you are near the end of a long race you might want to change driving style to finish with one less refueling.

laps_to_go - This will tell you if you are near the end of the race, which may affect your driving style, as noted above in a couple of places.  You can also record your fuel and damage versus this variable during a long race in order to predict when you will run out of fuel and when you will be out by accumulated damage.

nearby - This one is complicated, yet very important, so I am including a little sample code below.  "nearby" is an array of structures.  s.nearby[0] is the rel_state structure for the nearest car.  s.nearby[1] is for the next nearest car, and s.nearby[2] is for the next.  (There are only three elements of the nearby array.)  Looking at the definition of rel_state, in CAR.H, we see that there are 5 components: who, rel_x, rel_y, rel_xdot, and rel_ydot. The first component, who, tells you if there is any valid data in the structure.  If so, its value will be a car identifier, 0 through 15.  If there is no valid data then its value will be more than 15.  If you imagine x-y coordinates with the driver at the origin, the y-axis straight ahead of where the car is pointing, and the x-axis off to the driver's right, you can understand rel_x and rel_y.  They are the x and y coordinates of the other car, in feet.  y is how far in front of you and x is how far to the right.  rel_xdot and rel_ydot are the rates of change of rel_x and rel_y in feet per second, i.e., the apparent velocity components of the other car with respect to your robot.  As an example, if you are following 50 feet directly behind another car, and you are going 1 foot per second faster than he is, then rel_y will be 50, rel_ydot will be -1, and rel_x and rel_xdot will be 0.  One last thing, rel_y will never be negative; the algorithm deliberately ignores all cars that are even slightly behind you.

    // some sample code:
    for(i=0;i<3;i++) if (s.nearby[i].who<16) { // if there is a close car
      x=s.nearby[i].rel_x;         // get forward distance
      y=s.nearby[i].rel_y;         // get right distance
      vx=s.nearby[i].rel_xdot;     // get forward relative speed
      vy=s.nearby[i].rel_ydot;     // get lateral relative speed
      d=sqrt(x*x + y*y);           // compute car-to-car distance
      v=sqrt(vx*vx + vy*vy);       // compute separation velocity
      if(vy >= 0.0)            // no action if cars are moving apart:
      else if(x * vx > 0.0)    // no action if cars are moving apart:
      else if(d > 2.0 * CARLEN)  // no action if car is this far away:
      // If the execution gets this far, it means that there is a car
      ahead of you, and getting closer, and less than two car lengths
      away.  Evaluate the situation more carefully to decide if
      evasive action is warranted.

position - This is your position in the race.  You are in the lead if this is 0.  You are in second place if it's 1, etc.  You might want to alter your driving style as a function of your postion and other factors, but maybe not.  (See damage and fuel, above.)  It is also possible to note which cars are passing you or being passed by you.  This would be done by paying attention to s.nearby[i].who, s.nearby[i].rel_y and s.nearby[i].rel_ydot.

starting - This is 1 only at the very beginning of every race.  (The first call of your robot by the host is before the race starts, to get its name.)  Use "starting" to perform initialization of any kind, such as reading a data file, or assigning certain values to variables, or building a structure in your data area.

power - you might want to control your fuel consumption by controling this variable.  "Coasting" would be maintaining a very low value for power.  "Braking" is when power is negative; no fuel is used during braking, but kinetic energy is lost rapidly and this will require extra fuel when you accelerate again.  To get high mileage you want to avoid braking and maintain fairly high speed without too much power.

Group 3 - Useful for machine learning approaches.

If you are doing some kind of simulated evolution, or neural net, or automatic search of parameter space, then you will probably use some of these.

data_ptr - This is a pointer to a 4 K RAM area that you can do what you want with.  It will not be altered by the host after practice or between races.  You might read a file into this area and then take values from there to initialize parameters.  If your program "learns" and alters parameter values, then you can put those in the RAM area and later write it out to a file.

seg_ID - This refers to the track segment that your car is in.  The initial straightaway is alway segment 0.  This would be used if you want to memorize the track during the first lap of practice, or even the first lap of a race.  You would do that if you want to construct a table of how fast to take each turn, for example.

lap_flag - If you are paying attention to your lap time, to try and minimize it, then "lap_flag" can tell you when to look at it.  When lap_flag is non-zero, there is a new lap_time.

lap_time - This is the time in seconds in which the previous lap was
completed.  See lap_flag, above.

time_count - This is the time in seconds elapsed since the start of the race.  You might want to let your car run for several laps, and then use this as your factor-of-merit.  If you are always running for N laps, then the lower the time_count at the end of N laps, the better. (This is in seconds of simulated time; it will equal stopwatch seconds if you run in realistic speed.)


Group 4 : Others

I don't know what you would do with these, but you might think of something!

cur_len - This is the length of the current segment, in feet or radians.  Although I and others have used it, it only tells you about the past, and so it is theoretically of no value.  s.to_end is what is important.  s.cur_len - s.to_end tells you the length of the part of the segment that you have already traveled.  In my opinion a robot is better off to totally ignore s.cur_len.

alpha - The skid angle in radians used by the simulation.  Usually this is the same as the previous value of alpha that your robot returned.  However, the rate of change and magnitude of alpha are limited, so if you tried to suddenly make a large value of alpha, you might have gotten a smaller one.

vc - The actual tire speed used by the simulation.  Often, this is the same as the previous value of vc that your robot returned.  However, vc is limited by the available power, so if you requested a large value fo vc, you might get a smaller one.  This is a very common occurence with most robots; it is the usual case when accelerating, or cornering hard at high speed.

start_time - The value of time_count when your robot crossed the start/finish line.  The host begins calculating average speed at that time.

my_ID - Your robots identifier.  The only use for this is if you have two cars driven by the same robot, as we have often done with the robot "Dynamic".  Each car will have a different value of my_ID.

backward - This would be necessary if you don't use the stuck() function to handle escape from crashes.  If you do use it, then it appears as an input to stuck(), and that is all.  "backward" is set when the car's velocity vector is going the wrong way down the track.

power_req - This is the power that would be required if the original request for vc by the robot would have been honored.  When you want 100% power you can check to see if power_req is greater than PM.  If not, then you want to increase vc.

I hope the foregoing is useful to you.