343 lines
13 KiB
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->_trkPos));
|
|
|
|
speed.x = car->_speed_X;
|
|
speed.y = car->_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->_trkPos.seg->type == TR_STR) {
|
|
return car->_trkPos.toStart;
|
|
} else {
|
|
return car->_trkPos.toStart*car->_trkPos.seg->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->getCarPtr();
|
|
|
|
/* init state of opponent to ignore */
|
|
state = OPP_IGNORE;
|
|
|
|
/* if the car is out of the simulation ignore it */
|
|
if (car->_state & 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->_trkPos.seg->lgfromstart + getDistToSegStart();
|
|
distance = oppToStart - mycar->_distFromStartLine;
|
|
if (distance > track->length/2.0) {
|
|
distance -= track->length;
|
|
} else if (distance < -track->length/2.0) {
|
|
distance += track->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->_speed_X*car->_speed_X + car->_speed_Y*car->_speed_Y);
|
|
float alpha = acos(cosa);
|
|
width = car->_dimension_x*sin(alpha) + car->_dimension_y*cosa;
|
|
float SIDECOLLDIST = MIN(car->_dimension_x, mycar->_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 > -BACKCOLLDIST && distance < FRONTCOLLDIST) {
|
|
/* is opponent in front and slower */
|
|
if (distance > SIDECOLLDIST && speed < driver->getSpeed()) {
|
|
catchdist = driver->getSpeed()*distance/(driver->getSpeed() - speed);
|
|
state |= OPP_FRONT;
|
|
distance -= MAX(car->_dimension_x, mycar->_dimension_x);
|
|
distance -= LENGTH_MARGIN;
|
|
float cardist = car->_trkPos.toMiddle - mycar->_trkPos.toMiddle;
|
|
sidedist = cardist;
|
|
cardist = fabs(cardist) - fabs(width/2.0) - mycar->_dimension_y/2.0;
|
|
if (cardist < 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 < -SIDECOLLDIST && speed > driver->getSpeed()) {
|
|
catchdist = driver->getSpeed()*distance/(speed - driver->getSpeed());
|
|
state |= OPP_BACK;
|
|
distance -= MAX(car->_dimension_x, mycar->_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 > -SIDECOLLDIST &&
|
|
distance < SIDECOLLDIST) {
|
|
sidedist = car->_trkPos.toMiddle - mycar->_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->_ncars - 1];
|
|
int i, j = 0;
|
|
for (i = 0; i < s->_ncars; i++) {
|
|
if (s->cars[i] != driver->getCarPtr()) {
|
|
opponent[j].setCarPtr(s->cars[i]);
|
|
j++;
|
|
}
|
|
}
|
|
Opponent::setTrackPtr(driver->getTrackPtr());
|
|
nopponents = s->_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 < s->_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>
|