Skip to content

Commit

Permalink
Disallowing headway decrease for openGap(); Allow specifying space an…
Browse files Browse the repository at this point in the history
…d time headways, refs #4172
  • Loading branch information
Leonhard Luecken committed Nov 2, 2018
1 parent d18136b commit 6fc768b
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 46 deletions.
11 changes: 9 additions & 2 deletions src/libsumo/Vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,10 +1094,17 @@ Vehicle::slowDown(const std::string& vehicleID, double speed, double duration) {
}

void
Vehicle::openGap(const std::string& vehicleID, double newTau, double duration, double changeRate, double maxDecel) {
Vehicle::openGap(const std::string& vehicleID, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel) {
MSVehicle* veh = getVehicle(vehicleID);
const double originalTau = veh->getVehicleType().getCarFollowModel().getHeadwayTime();
veh->getInfluencer().activateGapController(originalTau, newTau, duration, changeRate, maxDecel);
if (newTimeHeadway == -1) {
newTimeHeadway = originalTau;
}
if (originalTau > newTimeHeadway) {
WRITE_WARNING("Ignoring openGap(). New time headway must not be smaller than the original.");
return;
}
veh->getInfluencer().activateGapController(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel);
}

void
Expand Down
2 changes: 1 addition & 1 deletion src/libsumo/Vehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class Vehicle {
static void changeSublane(const std::string& vehicleID, double latDist);

static void slowDown(const std::string& vehicleID, double speed, double duration);
static void openGap(const std::string& vehicleID, double newTau, double duration, double changeRate, double maxDecel);
static void openGap(const std::string& vehicleID, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel);
static void deactivateGapControl(const std::string& vehicleID);
static void setSpeed(const std::string& vehicleID, double speed);
static void setSpeedMode(const std::string& vehicleID, int speedMode);
Expand Down
35 changes: 18 additions & 17 deletions src/microsim/MSVehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,33 +240,36 @@ MSVehicle::WaitingTimeCollector::passTime(SUMOTime dt, bool waiting) {
* methods of MSVehicle::Influencer::GapControlState
* ----------------------------------------------------------------------- */
MSVehicle::Influencer::GapControlState::GapControlState() :
tauOriginal(-1), tauCurrent(-1), tauTarget(-1), remainingDuration(-1),
changeRate(-1), maxDecel(-1), active(false), gapAttained(false), prevLeader(nullptr), lastUpdate(-1) {}
tauOriginal(-1), tauCurrent(-1), tauTarget(-1), addGapCurrent(-1), addGapTarget(-1),
remainingDuration(-1), changeRate(-1), maxDecel(-1), active(false), gapAttained(false), prevLeader(nullptr),
lastUpdate(-1), timeHeadwayIncrement(0.0), spaceHeadwayIncrement(0.0) {}


void
MSVehicle::Influencer::GapControlState::activate(double tauOrig, double tauNew, double dur, double rate, double decel) {
MSVehicle::Influencer::GapControlState::activate(double tauOrig, double tauNew, double additionalGap, double dur, double rate, double decel) {
if (MSGlobals::gUseMesoSim) {
WRITE_ERROR("No gap control available for meso.")
} else {
tauOriginal = tauOrig;
tauCurrent = tauOrig;
tauTarget = tauNew;
addGapCurrent = 0.0;
addGapTarget = additionalGap;
remainingDuration = dur;
changeRate = rate;
maxDecel = decel;
active = true;
gapAttained = false;
prevLeader = nullptr;
lastUpdate = SIMSTEP - DELTA_T;
timeHeadwayIncrement = changeRate*TS*(tauTarget - tauOriginal);
spaceHeadwayIncrement = changeRate*TS*addGapTarget;
}
}

void
MSVehicle::Influencer::GapControlState::deactivate() {
remainingDuration = 0.0;
active = false;
gapAttained = false;
prevLeader = nullptr;
}


Expand Down Expand Up @@ -304,11 +307,11 @@ MSVehicle::Influencer::setSpeedTimeLine(const std::vector<std::pair<SUMOTime, do
}

void
MSVehicle::Influencer::activateGapController(double originalTau, double newTau, double duration, double changeRate, double maxDecel) {
MSVehicle::Influencer::activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel) {
if (myGapControlState == nullptr) {
myGapControlState = std::make_shared<GapControlState>();
}
myGapControlState->activate(originalTau, newTau, duration, changeRate, maxDecel);
myGapControlState->activate(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel);
}

void
Expand Down Expand Up @@ -410,14 +413,14 @@ MSVehicle::Influencer::gapControlSpeed(SUMOTime currentTime, const SUMOVehicle*
const double currentSpeed = veh->getSpeed();
const MSVehicle* msVeh = dynamic_cast<const MSVehicle*>(veh);
assert(msVeh != nullptr);
const double desiredTargetSpacing = myGapControlState->tauTarget*currentSpeed;
std::pair<const MSVehicle* const, double> leaderInfo = msVeh->getLeader(desiredTargetSpacing + 20.);
const double desiredTargetTimeSpacing = myGapControlState->tauTarget*currentSpeed;
std::pair<const MSVehicle* const, double> leaderInfo = msVeh->getLeader(desiredTargetTimeSpacing + 20.);
#ifdef DEBUG_TRACI
if DEBUG_COND2(veh) {
const double desiredCurrentSpacing = myGapControlState->tauCurrent*currentSpeed;
std::cout << " Gap control active:"
<< " currentSpeed=" << currentSpeed
<< ", desiredTargetSpacing=" << desiredTargetSpacing
<< ", desiredTargetTimeSpacing=" << desiredTargetTimeSpacing
<< ", desiredCurrentSpacing=" << desiredCurrentSpacing
<< ", leader=" << (leaderInfo.first==nullptr ? "NULL" : leaderInfo.first->getID())
<< ", dist=" << leaderInfo.second
Expand Down Expand Up @@ -467,7 +470,7 @@ MSVehicle::Influencer::gapControlSpeed(SUMOTime currentTime, const SUMOVehicle*
if (myGapControlState->tauCurrent == myGapControlState->tauTarget) {
if (!myGapControlState->gapAttained) {
// Check if the desired gap was established (add the POSITIONAL_EPS to avoid infinite asymptotic behavior without having established the gap)
myGapControlState->gapAttained = leaderInfo.first == nullptr || leaderInfo.second > desiredTargetSpacing - POSITION_EPS;
myGapControlState->gapAttained = leaderInfo.first == nullptr || leaderInfo.second > MAX2(desiredTargetTimeSpacing, myGapControlState->addGapTarget) - POSITION_EPS;
#ifdef DEBUG_TRACI
if DEBUG_COND2(veh) {
if (myGapControlState->gapAttained){
Expand All @@ -494,11 +497,9 @@ MSVehicle::Influencer::gapControlSpeed(SUMOTime currentTime, const SUMOVehicle*
}
}
} else {
if (myGapControlState->tauOriginal <= myGapControlState->tauTarget) {
myGapControlState->tauCurrent = MIN2(myGapControlState->tauCurrent + myGapControlState->changeRate*TS, myGapControlState->tauTarget);
} else {
myGapControlState->tauCurrent = MAX2(myGapControlState->tauCurrent - myGapControlState->changeRate*TS, myGapControlState->tauTarget);
}
// Adjust current headway values
myGapControlState->tauCurrent = MIN2(myGapControlState->tauCurrent + myGapControlState->timeHeadwayIncrement, myGapControlState->tauTarget);
myGapControlState->addGapCurrent = MIN2(myGapControlState->addGapCurrent + myGapControlState->spaceHeadwayIncrement, myGapControlState->addGapTarget);
}
}
if (myConsiderSafeVelocity) {
Expand Down
17 changes: 12 additions & 5 deletions src/microsim/MSVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -1353,17 +1353,22 @@ class MSVehicle : public MSBaseVehicle {
/// @brief Container for state and parameters of the gap control
struct GapControlState {
GapControlState();
void activate(double tauOriginal, double tauTarget, double duration, double changeRate, double maxDecel);
void activate(double tauOriginal, double tauTarget, double additionalGap, double duration, double changeRate, double maxDecel);
void deactivate();
/// @brief Original value for the desired headway (will be reset after duration has expired)
double tauOriginal;
/// @brief Current, interpolated value for the desired headway
/// @brief Current, interpolated value for the desired time headway
double tauCurrent;
/// @brief Target value for the desired headway
/// @brief Target value for the desired time headway
double tauTarget;
/// @brief Current, interpolated value for the desired space headway
double addGapCurrent;
/// @brief Target value for the desired space headway
double addGapTarget;
/// @brief Remaining duration for keeping the target headway
double remainingDuration;
/// @brief Rate by which the current headway is changed towards the target value
/// @brief Rate by which the current time and space headways are changed towards the target value.
/// (A rate of one corresponds to reaching the target value within one second)
double changeRate;
/// @brief Maximal deceleration to be applied due to the adapted headway
double maxDecel;
Expand All @@ -1375,6 +1380,8 @@ class MSVehicle : public MSBaseVehicle {
const MSVehicle* prevLeader;
/// @brief Time of the last update of the gap control
SUMOTime lastUpdate;
/// @brief cache storage for the headway increments of the current operation
double timeHeadwayIncrement, spaceHeadwayIncrement;
};
public:
/// @brief Constructor
Expand All @@ -1392,7 +1399,7 @@ class MSVehicle : public MSBaseVehicle {

/** @brief Activates the gap control with the given parameters, @see GapControlState
*/
void activateGapController(double originalTau, double newTau, double duration, double changeRate, double maxDecel);
void activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel);

/** @brief Deactivates the gap control
*/
Expand Down
33 changes: 21 additions & 12 deletions src/traci-server/TraCIServerAPI_Vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,27 +486,36 @@ TraCIServerAPI_Vehicle::processSet(TraCIServer& server, tcpip::Storage& inputSto
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "Create gap needs a compound object description.", outputStorage);
}
const int nParameter = inputStorage.readInt();
if (nParameter != 3 && nParameter != 4) {
if (nParameter != 4 && nParameter != 5) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "Create gap needs a compound object description of three or four items.", outputStorage);
}
double newTau = 0;
if (!server.readTypeCheckingDouble(inputStorage, newTau)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The first create gap parameter must be the new desired headway (tau) given as a double.", outputStorage);
double newTimeHeadway = 0;
if (!server.readTypeCheckingDouble(inputStorage, newTimeHeadway)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The first create gap parameter must be the new desired time headway (tau) given as a double.", outputStorage);
}
double newSpaceHeadway = 0;
if (!server.readTypeCheckingDouble(inputStorage, newSpaceHeadway)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The second create gap parameter must be the new desired space headway given as a double.", outputStorage);
}
double duration = 0.;
if (!server.readTypeCheckingDouble(inputStorage, duration)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The second create gap parameter must be the duration given as a double.", outputStorage);
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The third create gap parameter must be the duration given as a double.", outputStorage);
}
double changeRate = 0;
if (!server.readTypeCheckingDouble(inputStorage, changeRate)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The third create gap parameter must be the change rate given as a double.", outputStorage);
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The fourth create gap parameter must be the change rate given as a double.", outputStorage);
}

if (newTau == -1 && duration == -1 && changeRate == -1) {
if (newTimeHeadway == -1 && newSpaceHeadway == -1 && duration == -1 && changeRate == -1) {
libsumo::Vehicle::deactivateGapControl(id);
} else {
if (newTau <= 0) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The value for the new desired headway (tau) must be positive for create gap", outputStorage);
if (newTimeHeadway <= 0) {
if (newTimeHeadway != -1) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The value for the new desired time headway (tau) must be positive for create gap", outputStorage);
} // else: keep vehicles current headway
}
if (newSpaceHeadway < 0) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The value for the new desired space headway must be non-negative for create gap", outputStorage);
}
if (duration < 0 || SIMTIME + duration > STEPS2TIME(SUMOTime_MAX - DELTA_T)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "Invalid time interval for create gap", outputStorage);
Expand All @@ -515,15 +524,15 @@ TraCIServerAPI_Vehicle::processSet(TraCIServer& server, tcpip::Storage& inputSto
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The value for the change rate must be positive for create gap", outputStorage);
}
double maxDecel = -1;
if (nParameter == 4) {
if (nParameter == 5) {
if (!server.readTypeCheckingDouble(inputStorage, maxDecel)) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The fourth create gap parameter must be the maximal deceleration given as a double.", outputStorage);
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The fifth create gap parameter must be the maximal deceleration given as a double.", outputStorage);
}
if (changeRate <= 0) {
return server.writeErrorStatusCmd(CMD_SET_VEHICLE_VARIABLE, "The value for the maximal deceleration must be positive for create gap", outputStorage);
}
}
libsumo::Vehicle::openGap(id, newTau, duration, changeRate, maxDecel);
libsumo::Vehicle::openGap(id, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel);
}
}
break;
Expand Down
19 changes: 10 additions & 9 deletions tools/traci/_vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,36 +957,37 @@ def slowDown(self, vehID, speed, duration):
"!BiBdBd", tc.TYPE_COMPOUND, 2, tc.TYPE_DOUBLE, speed, tc.TYPE_DOUBLE, duration)
self._connection._sendExact()

def openGap(self, vehID, newHeadway, duration, changeRate, maxDecel = -1):
"""openGap(string, double, double, double, double) -> None
def openGap(self, vehID, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel = -1):
"""openGap(string, double, double, double, double, double) -> None
Changes the vehicle's desired headway (cf-parameter tau) smoothly to the given new value
using the given change rate. The vehicle is commanded to keep the increased headway for
Changes the vehicle's desired time headway (cf-parameter tau) smoothly to the given new value
using the given change rate. Similarly, the given space headway is applied gradually to achieve a minimal spacial gap.
The vehicle is commanded to keep the increased headway for
the given duration once its target value is attained. Optionally, a maximal value for the
deceleration (>0) can be given to prevent harsh braking due to the change of tau.
Note that this does only affect the following behavior regarding the current leader and does
not influence the gap acceptance during lane change, etc.
"""
if type(duration) is int and duration >= 1000:
warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
nParams = 3 + int(maxDecel>0)
nParams = 4 + int(maxDecel>0)
msgLength = 1 + 4 + (1 + 8)*nParams # compoundType, nParams, newHeadway, duration, changeRate, [maxDecel]
self._connection._beginMessage(
tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_OPENGAP, vehID, msgLength)
if (nParams == 3):
if (nParams == 4):
self._connection._string += struct.pack(
"!BiBdBdBd", tc.TYPE_COMPOUND, nParams, tc.TYPE_DOUBLE, newHeadway, tc.TYPE_DOUBLE, duration, tc.TYPE_DOUBLE, changeRate)
"!BiBdBdBdBd", tc.TYPE_COMPOUND, nParams, tc.TYPE_DOUBLE, newTimeHeadway, tc.TYPE_DOUBLE, newSpaceHeadway, tc.TYPE_DOUBLE, duration, tc.TYPE_DOUBLE, changeRate)
else:
self._connection._string += struct.pack(
"!BiBdBdBdBd", tc.TYPE_COMPOUND, nParams, tc.TYPE_DOUBLE, newHeadway, tc.TYPE_DOUBLE, duration, tc.TYPE_DOUBLE, changeRate, tc.TYPE_DOUBLE, maxDecel)
"!BiBdBdBdBdBd", tc.TYPE_COMPOUND, nParams, tc.TYPE_DOUBLE, newTimeHeadway, tc.TYPE_DOUBLE, newSpaceHeadway, tc.TYPE_DOUBLE, duration, tc.TYPE_DOUBLE, changeRate, tc.TYPE_DOUBLE, maxDecel)
self._connection._sendExact()

def deactivateGapControl(self, vehID):
"""deactivateGapControl(string) -> None
Deactivate the vehicle's gap control
"""
self.openGap(vehID, -1, -1, -1)
self.openGap(vehID, -1, -1, -1, -1)


def changeTarget(self, vehID, edgeID):
Expand Down

0 comments on commit 6fc768b

Please sign in to comment.