7.5 Overtaking

Introduction

To be able to overtake we need to modify again the steer value. This time we achieve that with the modification of the target point. Depending on the side we want to pass an opponent we slightly add an offset vector to the target point. This offset is perpendicular to the track tangent. The opponent we choose for overtaking is the one with the smallest catchdistance, because we will reach it first.

Changes in driver.h

Add the following method, variable and constant declarations to the private section.

        float getOvertakeOffset();

        float myoffset;  /* overtake offset sideways */

        static const float BORDER_OVERTAKE_MARGIN;
        static const float OVERTAKE_OFFSET_INC;

Implementation in driver.cpp

At the beginning of the file we define the new constants. You should also change the WIDTHDIV constant to 3.0.

const float Driver::BORDER_OVERTAKE_MARGIN = 0.5; /* [m] */
const float Driver::OVERTAKE_OFFSET_INC = 0.1;    /* [m/timestep] */

const float Driver::WIDTHDIV = 3.0;               /* [-] */

The BORDER_OVERTAKE_MARGIN is the border relative to the filterTrk width. It should avoid that we leave the range on the track where filterTrk allows acceleration. OVERTAKE_OFFSET_INC is the increment of the offset value. In Driver::newRace() we initialize myoffset to zero.

    myoffset = 0.0;

Now we have a look on how we compute the offset of the target point.

/* Compute an offset to the target point */
float Driver::getOvertakeOffset()
{
    int i;
    float catchdist, mincatchdist = FLT_MAX;
    Opponent *o = NULL;

    for (i = 0; i < opponents->getNOpponents(); i++) {
        if (opponent[i].getState() & OPP_FRONT) {
            catchdist = opponent[i].getCatchDist();
            if (catchdist < mincatchdist) {
                mincatchdist = catchdist;
                o = &opponent[i];
            }
        }
    }

First we find the opponent with the smallest catchdist. Remember, that is the car which we will reach first. Of course the candidates need to have OPP_FRONT set.

    if (o != NULL) {
        float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
        float otm = o->getCarPtr()->_trkPos.toMiddle;
        if (otm > 0.0 && myoffset > -w) myoffset -= OVERTAKE_OFFSET_INC;
        else if (otm < 0.0 && myoffset < w) myoffset += OVERTAKE_OFFSET_INC;
    } else {

In case there is an opponent to overtake we let slightly grow the offset toward the other track side to pass it. The borders are checked so that the offset stays within "w".

        if (myoffset > OVERTAKE_OFFSET_INC) myoffset -= OVERTAKE_OFFSET_INC;
        else if (myoffset < -OVERTAKE_OFFSET_INC) myoffset += OVERTAKE_OFFSET_INC;
        else myoffset = 0.0;
    }
    return myoffset;
}

In case we have not found an opponent the offset goes back slightly toward zero. In the next section we will add the offset to the target point.

Summary

  • You have implemented the code above.
  • You know how it works.