View Javadoc
1   package org.opentrafficsim.imb.transceiver.urbanstrategy;
2   
3   import java.rmi.RemoteException;
4   
5   import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
6   import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
7   import org.opentrafficsim.core.gtu.RelativePosition;
8   import org.opentrafficsim.core.network.Link;
9   import org.opentrafficsim.core.network.Network;
10  import org.opentrafficsim.core.network.OTSNetwork;
11  import org.opentrafficsim.imb.IMBException;
12  import org.opentrafficsim.imb.connector.Connector;
13  import org.opentrafficsim.imb.connector.Connector.IMBEventType;
14  import org.opentrafficsim.imb.transceiver.AbstractTransceiver;
15  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
16  import org.opentrafficsim.road.network.lane.CrossSectionLink;
17  import org.opentrafficsim.road.network.lane.Lane;
18  import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
19  
20  import nl.tudelft.simulation.event.Event;
21  import nl.tudelft.simulation.event.EventInterface;
22  import nl.tudelft.simulation.event.EventType;
23  import nl.tudelft.simulation.event.TimedEvent;
24  import nl.tudelft.simulation.language.d3.DirectedPoint;
25  
26  /**
27   * OTS publishes events about sensor triggers to IMB, e.g. to show that a vehicle has triggered a sensor for a traffic
28   * light.<br>
29   * At the start of the OTS simulation, or when a sensor is added later, a NEW message is sent to IMB to identify the sensor, the
30   * lane on which it resides, and the position on the lane. The CHANGE message is posted whenever a vehicle triggers the sensor.
31   * When a Sensor is removed from the network, a DELETE event is posted. The Sensor NEW messages are posted after the Network
32   * NEW, Node NEW, Link NEW, and Lane NEW messages are posted.
33   * <p>
34   * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style>
35   * <h2>NEW</h2>
36   * <table summary="" style="width:800px;">
37   * <thead>
38   * <tr>
39   * <th style="width:25%;">Variable</th>
40   * <th style="width:15%;">Type</th>
41   * <th style="width:60%;">Comments</th>
42   * </tr>
43   * </thead><tbody>
44   * <tr>
45   * <td>timestamp</td>
46   * <td>double</td>
47   * <td>time of the event, in simulation time seconds</td>
48   * </tr>
49   * <tr>
50   * <td>networkId</td>
51   * <td>String</td>
52   * <td>Id of the Network where the Link resides</td>
53   * </tr>
54   * <tr>
55   * <td>linkId</td>
56   * <td>String</td>
57   * <td>id of the Link; unique within the Network</td>
58   * </tr>
59   * <tr>
60   * <td>laneId</td>
61   * <td>String</td>
62   * <td>id of the Lane, unique within the Link</td>
63   * </tr>
64   * <tr>
65   * <td>sensorId</td>
66   * <td>String</td>
67   * <td>id of the Sensor, unique within the Lane</td>
68   * </tr>
69   * <tr>
70   * <td>longitudinalPosition</td>
71   * <td>double</td>
72   * <td>position on the center line of the lane, in meters</td>
73   * </tr>
74   * <tr>
75   * <td>length</td>
76   * <td>double</td>
77   * <td>length of the sensor, in meters</td>
78   * </tr>
79   * <tr>
80   * <td>sensorPosition.x</td>
81   * <td>double</td>
82   * <td>x-coordinate of the sensor position in (gis) coordinates</td>
83   * </tr>
84   * <tr>
85   * <td>sensorPosition.y</td>
86   * <td>double</td>
87   * <td>y-coordinate of the sensor position in (gis) coordinates</td>
88   * </tr>
89   * <tr>
90   * <td>sensorPosition.z</td>
91   * <td>double</td>
92   * <td>z-coordinate of the sensor position in (gis) coordinates</td>
93   * </tr>
94   * <tr>
95   * <td>triggerPosition</td>
96   * <td>String</td>
97   * <td>Relative position of the vehicle that triggers this sensor. One of {FRONT, REAR, REFERENCE, CONTOUR, CENTER, DRIVER}</td>
98   * </tr>
99   * </tbody>
100  * </table>
101  * </p>
102  * <p>
103  * <h2>CHANGE</h2>
104  * <table summary="" style="width:800px;">
105  * <thead>
106  * <tr>
107  * <th style="width:25%;">Variable</th>
108  * <th style="width:15%;">Type</th>
109  * <th style="width:60%;">Comments</th>
110  * </tr>
111  * </thead><tbody>
112  * <tr>
113  * <td>timestamp</td>
114  * <td>double</td>
115  * <td>time of the event, in simulation time seconds</td>
116  * </tr>
117  * <tr>
118  * <td>networkId</td>
119  * <td>String</td>
120  * <td>Id of the Network where the Lane resides</td>
121  * </tr>
122  * <tr>
123  * <td>linkId</td>
124  * <td>String</td>
125  * <td>id of the Link to which the lane belongs</td>
126  * </tr>
127  * <tr>
128  * <td>laneId</td>
129  * <td>String</td>
130  * <td>id of the Lane, unique within the Link</td>
131  * </tr>
132  * <tr>
133  * <td>sensorId</td>
134  * <td>String</td>
135  * <td>id of the Sensor, unique within the Lane</td>
136  * </tr>
137  * <tr>
138  * <td>gtuId</td>
139  * <td>String</td>
140  * <td>id of the vehicle that triggers the sensor</td>
141  * </tr>
142  * <tr>
143  * <td>speed</td>
144  * <td>double</td>
145  * <td>speed of the vehicle that triggers the sensor, in m/s</td>
146  * </tr>
147  * <tr>
148  * <td>triggerPosition</td>
149  * <td>String</td>
150  * <td>Relative position of the vehicle that triggers this sensor. One of {FRONT, REAR, REFERENCE, CONTOUR, CENTER, DRIVER}</td>
151  * </tr>
152  * </tbody>
153  * </table>
154  * </p>
155  * <p>
156  * <h2>DELETE</h2>
157  * <table summary="" style="width:800px;">
158  * <thead>
159  * <tr>
160  * <th style="width:25%;">Variable</th>
161  * <th style="width:15%;">Type</th>
162  * <th style="width:60%;">Comments</th>
163  * </tr>
164  * </thead><tbody>
165  * <tr>
166  * <td>timestamp</td>
167  * <td>double</td>
168  * <td>time of the event, in simulation time seconds</td>
169  * </tr>
170  * <tr>
171  * <td>networkId</td>
172  * <td>String</td>
173  * <td>Id of the Network where the Link resides</td>
174  * </tr>
175  * <tr>
176  * <td>linkId</td>
177  * <td>String</td>
178  * <td>id of the Link in the Network</td>
179  * </tr>
180  * <tr>
181  * <td>laneId</td>
182  * <td>String</td>
183  * <td>id of the Lane in the Link</td>
184  * </tr>
185  * <tr>
186  * <td>sensorId</td>
187  * <td>String</td>
188  * <td>id of the Sensor that is removed from the Lane</td>
189  * </tr>
190  * </tbody>
191  * </table>
192  * </p>
193  * <p>
194  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
195  * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
196  * </p>
197  * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 13, 2016 <br>
198  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
199  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
200  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
201  */
202 public class SensorGTUTransceiver extends AbstractTransceiver
203 {
204     /** */
205     private static final long serialVersionUID = 20160918L;
206 
207     /** the OTS network on which Links / Lanes are registered. */
208     private final OTSNetwork network;
209 
210     /**
211      * Construct a new SensorGTUTransceiver.
212      * @param connector Connector; the IMB connector through which this transceiver communicates
213      * @param simulator OTSDEVSSimulatorInterface; the simulator to schedule the incoming notifications on
214      * @param network OTSNetwork; the OTS network on which Links for Lanes are registered
215      * @throws IMBException when the registration of one of the channels fails
216      * @throws NullPointerException in case one of the arguments is null.
217      */
218     public SensorGTUTransceiver(final Connector connector, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
219             throws IMBException
220     {
221         super("Sensor_GTU", connector, simulator);
222         this.network = network;
223 
224         // listen on network changes and register the listener to all the Links
225         addListeners();
226     }
227 
228     /**
229      * Ensure that we get notified about newly created and destroyed Links instrument all currently existing Links.
230      * @throws IMBException in case notification of existing Lanes fails
231      */
232     private void addListeners() throws IMBException
233     {
234         // Subscribe to all future link creation and removal events.
235         this.network.addListener(this, Network.LINK_ADD_EVENT);
236         this.network.addListener(this, Network.LINK_REMOVE_EVENT);
237 
238         // For already existing links, post ourselves a LINK_ADD_EVENT
239         for (Link link : this.network.getLinkMap().values())
240         {
241             try
242             {
243                 this.notify(new TimedEvent<OTSSimTimeDouble>(Network.LINK_ADD_EVENT, this.network, link.getId(),
244                         getSimulator().getSimulatorTime()));
245             }
246             catch (RemoteException exception)
247             {
248                 throw new IMBException(exception);
249             }
250         }
251     }
252 
253     /** {@inheritDoc} */
254     @Override
255     public void notify(final EventInterface event) throws RemoteException
256     {
257         EventType type = event.getType();
258         if (type.equals(Network.LINK_ADD_EVENT))
259         {
260             Link link = this.network.getLink((String) event.getContent());
261             if (!(link instanceof CrossSectionLink))
262             {
263                 System.err.println("SensorGTUTransceiver.notify(LINK_ADD) - Don't know how to handle a non-CrossSectionLink");
264                 return;
265             }
266             CrossSectionLink csl = (CrossSectionLink) link;
267 
268             csl.addListener(this, CrossSectionLink.LANE_ADD_EVENT);
269             csl.addListener(this, CrossSectionLink.LANE_REMOVE_EVENT);
270 
271             // For already existing lanes, post ourselves a LANE_ADD_EVENT
272             for (Lane lane : csl.getLanes())
273             {
274                 try
275                 {
276                     this.notify(new Event(CrossSectionLink.LANE_ADD_EVENT, csl, new Object[] { link.getNetwork().getId(),
277                             link.getId(), lane.getId(), lane, csl.getLanes().indexOf(lane) }));
278                 }
279                 catch (RemoteException exception)
280                 {
281                     System.err.println("SensorGTUTransceiver.notify(LINK_ADD) - RemoteException: " + exception.getMessage());
282                     return;
283                 }
284             }
285         }
286 
287         else if (type.equals(CrossSectionLink.LANE_ADD_EVENT))
288         {
289             Object[] content = (Object[]) event.getContent();
290             Lane lane = (Lane) content[3];
291 
292             lane.addListener(this, Lane.SENSOR_ADD_EVENT);
293             lane.addListener(this, Lane.SENSOR_REMOVE_EVENT);
294 
295             // Post ourselves a SENSOR_ADD_EVENT for every Sensor currently on the lane
296             for (Sensor sensor : lane.getSensors())
297             {
298                 try
299                 {
300                     this.notify(new TimedEvent<OTSSimTimeDouble>(Lane.SENSOR_ADD_EVENT, lane,
301                             new Object[] { sensor.getId(), sensor }, getSimulator().getSimulatorTime()));
302                 }
303                 catch (RemoteException exception)
304                 {
305                     System.err.println("SensorGTUTransceiver.notify(LANE_ADD) - RemoteException: " + exception.getMessage());
306                     return;
307                 }
308             }
309         }
310 
311         else if (type.equals(Lane.SENSOR_ADD_EVENT))
312         {
313             Object[] content = (Object[]) event.getContent();
314             Sensor sensor = (Sensor) content[1];
315             sensor.addListener(this, Sensor.SENSOR_TRIGGER_EVENT);
316             
317             try
318             {
319                 getConnector().postIMBMessage("Sensor_GTU", IMBEventType.NEW, transformNew(event));
320             }
321             catch (IMBException exception)
322             {
323                 System.err.println("SensorGTUTransceiver.notify(SENSOR_ADD) - IMBException: " + exception.getMessage());
324                 return;
325             }
326         }
327 
328         else if (type.equals(Sensor.SENSOR_TRIGGER_EVENT))
329         {
330             try
331             {
332                 getConnector().postIMBMessage("Sensor_GTU", IMBEventType.CHANGE, transformChange(event));
333             }
334             catch (IMBException exception)
335             {
336                 System.err.println("SensorGTUTransceiver.notify(SENSOR_TRIGGER) - IMBException: " + exception.getMessage());
337                 return;
338             }
339         }
340 
341         else if (type.equals(Network.LINK_REMOVE_EVENT))
342         {
343             Link link = this.network.getLink((String) event.getContent());
344             if (!(link instanceof CrossSectionLink))
345             {
346                 System.err
347                         .println("SensorGTUTransceiver.notify(LINK_REMOVE) - Don't know how to handle a non-CrossSectionLink");
348                 return;
349             }
350             CrossSectionLink csl = (CrossSectionLink) link;
351 
352             csl.removeListener(this, CrossSectionLink.LANE_ADD_EVENT);
353             csl.removeListener(this, CrossSectionLink.LANE_REMOVE_EVENT);
354 
355             // For already existing lanes, post ourselves a LANE_REMOVE_EVENT
356             for (Lane lane : csl.getLanes())
357             {
358                 try
359                 {
360                     this.notify(new Event(CrossSectionLink.LANE_REMOVE_EVENT, csl,
361                             new Object[] { link.getNetwork().getId(), link.getId(), lane.getId() }));
362                 }
363                 catch (RemoteException exception)
364                 {
365                     System.err.println("SensorGTUTransceiver.notify(LINK_REMOVE) - RemoteException: " + exception.getMessage());
366                     return;
367                 }
368             }
369         }
370 
371         else if (type.equals(CrossSectionLink.LANE_REMOVE_EVENT))
372         {
373             Object[] content = (Object[]) event.getContent();
374             String laneId = (String) content[2];
375             CrossSectionLink csl = (CrossSectionLink) event.getSource();
376             Lane lane = (Lane) csl.getCrossSectionElement(laneId);
377 
378             lane.removeListener(this, Lane.SENSOR_ADD_EVENT);
379             lane.removeListener(this, Lane.SENSOR_REMOVE_EVENT);
380 
381             // Post ourselves a SENSOR_REMOVE_EVENT for every Sensor currently on the lane
382             for (Sensor sensor : lane.getSensors())
383             {
384                 try
385                 {
386                     this.notify(new TimedEvent<OTSSimTimeDouble>(Lane.SENSOR_REMOVE_EVENT, lane,
387                             new Object[] { sensor.getId(), sensor }, getSimulator().getSimulatorTime()));
388                 }
389                 catch (RemoteException exception)
390                 {
391                     System.err.println("SensorGTUTransceiver.notify(LANE_REMOVE) - RemoteException: " + exception.getMessage());
392                     return;
393                 }
394             }
395             
396             // post the Node message to de-register the lane from the IMB bus
397             try
398             {
399                 getConnector().postIMBMessage("Sensor_GTU", IMBEventType.DELETE, transformDelete(event));
400             }
401             catch (IMBException exception)
402             {
403                 System.err.println("SensorGTUTransceiver.notify(LANE_REMOVE) - IMBException: " + exception.getMessage());
404                 return;
405             }
406         }
407 
408         else if (type.equals(Lane.SENSOR_REMOVE_EVENT))
409         {
410             Object[] content = (Object[]) event.getContent();
411             Sensor sensor = (Sensor) content[1];
412             sensor.removeListener(this, Sensor.SENSOR_TRIGGER_EVENT);
413 
414             try
415             {
416                 getConnector().postIMBMessage("Sensor_GTU", IMBEventType.DELETE, transformDelete(event));
417             }
418             catch (IMBException exception)
419             {
420                 System.err.println("SensorGTUTransceiver.notify(SENSOR_REMOVE) - IMBException: " + exception.getMessage());
421                 return;
422             }
423         }
424 
425         else
426         {
427             System.err.println("SensorGTUTransceiver.notify - Unhandled event: " + event);
428         }
429     }
430 
431     /**
432      * Transform the addition of a Sensor to a Lane to a corresponding IMB message.
433      * @param event the event to transform to a NEW message.
434      * @return the NEW payload
435      */
436     private Object[] transformNew(final EventInterface event)
437     {
438         if (Lane.SENSOR_ADD_EVENT.equals(event.getType()))
439         {
440             // Object[] {String sensorId, Sensor sensor}
441             Object[] content = (Object[]) event.getContent();
442             String sensorId = (String) content[0];
443             Sensor sensor = (Sensor) content[1];
444             Lane lane = sensor.getLane();
445             double longitudinalPosition = sensor.getLongitudinalPosition().si;
446             double length = 0.0; // sensor has zero length right now
447             DirectedPoint pos = sensor.getLocation();
448             String triggerPosition = sensor.getPositionType().toString();
449             double timestamp = getSimulator().getSimulatorTime().getTime().si;
450             return new Object[] { timestamp, this.network.getId(), lane.getParentLink().getId(), lane.getId(), sensorId,
451                     longitudinalPosition, length, pos.x, pos.y, pos.z, triggerPosition };
452         }
453         System.err.println("SensorGTUTransceiver.transformNew: Don't know how to transform event " + event);
454         return new Object[] {};
455     }
456 
457     /**
458      * Transform the Sensor Triggered event content to a corresponding IMB message.
459      * @param event the event to transform to a CHANGE message.
460      * @return the CHANGE payload
461      */
462     private Object[] transformChange(final EventInterface event)
463     {
464         if (Sensor.SENSOR_TRIGGER_EVENT.equals(event.getType()))
465         {
466             // Object[] {String sensorId, Sensor sensor, LaneBasedGTU gtu, RelativePosition.TYPE relativePosition}
467             Object[] content = (Object[]) event.getContent();
468             String sensorId = (String) content[0];
469             Sensor sensor = (Sensor) content[1];
470             Lane lane = sensor.getLane();
471             LaneBasedGTU gtu = (LaneBasedGTU) content[2];
472             String gtuId = gtu.getId();
473             double gtuSpeed = gtu.getSpeed().si;
474             String triggerPosition = ((RelativePosition.TYPE) content[3]).toString();
475             double timestamp = getSimulator().getSimulatorTime().getTime().si;
476             return new Object[] { timestamp, this.network.getId(), lane.getParentLink().getId(), lane.getId(), sensorId, gtuId,
477                     gtuSpeed, triggerPosition };
478         }
479         System.err.println("SensorGTUTransceiver.transformChange: Don't know how to transform event " + event);
480         return new Object[] {};
481     }
482 
483     /**
484      * Transform the removal of a Sensor from a Lane to a corresponding IMB message.
485      * @param event the event to transform to a DELETE message.
486      * @return the DELETE payload
487      */
488     private Object[] transformDelete(final EventInterface event)
489     {
490         if (Lane.SENSOR_REMOVE_EVENT.equals(event.getType()))
491         {
492             // Object[] {String sensorId, Sensor sensor}
493             Object[] content = (Object[]) event.getContent();
494             String sensorId = (String) content[0];
495             Sensor sensor = (Sensor) content[1];
496             Lane lane = sensor.getLane();
497             double timestamp = getSimulator().getSimulatorTime().getTime().si;
498             return new Object[] { timestamp, this.network.getId(), lane.getParentLink().getId(), lane.getId(), sensorId };
499         }
500         System.err.println("SensorGTUTransceiver.transformDelete: Don't know how to transform event " + event);
501         return new Object[] {};
502     }
503 
504 }