speed-dreams/doc/tutorials/robot/torcs/robot/ch7/opponents.html

343 lines
13 KiB
HTML

<!DOCTYPE public "-//w3c//dtd html 4.01 transitional//en"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
copyright : (C) 2003-2004 Bernhard Wymann
email : berniw@bluewin.ch
version : $Id$
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
-->
<head>
<title>Collecting Data About Opponents</title>
<link rel="stylesheet" type="text/css" href="../../../css/format.css"/>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
<meta name="description" content="Collecting Data About Opponents"/>
<meta name="author" content="Bernhard Wymann"/>
<meta name="keywords" content="torcs, berniw, bernhard wymann, collision, avoidance, overtaking, opponent, collecting data"/>
<script src="../../../js/utilities.js" type="text/javascript"></script>
</head>
<body bgcolor="#ffffff">
<table class="maincontent">
<tr>
<td class="maincontent">
<h1>7.2 Collecting Data About Opponents Continued</h1>
<h3>The opponents.cpp File</h3>
<p>
Here we discuss the concrete implementation of the classes defined in opponent.h.
Put all this code into opponent.cpp in the <span style="color:red;">bt</span>
directory. We start with the header and the definition of some constants.
</p>
<p><pre class="lcolor">/***************************************************************************
file : opponent.cpp
created : Thu Apr 22 01:20:19 CET 2003
copyright : (C) 2003 Bernhard Wymann
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "opponent.h"
/* class variables and constants */
tTrack* Opponent::track;
float Opponent::FRONTCOLLDIST = 200.0; /* [m] distance to check for other cars */
float Opponent::BACKCOLLDIST = 50.0; /* [m] distance to check for other cars */
float Opponent::LENGTH_MARGIN = 2.0; /* [m] safety margin */
float Opponent::SIDE_MARGIN = 1.0; /* [m] safety margin */</pre></p>
<p>
To avoid collisions it is not necessary to take into account cars that are farther away
than a certain distance. With FRONTCOLLDIST and BACKCOLLDIST you can set the range you
want to check for opponents in front of your car and behind your car. The safety margins
define the minimal distance you would like to maintain to opponents. If you would like
to be able to change these parameters without recompilation, you could also put them into
the setup XML file and load them at startup.
</p>
<p><pre class="lcolor">Opponent::Opponent()
{
}
/* compute speed component parallel to the track */
float Opponent::getSpeed(tCarElt *car)
{
v2d speed, dir;
float trackangle = RtTrackSideTgAngleL(&(car-&gt;_trkPos));
speed.x = car-&gt;_speed_X;
speed.y = car-&gt;_speed_Y;
dir.x = cos(trackangle);
dir.y = sin(trackangle);
return speed*dir;
}</pre></p>
<p>
The Opponent::getSpeed(tCarElt *car) method computes the speed of the car in the
direction of the track. First we get the direction of the
track at the cars location. After that we compose the speed vector of the car. We use _speed_X
and _speed_Y
here, the uppercase X and Y means that the speed vector is in global coordinates, the
lowercase x and y are the speeds in the "instantaneously coincident frame of reference",
a coordinate system that is oriented like the cars body but doesn't move with the car
(if it would move with the car the _speed_x and _speed_y would always be zero). From the
trackangle we compute a direction vector of the track (its length is one). Finally we
compute the dot product
of the speed and the direction, which will give us the speed in the direction of the track.
</p>
<p><pre class="lcolor">/* Compute the length to the start of the segment */
float Opponent::getDistToSegStart()
{
if (car-&gt;_trkPos.seg-&gt;type == TR_STR) {
return car-&gt;_trkPos.toStart;
} else {
return car-&gt;_trkPos.toStart*car-&gt;_trkPos.seg-&gt;radius;
}
}</pre></p>
<p>
This method computes the distance of the opponent to the segments start. The reason
is that car->_trkPos.toStart contains the length of the segment for straight segments and
for turns the arc, so we need a conversion to the length.
</p>
<p>
Now we will have a look at the update function. It is responsible for the update of the
values in the Opponent instances.
</p>
<p><pre class="lcolor">/* Update the values in Opponent this */
void Opponent::update(tSituation *s, Driver *driver)
{
tCarElt *mycar = driver-&gt;getCarPtr();
/* init state of opponent to ignore */
state = OPP_IGNORE;
/* if the car is out of the simulation ignore it */
if (car-&gt;_state &amp; RM_CAR_STATE_NO_SIMU) {
return;
}</pre></p>
<p>
First we get a pointer to the drivers car, set the initial state to ignore the opponent
and if the opponent is not longer part of the simulation we return.
</p>
<p><pre class="lcolor"> /* updating distance along the middle */
float oppToStart = car-&gt;_trkPos.seg-&gt;lgfromstart + getDistToSegStart();
distance = oppToStart - mycar-&gt;_distFromStartLine;
if (distance &gt; track-&gt;length/2.0) {
distance -= track-&gt;length;
} else if (distance &lt; -track-&gt;length/2.0) {
distance += track-&gt;length;
}</pre></p>
<p>
Now we compute the distance of the center of the drivers car to the center of the
opponents car. We achieve that by computing the distances to the start line and taking
the difference. If you think about that you will recognize that this is just an
approximation of the real distance. If you want a more accurate value you have to compute it
with the cars corners (look up car.h).
The if part is to "normalize" the distance. From our position up to a
half
track length the opponent is in front of us (distance is positive), else it is behind
(distance is negative). A detail is that we can't use _distFromStartLine of the opponent,
because it is a private field.
</p>
<p><pre class="lcolor"> /* update speed in track direction */
speed = Opponent::getSpeed(car);
float cosa = speed/sqrt(car-&gt;_speed_X*car-&gt;_speed_X + car-&gt;_speed_Y*car-&gt;_speed_Y);
float alpha = acos(cosa);
width = car->_dimension_x*sin(alpha) + car-&gt;_dimension_y*cosa;
float SIDECOLLDIST = MIN(car-&gt;_dimension_x, mycar-&gt;_dimension_x);</pre></p>
<p>
We update the speed with the previously introduced getSpeed() method. Then we compute
the width of the opponents car on the track (think the car is turned 90 degrees on the
track, then the needed "width" is its length).
</p>
<p><pre class="lcolor"> /* is opponent in relevant range -50..200 m */
if (distance &gt; -BACKCOLLDIST &amp;&amp; distance &lt; FRONTCOLLDIST) {
/* is opponent in front and slower */
if (distance &gt; SIDECOLLDIST &amp;&amp; speed &lt; driver-&gt;getSpeed()) {
catchdist = driver-&gt;getSpeed()*distance/(driver-&gt;getSpeed() - speed);
state |= OPP_FRONT;
distance -= MAX(car-&gt;_dimension_x, mycar-&gt;_dimension_x);
distance -= LENGTH_MARGIN;
float cardist = car-&gt;_trkPos.toMiddle - mycar-&gt;_trkPos.toMiddle;
sidedist = cardist;
cardist = fabs(cardist) - fabs(width/2.0) - mycar-&gt;_dimension_y/2.0;
if (cardist &lt; SIDE_MARGIN) state |= OPP_COLL;
} else</pre></p>
<p>
Here we check if the opponent is in the range we defined as relevant. After that
the classification of the opponent starts. In this part we check if it is
in front of us and slower. If that is the case we compute the distance we need to
drive to catch the opponent (catchdist, we assume the speeds are constant) and set
the opponents flag OPP_FRONT. Because
the "distance" contains the value of the cars centers we need to subtract a car length
and the safety margin. At the end we check if we could collide with to opponent. If yes,
we set the flag OPP_COLL.
</p>
<p><pre class="lcolor"> /* is opponent behind and faster */
if (distance &lt; -SIDECOLLDIST &amp;&amp; speed &gt; driver-&gt;getSpeed()) {
catchdist = driver-&gt;getSpeed()*distance/(speed - driver-&gt;getSpeed());
state |= OPP_BACK;
distance -= MAX(car-&gt;_dimension_x, mycar-&gt;_dimension_x);
distance -= LENGTH_MARGIN;
} else</pre></p>
<p>
Here we check if the opponent is behind us and faster. We won't use that in the
tutorial robot, but you will need it if you want to let overlap faster opponents.
</p>
<p><pre class="lcolor"> /* is opponent aside */
if (distance &gt; -SIDECOLLDIST &amp;&amp;
distance &lt; SIDECOLLDIST) {
sidedist = car-&gt;_trkPos.toMiddle - mycar-&gt;_trkPos.toMiddle;
state |= OPP_SIDE;
}
}
}</pre></p>
<p>
This part is responsible to check if the opponent is aside of us. If yes we compute
the distance (sideways) and set the flag OPP_SIDE.
</p>
<p>
Now the implementation of the Opponents class follows.
</p>
<p><pre class="lcolor">/* Initialize the list of opponents */
Opponents::Opponents(tSituation *s, Driver *driver)
{
opponent = new Opponent[s-&gt;_ncars - 1];
int i, j = 0;
for (i = 0; i &lt; s-&gt;_ncars; i++) {
if (s-&gt;cars[i] != driver-&gt;getCarPtr()) {
opponent[j].setCarPtr(s-&gt;cars[i]);
j++;
}
}
Opponent::setTrackPtr(driver-&gt;getTrackPtr());
nopponents = s-&gt;_ncars - 1;
}
Opponents::~Opponents()
{
delete [] opponent;
}</pre></p>
<p>
The constructor allocates memory and generates the Opponent instances. The destructor
deletes the instances and frees the memory.
</p>
<p><pre class="lcolor">/* Updates all the Opponent instances */
void Opponents::update(tSituation *s, Driver *driver)
{
int i;
for (i = 0; i &lt; s-&gt;_ncars - 1; i++) {
opponent[i].update(s, driver);
}
}</pre></p>
<p>
The update method simply iterates through the Opponent instances and calls update on them.
</p>
<h3>Modifying driver.h</h3>
<p>
To access some data of Driver from Opponent we need to add some methods and variables
to driver.h. Put the following methods into the public section.
</p>
<p><pre class="lcolor"> tCarElt *getCarPtr() { return car; }
tTrack *getTrackPtr() { return track; }
float getSpeed() { return speed; }</pre></p>
<p>
We need also the speed of our car. For that we add a variable to the private section.
</p>
<p><pre class="lcolor"> float speed; /* speed in track direction */</pre></p>
<h3>Compiling opponent.cpp</h3>
<p>
To check if everything is ok so far you should compile opponent.cpp now. You need to
change the Makefile in the <span style="color:red;">bt</span> directory. Change the line
</p>
<p><pre class="lbcolor">SOURCES = ${ROBOT}.cpp driver.cpp</pre></p>
<p>
to
</p>
<p><pre class="lcolor">SOURCES = ${ROBOT}.cpp driver.cpp opponent.cpp</pre></p>
<p>
and run "make".
</p>
<h3>Downloads</h3>
<p>
In case you got lost, you can <a href="../download/bt72.tar.gz">download</a> my robot for TORCS 1.2.0 or later.
</p>
<h3>Summary</h3>
<ul style="list-style-type:disk; color:black;">
<li>You have created opponent.cpp.</li>
<li>You know how it works.</li>
</ul>
<br/>
</td>
</tr>
</table>
<table class="navigation_foot">
<tr>
<td class="navigation_foot">
<a href="./introduction.html">
<p style="text-align:left;">Back</p>
</a>
</td>
<td class="navigation_foot">
<a href="./collisions1.html">
<p style="text-align:right;">Avoiding front collisions.</p>
</a>
</td>
</tr>
</table>
</body>
</html>