SUMO - Simulation of Urban MObility
MSLCM_LC2013.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // A lane change model developed by D. Krajzewicz, J. Erdmann et al. between 2004 and 2013
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
14 // Copyright (C) 2001-2016 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 
26 // ===========================================================================
27 // included modules
28 // ===========================================================================
29 #ifdef _MSC_VER
30 #include <windows_config.h>
31 #else
32 #include <config.h>
33 #endif
34 
35 #include <iostream>
37 #include <microsim/MSEdge.h>
38 #include <microsim/MSLane.h>
39 #include <microsim/MSNet.h>
40 #include "MSLCM_LC2013.h"
41 
42 #ifdef CHECK_MEMORY_LEAKS
43 #include <foreign/nvwa/debug_new.h>
44 #endif // CHECK_MEMORY_LEAKS
45 
46 //#define DEBUG_VEHICLE_GUI_SELECTION 1
47 
48 // ===========================================================================
49 // variable definitions
50 // ===========================================================================
51 // 80km/h will be the threshold for dividing between long/short foresight
52 #define LOOK_FORWARD_SPEED_DIVIDER (SUMOReal)14.
53 
54 #define LOOK_FORWARD_RIGHT (SUMOReal)10.
55 #define LOOK_FORWARD_LEFT (SUMOReal)20.
56 
57 #define JAM_FACTOR (SUMOReal)1.
58 
59 #define LCA_RIGHT_IMPATIENCE (SUMOReal)-1.
60 #define CUT_IN_LEFT_SPEED_THRESHOLD (SUMOReal)27.
61 
62 #define LOOK_AHEAD_MIN_SPEED (SUMOReal)0.0
63 #define LOOK_AHEAD_SPEED_MEMORY (SUMOReal)0.9
64 #define LOOK_AHEAD_SPEED_DECREMENT 6.
65 
66 #define HELP_DECEL_FACTOR (SUMOReal)1.0
67 
68 #define HELP_OVERTAKE (SUMOReal)(10.0 / 3.6)
69 #define MIN_FALLBEHIND (SUMOReal)(14.0 / 3.6)
70 
71 #define URGENCY (SUMOReal)2.0
72 
73 #define ROUNDABOUT_DIST_BONUS (SUMOReal)80.0
74 
75 #define CHANGE_PROB_THRESHOLD_RIGHT (SUMOReal)2.0
76 #define CHANGE_PROB_THRESHOLD_LEFT (SUMOReal)0.2
77 #define KEEP_RIGHT_TIME (SUMOReal)5.0 // the number of seconds after which a vehicle should move to the right lane
78 #define KEEP_RIGHT_ACCEPTANCE (SUMOReal)2.0 // calibration factor for determining the desire to keep right
79 
80 #define RELGAIN_NORMALIZATION_MIN_SPEED (SUMOReal)10.0
81 
82 // ===========================================================================
83 // member method definitions
84 // ===========================================================================
87  mySpeedGainProbability(0),
88  myKeepRightProbability(0),
89  myLeadingBlockerLength(0),
90  myLeftSpace(0),
91  myLookAheadSpeed(LOOK_AHEAD_MIN_SPEED) {
92 }
93 
95  changed(0);
96 }
97 
98 
99 int
101  int laneOffset,
103  int blocked,
104  const std::pair<MSVehicle*, SUMOReal>& leader,
105  const std::pair<MSVehicle*, SUMOReal>& neighLead,
106  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
107  const MSLane& neighLane,
108  const std::vector<MSVehicle::LaneQ>& preb,
109  MSVehicle** lastBlocked,
110  MSVehicle** firstBlocked) {
111  const int result = _wantsChange(laneOffset, msgPass, blocked, leader, neighLead, neighFollow, neighLane, preb, lastBlocked, firstBlocked);
112  return result;
113 }
114 
115 
116 SUMOReal
117 MSLCM_LC2013::patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel& cfModel) {
118  const SUMOReal newSpeed = _patchSpeed(min, wanted, max, cfModel);
119  return newSpeed;
120 }
121 
122 
123 SUMOReal
124 MSLCM_LC2013::_patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel& cfModel) {
125  int state = myOwnState;
126 
127  // letting vehicles merge in at the end of the lane in case of counter-lane change, step#2
128  SUMOReal MAGIC_offset = 1.;
129  // if we want to change and have a blocking leader and there is enough room for him in front of us
130  if (myLeadingBlockerLength != 0) {
132  if (space > 0) {
133  // compute speed for decelerating towards a place which allows the blocking leader to merge in in front
134  SUMOReal safe = cfModel.stopSpeed(&myVehicle, myVehicle.getSpeed(), space);
135  // if we are approaching this place
136  if (safe < wanted) {
137  // return this speed as the speed to use
138  return MAX2(min, safe);
139  }
140  }
141  }
142 
143  SUMOReal nVSafe = wanted;
144  bool gotOne = false;
145  for (std::vector<SUMOReal>::const_iterator i = myVSafes.begin(); i != myVSafes.end(); ++i) {
146  SUMOReal v = (*i);
147  if (v >= min && v <= max) {
148  nVSafe = MIN2(v, nVSafe);
149  gotOne = true;
150  } else {
151  }
152  }
153 
154  if (gotOne && !myDontBrake) {
155  return nVSafe;
156  }
157 
158  // check whether the vehicle is blocked
159  if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) != 0) {
160  if ((state & LCA_STRATEGIC) != 0) {
161  // necessary decelerations are controlled via vSafe. If there are
162  // none it means we should speed up
163  return (max + wanted) / (SUMOReal) 2.0;
164  } else if ((state & LCA_COOPERATIVE) != 0) {
165  // only minor adjustments in speed should be done
166  if ((state & LCA_BLOCKED_BY_LEADER) != 0) {
167  return (min + wanted) / (SUMOReal) 2.0;
168  }
169  if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
170  return (max + wanted) / (SUMOReal) 2.0;
171  }
172  }
173  }
174 
175  // accelerate if being a blocking leader or blocking follower not able to brake
176  // (and does not have to change lanes)
177  if ((state & LCA_AMBLOCKINGLEADER) != 0) {
178  return (max + wanted) / (SUMOReal) 2.0;
179  }
180 
181  if ((state & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
182  }
183  if (myVehicle.getLane()->getEdge().getLanes().size() == 1) {
184  // remove chaning information if on a road with a single lane
185  changed(0);
186  }
187  return wanted;
188 }
189 
190 
191 void*
192 MSLCM_LC2013::inform(void* info, MSVehicle* /* sender */) {
193  Info* pinfo = (Info*) info;
194  myVSafes.push_back(pinfo->first);
195  myOwnState |= pinfo->second;
196  delete pinfo;
197  return (void*) true;
198 }
199 
200 
201 SUMOReal
203  int blocked,
204  int dir,
205  const std::pair<MSVehicle*, SUMOReal>& neighLead,
206  SUMOReal remainingSeconds) {
207  SUMOReal plannedSpeed = MIN2(myVehicle.getSpeed(),
209  for (std::vector<SUMOReal>::const_iterator i = myVSafes.begin(); i != myVSafes.end(); ++i) {
210  SUMOReal v = (*i);
212  plannedSpeed = MIN2(plannedSpeed, v);
213  }
214  }
215  if ((blocked & LCA_BLOCKED_BY_LEADER) != 0) {
216  assert(neighLead.first != 0);
217  MSVehicle* nv = neighLead.first;
218  // decide whether we want to overtake the leader or follow it
219  const SUMOReal dv = plannedSpeed - nv->getSpeed();
220  const SUMOReal overtakeDist = (neighLead.second // drive to back of follower
221  + nv->getVehicleType().getLengthWithGap() // drive to front of follower
222  + myVehicle.getVehicleType().getLength() // ego back reaches follower front
223  + nv->getCarFollowModel().getSecureGap( // save gap to follower
225 
226  if (dv < 0
227  // overtaking on the right on an uncongested highway is forbidden (noOvertakeLCLeft)
229  // not enough space to overtake?
230  || myLeftSpace < overtakeDist
231  // not enough time to overtake?
232  || dv * remainingSeconds < overtakeDist) {
233  // cannot overtake
234  msgPass.informNeighLeader(new Info(-1, dir | LCA_AMBLOCKINGLEADER), &myVehicle);
235  // slow down smoothly to follow leader
236  const SUMOReal targetSpeed = myCarFollowModel.followSpeed(
237  &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
238  if (targetSpeed < myVehicle.getSpeed()) {
239  // slow down smoothly to follow leader
241  MAX2(MIN_FALLBEHIND, (myVehicle.getSpeed() - targetSpeed) / remainingSeconds)));
242  const SUMOReal nextSpeed = MIN2(plannedSpeed, myVehicle.getSpeed() - decel);
243  myVSafes.push_back(nextSpeed);
244  return nextSpeed;
245  } else {
246  // leader is fast enough anyway
247  myVSafes.push_back(targetSpeed);
248  return plannedSpeed;
249  }
250  } else {
251  // overtaking, leader should not accelerate
252  msgPass.informNeighLeader(new Info(nv->getSpeed(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
253  return -1;
254  }
255  } else if (neighLead.first != 0) { // (remainUnblocked)
256  // we are not blocked now. make sure we stay far enough from the leader
257  MSVehicle* nv = neighLead.first;
258  const SUMOReal nextNVSpeed = nv->getSpeed() - HELP_OVERTAKE; // conservative
259  const SUMOReal dv = SPEED2DIST(myVehicle.getSpeed() - nextNVSpeed);
260  const SUMOReal targetSpeed = myCarFollowModel.followSpeed(
261  &myVehicle, myVehicle.getSpeed(), neighLead.second - dv, nextNVSpeed, nv->getCarFollowModel().getMaxDecel());
262  myVSafes.push_back(targetSpeed);
263  return MIN2(targetSpeed, plannedSpeed);
264  } else {
265  // not overtaking
266  return plannedSpeed;
267  }
268 }
269 
270 
271 void
273  int blocked,
274  int dir,
275  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
276  SUMOReal remainingSeconds,
277  SUMOReal plannedSpeed) {
278  if ((blocked & LCA_BLOCKED_BY_FOLLOWER) != 0) {
279  assert(neighFollow.first != 0);
280  MSVehicle* nv = neighFollow.first;
281 
282  // are we fast enough to cut in without any help?
283  if (plannedSpeed - nv->getSpeed() >= HELP_OVERTAKE) {
284  const SUMOReal neededGap = nv->getCarFollowModel().getSecureGap(nv->getSpeed(), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
285  if ((neededGap - neighFollow.second) / remainingSeconds < (plannedSpeed - nv->getSpeed())) {
286  // follower might even accelerate but not to much
287  msgPass.informNeighFollower(new Info(plannedSpeed - HELP_OVERTAKE, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
288  return;
289  }
290  }
291  // decide whether we will request help to cut in before the follower or allow to be overtaken
292 
293  // PARAMETERS
294  // assume other vehicle will assume the equivalent of 1 second of
295  // maximum deceleration to help us (will probably be spread over
296  // multiple seconds)
297  // -----------
298  const SUMOReal helpDecel = nv->getCarFollowModel().getMaxDecel() * HELP_DECEL_FACTOR ;
299 
300  // change in the gap between ego and blocker over 1 second (not STEP!)
301  const SUMOReal neighNewSpeed = MAX2((SUMOReal)0, nv->getSpeed() - ACCEL2SPEED(helpDecel));
302  const SUMOReal neighNewSpeed1s = MAX2((SUMOReal)0, nv->getSpeed() - helpDecel);
303  const SUMOReal dv = plannedSpeed - neighNewSpeed1s;
304  // new gap between follower and self in case the follower does brake for 1s
305  const SUMOReal decelGap = neighFollow.second + dv;
306  const SUMOReal secureGap = nv->getCarFollowModel().getSecureGap(neighNewSpeed1s, plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
307  if (decelGap > 0 && decelGap >= secureGap) {
308  // if the blocking neighbor brakes it could actually help
309  // how hard does it actually need to be?
310  // to be safe in the next step the following equation has to hold:
311  // vsafe <= followSpeed(gap=currentGap - SPEED2DIST(vsafe), ...)
312  // we compute an upper bound on vsafe by doing the computation twice
313  const SUMOReal vsafe1 = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
314  nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel()));
315  const SUMOReal vsafe = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
316  nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed - vsafe1), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel()));
317  assert(vsafe <= vsafe1);
318  msgPass.informNeighFollower(new Info(vsafe, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
319  } else if (dv > 0 && dv * remainingSeconds > (secureGap - decelGap + POSITION_EPS)) {
320  // decelerating once is sufficient to open up a large enough gap in time
321  msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
322  } else {
324  //if (dir == LCA_MRIGHT && myVehicle.getWaitingSeconds() > LCA_RIGHT_IMPATIENCE &&
325  // nv->getSpeed() > myVehicle.getSpeed()) {
326  if (nv->getSpeed() > myVehicle.getSpeed() &&
328  || (dir == LCA_MLEFT && plannedSpeed > CUT_IN_LEFT_SPEED_THRESHOLD) // VARIANT_22 (slowDownLeft)
329  )) {
330  // let the follower slow down to increase the likelyhood that later vehicles will be slow enough to help
331  // follower should still be fast enough to open a gap
332  vhelp = MAX2(neighNewSpeed, myVehicle.getSpeed() + HELP_OVERTAKE);
333  if ((nv->getSpeed() - myVehicle.getSpeed()) / helpDecel < remainingSeconds) {
334  msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
335  return;
336  }
337  }
338  msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
339  // this follower is supposed to overtake us. slow down smoothly to allow this
340  const SUMOReal overtakeDist = (neighFollow.second // follower reaches ego back
341  + myVehicle.getVehicleType().getLengthWithGap() // follower reaches ego front
342  + nv->getVehicleType().getLength() // follower back at ego front
343  + myVehicle.getCarFollowModel().getSecureGap( // follower has safe dist to ego
344  plannedSpeed, vhelp, nv->getCarFollowModel().getMaxDecel()));
345  // speed difference to create a sufficiently large gap
346  const SUMOReal needDV = overtakeDist / remainingSeconds;
347  // make sure the deceleration is not to strong
348  myVSafes.push_back(MAX2(vhelp - needDV, myVehicle.getSpeed() - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxDecel())));
349  }
350  }
351 }
352 
353 
354 void
356  // keep information about strategic change direction
359  myLeftSpace = 0;
360  myVSafes.clear();
361  myDontBrake = false;
362  // truncate to work around numerical instability between different builds
363  mySpeedGainProbability = ceil(mySpeedGainProbability * 100000.0) * 0.00001;
364  myKeepRightProbability = ceil(myKeepRightProbability * 100000.0) * 0.00001;
365 }
366 
367 
368 void
370  myOwnState = 0;
373  if (myVehicle.getBestLaneOffset() == 0) {
374  // if we are not yet on our best lane there might still be unseen blockers
375  // (during patchSpeed)
377  myLeftSpace = 0;
378  }
380  myVSafes.clear();
381  myDontBrake = false;
383 }
384 
385 
386 int
388  int laneOffset,
390  int blocked,
391  const std::pair<MSVehicle*, SUMOReal>& leader,
392  const std::pair<MSVehicle*, SUMOReal>& neighLead,
393  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
394  const MSLane& neighLane,
395  const std::vector<MSVehicle::LaneQ>& preb,
396  MSVehicle** lastBlocked,
397  MSVehicle** firstBlocked) {
398  assert(laneOffset == 1 || laneOffset == -1);
399  const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
400  // compute bestLaneOffset
401  MSVehicle::LaneQ curr, neigh, best;
402  int bestLaneOffset = 0;
403  SUMOReal currentDist = 0;
404  SUMOReal neighDist = 0;
405  int currIdx = 0;
406  MSLane* prebLane = myVehicle.getLane();
407  if (prebLane->getEdge().getPurpose() == MSEdge::EDGEFUNCTION_INTERNAL) {
408  // internal edges are not kept inside the bestLanes structure
409  prebLane = prebLane->getLinkCont()[0]->getLane();
410  }
411  for (int p = 0; p < (int) preb.size(); ++p) {
412  if (preb[p].lane == prebLane && p + laneOffset >= 0) {
413  assert(p + laneOffset < (int)preb.size());
414  curr = preb[p];
415  neigh = preb[p + laneOffset];
416  currentDist = curr.length;
417  neighDist = neigh.length;
418  bestLaneOffset = curr.bestLaneOffset;
419  if (bestLaneOffset == 0 && preb[p + laneOffset].bestLaneOffset == 0) {
420  bestLaneOffset = laneOffset;
421  }
422  best = preb[p + bestLaneOffset];
423  currIdx = p;
424  break;
425  }
426  }
427  // direction specific constants
428  const bool right = (laneOffset == -1);
429  const int lca = (right ? LCA_RIGHT : LCA_LEFT);
430  const int myLca = (right ? LCA_MRIGHT : LCA_MLEFT);
431  const int lcaCounter = (right ? LCA_LEFT : LCA_RIGHT);
432  const bool changeToBest = (right && bestLaneOffset < 0) || (!right && bestLaneOffset > 0);
433  // keep information about being a leader/follower
434  int ret = (myOwnState & 0xffff0000);
435  int req = 0; // the request to change or stay
436 
437  ret = slowDownForBlocked(lastBlocked, ret);
438  if (lastBlocked != firstBlocked) {
439  ret = slowDownForBlocked(firstBlocked, ret);
440  }
441 
442 
443  // we try to estimate the distance which is necessary to get on a lane
444  // we have to get on in order to keep our route
445  // we assume we need something that depends on our velocity
446  // and compare this with the free space on our wished lane
447  //
448  // if the free space is somehow less than the space we need, we should
449  // definitely try to get to the desired lane
450  //
451  // this rule forces our vehicle to change the lane if a lane changing is necessary soon
452  // lookAheadDistance:
453  // we do not want the lookahead distance to change all the time so we discrectize the speed a bit
454 
457  } else {
460  }
462  laDist += myVehicle.getVehicleType().getLengthWithGap() * (SUMOReal) 2.;
463 
464  // react to a stopped leader on the current lane
465  if (bestLaneOffset == 0 && leader.first != 0 && leader.first->isStopped()) {
466  // value is doubled for the check since we change back and forth
467  laDist = 0.5 * (myVehicle.getVehicleType().getLengthWithGap()
468  + leader.first->getVehicleType().getLengthWithGap());
469  }
470 
471  // free space that is available for changing
472  //const SUMOReal neighSpeed = (neighLead.first != 0 ? neighLead.first->getSpeed() :
473  // neighFollow.first != 0 ? neighFollow.first->getSpeed() :
474  // best.lane->getSpeedLimit());
475  // @note: while this lets vehicles change earlier into the correct direction
476  // it also makes the vehicles more "selfish" and prevents changes which are necessary to help others
477 
478  int roundaboutEdgesAhead = 0;
479  for (std::vector<MSLane*>::iterator it = curr.bestContinuations.begin(); it != curr.bestContinuations.end(); ++it) {
480  if ((*it) != 0 && (*it)->getEdge().isRoundabout()) {
481  roundaboutEdgesAhead += 1;
482  } else if (roundaboutEdgesAhead > 0) {
483  // only check the next roundabout
484  break;
485  }
486  }
487  int roundaboutEdgesAheadNeigh = 0;
488  for (std::vector<MSLane*>::iterator it = neigh.bestContinuations.begin(); it != neigh.bestContinuations.end(); ++it) {
489  if ((*it) != 0 && (*it)->getEdge().isRoundabout()) {
490  roundaboutEdgesAheadNeigh += 1;
491  } else if (roundaboutEdgesAheadNeigh > 0) {
492  // only check the next roundabout
493  break;
494  }
495  }
496  if (roundaboutEdgesAhead > 1) {
497  currentDist += roundaboutEdgesAhead * ROUNDABOUT_DIST_BONUS;
498  neighDist += roundaboutEdgesAheadNeigh * ROUNDABOUT_DIST_BONUS;
499  }
500 
501  const SUMOReal usableDist = (currentDist - myVehicle.getPositionOnLane() - best.occupation * JAM_FACTOR);
502  const SUMOReal maxJam = MAX2(preb[currIdx + laneOffset].occupation, preb[currIdx].occupation);
503  const SUMOReal neighLeftPlace = MAX2((SUMOReal) 0, neighDist - myVehicle.getPositionOnLane() - maxJam);
504 
505  if (changeToBest && bestLaneOffset == curr.bestLaneOffset
506  && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
508  ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
509  } else {
510 
511  if (!myAllowOvertakingRight && !right && !myVehicle.congested() && neighLead.first != 0) {
512  // check for slower leader on the left. we should not overtake but
513  // rather move left ourselves (unless congested)
514  MSVehicle* nv = neighLead.first;
515  if (nv->getSpeed() < myVehicle.getSpeed()) {
516  const SUMOReal vSafe = myCarFollowModel.followSpeed(
517  &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
518  myVSafes.push_back(vSafe);
519  if (vSafe < myVehicle.getSpeed()) {
521  }
522  }
523  }
524 
525  if (!changeToBest && (currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist))) {
526  // the opposite lane-changing direction should be done than the one examined herein
527  // we'll check whether we assume we could change anyhow and get back in time...
528  //
529  // this rule prevents the vehicle from moving in opposite direction of the best lane
530  // unless the way till the end where the vehicle has to be on the best lane
531  // is long enough
532  ret = ret | LCA_STAY | LCA_STRATEGIC;
533  } else if (bestLaneOffset == 0 && (neighLeftPlace * 2. < laDist)) {
534  // the current lane is the best and a lane-changing would cause a situation
535  // of which we assume we will not be able to return to the lane we have to be on.
536  // this rule prevents the vehicle from leaving the current, best lane when it is
537  // close to this lane's end
538  ret = ret | LCA_STAY | LCA_STRATEGIC;
539  }
540  }
541  // check for overriding TraCI requests
543  if ((ret & lcaCounter) != 0) {
544  // we are not interested in traci requests for the opposite direction here
545  ret &= ~(LCA_TRACI | lcaCounter | LCA_URGENT);
546  }
547 
548  if ((ret & LCA_STAY) != 0) {
549  return ret;
550  }
551  if ((ret & LCA_URGENT) != 0) {
552  // prepare urgent lane change maneuver
553  // save the left space
554  myLeftSpace = currentDist - myVehicle.getPositionOnLane();
555  if (changeToBest && abs(bestLaneOffset) > 1) {
556  // there might be a vehicle which needs to counter-lane-change one lane further and we cannot see it yet
557  myLeadingBlockerLength = MAX2((SUMOReal)(right ? 20.0 : 40.0), myLeadingBlockerLength);
558  }
559 
560  // letting vehicles merge in at the end of the lane in case of counter-lane change, step#1
561  // if there is a leader and he wants to change to the opposite direction
562  saveBlockerLength(neighLead.first, lcaCounter);
563  if (*firstBlocked != neighLead.first) {
564  saveBlockerLength(*firstBlocked, lcaCounter);
565  }
566 
567  const SUMOReal remainingSeconds = ((ret & LCA_TRACI) == 0 ?
570  const SUMOReal plannedSpeed = informLeader(msgPass, blocked, myLca, neighLead, remainingSeconds);
571  if (plannedSpeed >= 0) {
572  // maybe we need to deal with a blocking follower
573  informFollower(msgPass, blocked, myLca, neighFollow, remainingSeconds, plannedSpeed);
574  }
575 
576  return ret;
577  }
578 
579  if (roundaboutEdgesAhead > 1) {
580  // try to use the inner lanes of a roundabout to increase throughput
581  // unless we are approaching the exit
582  if (lca == LCA_LEFT) {
583  req = ret | lca | LCA_COOPERATIVE;
584  } else {
585  req = ret | LCA_STAY | LCA_COOPERATIVE;
586  }
587  if (!cancelRequest(req)) {
588  return ret | req;
589  }
590  }
591 
592  // let's also regard the case where the vehicle is driving on a highway...
593  // in this case, we do not want to get to the dead-end of an on-ramp
594  if (right) {
595  if (bestLaneOffset == 0 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6 && myLookAheadSpeed > SUMO_const_haltingSpeed) {
596  req = ret | LCA_STAY | LCA_STRATEGIC;
597  if (!cancelRequest(req)) {
598  return ret | req;
599  }
600  }
601  }
602  // --------
603 
604  // -------- make place on current lane if blocking follower
605  //if (amBlockingFollowerPlusNB()) {
606  // std::cout << myVehicle.getID() << ", " << currentDistAllows(neighDist, bestLaneOffset, laDist)
607  // << " neighDist=" << neighDist
608  // << " currentDist=" << currentDist
609  // << "\n";
610  //}
612  && (changeToBest || currentDistAllows(neighDist, abs(bestLaneOffset) + 1, laDist))) {
613 
614  req = ret | lca | LCA_COOPERATIVE | LCA_URGENT ;//| LCA_CHANGE_TO_HELP;
615  if (!cancelRequest(req)) {
616  return ret | req;
617  }
618  }
619 
620  // --------
621 
622 
625  //if ((blocked & LCA_BLOCKED) != 0) {
626  // return ret;
627  //}
629 
630  // -------- higher speed
631  //if ((congested(neighLead.first) && neighLead.second < 20) || predInteraction(leader.first)) { //!!!
632  // return ret;
633  //}
635  SUMOReal neighLaneVSafe = neighLane.getVehicleMaxSpeed(&myVehicle);
636  if (neighLead.first == 0) {
637  neighLaneVSafe = MIN2(neighLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), neighDist, 0, 0));
638  } else {
639  // @todo: what if leader is below safe gap?!!!
640  neighLaneVSafe = MIN2(neighLaneVSafe, myCarFollowModel.followSpeed(
641  &myVehicle, myVehicle.getSpeed(), neighLead.second, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()));
642  }
643  if (leader.first == 0) {
644  thisLaneVSafe = MIN2(thisLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), currentDist, 0, 0));
645  } else {
646  // @todo: what if leader is below safe gap?!!!
647  thisLaneVSafe = MIN2(thisLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), leader.second, leader.first->getSpeed(), leader.first->getCarFollowModel().getMaxDecel()));
648  }
649 
651  thisLaneVSafe = MIN2(thisLaneVSafe, vMax);
652  neighLaneVSafe = MIN2(neighLaneVSafe, vMax);
653  const SUMOReal relativeGain = (neighLaneVSafe - thisLaneVSafe) / MAX2(neighLaneVSafe,
655 
656  if (right) {
657  // ONLY FOR CHANGING TO THE RIGHT
658  if (thisLaneVSafe - 5 / 3.6 > neighLaneVSafe) {
659  // ok, the current lane is faster than the right one...
660  if (mySpeedGainProbability < 0) {
661  mySpeedGainProbability *= pow(0.5, TS);
662  //myKeepRightProbability /= 2.0;
663  }
664  } else {
665  // ok, the current lane is not (much) faster than the right one
666  // @todo recheck the 5 km/h discount on thisLaneVSafe
667 
668  // do not promote changing to the left just because changing to the
669  // right is bad
670  if (mySpeedGainProbability < 0 || relativeGain > 0) {
671  mySpeedGainProbability -= TS * relativeGain;
672  }
673 
674  // honor the obligation to keep right (Rechtsfahrgebot)
675  // XXX consider fast approaching followers on the current lane
676  //const SUMOReal vMax = myLookAheadSpeed;
677  const SUMOReal acceptanceTime = KEEP_RIGHT_ACCEPTANCE * vMax * MAX2((SUMOReal)1, myVehicle.getSpeed()) / myVehicle.getLane()->getSpeedLimit();
678  SUMOReal fullSpeedGap = MAX2((SUMOReal)0, neighDist - myVehicle.getCarFollowModel().brakeGap(vMax));
679  SUMOReal fullSpeedDrivingSeconds = MIN2(acceptanceTime, fullSpeedGap / vMax);
680  if (neighLead.first != 0 && neighLead.first->getSpeed() < vMax) {
681  fullSpeedGap = MAX2((SUMOReal)0, MIN2(fullSpeedGap,
682  neighLead.second - myVehicle.getCarFollowModel().getSecureGap(
683  vMax, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel())));
684  fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - neighLead.first->getSpeed()));
685  }
686  const SUMOReal deltaProb = (CHANGE_PROB_THRESHOLD_RIGHT
688  * (fullSpeedDrivingSeconds / acceptanceTime) / KEEP_RIGHT_TIME);
689  myKeepRightProbability -= TS * deltaProb;
690 
691  if (gDebugFlag2) {
692  std::cout << STEPS2TIME(currentTime)
693  << " veh=" << myVehicle.getID()
694  << " vMax=" << vMax
695  << " neighDist=" << neighDist
696  << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed())
697  << " leaderSpeed=" << (neighLead.first == 0 ? -1 : neighLead.first->getSpeed())
698  << " secGap=" << (neighLead.first == 0 ? -1 : myVehicle.getCarFollowModel().getSecureGap(
699  myVehicle.getSpeed(), neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()))
700  << " acceptanceTime=" << acceptanceTime
701  << " fullSpeedGap=" << fullSpeedGap
702  << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
703  << " dProb=" << deltaProb
704  << "\n";
705  }
707  req = ret | lca | LCA_KEEPRIGHT;
708  if (!cancelRequest(req)) {
709  return ret | req;
710  }
711  }
712  }
713 
715  && neighDist / MAX2((SUMOReal) .1, myVehicle.getSpeed()) > 20.) { //./MAX2((SUMOReal) .1, myVehicle.getSpeed())) { // -.1
716  req = ret | lca | LCA_SPEEDGAIN;
717  if (!cancelRequest(req)) {
718  return ret | req;
719  }
720  }
721  } else {
722  // ONLY FOR CHANGING TO THE LEFT
723  if (thisLaneVSafe > neighLaneVSafe) {
724  // this lane is better
725  if (mySpeedGainProbability > 0) {
726  mySpeedGainProbability *= pow(0.5, TS);
727  }
728  } else {
729  // left lane is better
730  mySpeedGainProbability += TS * relativeGain;
731  }
732  if (mySpeedGainProbability > CHANGE_PROB_THRESHOLD_LEFT && neighDist / MAX2((SUMOReal) .1, myVehicle.getSpeed()) > 20.) { // .1
733  req = ret | lca | LCA_SPEEDGAIN;
734  if (!cancelRequest(req)) {
735  return ret | req;
736  }
737  }
738  }
739  // --------
740  if (changeToBest && bestLaneOffset == curr.bestLaneOffset
741  && (right ? mySpeedGainProbability < 0 : mySpeedGainProbability > 0)) {
742  // change towards the correct lane, speedwise it does not hurt
743  req = ret | lca | LCA_STRATEGIC;
744  if (!cancelRequest(req)) {
745  return ret | req;
746  }
747  }
748 
749  return ret;
750 }
751 
752 
753 int
755  // if this vehicle is blocking someone in front, we maybe decelerate to let him in
756  if ((*blocked) != 0) {
757  SUMOReal gap = (*blocked)->getPositionOnLane() - (*blocked)->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
758  if (gap > POSITION_EPS) {
760  if ((*blocked)->getSpeed() < SUMO_const_haltingSpeed) {
762  } else {
763  state |= LCA_AMBACKBLOCKER;
764  }
767  (SUMOReal)(gap - POSITION_EPS), (*blocked)->getSpeed(),
768  (*blocked)->getCarFollowModel().getMaxDecel()));
769  }
770  }
771  }
772  return state;
773 }
774 
775 
776 void
777 MSLCM_LC2013::saveBlockerLength(MSVehicle* blocker, int lcaCounter) {
778  if (blocker != 0 && (blocker->getLaneChangeModel().getOwnState() & lcaCounter) != 0) {
779  // is there enough space in front of us for the blocker?
782  if (blocker->getVehicleType().getLengthWithGap() <= potential) {
783  // save at least his length in myLeadingBlockerLength
785  } else {
786  // we cannot save enough space for the blocker. It needs to save
787  // space for ego instead
789  }
790  }
791 }
792 /****************************************************************************/
793 
void changed(int dir)
void saveBlockerLength(MSVehicle *blocker, int lcaCounter)
save space for vehicles which need to counter-lane-change
#define CHANGE_PROB_THRESHOLD_RIGHT
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:467
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:80
SUMOReal getMaxSpeed() const
Get vehicle&#39;s maximum speed [m/s].
long long int SUMOTime
Definition: SUMOTime.h:43
MSLCM_LC2013(MSVehicle &v)
#define SPEED2DIST(x)
Definition: SUMOTime.h:55
int wantsChange(int laneOffset, MSAbstractLaneChangeModel::MSLCMessager &msgPass, int blocked, const std::pair< MSVehicle *, SUMOReal > &leader, const std::pair< MSVehicle *, SUMOReal > &neighLead, const std::pair< MSVehicle *, SUMOReal > &neighFollow, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked)
Called to examine whether the vehicle wants to change using the given laneOffset. This method gets th...
void prepareStep()
#define min(a, b)
Definition: polyfonts.c:66
const MSCFModel & getCarFollowModel() const
Returns the vehicle&#39;s car following model definition.
Definition: MSVehicle.h:627
#define MIN_FALLBEHIND
SUMOReal patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel &cfModel)
Called to adapt the speed in order to allow a lane change.
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:61
#define LOOK_FORWARD_RIGHT
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:185
The action is done to help someone else.
SUMOReal getLengthWithGap() const
Get vehicle&#39;s length including the minimum gap [m].
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive...
Definition: MSVehicle.h:553
bool congested() const
Definition: MSVehicle.h:474
virtual SUMOReal followSpeed(const MSVehicle *const veh, SUMOReal speed, SUMOReal gap2pred, SUMOReal predSpeed, SUMOReal predMaxDecel) const =0
Computes the vehicle&#39;s follow speed (no dawdling)
#define KEEP_RIGHT_ACCEPTANCE
The car-following model abstraction.
Definition: MSCFModel.h:59
SUMOReal myKeepRightProbability
Definition: MSLCM_LC2013.h:181
void * informNeighFollower(void *info, MSVehicle *sender)
Informs the follower on the desired lane.
SUMOReal getLength() const
Get vehicle&#39;s length [m].
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:160
T MAX2(T a, T b)
Definition: StdDefs.h:75
SUMOTime DELTA_T
Definition: SUMOTime.cpp:39
SUMOReal getSecureGap(const SUMOReal speed, const SUMOReal leaderSpeed, const SUMOReal leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum.
Definition: MSCFModel.h:272
SUMOReal getPositionOnLane() const
Get the vehicle&#39;s position along the lane.
Definition: MSVehicle.h:340
std::vector< SUMOReal > myVSafes
Definition: MSLCM_LC2013.h:190
#define TS
Definition: SUMOTime.h:52
The action is due to a TraCI request.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:255
SUMOReal length
The overall length which may be driven when using this lane without a lane change.
Definition: MSVehicle.h:545
The action is urgent (to be defined by lc-model)
#define abs(a)
Definition: polyfonts.c:67
void informFollower(MSAbstractLaneChangeModel::MSLCMessager &msgPass, int blocked, int dir, const std::pair< MSVehicle *, SUMOReal > &neighFollow, SUMOReal remainingSeconds, SUMOReal plannedSpeed)
decide whether we will try cut in before the follower or allow to be overtaken
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:2025
#define ROUNDABOUT_DIST_BONUS
static bool myAllowOvertakingRight
whether overtaking on the right is permitted
A class responsible for exchanging messages between cars involved in lane-change interaction.
Wants go to the left.
bool currentDistDisallows(SUMOReal dist, int laneOffset, SUMOReal lookForwardDist)
Definition: MSLCM_LC2013.h:163
bool currentDistAllows(SUMOReal dist, int laneOffset, SUMOReal lookForwardDist)
Definition: MSLCM_LC2013.h:166
#define max(a, b)
Definition: polyfonts.c:65
bool cancelRequest(int state)
whether the influencer cancels the given request
SUMOReal brakeGap(const SUMOReal speed) const
Returns the distance the vehicle needs to halt including driver&#39;s reaction time.
Definition: MSCFModel.h:234
SUMOReal myLeadingBlockerLength
Definition: MSLCM_LC2013.h:183
SUMOReal getMinGap() const
Get the free space in front of vehicles of this class.
#define CUT_IN_LEFT_SPEED_THRESHOLD
SUMOReal myLookAheadSpeed
Definition: MSLCM_LC2013.h:188
#define LOOK_AHEAD_SPEED_MEMORY
#define STEPS2TIME(x)
Definition: SUMOTime.h:65
int slowDownForBlocked(MSVehicle **blocked, int state)
compute useful slowdowns for blocked vehicles
T MIN2(T a, T b)
Definition: StdDefs.h:69
#define CHANGE_PROB_THRESHOLD_LEFT
#define RELGAIN_NORMALIZATION_MIN_SPEED
virtual SUMOReal stopSpeed(const MSVehicle *const veh, const SUMOReal speed, SUMOReal gap2pred) const =0
Computes the vehicle&#39;s safe speed for approaching a non-moving obstacle (no dawdling) ...
#define POSITION_EPS
Definition: config.h:187
SUMOReal getSpeedLimit() const
Returns the lane&#39;s maximum allowed speed.
Definition: MSLane.h:367
A structure representing the best lanes for continuing the route.
Definition: MSVehicle.h:541
SUMOReal getMaxDecel() const
Get the vehicle type&#39;s maximum deceleration [m/s^2].
Definition: MSCFModel.h:186
SUMOReal changeRequestRemainingSeconds(const SUMOTime currentTime) const
Return the remaining number of seconds of the current laneTimeLine assuming one exists.
Definition: MSVehicle.cpp:368
int myOwnState
The current state of the vehicle.
SUMOReal informLeader(MSAbstractLaneChangeModel::MSLCMessager &msgPass, int blocked, int dir, const std::pair< MSVehicle *, SUMOReal > &neighLead, SUMOReal remainingSeconds)
Wants go to the right.
virtual void saveBlockerLength(SUMOReal length)
reserve space at the end of the lane to avoid dead locks
std::pair< SUMOReal, int > Info
information regarding save velocity (unused) and state flags of the ego vehicle
Definition: MSLCM_LC2013.h:171
int _wantsChange(int laneOffset, MSAbstractLaneChangeModel::MSLCMessager &msgPass, int blocked, const std::pair< MSVehicle *, SUMOReal > &leader, const std::pair< MSVehicle *, SUMOReal > &neighLead, const std::pair< MSVehicle *, SUMOReal > &neighFollow, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked)
helper function for doing the actual work
MSVehicle & myVehicle
The vehicle this lane-changer belongs to.
void * informNeighLeader(void *info, MSVehicle *sender)
Informs the leader on the desired lane.
The action is needed to follow the route (navigational lc)
EdgeBasicFunction getPurpose() const
Returns the edge type (EdgeBasicFunction)
Definition: MSEdge.h:242
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:2826
#define JAM_FACTOR
SUMOReal occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition: MSVehicle.h:549
std::vector< MSLane * > bestContinuations
Consecutive lane that can be followed without a lane change (contribute to length and occupation) ...
Definition: MSVehicle.h:557
The action is due to the default of keeping right "Rechtsfahrgebot".
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type definition.
Definition: MSBaseVehicle.h:93
#define URGENCY
const SUMOReal SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:57
Needs to stay on the current lane.
virtual ~MSLCM_LC2013()
SUMOReal getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:348
SUMOReal getWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s)
Definition: MSVehicle.h:434
#define LOOK_FORWARD_LEFT
SUMOReal mySpeedGainProbability
a value for tracking the probability that a change to the offset with the same sign is beneficial ...
Definition: MSLCM_LC2013.h:177
SUMOReal myLeftSpace
Definition: MSLCM_LC2013.h:184
bool gDebugFlag2
Definition: StdDefs.cpp:92
#define SUMOReal
Definition: config.h:213
#define NUMERICAL_EPS
Definition: config.h:160
bool amBlockingFollowerPlusNB()
Definition: MSLCM_LC2013.h:160
#define HELP_OVERTAKE
const MSLinkCont & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.cpp:947
SUMOReal _patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel &cfModel)
#define LOOK_AHEAD_MIN_SPEED
#define LCA_RIGHT_IMPATIENCE
SUMOReal getVehicleMaxSpeed(const SUMOVehicle *const veh) const
Returns the lane&#39;s maximum speed, given a vehicle&#39;s speed limit adaptation.
Definition: MSLane.h:353
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:385
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
Definition: MSVehicle.cpp:2844
The edge is an internal edge.
Definition: MSEdge.h:97
void * inform(void *info, MSVehicle *sender)
Representation of a lane in the micro simulation.
Definition: MSLane.h:77
const MSCFModel & myCarFollowModel
The vehicle&#39;s car following model.
Interface for lane-change models.
int getBestLaneOffset() const
returns the current offset from the best lane
Definition: MSVehicle.cpp:2368
#define HELP_DECEL_FACTOR
const std::string & getID() const
Returns the name of the vehicle.
The action is due to the wish to be faster (tactical lc)
#define KEEP_RIGHT_TIME