1 package org.opentrafficsim.imb.transceiver.urbanstrategy; 2 3 import java.awt.Color; 4 import java.rmi.RemoteException; 5 6 import org.djunits.value.vdouble.scalar.Acceleration; 7 import org.djunits.value.vdouble.scalar.Length; 8 import org.djunits.value.vdouble.scalar.Speed; 9 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface; 10 import org.opentrafficsim.core.dsol.OTSSimTimeDouble; 11 import org.opentrafficsim.core.gtu.GTU; 12 import org.opentrafficsim.core.gtu.GTUException; 13 import org.opentrafficsim.core.gtu.TurnIndicatorStatus; 14 import org.opentrafficsim.core.network.Network; 15 import org.opentrafficsim.core.network.OTSNetwork; 16 import org.opentrafficsim.imb.IMBException; 17 import org.opentrafficsim.imb.connector.Connector; 18 import org.opentrafficsim.imb.transceiver.AbstractTransceiver; 19 import org.opentrafficsim.imb.transceiver.OTSToIMBTransformer; 20 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU; 21 import org.opentrafficsim.road.network.lane.DirectedLanePosition; 22 import org.opentrafficsim.road.network.lane.Lane; 23 24 import nl.tudelft.simulation.event.EventInterface; 25 import nl.tudelft.simulation.event.TimedEvent; 26 import nl.tudelft.simulation.language.d3.DirectedPoint; 27 28 /** 29 * The GTUTransceiver publishes the following information on the IMB bus: 30 * <ol> 31 * <li>LaneBasedGTU.LANEBASED_INIT_EVENT as an IMB NEW event for a GTU entering the network. This also is done for GTUs that 32 * have been registered at the start of the simulation.</li> 33 * <li>LaneBasedGTU.LANEBASED_MOVE_EVENT as an IMB CHANGE event for a GTU that moves on the network.</li> 34 * <li>LaneBasedGTU.LANEBASED_DESTROY_EVENT as an IMB DELETE event for a GTU that leaves the network.</li> 35 * </ol> 36 * GTUs are identified by their gtuId. 37 * <p> 38 * OTS publishes events about GTUs (vehicles) to IMB, e.g. to calculate statistics or emissions from the vehicles or to display 39 * them in the US animation. 40 * </p> 41 * <p> 42 * When a GTU is created, a NEW message is sent to IMB to identify the GTU and its initial characteristics, including the lane 43 * on which it resides with its reference point, and the position on the lane. The CHANGE message is posted whenever a vehicle 44 * initiates a new OperationalPlan, which coincides with a MOVE Event in OTS. When a GTU is removed from the network, a DELETE 45 * event is posted. The GTU NEW messages are posted after the Network NEW, Node NEW, Link NEW, and Lane NEW messages are posted 46 * to ensure the Lane on which the GTU resides is known. 47 * </p> 48 * <p> 49 * The longitudinal position of a GTU on a lane is the (projected) position on the center line of the lane, in meters. The 50 * zero-point is chosen at the start of the center line of the lane that has been provided in the Lane_GTU NEW message. 51 * </p> 52 * <p> 53 * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style> 54 * <h2>NEW</h2> 55 * <table summary="" style="width:800px;"> 56 * <thead> 57 * <tr> 58 * <th style="width:25%;">Variable</th> 59 * <th style="width:15%;">Type</th> 60 * <th style="width:60%;">Comments</th> 61 * </tr> 62 * </thead><tbody> 63 * <tr> 64 * <td>timestamp</td> 65 * <td>double</td> 66 * <td>time of the event, in simulation time seconds</td> 67 * </tr> 68 * <tr> 69 * <td>gtuId</td> 70 * <td>String</td> 71 * <td>id of the GTU that has been added to the simulation</td> 72 * </tr> 73 * <tr> 74 * <td>position.x</td> 75 * <td>double</td> 76 * <td>x-coordinate of the gtu position in (gis) coordinates</td> 77 * </tr> 78 * <tr> 79 * <td>position.y</td> 80 * <td>double</td> 81 * <td>y-coordinate of the gtu position in (gis) coordinates</td> 82 * </tr> 83 * <tr> 84 * <td>position.z</td> 85 * <td>double</td> 86 * <td>z-coordinate of the gtu position in (gis) coordinates</td> 87 * </tr> 88 * <tr> 89 * <td>position.rotZ</td> 90 * <td>double</td> 91 * <td>angle in the x-y plane of the gtu</td> 92 * </tr> 93 * <tr> 94 * <td>networkId</td> 95 * <td>String</td> 96 * <td>Id of the Network where the gtu's reference point is</td> 97 * </tr> 98 * <tr> 99 * <td>linkId</td> 100 * <td>String</td> 101 * <td>id of the Link; unique within the Network</td> 102 * </tr> 103 * <tr> 104 * <td>laneId</td> 105 * <td>String</td> 106 * <td>id of the Lane, unique within the Link</td> 107 * </tr> 108 * <tr> 109 * <td>longitudinalPosition</td> 110 * <td>double</td> 111 * <td>gtu position on the center line of the lane, in meters</td> 112 * </tr> 113 * <tr> 114 * <td>length</td> 115 * <td>double</td> 116 * <td>length of the gtu, in meters</td> 117 * </tr> 118 * <tr> 119 * <td>width</td> 120 * <td>double</td> 121 * <td>width of the gtu, in meters</td> 122 * </tr> 123 * <tr> 124 * <td>baseColor.R</td> 125 * <td>byte</td> 126 * <td>R-component of the gtu's base color</td> 127 * </tr> 128 * <tr> 129 * <td>baseColor.G</td> 130 * <td>byte</td> 131 * <td>G-component of the gtu's base color</td> 132 * </tr> 133 * <tr> 134 * <td>baseColor.B</td> 135 * <td>byte</td> 136 * <td>B-component of the gtu's base color</td> 137 * </tr> 138 * </tbody> 139 * </table> 140 * </p> 141 * <p> 142 * <h2>CHANGE</h2> 143 * <table summary="" style="width:800px;"> 144 * <thead> 145 * <tr> 146 * <th style="width:25%;">Variable</th> 147 * <th style="width:15%;">Type</th> 148 * <th style="width:60%;">Comments</th> 149 * </tr> 150 * </thead><tbody> 151 * <tr> 152 * <td>timestamp</td> 153 * <td>double</td> 154 * <td>time of the event, in simulation time seconds</td> 155 * </tr> 156 * <tr> 157 * <td>gtuId</td> 158 * <td>String</td> 159 * <td>id of the vehicle that has a new position</td> 160 * </tr> 161 * <tr> 162 * <td>position.x</td> 163 * <td>double</td> 164 * <td>x-coordinate of the gtu position at the timestamp</td> 165 * </tr> 166 * <tr> 167 * <td>position.y</td> 168 * <td>double</td> 169 * <td>y-coordinate of the gtu position at the timestamp</td> 170 * </tr> 171 * <tr> 172 * <td>position.z</td> 173 * <td>double</td> 174 * <td>z-coordinate of the gtu position at the timestamp</td> 175 * </tr> 176 * <tr> 177 * <td>position.rotZ</td> 178 * <td>double</td> 179 * <td>angle in the x-y plane of the gtu</td> 180 * </tr> 181 * <tr> 182 * <td>networkId</td> 183 * <td>String</td> 184 * <td>Id of the Network where the gtu's reference point is</td> 185 * </tr> 186 * <tr> 187 * <td>linkId</td> 188 * <td>String</td> 189 * <td>id of the Link; unique within the Network</td> 190 * </tr> 191 * <tr> 192 * <td>laneId</td> 193 * <td>String</td> 194 * <td>id of the Lane, unique within the Link</td> 195 * </tr> 196 * <tr> 197 * <td>longitudinalPosition</td> 198 * <td>double</td> 199 * <td>gtu position on the center line of the lane, in meters</td> 200 * </tr> 201 * <tr> 202 * <td>speed</td> 203 * <td>double</td> 204 * <td>current speed of the gtu, in m/s</td> 205 * </tr> 206 * <tr> 207 * <td>acceleration</td> 208 * <td>double</td> 209 * <td>current acceleration of the gtu, in m/s2</td> 210 * </tr> 211 * <tr> 212 * <td>turnIndicatorStatus</td> 213 * <td>String</td> 214 * <td>one of {NONE, LEFT, RIGHT, HAZARD, NOTPRESENT}</td> 215 * </tr> 216 * <tr> 217 * <td>brakingLights</td> 218 * <td>boolean</td> 219 * <td>braking lights on or off</td> 220 * </tr> 221 * <tr> 222 * <td>odometer</td> 223 * <td>double</td> 224 * <td>odometer reading of the GTU, in meters</td> 225 * </tr> 226 * </tbody> 227 * </table> 228 * </p> 229 * <p> 230 * <h2>DELETE</h2> 231 * <table summary="" style="width:800px;"> 232 * <thead> 233 * <tr> 234 * <th style="width:25%;">Variable</th> 235 * <th style="width:15%;">Type</th> 236 * <th style="width:60%;">Comments</th> 237 * </tr> 238 * </thead><tbody> 239 * <tr> 240 * <td>timestamp</td> 241 * <td>double</td> 242 * <td>time of the event, in simulation time seconds</td> 243 * </tr> 244 * <tr> 245 * <td>gtuId</td> 246 * <td>String</td> 247 * <td>id of the GTU that that is removed from the simulation</td> 248 * </tr> 249 * <tr> 250 * <td>lastPosition.x</td> 251 * <td>double</td> 252 * <td>x-coordinate of the gtu position at removal</td> 253 * </tr> 254 * <tr> 255 * <td>lastPosition.y</td> 256 * <td>double</td> 257 * <td>y-coordinate of the gtu position at removal</td> 258 * </tr> 259 * <tr> 260 * <td>lastPosition.z</td> 261 * <td>double</td> 262 * <td>z-coordinate of the gtu position at removal</td> 263 * </tr> 264 * <tr> 265 * <td>position.rotZ</td> 266 * <td>double</td> 267 * <td>angle in the x-y plane of the gtu</td> 268 * </tr> 269 * <tr> 270 * <td>lastNetworkId</td> 271 * <td>String</td> 272 * <td>Id of the Network where the Link resides</td> 273 * </tr> 274 * <tr> 275 * <td>lastLinkId</td> 276 * <td>String</td> 277 * <td>id of the Link where the GTU was destroyed</td> 278 * </tr> 279 * <tr> 280 * <td>lastLaneId</td> 281 * <td>String</td> 282 * <td>id of the Lane in the Link where the GTU was destroyed</td> 283 * </tr> 284 * <tr> 285 * <td>lastLongitudinalPosition</td> 286 * <td>double</td> 287 * <td>gtu position on the center line of the lane, in meters</td> 288 * </tr> 289 * <tr> 290 * <td>odometer</td> 291 * <td>double</td> 292 * <td>final odometer reading of the GTU, in meters</td> 293 * </tr> 294 * </tbody> 295 * </table> 296 * </p> 297 * <p> 298 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 299 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 300 * </p> 301 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $, 302 * initial version Sep 11, 2016 <br> 303 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 304 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a> 305 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a> 306 */ 307 public class GTUTransceiver extends AbstractTransceiver 308 { 309 /** */ 310 private static final long serialVersionUID = 20160911L; 311 312 /** the OTS network on which GTUs are registered. */ 313 private final OTSNetwork network; 314 315 /** 316 * Construct a new GTUTransceiver. 317 * @param connector Connector; the IMB connector through which this transceiver communicates 318 * @param simulator OTSDEVSSimulatorInterface; the simulator to schedule the incoming notifications on 319 * @param network OTSNetwork; the OTS network on which GTUs are registered 320 * @throws IMBException when the registration of one of the channels fails 321 * @throws NullPointerException in case one of the arguments is null. 322 */ 323 public GTUTransceiver(final Connector connector, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network) 324 throws IMBException 325 { 326 super("GTU", connector, simulator); 327 this.network = network; 328 329 // listen on network changes and register the listeners to the GTUs 330 addListeners(); 331 } 332 333 /** 334 * Ensure that we get notified about newly created and destroyed GTUs and for each already existing GTU generate a 335 * GTU_ADD_EVENT. 336 * @throws IMBException in case notification of existing GTU fails 337 */ 338 private void addListeners() throws IMBException 339 { 340 this.network.addListener(this, Network.GTU_ADD_EVENT); 341 this.network.addListener(this, Network.GTU_REMOVE_EVENT); 342 343 // Also add all GTUs that were instantiated when the model was constructed, and re-send their INIT event... 344 for (GTU gtu : this.network.getGTUs()) 345 { 346 try 347 { 348 this.notify(new TimedEvent<OTSSimTimeDouble>(Network.GTU_ADD_EVENT, this.network, gtu.getId(), 349 gtu.getSimulator().getSimulatorTime())); 350 LaneBasedGTU laneBasedGTU = (LaneBasedGTU) gtu; 351 DirectedLanePosition dlp = laneBasedGTU.getReferencePosition(); 352 this.notify(new TimedEvent<OTSSimTimeDouble>(LaneBasedGTU.LANEBASED_INIT_EVENT, gtu, 353 new Object[] { gtu.getId(), gtu.getLocation(), gtu.getLength(), gtu.getWidth(), gtu.getBaseColor(), 354 dlp.getLane(), dlp.getGtuDirection() }, 355 gtu.getSimulator().getSimulatorTime())); 356 } 357 catch (RemoteException | GTUException exception) 358 { 359 exception.printStackTrace(); 360 } 361 } 362 } 363 364 /** {@inheritDoc} */ 365 @Override 366 public void notify(final EventInterface event) throws RemoteException 367 { 368 try 369 { 370 // do not call super.notify(event); we will do that only when needed. 371 372 if (event.getType().equals(Network.GTU_ADD_EVENT)) 373 { 374 String gtuId = event.getContent().toString(); 375 GTU gtu = this.network.getGTU(gtuId); 376 gtu.addListener(this, LaneBasedGTU.LANEBASED_INIT_EVENT, true); 377 gtu.addListener(this, LaneBasedGTU.LANEBASED_MOVE_EVENT, true); 378 gtu.addListener(this, LaneBasedGTU.LANEBASED_DESTROY_EVENT, true); 379 } 380 381 else if (event.getType().equals(Network.GTU_REMOVE_EVENT)) 382 { 383 String gtuId = event.getContent().toString(); 384 GTU gtu = this.network.getGTU(gtuId); 385 gtu.removeListener(this, LaneBasedGTU.LANEBASED_INIT_EVENT); 386 gtu.removeListener(this, LaneBasedGTU.LANEBASED_MOVE_EVENT); 387 gtu.removeListener(this, LaneBasedGTU.LANEBASED_DESTROY_EVENT); 388 } 389 390 else if (event.getType().equals(LaneBasedGTU.LANEBASED_INIT_EVENT)) 391 { 392 // register the IMB channel for this GTU, and send NEW payload 393 getConnector().postIMBMessage("GTU", Connector.IMBEventType.NEW, transformNew(event)); 394 } 395 396 else if (event.getType().equals(LaneBasedGTU.LANEBASED_MOVE_EVENT)) 397 { 398 // send CHANGE payload 399 // TODO -- does not work because GTU is registered only once 400 // super.notify(event); 401 getConnector().postIMBMessage("GTU", Connector.IMBEventType.CHANGE, transformChange(event)); 402 } 403 404 else if (event.getType().equals(LaneBasedGTU.LANEBASED_DESTROY_EVENT)) 405 { 406 // send DELETE payload 407 getConnector().postIMBMessage("GTU", Connector.IMBEventType.DELETE, transformDelete(event)); 408 } 409 } 410 catch (IMBException exception) 411 { 412 // TODO implement proper error handling 413 exception.printStackTrace(); 414 } 415 } 416 417 /** 418 * Transform the addition of a GTU to the network to a corresponding IMB message. 419 * @param event the event to transform to a NEW message. 420 * @return the NEW payload 421 */ 422 private Object[] transformNew(final EventInterface event) 423 { 424 if (LaneBasedGTU.LANEBASED_INIT_EVENT.equals(event.getType())) 425 { 426 // content contains: [String gtuId, DirectedPoint initialPosition, Length length, Length width, Color 427 // gtuBaseColor, 428 // Lane referenceLane, Length positionOnReferenceLane] 429 Object[] content = (Object[]) event.getContent(); 430 double timestamp = getSimulator().getSimulatorTime().getTime().si; 431 String gtuId = content[0].toString(); 432 DirectedPoint location = (DirectedPoint) content[1]; 433 Lane lane = (Lane) content[5]; 434 double longitudinalPosition = ((Length) content[6]).si; 435 double length = ((Length) content[2]).si; 436 double width = ((Length) content[3]).si; 437 Color color = (Color) content[4]; 438 return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(), 439 lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition, 440 length, width, (byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue() }; 441 } 442 System.err.println("LaneGTUTransceiver.transformNew: Don't know how to transform event " + event); 443 return new Object[] {}; 444 } 445 446 /** 447 * Transform the deletion of a GTU from the network to a corresponding IMB message. 448 * @param event the event to transform to a DELETE message. 449 * @return the DELETE payload 450 */ 451 private Object[] transformDelete(final EventInterface event) 452 { 453 if (LaneBasedGTU.LANEBASED_DESTROY_EVENT.equals(event.getType())) 454 { 455 // content contains: [String gtuId, DirectedPoint lastPosition, Length odometer, Lane referenceLane, 456 // Length positionOnReferenceLane] 457 Object[] content = (Object[]) event.getContent(); 458 double timestamp = getSimulator().getSimulatorTime().getTime().si; 459 String gtuId = content[0].toString(); 460 DirectedPoint location = (DirectedPoint) content[1]; 461 double odometer = ((Length) content[2]).si; 462 Lane lane = (Lane) content[3]; 463 double longitudinalPosition = ((Length) content[4]).si; 464 return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(), 465 lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition, 466 odometer }; 467 } 468 System.err.println("LaneGTUTransceiver.transformNew: Don't know how to transform event " + event); 469 return new Object[] {}; 470 } 471 472 /** 473 * Transform the move of a GTU in the network to a corresponding IMB message. 474 * @param event the event to transform to a CHANGE message. 475 * @return the CHANGE payload 476 */ 477 private Object[] transformChange(final EventInterface event) 478 { 479 // moveInfo contains: {String gtuId, DirectedPoint position, Speed speed, Acceleration acceleration, 480 // TurnIndicatorStatus turnIndicatorStatus, Length odometer, Lane referenceLane, Length positionOnReferenceLane} 481 Object[] moveInfo = (Object[]) event.getContent(); 482 String gtuId = moveInfo[0].toString(); 483 DirectedPoint location = (DirectedPoint) moveInfo[1]; 484 LaneBasedGTU gtu = (LaneBasedGTU) event.getSource(); 485 Lane lane = (Lane) moveInfo[6]; 486 double longitudinalPosition = ((Length) moveInfo[7]).si; 487 double speed = ((Speed) moveInfo[2]).si; 488 double acceleration = ((Acceleration) moveInfo[3]).si; 489 double timestamp = gtu.getSimulator().getSimulatorTime().getTime().si; 490 String turnIndicatorStatus = ((TurnIndicatorStatus) moveInfo[4]).toString(); 491 double odometer = ((Length) moveInfo[5]).si; 492 boolean brakingLights = acceleration < 0.0; // TODO proper function for isBraking() 493 return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(), 494 lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition, 495 speed, acceleration, turnIndicatorStatus, brakingLights, odometer }; 496 } 497 498 /** 499 * Transform the LaneBasedGTU.LANEBASED_MOVE_EVENT content to a corresponding IMB message. 500 * <p> 501 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. 502 * <br> 503 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 504 * </p> 505 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $, 506 * initial version Sep 11, 2016 <br> 507 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 508 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a> 509 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a> 510 */ 511 static class GTUTransformerChange implements OTSToIMBTransformer 512 { 513 /** {@inheritDoc} */ 514 @Override 515 public Object[] transform(final EventInterface event) 516 { 517 // moveInfo contains: {String gtuId, DirectedPoint position, Speed speed, Acceleration acceleration, 518 // TurnIndicatorStatus turnIndicatorStatus, Length odometer, Lane referenceLane, Length positionOnReferenceLane} 519 Object[] moveInfo = (Object[]) event.getContent(); 520 String gtuId = moveInfo[0].toString(); 521 DirectedPoint location = (DirectedPoint) moveInfo[1]; 522 LaneBasedGTU gtu = (LaneBasedGTU) event.getSource(); 523 Lane lane = (Lane) moveInfo[6]; 524 double longitudinalPosition = ((Length) moveInfo[7]).si; 525 double speed = ((Speed) moveInfo[2]).si; 526 double acceleration = ((Acceleration) moveInfo[3]).si; 527 double timestamp = gtu.getSimulator().getSimulatorTime().getTime().si; 528 String turnIndicatorStatus = ((TurnIndicatorStatus) moveInfo[4]).toString(); 529 double odometer = ((Length) moveInfo[5]).si; 530 boolean brakingLights = acceleration < 0.0; // TODO proper function for isBraking() 531 return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(), 532 lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition, 533 speed, acceleration, turnIndicatorStatus, brakingLights, odometer }; 534 } 535 } 536 }