pit brake filter
Author: Bernhard Wymann
Keywords: torcs, berniw, bernhard wymann, pit, pit stop, brake, filter

# 8.6 Pit Brake Filter ### Introduction Remember first what we already have implemented to stop in the pit. We have a path into the pit and we have a strategy to decide if we want to stop in the pit. That is fine so far if we just want to drive through the pit, what is missing is a part for stopping in the pit and maintaining the speed limit. In this section you implement the brake filter which is responsible for those tasks.

### Changes in the Header File Add the following declarations into the header file driver.h.
            float brakedist(float allowedspeed, float mu);
Because we will use the calculation of the braking distance from the pit brake filter and other places, we encapsulate the formula finally into a method (at the moment we have it hardwired in the getBrake and filterBColl methods).
            float filterBPit(float brake);
The pit brake filter method.
            static const float PIT_LOOKAHEAD;
We need another (much shorter) lookahead value for the pit, because we have to make a very tough turn from the pit lane into the pit.
            static const float PIT_BRAKE_AHEAD;
            static const float PIT_MU;
These constants are used as workaround for two problems. The pit has on much tracks another surface than the track itself, so it would be necessary to analyse the friction to brake early enough. Because we do not take care (of course you will implement that, don't you?) we simply multiply on all tracks the friction with PIT_MU for the pit stop. The PIT_BRAKE_AHEAD is used to workaround the problem of pitentry points which are very close to the first pit. On such tracks we will simply brake too late to get the turn into the pit right, so we have to brake earlier. If you have added better pitentry points (via XML or computed with a heuristic) you can remove that. ### The Implementation Now let's have a look on the implementation. Apply all changes to the file driver.cpp.
    const float Driver::PIT_LOOKAHEAD = 6.0;       /* [m] */
    const float Driver::PIT_BRAKE_AHEAD = 200.0;   /* [m] */
    const float Driver::PIT_MU = 0.4;              /* [-] */
First define the constants at the beginning of the file.
    float Driver::brakedist(float allowedspeed, float mu)
    {
        float allowedspeedsqr = allowedspeed*allowedspeed;
        float cm = mu*G*mass;
        float ca = CA*mu + CW;
        return mass*(currentspeedsqr - allowedspeedsqr) / (2.0*(cm + allowedspeedsqr*ca));
    }
Here we encapsulate the brake distance formula into its own method (remember chapter 3). Now everything is in place and we can start with the implementation of the brake filter.
    float Driver::filterBPit(float brake)
    {
        if (pit->getPitstop() && !pit->getInPit()) {
            float dl, dw;
            RtDistToPit(car, track, &dl, &dw);
            if (dl < PIT_BRAKE_AHEAD) {
                float mu = car->_trkPos.seg->surface->kFriction*PIT_MU;
                if (brakedist(0.0, mu) > dl) return 1.0;
            }
        }
The above code is responsible for braking early enough to make the turn into the pit lane. Like already mentioned in the discusson of PIT_BRAKE_AHEAD you can remove that code if you have better pitentry values. Now lets have a look on the nice part.
        if (pit->getInPit()) {
            float s = pit->toSplineCoord(car->_distFromStartLine);
If we are on the pit trajectory, convert the position of our car into spline coordinates.
            /* pit entry */
            if (pit->getPitstop()) {
If pitstop is true the pit is in front of us.
                float mu = car->_trkPos.seg->surface->kFriction*PIT_MU;
                if (s < pit->getNPitStart()) {
If we are not yet in the range of the speed limit we have to check if we need to brake to the speed limit.
                    /* brake to pit speed limit */
                    float dist = pit->getNPitStart() - s;
                    if (brakedist(pit->getSpeedlimit(), mu) > dist) return 1.0;
First compute the distance to the speed limit zone (p1). Then check if we need already to brake.
                } else {
                    /* hold speed limit */
                    if (currentspeedsqr > pit->getSpeedlimitSqr()) return 1.0;
                }
If we take the else we are already in the speed limit zone and have to maintain the speed limit. It is (like always in this tutorial) a very simple implementation.
                /* brake into pit (speed limit 0.0 to stop ) */
                float dist = pit->getNPitLoc() - s;
                if (brakedist(0.0, mu) > dist) return 1.0;
If we did not brake till now we have to check if we need to brake to stop in the pit. We compute the distance to the pit and check the brake distance.
                /* hold in the pit */
                if (s > pit->getNPitLoc()) return 1.0;
Finally if we passed the pit center and still want to pit we have to brake full, else we will miss the pit.
            } else {
                /* pit exit */
                if (s < pit->getNPitEnd()) {
                    /* pit speed limit */
                    if (currentspeedsqr > pit->getSpeedlimitSqr()) return 1.0;
                }
            }
        }
In this code section the pitstop variable is false, so we have just to check if we are in the speed limit zone and to maintain the speed limit in it.
        return brake;
    }
If none of the above expressions returned a brake value, we return the given value. ### Conclusion You have implemented a simple brake filter to stop in the pit. If you analyse the code, you will discover some unpleasant things. Assume for example that an opponent hits us before we stop in the pit and pushes our car over the pit center. Our code will then apply full brakes, but if we got pushed too far away from the pit center TORCS will not capture our car. That means we stay there with full applied brakes forever. I did not fix that because it happens not often, my berniw robot has the same problem. You can solve that with kind of a timeout mechanism or distance measurement to the pit. I leave it up to you to replace the brake distance code from getBrake and filterBColl through the new brakedist call. In the next section we will put all the stuff together. If you want to celebrate the pit stops with a cold juice it is now time to put it into the fridge. ### Summary You have implemented and understood the brake filter.