1 package org.opentrafficsim.road.gtu.lane.tactical.cacc;
2
3 import java.util.SortedSet;
4
5 import org.djunits.value.vdouble.scalar.Acceleration;
6 import org.djunits.value.vdouble.scalar.Duration;
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djunits.value.vdouble.scalar.Speed;
9 import org.djunits.value.vdouble.scalar.Time;
10 import org.opentrafficsim.base.parameters.ParameterException;
11 import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
12 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
13 import org.opentrafficsim.base.parameters.ParameterTypeLength;
14 import org.opentrafficsim.base.parameters.ParameterTypes;
15 import org.opentrafficsim.base.parameters.Parameters;
16 import org.opentrafficsim.core.gtu.GTUException;
17 import org.opentrafficsim.core.gtu.TurnIndicatorStatus;
18 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
19 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
20 import org.opentrafficsim.core.network.LateralDirectionality;
21 import org.opentrafficsim.core.network.NetworkException;
22 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
23 import org.opentrafficsim.road.gtu.lane.perception.InfrastructureLaneChangeInfo;
24 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
25 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
26 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
27 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
28 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneChange;
29 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder;
30 import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
31 import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
32 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
33 import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
34 import org.opentrafficsim.road.gtu.lane.tactical.util.lmrs.Desire;
35 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
36 import org.opentrafficsim.road.network.speed.SpeedLimitProspect;
37
38 import nl.tudelft.simulation.language.d3.DirectedPoint;
39
40
41
42
43
44
45
46
47
48
49
50 @SuppressWarnings("serial")
51 public class CaccTacticalPlanner extends AbstractLaneBasedTacticalPlanner
52 {
53
54
55 private final LaneChange laneChange;
56
57
58 private final CaccController controller;
59
60
61 private Platoon platoon;
62
63
64 protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
65
66
67 public static final ParameterTypeDuration T_GAP = CaccParameters.T_GAP;
68
69
70 public static final ParameterTypeDuration T0 = ParameterTypes.T0;
71
72
73 public static final ParameterTypeDuration DT = ParameterTypes.DT;
74
75
76 public static final ParameterTypeAcceleration A_REDUCED = CaccParameters.A_REDUCED;
77
78
79
80
81
82
83
84 public CaccTacticalPlanner(final CarFollowingModel carFollowingModel, final LaneBasedGTU gtu,
85 final LanePerception lanePerception, final CaccController controller)
86 {
87 super(carFollowingModel, gtu, lanePerception);
88 this.controller = controller;
89 this.laneChange = new LaneChange(gtu);
90 }
91
92
93
94
95
96 public void setPlatoon(final Platoon platoon)
97 {
98 this.platoon = platoon;
99 this.controller.setPlatoon(platoon);
100 }
101
102
103
104
105 @Override
106 public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
107 throws OperationalPlanException, GTUException, NetworkException, ParameterException
108 {
109
110
111 LanePerception perception = getPerception();
112 getGtu().getTacticalPlanner().getPerception().perceive();
113 ControllerPerceptionCategory sensors = getPerception().getPerceptionCategory(ControllerPerceptionCategory.class);
114 InfrastructurePerception infra = getPerception().getPerceptionCategory(InfrastructurePerception.class);
115
116
117 LaneBasedGTU gtu = getGtu();
118 Speed speed = gtu.getSpeed();
119 Parameters parameters = gtu.getParameters();
120
121
122 SpeedLimitProspect slp = getPerception().getPerceptionCategory(InfrastructurePerception.class)
123 .getSpeedLimitProspect(RelativeLane.CURRENT);
124 SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
125
126
127 String gtuId = gtu.getId();
128
129
130 SimpleOperationalPlan/plan/operational/SimpleOperationalPlan.html#SimpleOperationalPlan">SimpleOperationalPlan plan = new SimpleOperationalPlan(Acceleration.ZERO, Duration.ZERO);
131
132
133 SortedSet<InfrastructureLaneChangeInfo> currentInfo = infra.getInfrastructureLaneChangeInfo(RelativeLane.CURRENT);
134 Length currentFirst = currentInfo.isEmpty() || currentInfo.first().getRequiredNumberOfLaneChanges() == 0
135 ? Length.POSITIVE_INFINITY : currentInfo.first().getRemainingDistance();
136
137 double dCurr = 0.0;
138 double dLeft = 0.0;
139 double dRigh = 0.0;
140
141
142 if (infra.getCrossSection().contains(RelativeLane.CURRENT))
143 {
144 dCurr = determineDesire(infra, parameters, speed, RelativeLane.CURRENT);
145 }
146
147
148 if (perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT)
149 && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).neg().lt(currentFirst))
150 {
151
152 dLeft = determineDesire(infra, parameters, speed, RelativeLane.LEFT);
153
154 dLeft = dLeft < dCurr ? dCurr : dLeft > dCurr ? -dLeft : 0;
155 }
156
157
158 if (perception.getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT) && infra
159 .getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).neg().lt(currentFirst))
160 {
161
162 dRigh = determineDesire(infra, parameters, speed, RelativeLane.RIGHT);
163
164 dRigh = dRigh < dCurr ? dCurr : dRigh > dCurr ? -dRigh : 0;
165 }
166
167 dRigh = dRigh + 0.01;
168 Desireroad/gtu/lane/tactical/util/lmrs/Desire.html#Desire">Desire desire = new Desire(dLeft, dRigh);
169
170
171 LateralDirectionality laneChangeDirection;
172 laneChangeDirection = LateralDirectionality.NONE;
173 double thresholdLeft = 0.1;
174 double thresholdRigh = 0.0;
175
176
177 LateralDirectionality direction = LateralDirectionality.NONE;
178 TurnIndicatorStatus turndirection;
179
180 if (this.platoon != null)
181 {
182 if (desire.leftIsLargerOrEqual() && desire.getLeft() > thresholdLeft
183 && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.LEFT).gt0())
184 {
185
186 turndirection = TurnIndicatorStatus.LEFT;
187
188 if (this.platoon.canInitiateLaneChangeProcess())
189 {
190 laneChangeDirection = LateralDirectionality.LEFT;
191 this.platoon.initiateLaneChange(laneChangeDirection);
192 }
193 }
194 else if (!desire.leftIsLargerOrEqual() && desire.getRight() > thresholdRigh
195 && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, LateralDirectionality.RIGHT).gt0())
196 {
197
198 turndirection = TurnIndicatorStatus.RIGHT;
199
200 if (this.platoon.canInitiateLaneChangeProcess())
201 {
202 laneChangeDirection = LateralDirectionality.RIGHT;
203 this.platoon.initiateLaneChange(laneChangeDirection);
204 }
205 }
206 else
207 {
208 turndirection = TurnIndicatorStatus.NONE;
209 }
210
211
212 direction = this.platoon.shouldChangeLane(gtuId);
213
214 }
215 else
216 {
217 turndirection = TurnIndicatorStatus.NONE;
218 }
219
220
221 HeadwayGTU adjacentLeader = sensors.getLeader(direction);
222 HeadwayGTU adjacentFollower = sensors.getFollower(direction);
223
224
225 LateralDirectionality allowedDirection = LateralDirectionality.NONE;
226
227
228 CarFollowingModel cfEgo = this.getCarFollowingModel();
229 Acceleration b0 = parameters.getParameter(ParameterTypes.B0);
230
231
232 if (!direction.isNone() && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, direction).gt0())
233 {
234
235 gtu.setTurnIndicatorStatus(turndirection);
236
237
238 if (this.platoon.laneChangeInProgress())
239 {
240 if (adjacentLeader == null || adjacentFollower == null
241 || (adjacentLeader.getOverlap() == null && adjacentFollower.getOverlap() == null
242 && CarFollowingUtil.followSingleLeader(cfEgo, parameters, gtu.getSpeed(), sli,
243 adjacentLeader.getDistance(), adjacentLeader.getSpeed()).ge(b0.neg())
244 || (this.platoon.isInPlatoon(adjacentLeader.getId()) && adjacentLeader.getOverlap() == null
245 && adjacentFollower.getOverlap() == null)))
246 {
247 if (this.platoon.getIndex(gtuId) == (this.platoon.numberOfChanged() - 1))
248 {
249
250 if (this.platoon.isInPlatoon(adjacentFollower.getId()))
251 {
252
253 allowedDirection = direction;
254 this.platoon.addLaneChange(getGtu());
255
256 gtu.setTurnIndicatorStatus(TurnIndicatorStatus.NONE);
257
258 }
259 }
260 }
261 }
262 else if (adjacentLeader == null || adjacentFollower == null
263 || (adjacentLeader.getOverlap() == null && adjacentFollower.getOverlap() == null
264 && CarFollowingUtil.followSingleLeader(cfEgo, parameters, gtu.getSpeed(), sli,
265 adjacentLeader.getDistance(), adjacentLeader.getSpeed()).ge(b0.neg())))
266 {
267
268 if (adjacentFollower == null
269 || CarFollowingUtil
270 .followSingleLeader(adjacentFollower.getCarFollowingModel(), parameters,
271 adjacentFollower.getSpeed(), sli, adjacentFollower.getDistance(), gtu.getSpeed())
272 .ge(b0.neg()))
273 {
274
275 allowedDirection = direction;
276 this.platoon.addLaneChange(getGtu());
277 gtu.setTurnIndicatorStatus(TurnIndicatorStatus.NONE);
278 }
279 }
280 }
281
282
283
284
285
286
287 if (this.platoon != null && this.platoon.getIndex(gtuId) == 0 && !this.platoon.canInitiateLaneChangeProcess()
288
289
290
291 && allowedDirection.isNone() && !direction.isNone()
292 && infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, direction).gt0())
293 {
294
295
296 Acceleration atemp = this.controller.calculateAcceleration(gtu);
297 Acceleration reduction = parameters.getParameter(A_REDUCED);
298 Acceleration amax = parameters.getParameter(CaccParameters.A_MAX);
299 Acceleration amin = parameters.getParameter(CaccParameters.A_MIN);
300 Acceleration areduced = atemp.minus(reduction);
301
302 Acceleration aredLimit = Acceleration
303 .instantiateSI(areduced.si < amax.si ? (areduced.si > amin.si ? areduced.si : amin.si) : amax.si);
304 plan = new SimpleOperationalPlan(aredLimit, parameters.getParameter(DT), allowedDirection);
305
306 }
307 else
308 {
309 plan = new SimpleOperationalPlan(this.controller.calculateAcceleration(gtu), parameters.getParameter(DT),
310 allowedDirection);
311 }
312
313 return LaneOperationalPlanBuilder.buildPlanFromSimplePlan(getGtu(), startTime, plan, this.laneChange);
314
315 }
316
317
318
319
320
321
322
323
324 private Double determineDesire(final InfrastructurePerception infra, final Parameters parameters, final Speed speed,
325 final RelativeLane laneDirection) throws ParameterException
326 {
327 double dCurr;
328
329 double dOut = 0.0;
330
331 for (InfrastructureLaneChangeInfo info : infra.getInfrastructureLaneChangeInfo(laneDirection))
332 {
333 double d;
334
335
336 double d1 = 1 - info.getRemainingDistance().si
337 / (info.getRequiredNumberOfLaneChanges() * parameters.getParameter(LOOKAHEAD).si);
338 double d2 = 1 - (info.getRemainingDistance().si / speed.si)
339 / (info.getRequiredNumberOfLaneChanges() * parameters.getParameter(T0).si);
340 d1 = d2 > d1 ? d2 : d1;
341
342 d = d1 < 0 ? 0 : d1;
343
344 dOut = d > dOut ? d : dOut;
345 }
346
347 dCurr = dOut;
348
349 return dCurr;
350 }
351
352 }