Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add repeated CarriageDescriptor to VehicleDescriptor to encapsulate carriage specific information #66

Closed
wants to merge 11 commits into from

Conversation

RachM
Copy link
Contributor

@RachM RachM commented Jul 11, 2017

This PR adds CarriageDescriptor as a repeated field to VehicleDescriptor. The goal is to allow carriage-specific information to be specified in TripUpdates and VehiclePositions.

The repeated field was chosen as it allows producers to specify information about every carriage. In the instance where there is a single carriage (e.g. a standard bus), then producers can specify one.

The type of information that can vary by carriage that I'm interested in is:

  • Wheelchair accessibility
  • Occupancy status
  • Air conditioning
  • Toilet facilities
  • WiFi
  • Bicycle storage

Announced on GTFS-realtime Google Group at: https://groups.google.com/forum/#!topic/gtfs-realtime/VFkZYh0pnWM

@abyrd
Copy link

abyrd commented Jul 12, 2017

Hi @RachM, it does seem like a good idea to describe the composition of multi-carriage trains. Many rail travelers would appreciate this kind of information.

In an existing system in the Netherlands two additional fields are present: train-equipment-type and train-equipment-code. In many cases these imply the other amenity fields so are somewhat redundant, but it's could imply additional detail (I'm thinking of double-deck trains or large seatless areas near doors). In a particularly good implementation, it may actually allow you to visually recognize the train in the station. Check out https://drgl.nl/stop/NL:S:ut and click on any train to see its status with images and names for the carriage types, derived from such fields.

@skinkie or @skywave might be able to give you more information about this data source.

