1 /***************************************************************************
2
3 file : driver.cpp
4 created : Thu Dec 20 01:21:49 CET 2002
5 copyright : (C) 2002-2004 Bernhard Wymann
6 email : berniw@bluewin.ch
7 version : $Id: driver.cpp,v 1.1.2.2 2008/12/31 03:53:53 berniw Exp $
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20 #include "driver.h"
21
22 const float Driver::MAX_UNSTUCK_ANGLE = 15.0f/180.0f*PI; // [radians] If the angle of the car on the track is smaller, we assume we are not stuck.
23 const float Driver::UNSTUCK_TIME_LIMIT = 2.0f; // [s] We try to get unstuck after this time.
24 const float Driver::MAX_UNSTUCK_SPEED = 5.0f; // [m/s] Below this speed we consider being stuck.
25 const float Driver::MIN_UNSTUCK_DIST = 3.0f; // [m] If we are closer to the middle we assume to be not stuck.
26 const float Driver::G = 9.81f; // [m/(s*s)] Welcome on Earth.
27 const float Driver::FULL_ACCEL_MARGIN = 1.0f; // [m/s] Margin reduce oscillation of brake/acceleration.
28 const float Driver::SHIFT = 0.9f; // [-] (% of rpmredline) When do we like to shift gears.
29 const float Driver::SHIFT_MARGIN = 4.0f; // [m/s] Avoid oscillating gear changes.
30 const float Driver::ABS_SLIP = 2.0f; // [m/s] range [0..10]
31 const float Driver::ABS_RANGE = 5.0f; // [m/s] range [0..10]
32 const float Driver::ABS_MINSPEED = 3.0f; // [m/s] Below this speed the ABS is disabled (numeric, division by small numbers).
33 const float Driver::TCL_SLIP = 2.0f; // [m/s] range [0..10]
34 const float Driver::TCL_RANGE = 10.0f; // [m/s] range [0..10]
35 const float Driver::LOOKAHEAD_CONST = 17.0f; // [m]
36 const float Driver::LOOKAHEAD_FACTOR = 0.33f; // [-]
37 const float Driver::WIDTHDIV = 3.0f; // [-] Defines the percentage of the track to use (2/WIDTHDIV).
38 const float Driver::SIDECOLL_MARGIN = 3.0f; // [m] Distance between car centers to avoid side collisions.
39 const float Driver::BORDER_OVERTAKE_MARGIN = 0.5f; // [m]
40 const float Driver::OVERTAKE_OFFSET_SPEED = 5.0f; // [m/s] Offset change speed.
41 const float Driver::PIT_LOOKAHEAD = 6.0f; // [m] Lookahead to stop in the pit.
42 const float Driver::PIT_BRAKE_AHEAD = 200.0f; // [m] Workaround for "broken" pitentries.
43 const float Driver::PIT_MU = 0.4f; // [-] Friction of pit concrete.
44 const float Driver::MAX_SPEED = 84.0f; // [m/s] Speed to compute the percentage of brake to apply.
45 const float Driver::MAX_FUEL_PER_METER = 0.0008f; // [liter/m] fuel consumtion.
46 const float Driver::CLUTCH_SPEED = 5.0f; // [m/s]
47 const float Driver::CENTERDIV = 0.1f; // [-] (factor) [0.01..0.6].
48 const float Driver::DISTCUTOFF = 200.0f; // [m] How far to look, terminate while loops.
49 const float Driver::MAX_INC_FACTOR = 5.0f; // [m] Increment faster if speed is slow [1.0..10.0].
50 const float Driver::CATCH_FACTOR = 10.0f; // [-] select MIN(catchdist, dist*CATCH_FACTOR) to overtake.
51 const float Driver::CLUTCH_FULL_MAX_TIME = 2.0f; // [s] Time to apply full clutch.
52 const float Driver::USE_LEARNED_OFFSET_RANGE = 0.2f; // [m] if offset < this use the learned stuff
53
54 const float Driver::TEAM_REAR_DIST = 50.0f; //
55 const int Driver::TEAM_DAMAGE_CHANGE_LEAD = 700; // When to change position in the team?
56
57 // Static variables.
58 Cardata *Driver::cardata = NULL;
59 double Driver::currentsimtime;
60
61
Driver(int index)62 Driver::Driver(int index)
63 {
64 INDEX = index;
65 }
66
67
~Driver()68 Driver::~Driver()
69 {
70 delete opponents;
71 delete pit;
72 delete [] radius;
73 delete learn;
74 delete strategy;
75 if (cardata != NULL) {
76 delete cardata;
77 cardata = NULL;
78 }
79 }
80
81
82 // Called for every track change or new race.
initTrack(tTrack * t,void * carHandle,void ** carParmHandle,tSituation * s)83 void Driver::initTrack(tTrack* t, void *carHandle, void **carParmHandle, tSituation *s)
84 {
85 track = t;
86
87 const int BUFSIZE = 256;
88 char buffer[BUFSIZE];
89 // Load a custom setup if one is available.
90 // Get a pointer to the first char of the track filename.
91 char* trackname = strrchr(track->filename, '/') + 1;
92
93 switch (s->_raceType) {
94 case RM_TYPE_PRACTICE:
95 snprintf(buffer, BUFSIZE, "drivers/damned/%d/practice/%s", INDEX, trackname);
96 break;
97 case RM_TYPE_QUALIF:
98 snprintf(buffer, BUFSIZE, "drivers/damned/%d/qualifying/%s", INDEX, trackname);
99 break;
100 case RM_TYPE_RACE:
101 snprintf(buffer, BUFSIZE, "drivers/damned/%d/race/%s", INDEX, trackname);
102 break;
103 default:
104 break;
105 }
106
107 *carParmHandle = GfParmReadFile(buffer, GFPARM_RMODE_STD);
108 if (*carParmHandle == NULL) {
109 snprintf(buffer, BUFSIZE, "drivers/damned/%d/default.xml", INDEX);
110 *carParmHandle = GfParmReadFile(buffer, GFPARM_RMODE_STD);
111 }
112
113 // Create a pit stop strategy object.
114 strategy = new SimpleStrategy2();
115
116 // Init fuel.
117 strategy->setFuelAtRaceStart(t, carParmHandle, s, INDEX);
118
119 // Load and set parameters.
120 MU_FACTOR = GfParmGetNum(*carParmHandle, BT_SECT_PRIV, BT_ATT_MUFACTOR, (char*)NULL, 0.69f);
121 }
122
123
124 // Start a new race.
newRace(tCarElt * car,tSituation * s)125 void Driver::newRace(tCarElt* car, tSituation *s)
126 {
127 float deltaTime = (float) RCM_MAX_DT_ROBOTS;
128 MAX_UNSTUCK_COUNT = int(UNSTUCK_TIME_LIMIT/deltaTime);
129 OVERTAKE_OFFSET_INC = OVERTAKE_OFFSET_SPEED*deltaTime;
130 stuck = 0;
131 alone = 1;
132 clutchtime = 0.0f;
133 oldlookahead = 0.0f;
134 this->car = car;
135 CARMASS = GfParmGetNum(car->_carHandle, SECT_CAR, PRM_MASS, NULL, 1000.0f);
136 myoffset = 0.0f;
137 initCa();
138 initCw();
139 initTireMu();
140 initTCLfilter();
141
142 // Create just one instance of cardata shared by all drivers.
143 if (cardata == NULL) {
144 cardata = new Cardata(s);
145 }
146 mycardata = cardata->findCar(car);
147 currentsimtime = s->currentTime;
148
149 // initialize the list of opponents.
150 opponents = new Opponents(s, this, cardata);
151 opponent = opponents->getOpponentPtr();
152
153 // Set team mate.
154 const char *teammate = GfParmGetStr(car->_carHandle, BT_SECT_PRIV, BT_ATT_TEAMMATE, NULL);
155 if (teammate != NULL) {
156 opponents->setTeamMate(teammate);
157 }
158
159 // Initialize radius of segments.
160 radius = new float[track->nseg];
161 computeRadius(radius);
162
163 learn = new SegLearn(track, s, INDEX);
164
165 // create the pit object.
166 pit = new Pit(s, this);
167 }
168
169
170 // Drive during race.
drive(tSituation * s)171 void Driver::drive(tSituation *s)
172 {
173 memset(&car->ctrl, 0, sizeof(tCarCtrl));
174
175 update(s);
176
177 //pit->setPitstop(true);
178
179 if (isStuck()) {
180 car->_steerCmd = -mycardata->getCarAngle() / car->_steerLock;
181 car->_gearCmd = -1; // Reverse gear.
182 car->_accelCmd = 1.0f; // 100% accelerator pedal.
183 car->_brakeCmd = 0.0f; // No brakes.
184 car->_clutchCmd = 0.0f; // Full clutch (gearbox connected with engine).
185 } else {
186 car->_steerCmd = filterSColl(getSteer());
187 car->_gearCmd = getGear();
188 car->_brakeCmd = filterABS(filterBrakeSpeed(filterBColl(filterBPit(getBrake()))));
189 if (car->_brakeCmd == 0.0f) {
190 car->_accelCmd = filterTCL(filterTrk(filterOverlap(getAccel())));
191 } else {
192 car->_accelCmd = 0.0f;
193 }
194 car->_clutchCmd = getClutch();
195
196 }
197 }
198
199
200 // Set pitstop commands.
pitCommand(tSituation * s)201 int Driver::pitCommand(tSituation *s)
202 {
203 car->_pitRepair = strategy->pitRepair(car, s);
204 car->_pitFuel = strategy->pitRefuel(car, s);
205 // This should be the only place where the pit stop is set to false!
206 pit->setPitstop(false);
207 return ROB_PIT_IM; // return immediately.
208 }
209
210
211 // End of the current race.
endRace(tSituation * s)212 void Driver::endRace(tSituation *s)
213 {
214 // Nothing for now.
215 }
216
217
218 /***************************************************************************
219 *
220 * utility functions
221 *
222 ***************************************************************************/
223
224
computeRadius(float * radius)225 void Driver::computeRadius(float *radius)
226 {
227 float lastturnarc = 0.0f;
228 int lastsegtype = TR_STR;
229
230 tTrackSeg *currentseg, *startseg = track->seg;
231 currentseg = startseg;
232
233 do {
234 if (currentseg->type == TR_STR) {
235 lastsegtype = TR_STR;
236 radius[currentseg->id] = FLT_MAX;
237 } else {
238 if (currentseg->type != lastsegtype) {
239 float arc = 0.0f;
240 tTrackSeg *s = currentseg;
241 lastsegtype = currentseg->type;
242
243 while (s->type == lastsegtype && arc < PI/2.0f) {
244 arc += s->arc;
245 s = s->next;
246 }
247 lastturnarc = arc/(PI/2.0f);
248 }
249 radius[currentseg->id] = (currentseg->radius + currentseg->width/2.0)/lastturnarc;
250 }
251 currentseg = currentseg->next;
252 } while (currentseg != startseg);
253
254 }
255
256
257 // Compute the allowed speed on a segment.
getAllowedSpeed(tTrackSeg * segment)258 float Driver::getAllowedSpeed(tTrackSeg *segment)
259 {
260 float mu = segment->surface->kFriction*TIREMU*MU_FACTOR;
261 float r = radius[segment->id];
262 float dr = learn->getRadius(segment);
263 if (dr < 0.0f) {
264 r += dr;
265 } else {
266 float tdr = dr*(1.0f - MIN(1.0f, fabs(myoffset)*2.0f/segment->width));
267 r += tdr;
268 }
269 // README: the outcommented code is the more save version.
270 /*if ((alone > 0 && fabs(myoffset) < USE_LEARNED_OFFSET_RANGE) ||
271 dr < 0.0f
272 ) {
273 r += dr;
274 }*/
275 r = MAX(1.0, r);
276
277 return sqrt((mu*G*r)/(1.0f - MIN(1.0f, r*CA*mu/mass)));
278 }
279
280
281 // Compute the length to the end of the segment.
getDistToSegEnd()282 float Driver::getDistToSegEnd()
283 {
284 if (car->_trkPos.seg->type == TR_STR) {
285 return car->_trkPos.seg->length - car->_trkPos.toStart;
286 } else {
287 return (car->_trkPos.seg->arc - car->_trkPos.toStart)*car->_trkPos.seg->radius;
288 }
289 }
290
291
292 // Compute fitting acceleration.
getAccel()293 float Driver::getAccel()
294 {
295 if (car->_gear > 0) {
296 float allowedspeed = getAllowedSpeed(car->_trkPos.seg);
297 if (allowedspeed > car->_speed_x + FULL_ACCEL_MARGIN) {
298 return 1.0;
299 } else {
300 float gr = car->_gearRatio[car->_gear + car->_gearOffset];
301 float rm = car->_enginerpmRedLine;
302 return allowedspeed/car->_wheelRadius(REAR_RGT)*gr /rm;
303 }
304 } else {
305 return 1.0;
306 }
307 }
308
309
310 // If we get lapped reduce accelerator.
filterOverlap(float accel)311 float Driver::filterOverlap(float accel)
312 {
313 int i;
314 for (i = 0; i < opponents->getNOpponents(); i++) {
315 if (opponent[i].getState() & OPP_LETPASS) {
316 return MIN(accel, 0.5f);
317 }
318 }
319 return accel;
320 }
321
322
323 // Compute initial brake value.
getBrake()324 float Driver::getBrake()
325 {
326 // Car drives backward?
327 if (car->_speed_x < -MAX_UNSTUCK_SPEED) {
328 // Yes, brake.
329 return 1.0;
330 } else {
331 // We drive forward, normal braking.
332 tTrackSeg *segptr = car->_trkPos.seg;
333 float mu = segptr->surface->kFriction;
334 float maxlookaheaddist = currentspeedsqr/(2.0f*mu*G);
335 float lookaheaddist = getDistToSegEnd();
336
337 float allowedspeed = getAllowedSpeed(segptr);
338 if (allowedspeed < car->_speed_x) {
339 return MIN(1.0f, (car->_speed_x-allowedspeed)/(FULL_ACCEL_MARGIN));
340 }
341
342 segptr = segptr->next;
343 while (lookaheaddist < maxlookaheaddist) {
344 allowedspeed = getAllowedSpeed(segptr);
345 if (allowedspeed < car->_speed_x) {
346 if (brakedist(allowedspeed, mu) > lookaheaddist) {
347 return 1.0f;
348 }
349 }
350 lookaheaddist += segptr->length;
351 segptr = segptr->next;
352 }
353 return 0.0f;
354 }
355 }
356
357
358 // Compute gear.
getGear()359 int Driver::getGear()
360 {
361 if (car->_gear <= 0) {
362 return 1;
363 }
364 float gr_up = car->_gearRatio[car->_gear + car->_gearOffset];
365 float omega = car->_enginerpmRedLine/gr_up;
366 float wr = car->_wheelRadius(2);
367
368 if (omega*wr*SHIFT < car->_speed_x) {
369 return car->_gear + 1;
370 } else {
371 float gr_down = car->_gearRatio[car->_gear + car->_gearOffset - 1];
372 omega = car->_enginerpmRedLine/gr_down;
373 if (car->_gear > 1 && omega*wr*SHIFT > car->_speed_x + SHIFT_MARGIN) {
374 return car->_gear - 1;
375 }
376 }
377 return car->_gear;
378 }
379
380
381 // Compute steer value.
getSteer()382 float Driver::getSteer()
383 {
384 float targetAngle;
385 vec2f target = getTargetPoint();
386
387 targetAngle = atan2(target.y - car->_pos_Y, target.x - car->_pos_X);
388 targetAngle -= car->_yaw;
389 NORM_PI_PI(targetAngle);
390 return targetAngle / car->_steerLock;
391 }
392
393
394 // Compute the clutch value.
getClutch()395 float Driver::getClutch()
396 {
397 if (car->_gear > 1) {
398 clutchtime = 0.0f;
399 return 0.0f;
400 } else {
401 float drpm = car->_enginerpm - car->_enginerpmRedLine/2.0f;
402 clutchtime = MIN(CLUTCH_FULL_MAX_TIME, clutchtime);
403 float clutcht = (CLUTCH_FULL_MAX_TIME - clutchtime)/CLUTCH_FULL_MAX_TIME;
404 if (car->_gear == 1 && car->_accelCmd > 0.0f) {
405 clutchtime += (float) RCM_MAX_DT_ROBOTS;
406 }
407
408 if (drpm > 0) {
409 float speedr;
410 if (car->_gearCmd == 1) {
411 // Compute corresponding speed to engine rpm.
412 float omega = car->_enginerpmRedLine/car->_gearRatio[car->_gear + car->_gearOffset];
413 float wr = car->_wheelRadius(2);
414 speedr = (CLUTCH_SPEED + MAX(0.0f, car->_speed_x))/fabs(wr*omega);
415 float clutchr = MAX(0.0f, (1.0f - speedr*2.0f*drpm/car->_enginerpmRedLine));
416 return MIN(clutcht, clutchr);
417 } else {
418 // For the reverse gear.
419 clutchtime = 0.0f;
420 return 0.0f;
421 }
422 } else {
423 return clutcht;
424 }
425 }
426 }
427
428 // Compute target point for steering.
getTargetPoint()429 vec2f Driver::getTargetPoint()
430 {
431 tTrackSeg *seg = car->_trkPos.seg;
432 float lookahead;
433 float length = getDistToSegEnd();
434 float offset = getOffset();
435
436 if (pit->getInPit()) {
437 // To stop in the pit we need special lookahead values.
438 if (currentspeedsqr > pit->getSpeedlimitSqr()) {
439 lookahead = PIT_LOOKAHEAD + car->_speed_x*LOOKAHEAD_FACTOR;
440 } else {
441 lookahead = PIT_LOOKAHEAD;
442 }
443 } else {
444 // Usual lookahead.
445 lookahead = LOOKAHEAD_CONST + car->_speed_x*LOOKAHEAD_FACTOR;
446 // Prevent "snap back" of lookahead on harsh braking.
447 float cmplookahead = oldlookahead - car->_speed_x*RCM_MAX_DT_ROBOTS;
448 if (lookahead < cmplookahead) {
449 lookahead = cmplookahead;
450 }
451 }
452
453 oldlookahead = lookahead;
454
455 // Search for the segment containing the target point.
456 while (length < lookahead) {
457 seg = seg->next;
458 length += seg->length;
459 }
460
461 length = lookahead - length + seg->length;
462 float fromstart = seg->lgfromstart;
463 fromstart += length;
464
465 // Compute the target point.
466 offset = myoffset = pit->getPitOffset(offset, fromstart);
467
468 vec2f s;
469 s.x = (seg->vertex[TR_SL].x + seg->vertex[TR_SR].x)/2.0f;
470 s.y = (seg->vertex[TR_SL].y + seg->vertex[TR_SR].y)/2.0f;
471
472 if ( seg->type == TR_STR) {
473 vec2f d, n;
474 n.x = (seg->vertex[TR_EL].x - seg->vertex[TR_ER].x)/seg->length;
475 n.y = (seg->vertex[TR_EL].y - seg->vertex[TR_ER].y)/seg->length;
476 n.normalize();
477 d.x = (seg->vertex[TR_EL].x - seg->vertex[TR_SL].x)/seg->length;
478 d.y = (seg->vertex[TR_EL].y - seg->vertex[TR_SL].y)/seg->length;
479 return s + d*length + offset*n;
480 } else {
481 vec2f c, n;
482 c.x = seg->center.x;
483 c.y = seg->center.y;
484 float arc = length/seg->radius;
485 float arcsign = (seg->type == TR_RGT) ? -1.0f : 1.0f;
486 arc = arc*arcsign;
487 s = s.rotate(c, arc);
488
489 n = c - s;
490 n.normalize();
491 return s + arcsign*offset*n;
492 }
493 }
494
495
496 // Compute offset to normal target point for overtaking or let pass an opponent.
getOffset()497 float Driver::getOffset()
498 {
499 int i;
500 float catchdist, mincatchdist = FLT_MAX, mindist = -1000.0f;
501 Opponent *o = NULL;
502
503 // Increment speed dependent.
504 float incfactor = MAX_INC_FACTOR - MIN(fabs(car->_speed_x)/MAX_INC_FACTOR, (MAX_INC_FACTOR - 1.0f));
505
506 // Let overlap or let less damaged team mate pass.
507 for (i = 0; i < opponents->getNOpponents(); i++) {
508 // Let the teammate with less damage overtake to use slipstreaming.
509 // The position change happens when the damage difference is greater than
510 // TEAM_DAMAGE_CHANGE_LEAD.
511 if (((opponent[i].getState() & OPP_LETPASS) && !opponent[i].isTeamMate()) ||
512 (opponent[i].isTeamMate() && (car->_dammage - opponent[i].getDamage() > TEAM_DAMAGE_CHANGE_LEAD) &&
513 (opponent[i].getDistance() > -TEAM_REAR_DIST) && (opponent[i].getDistance() < -car->_dimension_x) &&
514 car->race.laps == opponent[i].getCarPtr()->race.laps))
515 {
516 // Behind, larger distances are smaller ("more negative").
517 if (opponent[i].getDistance() > mindist) {
518 mindist = opponent[i].getDistance();
519 o = &opponent[i];
520 }
521 }
522 }
523
524 if (o != NULL) {
525 tCarElt *ocar = o->getCarPtr();
526 float side = car->_trkPos.toMiddle - ocar->_trkPos.toMiddle;
527 float w = car->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
528 if (side > 0.0f) {
529 if (myoffset < w) {
530 myoffset += OVERTAKE_OFFSET_INC*incfactor;
531 }
532 } else {
533 if (myoffset > -w) {
534 myoffset -= OVERTAKE_OFFSET_INC*incfactor;
535 }
536 }
537 return myoffset;
538 }
539
540
541 // Overtake.
542 for (i = 0; i < opponents->getNOpponents(); i++) {
543 if ((opponent[i].getState() & OPP_FRONT) &&
544 !(opponent[i].isTeamMate() && car->race.laps <= opponent[i].getCarPtr()->race.laps))
545 {
546 catchdist = MIN(opponent[i].getCatchDist(), opponent[i].getDistance()*CATCH_FACTOR);
547 if (catchdist < mincatchdist) {
548 mincatchdist = catchdist;
549 o = &opponent[i];
550 }
551 }
552 }
553
554 if (o != NULL) {
555 // Compute the width around the middle which we can use for overtaking.
556 float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
557 // Compute the opponents distance to the middle.
558 float otm = o->getCarPtr()->_trkPos.toMiddle;
559 // Define the with of the middle range.
560 float wm = o->getCarPtr()->_trkPos.seg->width*CENTERDIV;
561
562 if (otm > wm && myoffset > -w) {
563 myoffset -= OVERTAKE_OFFSET_INC*incfactor;
564 } else if (otm < -wm && myoffset < w) {
565 myoffset += OVERTAKE_OFFSET_INC*incfactor;
566 } else {
567 // If the opponent is near the middle we try to move the offset toward
568 // the inside of the expected turn.
569 // Try to find out the characteristic of the track up to catchdist.
570 tTrackSeg *seg = car->_trkPos.seg;
571 float length = getDistToSegEnd();
572 float oldlen, seglen = length;
573 float lenright = 0.0f, lenleft = 0.0f;
574 mincatchdist = MIN(mincatchdist, DISTCUTOFF);
575
576 do {
577 switch (seg->type) {
578 case TR_LFT:
579 lenleft += seglen;
580 break;
581 case TR_RGT:
582 lenright += seglen;
583 break;
584 default:
585 // Do nothing.
586 break;
587 }
588 seg = seg->next;
589 seglen = seg->length;
590 oldlen = length;
591 length += seglen;
592 } while (oldlen < mincatchdist);
593
594 // If we are on a straight look for the next turn.
595 if (lenleft == 0.0f && lenright == 0.0f) {
596 while (seg->type == TR_STR) {
597 seg = seg->next;
598 }
599 // Assume: left or right if not straight.
600 if (seg->type == TR_LFT) {
601 lenleft = 1.0f;
602 } else {
603 lenright = 1.0f;
604 }
605 }
606
607 // Because we are inside we can go to the border.
608 float maxoff = (o->getCarPtr()->_trkPos.seg->width - car->_dimension_y)/2.0-BORDER_OVERTAKE_MARGIN;
609 if (lenleft > lenright) {
610 if (myoffset < maxoff) {
611 myoffset += OVERTAKE_OFFSET_INC*incfactor;
612 }
613 } else {
614 if (myoffset > -maxoff) {
615 myoffset -= OVERTAKE_OFFSET_INC*incfactor;
616 }
617 }
618 }
619 } else {
620 // There is no opponent to overtake, so the offset goes slowly back to zero.
621 if (myoffset > OVERTAKE_OFFSET_INC) {
622 myoffset -= OVERTAKE_OFFSET_INC;
623 } else if (myoffset < -OVERTAKE_OFFSET_INC) {
624 myoffset += OVERTAKE_OFFSET_INC;
625 } else {
626 myoffset = 0.0f;
627 }
628 }
629
630 return myoffset;
631 }
632
633
634 // Update my private data every timestep.
update(tSituation * s)635 void Driver::update(tSituation *s)
636 {
637 // Update global car data (shared by all instances) just once per timestep.
638 if (currentsimtime != s->currentTime) {
639 currentsimtime = s->currentTime;
640 cardata->update();
641 }
642
643 // Update the local data rest.
644 speedangle = mycardata->getTrackangle() - atan2(car->_speed_Y, car->_speed_X);
645 NORM_PI_PI(speedangle);
646 mass = CARMASS + car->_fuel;
647 currentspeedsqr = car->_speed_x*car->_speed_x;
648 opponents->update(s, this);
649 strategy->update(car, s);
650 if (!pit->getPitstop()) {
651 pit->setPitstop(strategy->needPitstop(car, s));
652 }
653 pit->update();
654 alone = isAlone();
655 learn->update(s, track, car, alone, myoffset, car->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN, radius);
656 }
657
658
isAlone()659 int Driver::isAlone()
660 {
661 int i;
662 for (i = 0; i < opponents->getNOpponents(); i++) {
663 if (opponent[i].getState() & (OPP_COLL | OPP_LETPASS)) {
664 return 0; // Not alone.
665 }
666 }
667 return 1; // Alone.
668 }
669
670
671 // Check if I'm stuck.
isStuck()672 bool Driver::isStuck()
673 {
674 if (fabs(mycardata->getCarAngle()) > MAX_UNSTUCK_ANGLE &&
675 car->_speed_x < MAX_UNSTUCK_SPEED &&
676 fabs(car->_trkPos.toMiddle) > MIN_UNSTUCK_DIST) {
677 if (stuck > MAX_UNSTUCK_COUNT && car->_trkPos.toMiddle*mycardata->getCarAngle() < 0.0) {
678 return true;
679 } else {
680 stuck++;
681 return false;
682 }
683 } else {
684 stuck = 0;
685 return false;
686 }
687 }
688
689
690 // Compute aerodynamic downforce coefficient CA.
initCa()691 void Driver::initCa()
692 {
693 const char *WheelSect[4] = {SECT_FRNTRGTWHEEL, SECT_FRNTLFTWHEEL, SECT_REARRGTWHEEL, SECT_REARLFTWHEEL};
694 float rearwingarea = GfParmGetNum(car->_carHandle, SECT_REARWING, PRM_WINGAREA, (char*) NULL, 0.0f);
695 float rearwingangle = GfParmGetNum(car->_carHandle, SECT_REARWING, PRM_WINGANGLE, (char*) NULL, 0.0f);
696 float wingca = 1.23f*rearwingarea*sin(rearwingangle);
697
698 float cl = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_FCL, (char*) NULL, 0.0f) +
699 GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_RCL, (char*) NULL, 0.0f);
700 float h = 0.0f;
701 int i;
702 for (i = 0; i < 4; i++)
703 h += GfParmGetNum(car->_carHandle, WheelSect[i], PRM_RIDEHEIGHT, (char*) NULL, 0.20f);
704 h*= 1.5f; h = h*h; h = h*h; h = 2.0f * exp(-3.0f*h);
705 CA = h*cl + 4.0f*wingca;
706 }
707
708
709 // Compute aerodynamic drag coefficient CW.
initCw()710 void Driver::initCw()
711 {
712 float cx = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_CX, (char*) NULL, 0.0f);
713 float frontarea = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_FRNTAREA, (char*) NULL, 0.0f);
714 CW = 0.645f*cx*frontarea;
715 }
716
717
718 // Init the friction coefficient of the the tires.
initTireMu()719 void Driver::initTireMu()
720 {
721 const char *WheelSect[4] = {SECT_FRNTRGTWHEEL, SECT_FRNTLFTWHEEL, SECT_REARRGTWHEEL, SECT_REARLFTWHEEL};
722 float tm = FLT_MAX;
723 int i;
724
725 for (i = 0; i < 4; i++) {
726 tm = MIN(tm, GfParmGetNum(car->_carHandle, WheelSect[i], PRM_MU, (char*) NULL, 1.0f));
727 }
728 TIREMU = tm;
729 }
730
731
732 // Reduces the brake value such that it fits the speed (more downforce -> more braking).
filterBrakeSpeed(float brake)733 float Driver::filterBrakeSpeed(float brake)
734 {
735 float weight = (CARMASS + car->_fuel)*G;
736 float maxForce = weight + CA*MAX_SPEED*MAX_SPEED;
737 float force = weight + CA*currentspeedsqr;
738 return brake*force/maxForce;
739 }
740
741
742 // Brake filter for pit stop.
filterBPit(float brake)743 float Driver::filterBPit(float brake)
744 {
745 if (pit->getPitstop() && !pit->getInPit()) {
746 float dl, dw;
747 RtDistToPit(car, track, &dl, &dw);
748 if (dl < PIT_BRAKE_AHEAD) {
749 float mu = car->_trkPos.seg->surface->kFriction*TIREMU*PIT_MU;
750 if (brakedist(0.0f, mu) > dl) {
751 return 1.0f;
752 }
753 }
754 }
755
756 if (pit->getInPit()) {
757 float s = pit->toSplineCoord(car->_distFromStartLine);
758 // Pit entry.
759 if (pit->getPitstop()) {
760 float mu = car->_trkPos.seg->surface->kFriction*TIREMU*PIT_MU;
761 if (s < pit->getNPitStart()) {
762 // Brake to pit speed limit.
763 float dist = pit->getNPitStart() - s;
764 if (brakedist(pit->getSpeedlimit(), mu) > dist) {
765 return 1.0f;
766 }
767 } else {
768 // Hold speed limit.
769 if (currentspeedsqr > pit->getSpeedlimitSqr()) {
770 return pit->getSpeedLimitBrake(currentspeedsqr);
771 }
772 }
773 // Brake into pit (speed limit 0.0 to stop)
774 float dist = pit->getNPitLoc() - s;
775 if (pit->isTimeout(dist)) {
776 pit->setPitstop(false);
777 return 0.0f;
778 } else {
779 if (brakedist(0.0f, mu) > dist) {
780 return 1.0f;
781 } else if (s > pit->getNPitLoc()) {
782 // Stop in the pit.
783 return 1.0f;
784 }
785 }
786 } else {
787 // Pit exit.
788 if (s < pit->getNPitEnd()) {
789 // Pit speed limit.
790 if (currentspeedsqr > pit->getSpeedlimitSqr()) {
791 return pit->getSpeedLimitBrake(currentspeedsqr);
792 }
793 }
794 }
795 }
796
797 return brake;
798 }
799
800
801 // Brake filter for collision avoidance.
filterBColl(float brake)802 float Driver::filterBColl(float brake)
803 {
804 float mu = car->_trkPos.seg->surface->kFriction;
805 int i;
806 for (i = 0; i < opponents->getNOpponents(); i++) {
807 if (opponent[i].getState() & OPP_COLL) {
808 if (brakedist(opponent[i].getSpeed(), mu) > opponent[i].getDistance()) {
809 return 1.0f;
810 }
811 }
812 }
813 return brake;
814 }
815
816
817 // Steer filter for collision avoidance.
filterSColl(float steer)818 float Driver::filterSColl(float steer)
819 {
820 int i;
821 float sidedist = 0.0f, fsidedist = 0.0f, minsidedist = FLT_MAX;
822 Opponent *o = NULL;
823
824 // Get the index of the nearest car (o).
825 for (i = 0; i < opponents->getNOpponents(); i++) {
826 if (opponent[i].getState() & OPP_SIDE) {
827 sidedist = opponent[i].getSideDist();
828 fsidedist = fabs(sidedist);
829 if (fsidedist < minsidedist) {
830 minsidedist = fsidedist;
831 o = &opponent[i];
832 }
833 }
834 }
835
836 // If there is another car handle the situation.
837 if (o != NULL) {
838 float d = fsidedist - o->getWidth();
839 // Near, so we need to look at it.
840 if (d < SIDECOLL_MARGIN) {
841 /* compute angle between cars */
842 tCarElt *ocar = o->getCarPtr();
843 float diffangle = ocar->_yaw - car->_yaw;
844 NORM_PI_PI(diffangle);
845 // We are near and heading toward the car.
846 if (diffangle*o->getSideDist() < 0.0f) {
847 const float c = SIDECOLL_MARGIN/2.0f;
848 d = d - c;
849 if (d < 0.0f) {
850 d = 0.0f;
851 }
852
853 // Steer delta required to drive parallel to the opponent.
854 float psteer = diffangle/car->_steerLock;
855 myoffset = car->_trkPos.toMiddle;
856
857 // Limit myoffset to suitable limits.
858 float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
859 if (fabs(myoffset) > w) {
860 myoffset = (myoffset > 0.0f) ? w : -w;
861 }
862
863 // On straights the car near to the middle can correct more, in turns the car inside
864 // the turn does (because if you leave the track on the turn "inside" you will skid
865 // back to the track.
866 if (car->_trkPos.seg->type == TR_STR) {
867 if (fabs(car->_trkPos.toMiddle) > fabs(ocar->_trkPos.toMiddle)) {
868 // Its me, I do correct not that much.
869 psteer = steer*(d/c) + 1.5f*psteer*(1.0f - d/c);
870 } else {
871 // Its the opponent, so I correct more.
872 psteer = steer*(d/c) + 2.0f*psteer*(1.0f - d/c);
873 }
874 } else {
875 // Who is outside, heavy corrections are less dangerous
876 // if you drive near the middle of the track.
877 float outside = car->_trkPos.toMiddle - ocar->_trkPos.toMiddle;
878 float sign = (car->_trkPos.seg->type == TR_RGT) ? 1.0f : -1.0f;
879 if (outside*sign > 0.0f) {
880 psteer = steer*(d/c) + 1.5f*psteer*(1.0f - d/c);
881 } else {
882 psteer = steer*(d/c) + 2.0f*psteer*(1.0f - d/c);
883 }
884 }
885
886 if (psteer*steer > 0.0f && fabs(steer) > fabs(psteer)) {
887 return steer;
888 } else {
889 return psteer;
890 }
891 }
892 }
893 }
894 return steer;
895 }
896
897
898 // Antilocking filter for brakes.
filterABS(float brake)899 float Driver::filterABS(float brake)
900 {
901 if (car->_speed_x < ABS_MINSPEED) return brake;
902 int i;
903 float slip = 0.0f;
904 for (i = 0; i < 4; i++) {
905 slip += car->_wheelSpinVel(i) * car->_wheelRadius(i);
906 }
907 slip = car->_speed_x - slip/4.0f;
908 if (slip > ABS_SLIP) {
909 brake = brake - MIN(brake, (slip - ABS_SLIP)/ABS_RANGE);
910 }
911 return brake;
912 }
913
914
915 // TCL filter for accelerator pedal.
filterTCL(float accel)916 float Driver::filterTCL(float accel)
917 {
918 float slip = (this->*GET_DRIVEN_WHEEL_SPEED)() - car->_speed_x;
919 if (slip > TCL_SLIP) {
920 accel = accel - MIN(accel, (slip - TCL_SLIP)/TCL_RANGE);
921 }
922 return accel;
923 }
924
925
926 // Traction Control (TCL) setup.
initTCLfilter()927 void Driver::initTCLfilter()
928 {
929 const char *traintype = GfParmGetStr(car->_carHandle, SECT_DRIVETRAIN, PRM_TYPE, VAL_TRANS_RWD);
930 if (strcmp(traintype, VAL_TRANS_RWD) == 0) {
931 GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_RWD;
932 } else if (strcmp(traintype, VAL_TRANS_FWD) == 0) {
933 GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_FWD;
934 } else if (strcmp(traintype, VAL_TRANS_4WD) == 0) {
935 GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_4WD;
936 }
937 }
938
939
940 // TCL filter plugin for rear wheel driven cars.
filterTCL_RWD()941 float Driver::filterTCL_RWD()
942 {
943 return (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
944 car->_wheelRadius(REAR_LFT) / 2.0f;
945 }
946
947
948 // TCL filter plugin for front wheel driven cars.
filterTCL_FWD()949 float Driver::filterTCL_FWD()
950 {
951 return (car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
952 car->_wheelRadius(FRNT_LFT) / 2.0f;
953 }
954
955
956 // TCL filter plugin for all wheel driven cars.
filterTCL_4WD()957 float Driver::filterTCL_4WD()
958 {
959 return ((car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
960 car->_wheelRadius(FRNT_LFT) +
961 (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
962 car->_wheelRadius(REAR_LFT)) / 4.0f;
963 }
964
965
966 // Hold car on the track.
filterTrk(float accel)967 float Driver::filterTrk(float accel)
968 {
969 tTrackSeg* seg = car->_trkPos.seg;
970
971 if (car->_speed_x < MAX_UNSTUCK_SPEED || // Too slow.
972 pit->getInPit() || // Pit stop.
973 car->_trkPos.toMiddle*speedangle > 0.0f) // Speedvector points to the inside of the turn.
974 {
975 return accel;
976 }
977
978 if (seg->type == TR_STR) {
979 float tm = fabs(car->_trkPos.toMiddle);
980 float w = (seg->width - car->_dimension_y)/2.0f ;
981 if (tm > w) {
982 return 0.0f;
983 } else {
984 return accel;
985 }
986 } else {
987 float sign = (seg->type == TR_RGT) ? -1.0f : 1.0f;
988 if (car->_trkPos.toMiddle*sign > 0.0f) {
989 return accel;
990 } else {
991 float tm = fabs(car->_trkPos.toMiddle);
992 float w = seg->width/WIDTHDIV;
993 if (tm > w) {
994 return 0.0f;
995 } else {
996 return accel;
997 }
998 }
999 }
1000 }
1001
1002
1003 // Compute the needed distance to brake.
brakedist(float allowedspeed,float mu)1004 float Driver::brakedist(float allowedspeed, float mu)
1005 {
1006 float c = mu*G;
1007 float d = (CA*mu + CW)/mass;
1008 float v1sqr = currentspeedsqr;
1009 float v2sqr = allowedspeed*allowedspeed;
1010 return -log((c + v2sqr*d)/(c + v1sqr*d))/(2.0f*d);
1011 }
1012
1013