aboutsummaryrefslogtreecommitdiff
path: root/.idea/gtfs-realtime-book/ch-03-vehicle-positions.md
blob: f247ae700f2037cf089ebabbc0d4bdb826deeb0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
## 3. Introduction to Vehicle Positions

A vehicle position message communicates the physical location of a bus,
train, ferry or otherwise. In addition to location of the vehicle, it
can also provide information about the vehicle's speed, bearing (the
direction it is facing), and how to match up the vehicle with a trip in
the static schedule.

A recent addition to the GTFS-realtime specification (experimental at
time of writing -- see
<https://developers.google.com/transit/gtfs-realtime/changes>) is the
ability to indicate how full a vehicle is. Although this element is not
yet formally a part of the specification, it has been included in this
book so it aligns with current documentation.

### Sample Feed

The following extract is from the vehicle position feed of MBTA in
Boston (<https://openmobilitydata.org/p/mbta/92>). MBTA also provide separate
feeds for service alerts and trip updates.

This extract contains a single GTFS-realtime entity, which represents a
single vehicle position.

```
entity {
  id: "v1211"
  
  vehicle {
    trip {
      trip_id: "25906883"
      start_date: "20150117"
      schedule_relationship: SCHEDULED
      route_id: "28"
    }
    
    position {
      latitude: 42.267967
      longitude: -71.093834
    }
    
    current_stop_sequence: 35
    timestamp: 1421565564
    stop_id: "1721"
    
    vehicle {
      id: "y2189"
      label: "2189"
    }
  }
}
```

***Note:** This extract has been converted from its binary format into a
human-readable version. *Outputting Human-Readable GTFS-realtime Feeds*
shows you how this is achieved.*

Rendering the vehicle position and its path on a map along with the
referenced stop looks as follows.

![Vehicle Position](images/vehicle-position.png)

The elements of the vehicle position are described below. The outer
`vehicle` element in this entity is of type `VehiclePosition`. The
inner `vehicle` element is a `VehicleDescriptor`, which is described
shortly.

### Trip

If specified, this element is used to link the vehicle position to a
specific trip in the corresponding GTFS feed, or to a trip that has been
added to the schedule. Using MBTA's GTFS feed, you can determine that
the trip can be matched to the record below. You can find this in the
trips.txt file at
<https://openmobilitydata.org/p/mbta/64/latest/file/trips.txt>.

| `route_id` | `service_id`                   | `trip_id` | `trip_headsign`                      |
| :--------- | :----------------------------- | :-------- | :-------------- |
| 28         | BUSS12015-hbs15no6-Saturday-02 | 25906883  |  Mattapan Station via Dudley Station |

**Note:** If the schedule_relationship value was ADDED or UNSCHEDULED,
there would not have been a corresponding record in trips.txt.

If you then look up the trip's records in stop_times.txt, you can
determine the trip begins at 25:45:00. This means the trip begins at
1:45 AM on the morning following its service date. In this case, the
start date in the vehicle position is specified as January 17. This
means that this trip actually takes place on the morning of January 18.
If the start date was not included with the vehicle position, it may
have been difficult to determine the specific trip being referenced.

### Position

This element contains the geographic location of the vehicle. In this
instance, only the latitude and longitude are specified. It is also
possible to include the vehicle's bearing, odometer and speed, however
only that latitude and longitude are required.

### Current Stop

A vehicle position can include information about its position relative
to its current or next stop.

The status of the stop is indicated by the `current_status` value. In
this example, the `current_status` is not specified, which means the
vehicle is currently in transit to the stop (in other words, it is not
stopped there, nor is it about to stop).

The stop referred to in this instance has a `stop_id` of `1721`.
Referring once again to the MBTA GTFS feed
(<https://openmobilitydata.org/p/mbta/64/latest/stop/1721>), this stop is as
follows.

| `stop_id` | `stop_code` | `stop_name`               | `stop_lat` | `stop_lon` |
| :-------- | :---------- | :------------------------ | :--------- | :--------- |
| 1721      |   1721      |  Blue Hill Ave @ River St | 42.267151  | -71.09362  |

The other value used to identify the upcoming or current stop is the
`current_stop_sequence` value. This refers to the `stop_sequence`
value in `stop_times.txt`.

***Note:** Technically, you can infer the stop based on the trip and
current_stop_sequence value, so you do not strictly need the stop_id
value. However, in some cases it may not be possible to identify the
trip (and therefore not be able to infer the specific stop), so having
the `stop_id` value available in the vehicle position is useful.*

By looking up the stop ID and trip ID in `stop_times.txt`, you can
locate the following entry:

| `trip_id` | `stop_sequence` | `stop_id` | `arrival_time` | `departure_time` |
| :-------- | :-------------- | :-------- | :------------- | :--------------- |
| 25906883  | 35              | 1721      | 26:14:00       | 26:14:00         |

***Note:** Remember that an hour value of 26 corresponds to 2 AM on the
following day (in this instance, the trip value specifies the trip's
date as January 17, so this stop time is 2 AM on January 18).*

In plain English, this can be interpreted as "the vehicle is currently
in transit to stop 1721, scheduled to arrive at 2:14 AM." Note however,
that the timestamp value corresponds to 2:19 AM, meaning the bus is
about 5 minutes late.

Tip: You can quickly find the human-readable version of a timestamp
using the command-line tool date. You may need to set the local timezone
first. In this instance, Boston's timezone can be set using export
TZ=America/New_York. You can then use date -r 1421565564 to find the
value of Sun 18 Jan 2015 02:19:24 EST.

### Vehicle Descriptor

The vehicle descriptor provides information to identify the specific
vehicle. In this example, the internal vehicle identifier is `y2189`.
It should remain consistent for this particular vehicle across the
system. Any subsequent vehicle positions or trip updates that refer to
this vehicle should use the same identifier.

The vehicle ID value is not intended to be presented to end-users.
Instead, the label field should be used. The label could refer to a
particular train number, or perhaps a number painted on the side of a
bus. In the case of vehicle 2189, the number appears as in the following
photograph.

![MBTA Bus](images/mbta_bus.png)

The other piece of identifying information that can be presented to
users is the license plate of the vehicle. The MBTA's feed doesn't
specify this value, presumably because it duplicates the `label`
value.

### Improvements

Although this sample vehicle position contains the most pertinent
information (the coordinates of the vehicle and its corresponding trip),
knowing the direction that the vehicle is facing can also be useful.

A common way of presenting vehicle positions on a map is to show all
positions for a given route on a map. If you can provide this extra
piece of information, a passenger can look at a map of all vehicle
positions for a given route and determine which are traveling in their
desired direction, and which are traveling in the opposite direction.

***Note:** When you can match up a vehicle position to a specific trip,
it may be possible to filter which vehicles appear on the map using the
`direction_id` value for the trip. In some instances though, you may only
know the route of a vehicle and not its specific trip.*

*Chapter 7. Consuming Vehicle Positions* shows you how to
determine the bearing of a vehicle if it is not included by the data
provider.

### Specification

This section contains the specification for the `VehiclePosition`
entity type. Some of this information has been sourced from the
GTFS-realtime reference page
(<https://developers.google.com/transit/GTFS-realtime/reference>).

### VehiclePosition

A `VehiclePosition` element is used to specify the geographic position
and other attributes of a single vehicle, as well as providing
information to match that vehicle back to the corresponding GTFS feed.

| Field | Type | Frequency | Description |
| :---- | :--- | :-------- | :---------- |
| `trip`                  | `TripDescriptor`                   | Optional | This is used to match the vehicle position to a specific trip from `trips.txt` in the corresponding GTFS feed. |
| `vehicle`               | `VehicleDescriptor`                | Optional | This element provides information that can be used to identify a particular vehicle. |
| `position`              | `Position`                         | Optional | The vehicle's geographic location, bearing and speed are specified using the `Position` type. |
| `current_stop_sequence` | `int32` (32-bit signed integer)    | Optional | The sequence of the current stop, as it appears in the `stop_sequence` value for the trip matched in the corresponding `stop_times.txt` file. |
| `stop_id`               | `string`                           | Optional | This is used to identify the current stop. If specified, the `stop_id` value must correspond to an entry in the `stops.txt` file of the corresponding GTFS feed. |
| `current_status`        | `VehicleStopStatus`                | Optional | If the current stop is specified (using `current_stop_sequence`), this value specifies what the "current stop" means. If this value isn't specified, it is assumed to be `IN_TRANSIT_TO`. |
| `timestamp`             | `uint64` (64 bit unsigned integer) | Optional | This value refers to the moment at which the vehicle's position was measured, specified in number of seconds since 1-Jan-1970 00:00:00 UTC. |
| `congestion_level`      | `CongestionLevel`                  | Optional | This value indicates the status of the traffic flow the vehicle is currently experiencing. The possible values for this element are listed below this table. |
| `occupancy_status`      | `OccupancyStatus`                  | Optional | At time of writing, this field is experimental only. If specified, it indicates how full a given vehicle is. |

The possible values for the `VehicleStopStatus` enumerator are as
follows:

| Value | Description |
| :---- | :---------- |
| `INCOMING_AT` | The vehicle is just about to arrive at the specified stop. In some vehicles, there is a visual display or audio announcement when approaching the next stop. This could correspond with `current_status` changing from `IN_TRANSIT_TO` to `INCOMING_AT`. |
| `STOPPED_AT` | The vehicle is currently stationary at the stop. Once it departs the `current_status` would update to `IN_TRANSIT_TO`. |
| `IN_TRANSIT_TO` | The vehicle has departed the previous stop and is on its way to the specified stop. This is the default value if `current_status` is not specified. |

The possible values for the `CongestionLevel` enumerator are as
follows:

| Value | Description |
| :---- | :---------- |
| `UNKNOWN_CONGESTION_LEVEL` | If the congestion level is not specified, then this is the default value. |
| `RUNNING_SMOOTHLY` | Traffic is flowing smoothly. |
| `STOP_AND_GO` | Traffic is flowing, but not smoothly. |
| `CONGESTION` | The vehicle is experiencing some level of congestion, and therefore likely to be moving very slowly. |
| `SEVERE_CONGESTION` | The vehicle is experiencing a high level of congestion, and therefore likely to be not moving. |

While this information can be useful to present to the user, it does not
allow you to make any inference as to whether the vehicle will adhere to
its schedule. Schedules are often designed to account for levels of
congestion, depending on the time of day.

For this value to be useful in telling a user why their vehicle may be
late, the GTFS `stop_times.txt` would likely also need a field to
indicate the expected congestion level for any given stop time.
Realistically though, this is where the `TripUpdate` element comes
into play. This is covered in *Chapter 4. Introduction to Trip Updates*.

### TripDescriptor

The meaning of the trip descriptor differs slightly for a vehicle
position than for a service alert. In a service alert, if the
`route_id` is specified but the `trip_id` is not, then the service
alert applies to all trips for that route.

In the case of a vehicle position, if the `route_id` is specified but
not the `trip_id`, then it means the vehicle position corresponds to
"some" trip for that route, not "all" trips (it does not make sense for
it to apply to all trips).

This means that if a user wants to know the vehicle positions for a
given route, you can show them all known positions, even if you are
unable to match the trip back to a trip in the corresponding GTFS feed.

Refer to Chapter 4 for a description of all elements in a
`TripDescriptor`.

### VehicleDescriptor

This element is used to identify a specific vehicle, both internally and
for passengers. Every single vehicle in the system must have its own
identifier, and it should carry across all vehicle positions and trip
updates that correspond to the specific vehicle.

| Field | Type | Frequency | Description |
| :---- | :--- | :-------- | :---------- |
| `id`            | `string` | Optional | A unique identifier for a vehicle. This value is not intended to be shown to passengers, but rather for identifying the vehicle internally. |
| `label`         | `string` | Optional | A label that identifies the vehicle to passengers. Unlike the `id` value, this value may be repeated for multiple vehicles, and it may change for a given vehicle over the course of a trip or series of trips. This might correspond to a route number that is displayed on a bus, or a particular train number, or some other identifier that passengers can see. |
| `license_plate` | `string` | Optional | The license plate of the vehicle. |

### Position

This element specifies the geographic position of a vehicle, as well as
related attributes such as bearing and speed.

| Field | Type | Frequency | Description |
| :---- | :--- | :-------- | :---------- |
| `latitude`  | `float`  | Required | The latitude of the vehicle (a number in the range of `-90` to `90`). |
| `longitude` | `float`  | Required | The longitude of the vehicle (a number in the range of `-180` to `180`). |
| `bearing`   | `float`  | Optional | Degrees, clockwise from True North. 0 is North, 90 is East, 180 is South, 270 is West. This can be either the direction the vehicle is facing, or the direction towards the next stop (GTFS-realtime does not provide a mechanism to determine which). |
| `odometer`  | `double` | Optional | A measure of distance in meters. The GTFS-realtime specification does not state exactly what this value should represent. It could represent either the total number of meters the vehicle has ever travelled, or the number of meters travelled since the beginning of its current trip. |
| `speed`     | `float`  | Optional | The speed of the vehicle at the time of the reading, in meters per second. |

While the latitude and longitude are the most important pieces of
information in this element, the vehicle's bearing can also be useful
to know. *Determining a Vehicle's Bearing* shows you how to
determine the bearing if it is not specified.

### OccupancyStatus

***Warning:** At time of writing the OccupancyStatus enumerator is
considered experimental only.*

This enumerator is used for indicating how full a vehicle is. This can
be useful for warning passengers waiting for this vehicle that they may
not be able to fit and should instead attempt to use a different
vehicle.

| Value | Description |
| :---- | :---------- |
| `EMPTY` | Used to indicate there are no (or very few) passengers on board. |
| `MANY_SEATS_AVAILABLE` | The vehicle is not empty, but it has many seats available. |
| `FEW_SEATS_AVAILABLE` | The vehicle has some seats available and is still accepting passengers. |
| `STANDING_ROOM_AVAILABLE` | The vehicle is still accepting passengers, but they will have to stand. |
| `CRUSHED_STANDING_ROOM_ONLY` | The vehicle is still accepting passengers, but they will have to stand and there is very limited space. |
| `FULL` | The vehicle is considered full but may still be accepting new passengers |
| `NOT_ACCEPTING_PASSENGERS` | The vehicle is not accepting new passengers. |