Add cyclist position availability fields to VehiclePosition and CarriageDetails#611
Conversation
…ageDetails Add four new experimental fields to enable real-time reporting of bicycle rack/storage availability on transit vehicles: - VehiclePosition.cyclist_positions_available (field 12) - VehiclePosition.total_cyclist_positions (field 13) - CarriageDetails.cyclist_positions_available (field 6) - CarriageDetails.total_cyclist_positions (field 7) These fields allow transit apps to display bike rack availability alongside existing vehicle position and occupancy information. A working producer implementation (Sportworks Global LLC Velolink) is live at https://cascadia-metro-gtfs-rt.sportworks.com/gtfs-rt/vehicle-positions and has been validated against protoc, Python gtfs-realtime-bindings, and Node.js gtfs-realtime-bindings.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
Hello @oliver-sturrock, and thank you for this proposal. According to the GTFS Realtime governance process, we typically start by reaching community consensus on an Issue regarding the field's usefulness and type. A Pull Request follows once consensus is reached. Since you’ve opened both, I suggest moving this PR to draft for now so we can focus the discussion on the Issue first. |
|
I have implemented this on TransSee and set up the feed at https://www.transsee.ca/fleetfind?a=cascadia. |
|
I still find it an omission to add static data in realtime. While for end-user perspective only the field "free_cyclists_positions_available" would be enough. |
|
I'm not familiar with the term "positions" in the context of bike carriage. Is this the correct industry-specific term? |
It is certainly how people refer to the number of locations available for bikes on a rack. Transit agencies will typically buy 2 or 3 position racks depending on their capacity needs. 3 is the largest capacity for external (front of bus) racks. More can be fitting on the interior, thus wanting to allow for more than 3. |
I don't disagree. We are not in the position to propose a static data change, since we are not a producer, but I can see that the inclusion of total_cyclist_positions in the RT feed could be unnecessary in most cases. The question is whether there are frequent changes to total capacity that could be too rapid for propagation of changes to static data, e.g. in train carriages that can be reconfigured daily or more frequently for bicycle / wheelchair / seating capacity. The original thought was that it is more useful for e.g. signage that may want to display capacity for a rail carriage in terms of X of Y available, to have all of the needed data in the RT feed. |
Resolves #610
Summary
This proposal adds two new experimental fields to the
VehiclePositionandCarriageDetailsmessages to enable real-time reporting of bicycle rack/storage availability on transit vehicles.Proposed Fields
cyclist_positions_availableuint32VehiclePosition,CarriageDetailstotal_cyclist_positionsuint32VehiclePosition,CarriageDetailsMotivation
Transit passengers traveling with bicycles currently have no way to know whether a bike rack or bike storage area will be available on an approaching vehicle. A typical transit bus has only 2–3 external bike rack positions, and when full, cyclists are denied boarding — they must wait for the next vehicle or abandon their transit trip entirely.
This is a documented and quantified problem:
Providing this data in GTFS-RT enables trip planning applications (Transit App, Google Maps, Apple Maps) to display bike rack availability alongside existing vehicle position and occupancy information.
Working Implementation
Producer: Sportworks Global LLC — Velolink — a commercially available bike rack occupancy monitoring system deployed on transit buses. Velolink uses magnetic reed switches embedded in Sportworks Apex-3 bike racks to detect individual slot occupancy in real-time, transmitting data via cellular modem to a cloud platform with a public API.
https://cascadia-metro-gtfs-rt.sportworks.com/gtfs-rt/vehicle-positions— live VehiclePositions feed includingcyclist_positions_available(field 12) andtotal_cyclist_positions(field 13)https://cascadia-metro-gtfs-rt.sportworks.com/gtfs-rt/gtfs.zipConsumer: [TO BE CONFIRMED — we are actively reaching out to Transit App, Swiftly, OpenTripPlanner, Google Maps, and Apple Maps to secure a consumer implementation before calling for a vote.] Example consumer: https://cascadia-metro-gtfs-rt.sportworks.com/consumer
Ecosystem Validation Results
The public GTFS-RT feed has been tested against all major ecosystem tools. All 11 tests pass:
/validate)protoc --decode_rawprotoc --decode(official proto)protoc --decode(extended proto)cyclist_positions_availableandtotal_cyclist_positionsnamedgtfs-realtime-bindings2.0.0gtfs-realtime-bindings0x60/0x68tags correct, all values in boundsAccess-Control-Allow-Origin: *on all endpointsForward Compatibility
Adding
optional uint32fields is a fully forward-compatible change under proto2 semantics:UnknownFieldSetand preservedXXX_unrecognizedand preservedThis is the same pattern used when
occupancy_status(field 9),occupancy_percentage(field 10), andmulti_carriage_details(field 11) were previously added to the specification.Design Decisions
Why separate
availableandtotalfields?This mirrors the existing pattern of
occupancy_statusalongsideoccupancy_percentage. For cyclist positions:cyclist_positions_availableprovides the real-time signal consumers need ("2 of 3 bike spots open")total_cyclist_positionsprovides the capacity context needed for meaningful displayWhy
uint32instead of an enum?Cyclist positions are discrete, low-count integers (typically 2–3 on buses, 4–10 per train car). An exact count is more useful than a qualitative classification, and the low cardinality makes exact counts practical.
Why both VehiclePosition and CarriageDetails?
Absence vs. zero semantics
Following GTFS-RT conventions:
Privacy Considerations
A typical bus has 2–3 bike rack positions. Sequential occupancy changes could theoretically identify an individual cyclist boarding. However:
OccupancyStatusvalues on small vehiclesExample: Bus with Apex-3 Bike Rack
entity { id: "vehicle_4403" vehicle { trip { trip_id: "trip_22_1045" route_id: "22" direction_id: 0 } position { latitude: 37.3382 longitude: -121.8863 } occupancy_status: FEW_SEATS_AVAILABLE cyclist_positions_available: 1 # 1 of 3 rack slots open total_cyclist_positions: 3 # Apex-3 rack = 3 slots } }Example: Multi-Car Train
entity { id: "vehicle_lrv_101" vehicle { cyclist_positions_available: 5 # Vehicle-level total total_cyclist_positions: 8 multi_carriage_details { id: "car_A" carriage_sequence: 1 cyclist_positions_available: 2 total_cyclist_positions: 4 } multi_carriage_details { id: "car_B" carriage_sequence: 2 # No cyclist fields — no bike storage } multi_carriage_details { id: "car_C" carriage_sequence: 3 cyclist_positions_available: 3 total_cyclist_positions: 4 } } }Checklist
.protofile with correct field numbersContact
Oliver Sturrock
olst+gtfs@silverfallscapital.com
(425) 358-9055
Sportworks Global LLC / Silver Falls Capital