SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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-sim.org/
14 // Copyright (C) 2001-2013 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 "MSEdge.h"
38 #include "MSLane.h"
39 #include "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 #ifdef DEBUG_VEHICLE_GUI_SELECTION
49 #include <guisim/GUIVehicle.h>
50 #include <guisim/GUILane.h>
51 #endif
52 
53 
54 
55 // ===========================================================================
56 // variable definitions
57 // ===========================================================================
58 // 80km/h will be the threshold for dividing between long/short foresight
59 #define LOOK_FORWARD_SPEED_DIVIDER (SUMOReal)14.
60 
61 #define LOOK_FORWARD_RIGHT (SUMOReal)10.
62 #define LOOK_FORWARD_LEFT (SUMOReal)20.
63 
64 #define JAM_FACTOR (SUMOReal)1.
65 
66 #define LCA_RIGHT_IMPATIENCE (SUMOReal)-1.
67 
68 #define LOOK_AHEAD_MIN_SPEED (SUMOReal)0.0
69 #define LOOK_AHEAD_SPEED_MEMORY (SUMOReal)0.9
70 #define LOOK_AHEAD_SPEED_DECREMENT 6.
71 
72 #define HELP_DECEL_FACTOR (SUMOReal)1.0
73 
74 #define HELP_OVERTAKE (SUMOReal)(10.0 / 3.6)
75 #define MIN_FALLBEHIND (SUMOReal)(14.0 / 3.6)
76 
77 #define KEEP_RIGHT_HEADWAY (SUMOReal)2.0
78 
79 #define URGENCY (SUMOReal)2.0
80 
81 #define ROUNDABOUT_DIST_BONUS (SUMOReal)80.0
82 
83 
84 // ===========================================================================
85 // member method definitions
86 // ===========================================================================
89  mySpeedGainProbability(0),
90  myKeepRightProbability(0),
91  myLeadingBlockerLength(0),
92  myLeftSpace(0),
93  myLookAheadSpeed(LOOK_AHEAD_MIN_SPEED)
94 {}
95 
97  changed();
98 }
99 
100 
101 int
103  int laneOffset,
105  int blocked,
106  const std::pair<MSVehicle*, SUMOReal>& leader,
107  const std::pair<MSVehicle*, SUMOReal>& neighLead,
108  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
109  const MSLane& neighLane,
110  const std::vector<MSVehicle::LaneQ>& preb,
111  MSVehicle** lastBlocked,
112  MSVehicle** firstBlocked) {
113  const int result = _wantsChange(laneOffset, msgPass, blocked, leader, neighLead, neighFollow, neighLane, preb, lastBlocked, firstBlocked);
114  return result;
115 }
116 
117 
118 SUMOReal
119 MSLCM_LC2013::patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel& cfModel) {
120  const SUMOReal newSpeed = _patchSpeed(min, wanted, max, cfModel);
121  return newSpeed;
122 }
123 
124 
125 SUMOReal
126 MSLCM_LC2013::_patchSpeed(const SUMOReal min, const SUMOReal wanted, const SUMOReal max, const MSCFModel& cfModel) {
127  int state = myOwnState;
128 
129  // letting vehicles merge in at the end of the lane in case of counter-lane change, step#2
130  SUMOReal MAGIC_offset = 1.;
131  // if we want to change and have a blocking leader and there is enough room for him in front of us
132  if (myLeadingBlockerLength != 0) {
134  if (space > 0) {
135  // compute speed for decelerating towards a place which allows the blocking leader to merge in in front
136  SUMOReal safe = cfModel.stopSpeed(&myVehicle, myVehicle.getSpeed(), space);
137  // if we are approaching this place
138  if (safe < wanted) {
139  // return this speed as the speed to use
140  return MAX2(min, safe);
141  }
142  }
143  }
144 
145  SUMOReal nVSafe = wanted;
146  bool gotOne = false;
147  for (std::vector<SUMOReal>::const_iterator i = myVSafes.begin(); i != myVSafes.end(); ++i) {
148  SUMOReal v = (*i);
149  if (v >= min && v <= max) {
150  nVSafe = MIN2(v, nVSafe);
151  gotOne = true;
152  } else {
153  }
154  }
155 
156  if (gotOne && !myDontBrake) {
157  return nVSafe;
158  }
159 
160  // check whether the vehicle is blocked
161  if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) != 0) {
162  if ((state & LCA_STRATEGIC) != 0) {
163  // necessary decelerations are controlled via vSafe. If there are
164  // none it means we should speed up
165  return (max + wanted) / (SUMOReal) 2.0;
166  } else if ((state & LCA_COOPERATIVE) != 0) {
167  // only minor adjustments in speed should be done
168  if ((state & LCA_BLOCKED_BY_LEADER) != 0) {
169  return (min + wanted) / (SUMOReal) 2.0;
170  }
171  if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
172  return (max + wanted) / (SUMOReal) 2.0;
173  }
174  }
175  }
176 
177  // accelerate if being a blocking leader or blocking follower not able to brake
178  // (and does not have to change lanes)
179  if ((state & LCA_AMBLOCKINGLEADER) != 0) {
180  return (max + wanted) / (SUMOReal) 2.0;
181  }
182 
183  if ((state & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
184  }
185  if (myVehicle.getLane()->getEdge().getLanes().size() == 1) {
186  // remove chaning information if on a road with a single lane
187  changed();
188  }
189  return wanted;
190 }
191 
192 
193 void*
194 MSLCM_LC2013::inform(void* info, MSVehicle* /* sender */) {
195  Info* pinfo = (Info*) info;
196  myVSafes.push_back(pinfo->first);
197  myOwnState |= pinfo->second;
198  delete pinfo;
199  return (void*) true;
200 }
201 
202 
203 SUMOReal
205  int blocked,
206  int dir,
207  const std::pair<MSVehicle*, SUMOReal>& neighLead,
208  SUMOReal remainingSeconds) {
209  SUMOReal plannedSpeed = MIN2(myVehicle.getSpeed(),
211  for (std::vector<SUMOReal>::const_iterator i = myVSafes.begin(); i != myVSafes.end(); ++i) {
212  SUMOReal v = (*i);
214  plannedSpeed = MIN2(plannedSpeed, v);
215  }
216  }
217  if ((blocked & LCA_BLOCKED_BY_LEADER) != 0) {
218  assert(neighLead.first != 0);
219  MSVehicle* nv = neighLead.first;
220  // decide whether we want to overtake the leader or follow it
221  const SUMOReal dv = plannedSpeed - nv->getSpeed();
222  const SUMOReal overtakeDist = (neighLead.second // drive to back of follower
223  + nv->getVehicleType().getLengthWithGap() // drive to front of follower
224  + myVehicle.getVehicleType().getLength() // ego back reaches follower front
225  + nv->getCarFollowModel().getSecureGap( // save gap to follower
227 
228  if (dv < 0
229  // overtaking on the right on an uncongested highway is forbidden (noOvertakeLCLeft)
230  || (dir == LCA_MLEFT && !myVehicle.congested())
231  // not enough space to overtake?
232  || myLeftSpace < overtakeDist
233  // not enough time to overtake?
234  || dv * remainingSeconds < overtakeDist) {
235  // cannot overtake
236  msgPass.informNeighLeader(new Info(-1, dir | LCA_AMBLOCKINGLEADER), &myVehicle);
237  // slow down smoothly to follow leader
238  const SUMOReal targetSpeed = myCarFollowModel.followSpeed(
239  &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
240  if (targetSpeed < myVehicle.getSpeed()) {
241  // slow down smoothly to follow leader
243  MAX2(MIN_FALLBEHIND, (myVehicle.getSpeed() - targetSpeed) / remainingSeconds)));
244  const SUMOReal nextSpeed = MIN2(plannedSpeed, myVehicle.getSpeed() - decel);
245  myVSafes.push_back(nextSpeed);
246  return nextSpeed;
247  } else {
248  // leader is fast enough anyway
249  myVSafes.push_back(targetSpeed);
250  return plannedSpeed;
251  }
252  } else {
253  // overtaking, leader should not accelerate
254  msgPass.informNeighLeader(new Info(nv->getSpeed(), dir | LCA_AMBLOCKINGLEADER), &myVehicle);
255  return -1;
256  }
257  } else if (neighLead.first != 0) { // (remainUnblocked)
258  // we are not blocked now. make sure we stay far enough from the leader
259  MSVehicle* nv = neighLead.first;
260  const SUMOReal nextNVSpeed = nv->getSpeed() - HELP_OVERTAKE; // conservative
261  const SUMOReal dv = SPEED2DIST(myVehicle.getSpeed() - nextNVSpeed);
262  const SUMOReal targetSpeed = myCarFollowModel.followSpeed(
263  &myVehicle, myVehicle.getSpeed(), neighLead.second - dv, nextNVSpeed, nv->getCarFollowModel().getMaxDecel());
264  myVSafes.push_back(targetSpeed);
265  return MIN2(targetSpeed, plannedSpeed);
266  } else {
267  // not overtaking
268  return plannedSpeed;
269  }
270 }
271 
272 
273 void
275  int blocked,
276  int dir,
277  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
278  SUMOReal remainingSeconds,
279  SUMOReal plannedSpeed) {
280  if ((blocked & LCA_BLOCKED_BY_FOLLOWER) != 0) {
281  assert(neighFollow.first != 0);
282  MSVehicle* nv = neighFollow.first;
283 
284  // are we fast enough to cut in without any help?
285  if (plannedSpeed - nv->getSpeed() >= HELP_OVERTAKE) {
286  const SUMOReal neededGap = nv->getCarFollowModel().getSecureGap(nv->getSpeed(), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
287  if ((neededGap - neighFollow.second) / remainingSeconds < (plannedSpeed - nv->getSpeed())) {
288  // follower might even accelerate but not to much
289  msgPass.informNeighFollower(new Info(plannedSpeed - HELP_OVERTAKE, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
290  return;
291  }
292  }
293  // decide whether we will request help to cut in before the follower or allow to be overtaken
294 
295  // PARAMETERS
296  // assume other vehicle will assume the equivalent of 1 second of
297  // maximum deceleration to help us (will probably be spread over
298  // multiple seconds)
299  // -----------
300  const SUMOReal helpDecel = nv->getCarFollowModel().getMaxDecel() * HELP_DECEL_FACTOR ;
301 
302  // change in the gap between ego and blocker over 1 second (not STEP!)
303  const SUMOReal neighNewSpeed = MAX2((SUMOReal)0, nv->getSpeed() - ACCEL2SPEED(helpDecel));
304  const SUMOReal neighNewSpeed1s = MAX2((SUMOReal)0, nv->getSpeed() - helpDecel);
305  const SUMOReal dv = plannedSpeed - neighNewSpeed1s;
306  // new gap between follower and self in case the follower does brake for 1s
307  const SUMOReal decelGap = neighFollow.second + dv;
308  const SUMOReal secureGap = nv->getCarFollowModel().getSecureGap(neighNewSpeed1s, plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
309  if (decelGap > 0 && decelGap >= secureGap) {
310  // if the blocking neighbor brakes it could actually help
311  // how hard does it actually need to be?
312  const SUMOReal vsafe = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
313  nv, nv->getSpeed(), neighFollow.second, plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel()));
314  msgPass.informNeighFollower(new Info(vsafe, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
315  } else if (dv > 0 && dv * remainingSeconds > (secureGap - decelGap + POSITION_EPS)) {
316  // decelerating once is sufficient to open up a large enough gap in time
317  msgPass.informNeighFollower(new Info(neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
318  } else {
321  nv->getSpeed() > myVehicle.getSpeed()) {
322  // let the follower slow down to increase the likelyhood that later vehicles will be slow enough to help
323  // follower should still be fast enough to open a gap
324  vhelp = MAX2(neighNewSpeed, myVehicle.getSpeed() + HELP_OVERTAKE);
325  if ((nv->getSpeed() - myVehicle.getSpeed()) / helpDecel < remainingSeconds) {
326  msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
327  return;
328  }
329  }
330  msgPass.informNeighFollower(new Info(vhelp, dir | LCA_AMBLOCKINGFOLLOWER), &myVehicle);
331  // this follower is supposed to overtake us. slow down smoothly to allow this
332  const SUMOReal overtakeDist = (neighFollow.second // follower reaches ego back
333  + myVehicle.getVehicleType().getLengthWithGap() // follower reaches ego front
334  + nv->getVehicleType().getLength() // follower back at ego front
335  + myVehicle.getCarFollowModel().getSecureGap( // follower has safe dist to ego
336  plannedSpeed, vhelp, nv->getCarFollowModel().getMaxDecel()));
337  // speed difference to create a sufficiently large gap
338  const SUMOReal needDV = overtakeDist / remainingSeconds;
339  // make sure the deceleration is not to strong
340  myVSafes.push_back(MAX2(vhelp - needDV, myVehicle.getSpeed() - ACCEL2SPEED(myVehicle.getCarFollowModel().getMaxDecel())));
341  }
342  }
343 }
344 
345 
346 void
348  myOwnState = 0;
350  myLeftSpace = 0;
351  myVSafes.clear();
352  myDontBrake = false;
353  // truncate to work around numerical instability between different builds
354  mySpeedGainProbability = ceil(mySpeedGainProbability * 100000.0) * 0.00001;
355  myKeepRightProbability = ceil(myKeepRightProbability * 100000.0) * 0.00001;
356 }
357 
358 
359 void
361  myOwnState = 0;
365  if (myVehicle.getBestLaneOffset() == 0) {
366  // if we are not yet on our best lane there might still be unseen blockers
367  // (during patchSpeed)
369  myLeftSpace = 0;
370  }
372  myVSafes.clear();
373  myDontBrake = false;
374 }
375 
376 
377 int
379  int laneOffset,
381  int blocked,
382  const std::pair<MSVehicle*, SUMOReal>& leader,
383  const std::pair<MSVehicle*, SUMOReal>& neighLead,
384  const std::pair<MSVehicle*, SUMOReal>& neighFollow,
385  const MSLane& neighLane,
386  const std::vector<MSVehicle::LaneQ>& preb,
387  MSVehicle** lastBlocked,
388  MSVehicle** firstBlocked) {
389  assert(laneOffset == 1 || laneOffset == -1);
390  const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
391  // compute bestLaneOffset
392  MSVehicle::LaneQ curr, neigh, best;
393  int bestLaneOffset = 0;
394  SUMOReal currentDist = 0;
395  SUMOReal neighDist = 0;
396  int currIdx = 0;
397  MSLane* prebLane = myVehicle.getLane();
398  if (prebLane->getEdge().getPurpose() == MSEdge::EDGEFUNCTION_INTERNAL) {
399  // internal edges are not kept inside the bestLanes structure
400  prebLane = prebLane->getLinkCont()[0]->getLane();
401  }
402  for (int p = 0; p < (int) preb.size(); ++p) {
403  if (preb[p].lane == prebLane && p + laneOffset >= 0) {
404  assert(p + laneOffset < (int)preb.size());
405  curr = preb[p];
406  neigh = preb[p + laneOffset];
407  currentDist = curr.length;
408  neighDist = neigh.length;
409  bestLaneOffset = curr.bestLaneOffset;
410  if (bestLaneOffset == 0 && preb[p + laneOffset].bestLaneOffset == 0) {
411  bestLaneOffset = laneOffset;
412  }
413  best = preb[p + bestLaneOffset];
414  currIdx = p;
415  break;
416  }
417  }
418  // direction specific constants
419  const bool right = (laneOffset == -1);
420  const int lca = (right ? LCA_RIGHT : LCA_LEFT);
421  const int myLca = (right ? LCA_MRIGHT : LCA_MLEFT);
422  const int lcaCounter = (right ? LCA_LEFT : LCA_RIGHT);
423  const bool changeToBest = (right && bestLaneOffset < 0) || (!right && bestLaneOffset > 0);
424  // keep information about being a leader/follower
425  int ret = (myOwnState & 0xffff0000);
426 
427  ret = slowDownForBlocked(lastBlocked, ret);
428  if (lastBlocked != firstBlocked) {
429  ret = slowDownForBlocked(firstBlocked, ret);
430  }
431 
432 
433  // we try to estimate the distance which is necessary to get on a lane
434  // we have to get on in order to keep our route
435  // we assume we need something that depends on our velocity
436  // and compare this with the free space on our wished lane
437  //
438  // if the free space is somehow less than the space we need, we should
439  // definitely try to get to the desired lane
440  //
441  // this rule forces our vehicle to change the lane if a lane changing is necessary soon
442  // lookAheadDistance:
443  // we do not want the lookahead distance to change all the time so we discrectize the speed a bit
444 
447  } else {
450  }
452  laDist += myVehicle.getVehicleType().getLengthWithGap() * (SUMOReal) 2.;
453  // free space that is available for changing
454  //const SUMOReal neighSpeed = (neighLead.first != 0 ? neighLead.first->getSpeed() :
455  // neighFollow.first != 0 ? neighFollow.first->getSpeed() :
456  // best.lane->getSpeedLimit());
457  // @note: while this lets vehicles change earlier into the correct direction
458  // it also makes the vehicles more "selfish" and prevents changes which are necessary to help others
459 
460  int roundaboutEdgesAhead = 0;
461  for (std::vector<MSLane*>::iterator it = curr.bestContinuations.begin(); it != curr.bestContinuations.end(); ++it) {
462  if ((*it) != 0 && (*it)->getEdge().isRoundabout()) {
463  roundaboutEdgesAhead += 1;
464  } else if (roundaboutEdgesAhead > 0) {
465  // only check the next roundabout
466  break;
467  }
468  }
469  int roundaboutEdgesAheadNeigh = 0;
470  for (std::vector<MSLane*>::iterator it = neigh.bestContinuations.begin(); it != neigh.bestContinuations.end(); ++it) {
471  if ((*it) != 0 && (*it)->getEdge().isRoundabout()) {
472  roundaboutEdgesAheadNeigh += 1;
473  } else if (roundaboutEdgesAheadNeigh > 0) {
474  // only check the next roundabout
475  break;
476  }
477  }
478  if (roundaboutEdgesAhead > 1) {
479  currentDist += roundaboutEdgesAhead * ROUNDABOUT_DIST_BONUS;
480  neighDist += roundaboutEdgesAheadNeigh * ROUNDABOUT_DIST_BONUS;
481  }
482 
483  const SUMOReal usableDist = (currentDist - myVehicle.getPositionOnLane() - best.occupation * JAM_FACTOR);
484  const SUMOReal maxJam = MAX2(preb[currIdx + laneOffset].occupation, preb[currIdx].occupation);
485  const SUMOReal neighLeftPlace = MAX2((SUMOReal) 0, neighDist - myVehicle.getPositionOnLane() - maxJam);
486 
487  if (changeToBest && bestLaneOffset == curr.bestLaneOffset
488  && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
490  ret = ret | lca | LCA_STRATEGIC | LCA_URGENT;
491  } else {
492 
493  if (!right && !myVehicle.congested() && neighLead.first != 0) {
494  // check for slower leader on the left. we should not overtake but
495  // rather move left ourselves (unless congested)
496  MSVehicle* nv = neighLead.first;
497  if (nv->getSpeed() < myVehicle.getSpeed()) {
499  &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel()));
500  mySpeedGainProbability += 0.3;
501  }
502  }
503 
504  if (!changeToBest && (currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist))) {
505  // the opposite lane-changing direction should be done than the one examined herein
506  // we'll check whether we assume we could change anyhow and get back in time...
507  //
508  // this rule prevents the vehicle from moving in opposite direction of the best lane
509  // unless the way till the end where the vehicle has to be on the best lane
510  // is long enough
511  ret = ret | LCA_STAY | LCA_STRATEGIC;
512  } else if (bestLaneOffset == 0 && (neighLeftPlace * 2. < laDist)) {
513  // the current lane is the best and a lane-changing would cause a situation
514  // of which we assume we will not be able to return to the lane we have to be on.
515  // this rule prevents the vehicle from leaving the current, best lane when it is
516  // close to this lane's end
517  ret = ret | LCA_STAY | LCA_STRATEGIC;
518  }
519  }
520  // check for overriding TraCI requests
522  if ((ret & lcaCounter) != 0) {
523  // we are not interested in traci requests for the opposite direction here
524  ret &= ~(LCA_TRACI | lcaCounter | LCA_URGENT);
525  }
526 
527  if ((ret & LCA_STAY) != 0) {
528  return ret;
529  }
530  if ((ret & LCA_URGENT) != 0) {
531  // prepare urgent lane change maneuver
532  // save the left space
533  myLeftSpace = currentDist - myVehicle.getPositionOnLane();
534  if (changeToBest && abs(bestLaneOffset) > 1) {
535  // there might be a vehicle which needs to counter-lane-change one lane further and we cannot see it yet
536  myLeadingBlockerLength = MAX2((SUMOReal)(right ? 20.0 : 40.0), myLeadingBlockerLength);
537  }
538 
539  // letting vehicles merge in at the end of the lane in case of counter-lane change, step#1
540  // if there is a leader and he wants to change to the opposite direction
541  saveBlockerLength(neighLead.first, lcaCounter);
542  if (*firstBlocked != neighLead.first) {
543  saveBlockerLength(*firstBlocked, lcaCounter);
544  }
545 
546  const SUMOReal remainingSeconds = ((ret & LCA_TRACI) == 0 ?
547  MAX2((SUMOReal)STEPS2TIME(TS), myLeftSpace / myLookAheadSpeed / abs(bestLaneOffset) / URGENCY) :
549  const SUMOReal plannedSpeed = informLeader(msgPass, blocked, myLca, neighLead, remainingSeconds);
550  if (plannedSpeed >= 0) {
551  // maybe we need to deal with a blocking follower
552  informFollower(msgPass, blocked, myLca, neighFollow, remainingSeconds, plannedSpeed);
553  }
554 
555  return ret;
556  }
557 
558  if (roundaboutEdgesAhead > 1) {
559  // try to use the inner lanes of a roundabout to increase throughput
560  // unless we are approaching the exit
561  if (lca == LCA_LEFT) {
562  return ret | lca | LCA_COOPERATIVE;
563  } else {
564  return ret | LCA_STAY | LCA_COOPERATIVE;
565  }
566  }
567 
568  // let's also regard the case where the vehicle is driving on a highway...
569  // in this case, we do not want to get to the dead-end of an on-ramp
570  if (right) {
571  if (bestLaneOffset == 0 && myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle) > 80. / 3.6 && myLookAheadSpeed > SUMO_const_haltingSpeed) {
572  return ret | LCA_STAY | LCA_STRATEGIC;
573  }
574  }
575  // --------
576 
577  // -------- make place on current lane if blocking follower
578  //if (amBlockingFollowerPlusNB()) {
579  // std::cout << myVehicle.getID() << ", " << currentDistAllows(neighDist, bestLaneOffset, laDist)
580  // << " neighDist=" << neighDist
581  // << " currentDist=" << currentDist
582  // << "\n";
583  //}
585  && (changeToBest || currentDistAllows(neighDist, abs(bestLaneOffset) + 1, laDist))) {
586 
587  return ret | lca | LCA_COOPERATIVE | LCA_URGENT ;//| LCA_CHANGE_TO_HELP;
588  }
589 
590  // --------
591 
592 
595  //if ((blocked & LCA_BLOCKED) != 0) {
596  // return ret;
597  //}
599 
600  // -------- higher speed
601  //if ((congested(neighLead.first) && neighLead.second < 20) || predInteraction(leader.first)) { //!!!
602  // return ret;
603  //}
605  SUMOReal neighLaneVSafe = neighLane.getVehicleMaxSpeed(&myVehicle);
606  if (neighLead.first == 0) {
607  neighLaneVSafe = MIN2(neighLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), neighDist, 0, 0));
608  } else {
609  // @todo: what if leader is below safe gap?!!!
610  neighLaneVSafe = MIN2(neighLaneVSafe, myCarFollowModel.followSpeed(
611  &myVehicle, myVehicle.getSpeed(), neighLead.second, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()));
612  }
613  if (leader.first == 0) {
614  thisLaneVSafe = MIN2(thisLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), currentDist, 0, 0));
615  } else {
616  // @todo: what if leader is below safe gap?!!!
617  thisLaneVSafe = MIN2(thisLaneVSafe, myCarFollowModel.followSpeed(&myVehicle, myVehicle.getSpeed(), leader.second, leader.first->getSpeed(), leader.first->getCarFollowModel().getMaxDecel()));
618  }
619 
620  thisLaneVSafe = MIN3(thisLaneVSafe, myVehicle.getVehicleType().getMaxSpeed(), myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle));
621  neighLaneVSafe = MIN3(neighLaneVSafe, myVehicle.getVehicleType().getMaxSpeed(), neighLane.getVehicleMaxSpeed(&myVehicle));
622 
623  if (right) {
624  // ONLY FOR CHANGING TO THE RIGHT
625  if (thisLaneVSafe - neighLaneVSafe > 5. / 3.6) {
626  // ok, the current lane is faster than the right one...
627  if (mySpeedGainProbability < 0) {
628  mySpeedGainProbability /= 2.0;
629  myKeepRightProbability /= 2.0;
630  }
631  } else {
632  // ok, the right lane is faster than the current
633  mySpeedGainProbability -= (SUMOReal)((neighLaneVSafe - thisLaneVSafe) / (myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle)));
634  }
635 
636  // let's recheck the "Rechtsfahrgebot"
637  //keepRight(neighLead.first);
638  keepRight(neighFollow.first);
639 
640  if (mySpeedGainProbability < -2 && neighDist / MAX2((SUMOReal) .1, myVehicle.getSpeed()) > 20.) { //./MAX2((SUMOReal) .1, myVehicle.getSpeed())) { // -.1
642  return ret | lca | LCA_KEEPRIGHT;
643  } else {
644  return ret | lca | LCA_SPEEDGAIN;
645  }
646  }
647  } else {
648  // ONLY FOR CHANGING TO THE LEFT
649  if (thisLaneVSafe > neighLaneVSafe) {
650  // this lane is better
651  if (mySpeedGainProbability > 0) {
652  mySpeedGainProbability /= 2.0;
653  }
654  } else {
655  // left lane is better
656  mySpeedGainProbability += (SUMOReal)((neighLaneVSafe - thisLaneVSafe) / (myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle))); // !!! Fahrzeuggeschw.!
657  }
658  if (mySpeedGainProbability > .2 && neighDist / MAX2((SUMOReal) .1, myVehicle.getSpeed()) > 20.) { // .1
659  return ret | lca | LCA_SPEEDGAIN;
660  }
661  }
662  // --------
663  if (changeToBest && bestLaneOffset == curr.bestLaneOffset
664  && (right ? mySpeedGainProbability < 0 : mySpeedGainProbability > 0)) {
665  // change towards the correct lane, speedwise it does not hurt
666  return ret | lca | LCA_STRATEGIC;
667  }
668 
669  return ret;
670 }
671 
672 
673 void
675  if (neigh != 0 && neigh->getSpeed() > myVehicle.getSpeed()) {
676  const SUMOReal dProb = (neigh->getSpeed() - myVehicle.getSpeed()) / neigh->getSpeed();
677  myKeepRightProbability -= dProb;
678  mySpeedGainProbability -= dProb;
679  }
680 }
681 
682 
683 int
685  // if this vehicle is blocking someone in front, we maybe decelerate to let him in
686  if ((*blocked) != 0) {
687  SUMOReal gap = (*blocked)->getPositionOnLane() - (*blocked)->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
688  if (gap > POSITION_EPS) {
690  if ((*blocked)->getSpeed() < SUMO_const_haltingSpeed) {
692  } else {
693  state |= LCA_AMBACKBLOCKER;
694  }
697  (SUMOReal)(gap - POSITION_EPS), (*blocked)->getSpeed(),
698  (*blocked)->getCarFollowModel().getMaxDecel()));
699  }
700  }
701  }
702  return state;
703 }
704 
705 
706 void
707 MSLCM_LC2013::saveBlockerLength(MSVehicle* blocker, int lcaCounter) {
708  if (blocker != 0 && (blocker->getLaneChangeModel().getOwnState() & lcaCounter) != 0) {
709  // is there enough space in front of us for the blocker?
712  if (blocker->getVehicleType().getLengthWithGap() <= potential) {
713  // save at least his length in myLeadingBlockerLength
715  } else {
716  // we cannot save enough space for the blocker. It needs to save
717  // space for ego instead
719  }
720  }
721 }
722 /****************************************************************************/
723 
void saveBlockerLength(MSVehicle *blocker, int lcaCounter)
save space for vehicles which need to counter-lane-change
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:447
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
SUMOReal getMaxSpeed() const
Get vehicle&#39;s maximum speed [m/s].
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:62
const MSCFModel & getCarFollowModel() const
Returns the vehicle&#39;s car following model definition.
Definition: MSVehicle.h:510
#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:168
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:443
bool congested() const
Definition: MSVehicle.h:375
virtual SUMOReal followSpeed(const MSVehicle *const veh, SUMOReal speed, SUMOReal gap2pred, SUMOReal predSpeed, SUMOReal predMaxDecel) const =0
Computes the vehicle&#39;s safe speed (no dawdling)
The car-following model abstraction.
Definition: MSCFModel.h:58
SUMOReal myKeepRightProbability
a value for tracking the probability of following the/&quot;Rechtsfahrgebot&quot; (never a positive value) ...
Definition: MSLCM_LC2013.h:182
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:150
T MAX2(T a, T b)
Definition: StdDefs.h:63
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:232
SUMOReal getPositionOnLane() const
Get the vehicle&#39;s position along the lane.
Definition: MSVehicle.h:283
std::vector< SUMOReal > myVSafes
Definition: MSLCM_LC2013.h:191
#define TS
Definition: SUMOTime.h:52
The action is due to a TraCI request.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step (in s)
Definition: MSNet.cpp:502
SUMOReal length
The overall length which may be driven when using this lane without a lane change.
Definition: MSVehicle.h:437
The action is urgent (to be defined by lc-model)
#define abs(a)
Definition: polyfonts.c:63
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:1661
#define ROUNDABOUT_DIST_BONUS
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:166
bool currentDistAllows(SUMOReal dist, int laneOffset, SUMOReal lookForwardDist)
Definition: MSLCM_LC2013.h:169
#define max(a, b)
Definition: polyfonts.c:61
SUMOReal brakeGap(const SUMOReal speed) const
Returns the distance the vehicle needs to halt including driver&#39;s reaction time.
Definition: MSCFModel.h:213
void keepRight(MSVehicle *neigh)
updated myKeepRightProbability and mySpeedGainProbability if the right neighbours are faster ...
SUMOReal myLeadingBlockerLength
Definition: MSLCM_LC2013.h:184
SUMOReal getMinGap() const
Get the free space in front of vehicles of this class.
SUMOReal myLookAheadSpeed
Definition: MSLCM_LC2013.h:189
#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:57
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:186
A structure representing the best lanes for continuing the route.
Definition: MSVehicle.h:433
SUMOReal getMaxDecel() const
Get the vehicle type&#39;s maximum deceleration [m/s^2].
Definition: MSCFModel.h:165
SUMOReal changeRequestRemainingSeconds(const SUMOTime currentTime) const
Return the remaining number of seconds of the current laneTimeLine assuming one exists.
Definition: MSVehicle.cpp:292
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:174
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:204
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:2187
#define JAM_FACTOR
SUMOTime myLastLaneChangeOffset
information how long ago the vehicle has performed a lane-change
SUMOReal occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition: MSVehicle.h:439
std::vector< MSLane * > bestContinuations
Consecutive lane that can be followed without a lane change (contribute to length and occupation) ...
Definition: MSVehicle.h:447
The action is due to the default of keeping right &quot;Rechtsfahrgebot&quot;.
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type definition.
Definition: MSBaseVehicle.h:94
#define URGENCY
const SUMOReal SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:49
Needs to stay on the current lane.
virtual ~MSLCM_LC2013()
SUMOReal getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:291
SUMOReal getWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s)
Definition: MSVehicle.h:352
#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:180
SUMOReal myLeftSpace
Definition: MSLCM_LC2013.h:185
#define SUMOReal
Definition: config.h:215
T MIN3(T a, T b, T c)
Definition: StdDefs.h:70
bool amBlockingFollowerPlusNB()
Definition: MSLCM_LC2013.h:163
#define HELP_OVERTAKE
const MSLinkCont & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.cpp:981
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:349
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:322
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
Definition: MSVehicle.cpp:2205
The edge is an internal edge.
Definition: MSEdge.h:90
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:1974
#define HELP_DECEL_FACTOR
The action is due to the wish to be faster (tactical lc)