| **air_conditioning** | [AirConditioning](#enum-airconditioning) | optional | Whether the carriage is air conditioned. |
| **bicycles_allowed** | [BicyclesAllowed](#enum-bicyclesallowed) | optional | Whether bicycles are allowed in the carriage. |

## _enum_ WheelchairAccessible
Copy link
Collaborator

@barbeau barbeau Jul 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheelchair accessibility always seems to be a tricky one to tackle. I'd love to see this included, although I'd be curious to hear from producers whether or not carriage wheelchair accessibility can be appropriately modeled as a boolean (effectively, given the below enumerations). For example, does WHEELCHAIR_ACCESSIBLE mean that a wheelchair can board the carriage (i.e., travel through the doorway)? Or does it mean that there is accessible seating/tiedowns for a wheelchair? Are toilet facilities accessible to a wheelchair? All / some / none of the above?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi everyone, Sean asked me to comment on this thread. I lead a research center on accessible transportation which includes both IT and vehicle accessibility research. Being able to specify a vehicle is wheelchair accessible is important but there are some subtle nuances you all might want to consider.

As Sean mentioned, there's a difference between accessible boarding and there being accessibility features inside the vehicle. There are also cases where the accessible boarding is only at certain stations that have the right height platforms or portable lifts. Furthermore, wheelchair access is sometimes limited to specific cars on a train. Since boarding is often tied to stations or even train platforms, you may want to split boarding out from vehicle interior. Perhaps something like AccessibleBoarding (yes, no, accessible platforms only, unknown) and WheelchairParkingArea (integer from 0). These are just brainstorms since I don't know the rest of the vehicle spec discussions.

I recommend adding something to the toilet and dining car elements (if any) to indicate whether those facilities are accessible, rather than trying to fold it into a single accessibility element.

As an aside, you may also want to think about in-vehicle announcements as an element too. Visual message signs, audio announcements, etc. Those have universal value beyond just deaf and blind riders.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for the insightful comments! It's fantastic to have an accessibility expert weigh in; I'm keen to get this right.

In regards to having the accessible boarding tied to the vehicle; I've experienced both a stop/station needing to be accessible as well as the vehicle. We already capture stop accessibility (wheelchair_boarding in stops.txt), but I thought it would be useful to capture vehicle as well (for the scenario where only some vehicles servicing the stop are wheelchair-boarding accessible). The use case I have in mind is buses in Sydney; not all are wheelchair accessible, and I think it would be great to show this information to users so they can better plan their trips.

I think it's clear that my original accessibility field is too simplistic. Maybe we need a whole message to encapsulate all of the relevant accessibility information? Maybe it doesn't all belong in a message? I'll think more about this....

Summarizing the potentially important accessibility features:

  • Accessible boarding
  • Accessible boarding instructions?
  • Wheelchair parking area
  • Accessible seating
  • Accessible toilet facilities
  • Braille signage
  • Audio announcements
  • Visual announcements

Anything else that I'm missing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially hearing "T" loop for the audio announcements as well?

A common complaint from wheelchair users is that there's no way to determine if the designated wheelchair spaces on-board are already occupied. It's one thing to have a wheelchair parking space, but they're only useful if they're available. It's a similar scenario for accessible seating.

Perhaps availability of wheelchair parking can be expressed as:

  • There is a parking space, but they are all occupied
  • There is a parking space, and there is at least one available
  • There is a parking space, and its availability is unknown (if the operator cannot determine its availability in real-time)
  • There is no parking space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point! One concern; are producers able to capture this type of information?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that audio announcements can vary between computer announcements and operator announcements. The latter are notoriously unintelligible in most systems since operators frequently mumble or fail to speak loudly.

We've looked at wheelchair space occupancy in our crowdsourcing transit information app (Tiramisu) and intentionally opted for overall vehicle loading instead. In most cases there is a direct relationship between loading and wheelchair space availability. Our concern about about using wheelchair space in a crowdsource system was twofold. First, most non-experts might not properly classify an opening if people without disabilities are seated in those areas. Second, we were concerned about malicious reporting that spots were full so people with wheelchairs would opt for another bus, thereby discouraging long dwell times for ingress/egress.

@@ -347,7 +422,7 @@ Un mensaje internacionalizado que contiene versiones por idioma de un fragmento

| _**Nombre del campo**_ | _**Tipo**_ | _**Cardinalidad**_ | _**Descripción**_ |
|------------------------|------------|--------------------|-------------------|
| **translation** | [Translation](#Translation) | repetido | Se debe proporcionar al menos una traducción. |
| **translation** | [Translation](#mensaje-translation) | repetido | Se debe proporcionar al menos una traducción. |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this change should be in the PR?

Copy link
Contributor Author

@RachM RachM Jul 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries - moved to PR #67.

@@ -336,7 +411,7 @@ Un selector para una entidad en un feed GTFS. Los valores de los campos deben co
| **agency_id** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | opcional |
| **route_id** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | opcional |
| **route_type** | [int32](https://developers.google.com/protocol-buffers/docs/proto#scalar) | opcional |
| **trip** | [TripDescriptor](#TripDescriptor) | opcional |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this change should be in the PR?

Copy link
Contributor Author

@RachM RachM Jul 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries - split into PR #67.


optional AirConditioning air_conditioning = 7 [default = UNKNOWN];

// Whether bicycles are allowed in the carriage.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think BicyclesAllowed would be useful outside of just the carriage use case - agencies have told me they'd like to see this for buses, including real-time capacity of racks, although I'm not aware of any real-time system that currently exposes this via an API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that a bus amenities/info can be modelled by having a single CarriageDescriptor. Hence this works for buses.

Capacity for the rack is interesting; it could certainly be added at a later stage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, maybe 'Carriage' is the wrong word to use? I want it to be used for all vehicle types, and if that's not clear, we should change the name.

Let me know if you have other name suggestions. Car? Compartment? Section?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you have other name suggestions. Car? Compartment? Section?

I couldn't come up with anything better and more general than Carriage. I think as long as we make it clear in the spec that this can apply to any transit vehicle this would work for buses too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool - I've clarified the single-vehicle case in the reference as well as the proto.

* [StopTimeUpdate](#message-stoptimeupdate)
* [StopTimeEvent](#message-stoptimeevent)
* [ScheduleRelationship](#enum-schedulerelationship)
* [VehiclePosition](#message-vehicleposition)
* [TripDescriptor](#message-tripdescriptor)
* [ScheduleRelationship](#enum-schedulerelationship-1)
* [VehicleDescriptor](#message-vehicledescriptor)
* [CarriageDescriptor](#message-carriagedescriptor)
* [OccupancyStatus](#enum-occupancystatus)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a design decision made when originally adding OccupancyStatus that VehicleDescriptor should only contain immutable information, while VehiclePosition should contain mutable statuses (discussion starting at https://groups.google.com/d/msg/gtfs-realtime/_HtNTGp5LxM/86U3GGxDbngJ).

This proposal breaks from that design decision by putting OccupancyStatus as a child element of VehicleDescriptor->CarriageDescriptor. You could also argue that some of the other elements are mutable as well (e.g., bathroom closed for cleaning/maintenance, bikes allowed only at certain times of the day).

At the time of the OccupancyStatus proposal, I actually argued for including OccupancyStatus in VehicleDescriptor instead of VehiclePosition, but was overruled :). I bring this up for discussion - please discuss :).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the context Sean!

My reasoning for putting it in VehicleDescriptor:

  • It seems like a property of the vehicle, and I (perhaps naively) thought VehicleDescriptor encapsulated properties of vehicles. I don't see why we should strive to maintain immutability, especially when this isn't mentioned (or enforced?) anywhere.
  • By putting it in VehicleDescriptor, it gets to be in either/both TripUpdates and VehiclePositions.

I didn't realise VehicleDescriptor was intended to be immutable. If people care deeply about maintaining this, then perhaps we should at least document this in the spec?

Keen to hear others thoughts :-)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RachM That was my exact same reasoning for originally proposing OccupancyStatus in VehicleDescriptor. So, I'm also interested to hear others thoughts :).

@jxeeno
Copy link
Contributor

jxeeno commented Jul 13, 2017

With in-seat power being made available in some services now, that could be a feature that's of interest to commuters. You could identify types of ports available e.g. USB, GPO, both, none.

@abyrd
Copy link

abyrd commented Jul 13, 2017

@jxeeno agreed, that can be an important consideration when trying to work during long-distance travel. People will want this information.

@RachM
Copy link
Contributor Author

RachM commented Jul 13, 2017

@jxeeno and @abyrd: great idea, although I have no idea if producers a) have this info and b) can incorporate it in gtfs-rt.

Producers: are you able to capture this info for individual carriages?

| **label** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | optional | User visible label, i.e., something that must be shown to the passenger to help identify the correct vehicle. |
| **license_plate** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | optional | The license plate of the vehicle. |
| **carriage_descriptor** | [CarriageDescriptor](#message-carriagedescriptor) | repeated | An ordered list of carriage information. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should define how the carriages should be ordered. The original proposal from NSW Trains was to use a well-defined central point. A more logical one for me is to start with the first carriage in the direction of travel and move back from there.

Copy link
Collaborator

@barbeau barbeau Jul 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should define how the carriages should be ordered.

That's a really good point, especially on the accessibility attributes. The whole point of providing this data would be to allow a rider in a wheelchair to position themselves in the proper place on the platform before the vehicle arrives, and if the order isn't well defined, they will end up in the wrong place.

A more logical one for me is to start with the first carriage in the direction of travel and move back from there.

This would be good. Maybe there should also be a required carriage_sequence int within CarriageDescriptor (similar to stop_sequence), that would explicitly define ordering? Otherwise it will be difficult from a consumers perspective to know if implicit ordering is correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added carriage_sequence to CarriageDescriptor. Can you take a quick look and see if it looks OK?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely support adding such field, but I'm a bit unsure how it would handle a situation when a train changes direction of its travel during its journey e.g. in a dead-end station.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qwasar Good point. It would be good to know how this scenario is typically modeled with trip_ids in GTFS and GTFS-realtime. If the trip_id changes, which I would imagine it would, then I would expect carriage_sequence to change with the trip_id, which should have a different direction_I'd. One option would be to make GTFS trips.txt direction_I'd conditionally required if CarriageDescriptor is provided to make the behavior and expectations clearer. Consumer could change display for outgoing trip a certain amount of time become outgoing departure.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand your idea. My objection was that it is probably not a feasible solution for cases where such train is modeled as a single trip (which can have only a single value of direction_id). It would require to slice the train journey to several trips arbitrarily just for the sake of export to GTFS. Even so, using direction_id for this purpose still feels wrong to me, as the train (even with the order of carriages reversed) still follows the same direction in the sense of trips.txt's direction_id semantics.

Take the Copenhagen-Karlskrona route as an example:
Copenhagen-Kristianstad-Karlskrona, direction_id=0
Karlskrona-Kristianstad-Copenhagen, direction_id=1
and the order of carriages has got always reversed in Kristianstad.

And if CarriageDescriptor[] would be tight to a TripDescriptor only, then while the train would be in the Copenhagen-Kristianstad section, the feed would advertise misleading order of carriages for the rest of its journey after Kristianstad. That might be quite inconvenient for passengers boarding at stations in that section and checking the status of the train in advance.

Copy link
Contributor Author

@RachM RachM Jul 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the example; it's a really good one! I agree my use of direction_id is not appropriate, so let's scratch that idea.

I have a new solution that I think solves our problem; have TWO fields for the sequence:

  • next_station_arrival_sequence: the order that the carriage will arrive at the next station
  • next_station_departure_sequence: the order that the carriage will depart from the next station

For non-dead end stations, next_station_arrival_sequence = next_station_departure_sequence. For dead-end stations, they will be the reverse of each other. So for my dead-end picture above:

TUs/VPs before arriving at the station:

carriage_descriptor {
  label = 'A'
  next_station_arrival_sequence: 1
  next_station_departure_sequence: 3
},
carriage_descriptor {
  label = 'B'
  next_station_arrival_sequence: 2
  next_station_departure_sequence: 2
},
carriage_descriptor {
  label = 'C'
  next_station_arrival_sequence: 3
  next_station_departure_sequence = 1
}

Consumers can know from this that it's a dead-end station, and can decide on an appropriate UI/info to show to the user.

Thoughts?

Copy link

@qwasar qwasar Aug 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RachM Sorry for being late with reaction, I've been off-grid.

I'm still afraid your latest proposal wouldn't allow us to handle all the cases I'd like to see addressed.

Let me expand on the example of the Copenhagen-Karlskrona train. Before boring the Citytunneln in Malmö in 2010, the Malmö Central used to be a dead-end station as well. So that train had changed its direction twice during its journey (in Malmö and Kristianstad). I can't help myself, but I think to describe such situation we really have to add CarriageDescriptor[] as an optional field to StopTimeUpdate as well. Something like this:

TripUpdate
    TripDescriptor
        CarriageDescriptor[]=[(A,B,C)+(D,E,F)] // two three-carriages units due to high demand
    StopTimeUpdate
        stop_id=Malmö, 
        CarriageDescriptor[]=[(F,E,D)+(C,B,A)] // first reversal
    StopTimeUpdate
        stop_id=Kristianstad, 
        CarriageDescriptor[]=[(A,B,C)] // second reversal, only single unit continues to Karlskrona

I found it very analogous to how Trip.trip_headsign can be overridden by StopTime.stop_headsigns in GTFS.

And on top of that it would be really great to have such info in GTFS too as it is quite common that the very same trip (train number) is served by quite different carriages on weekdays and on weekend.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More examples:
railjets at Wien-Zürich HB route changes direction twice at Buchs and Sargans stations.

LeoExpress at Košice-Prague route changes direction twice at Prešov and Přerov stations.

Copy link
Contributor Author

@RachM RachM Aug 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right - I was thinking mainly in terms of VehiclePositions (and hence only considered the next station). However, TripUpdates can specify many stations, so we need info about the carriage directions for each of them.

I still think it's important to know what both the arriving and departing sequence is at a particular station.

Revising:

  • CarriageDescriptor still sits in VehicleDescriptor, but only contains info about the carriage facilities (no sequencing info). Some of this could actually be moved to GTFS, in a carriages.txt file.
  • TUs: StopTimeUpdates contain the carriage sequences
  • VPs: the carriage sequence is at the top level, and is for the stop specified in stop_id

More concretely:

message VehicleDescriptor {
  ....
  repeated CarriageDescriptor carriage_descriptor;
  message CarriageDescriptor {
    optional string id = 1;
    ... wifi, occupancy, bicycles etc
  }
}

message CarriageSequence {
  optional string carriage_descriptor_id = 1;
  optional int sequence = 2;
}

message TripUpdate {
  ...
  message StopTimeUpdate {
    ...
    optional string stop_id = 4;
    ...
    repeated CarriageSequence arrival_carriage_sequence = X;
    repeated CarriageSequence departure_carriage_sequence = X+1;
  }
}

message VehiclePosition {
  ...
  optional string stop_id = 7;
  ...
  repeated CarriageSequence arrival_carriage_sequence = X;
  repeated CarriageSequence departure_carriage_sequence = X+1;
}

@qwasar
Copy link

qwasar commented Jul 25, 2017

How about adding an information on dining facilities as well? With enum values like:

  • restaurant (tables with seating)
  • bistro (standing or bar stools only)
  • in-seat service/minibar
  • vending machine

Counting on having a breakfast in a restaurant carriage which is unexpectedly not present is not a good start of a day...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants