Reputation: 1742
I work on turning a dataframe into a GTFS realtime, and am struggling on the vehicle position part.
My data looks like that (stored in a dataframe called "vehicle"):
## Input data looks that way, one line per on-going vehicle
vehicle_id trip_id lat lon bear speed stop_time
52108 4.264930e+05 45.40 -71.92 1 9 2017-05-02 15:19:05
60105 4.273610e+05 45.40 -71.90 246 6 2017-05-02 15:18:59
59104 4.270150e+05 45.40 -71.87 81 7 2017-05-02 15:18:54
The details of my code is:
library(dplyr)
library(XML)
library(stringr)
library(RProtoBuf)
library(RODBC)
## Read the google gtfs proto file
readProtoFiles("gtfs-realtime.proto")
## List of current vehicles
current_vehicles <- unique(vehicle$vehicle_id)
## Create an empty list, 1 entry for each vehicle
protobuf_list <- vector(mode = "list", length = length(current_vehicles))
## Loop over all current vehicles
for(i in 1:length(current_vehicles)) {
## protobuf object
vehicle_position_update <- new(transit_realtime.VehiclePosition,
vehicle = vehicle$vehicle_id[i],
stop_id = vehicle$stop_id[i],
trip = vehicle$trip_id[i],
latitude = vehicle$lat[i],
longitude = vehicle$lon[i],
bearing = vehicle$bear[i],
speed = vehicle$speed[i])
## protobuf feed entity
e <- new(transit_realtime.FeedEntity,
id = as.character(vehicle$vehicle_id[i]),
vehicle = new(transit_realtime.VehiclePosition,
trip = new(transit_realtime.VehicleDescriptor,
id = vehicle$vehicle_id[i]),
VehiclePosition = vehicle_position_update))
## Fill the list
protobuf_list[[i]] <- e
}# Loop over vehicles
## GTFS header
header_object <- new(transit_realtime.FeedHeader,
gtfs_realtime_version = "1.0",
incrementality = "FULL_DATASET",
timestamp = as.numeric(as.POSIXlt(Sys.time())))
## Build the full GTFS
m <- new(transit_realtime.FeedMessage,
header = header_object,
entity = protobuf_list) # use entity_list
## Write the GTFS
writeLines(as.character(m))
## Turn it into binary
serialize(m, "vehiclePositions.pb")
When creating the protobuffer object vehicle_position_update, it crashes with the message:
type mismatch, expecting a 'Message' object
I went through the gtfs-realtime.proto, and my understanding of the different messages to include seems fine (well, obviously it'nt..).
Does anyone see why this protobuffer file cannot be created?
ADDED FOR A CLEAR SOLUTION:
My issue was that I was'nt following exactly the gtfs proto descriptions of the different messages. Once this point corrected, the loop over the vehicles becomes:
## Loop over all current vehicles
for(i in 1:length(current_vehicles)) {
## protobuf object
vehicle_position_update <- new(transit_realtime.Position,
latitude = vehicle$lat[i],
longitude = vehicle$lon[i],
bearing = vehicle$bear[i],
speed = vehicle$speed[i])
## protobuf feed entity
e <- new(transit_realtime.FeedEntity,
id = as.character(vehicle$vehicle_id[i]),
vehicle = new(transit_realtime.VehiclePosition,
trip = new(transit_realtime.TripDescriptor,
trip_id = vehicle$trip_id[i],
route_id = vehicle$route_id[i]),
stop_id = vehicle$stop_id[i],
position = vehicle_position_update))
## Fill the list
protobuf_list[[i]] <- e
}# Loop over vehicles
and it works
Upvotes: 1
Views: 901
Reputation: 26258
The message definition tells you what fields it requires, for example
writeLines(as.character(RProtoBuf::fileDescriptor(transit_realtime.FeedMessage)))
message FeedMessage {
required .transit_realtime.FeedHeader header = 1;
repeated .transit_realtime.FeedEntity entity = 2;
extensions 1000 to 1999;
}
message FeedHeader {
enum Incrementality {
FULL_DATASET = 0;
DIFFERENTIAL = 1;
}
required string gtfs_realtime_version = 1;
optional .transit_realtime.FeedHeader.Incrementality incrementality = 2 [default = FULL_DATASET];
optional uint64 timestamp = 3;
extensions 1000 to 1999;
}
message FeedEntity {
required string id = 1;
optional bool is_deleted = 2 [default = false];
optional .transit_realtime.TripUpdate trip_update = 3;
optional .transit_realtime.VehiclePosition vehicle = 4;
optional .transit_realtime.Alert alert = 5;
extensions 1000 to 1999;
}
... etc
Then, if you take a look at the Position
message, you see the fields
message Position {
required float latitude = 1;
required float longitude = 2;
optional float bearing = 3;
optional double odometer = 4;
optional float speed = 5;
extensions 1000 to 1999;
}
So you define the Position
using those values, e.g.
RProtoBuf::new(transit_realtime.Position, latitude = 0, longitude = 0)
And the VehiclePosition
message is
message VehiclePosition {
enum VehicleStopStatus {
INCOMING_AT = 0;
STOPPED_AT = 1;
IN_TRANSIT_TO = 2;
}
enum CongestionLevel {
UNKNOWN_CONGESTION_LEVEL = 0;
RUNNING_SMOOTHLY = 1;
STOP_AND_GO = 2;
CONGESTION = 3;
SEVERE_CONGESTION = 4;
}
enum OccupancyStatus {
EMPTY = 0;
MANY_SEATS_AVAILABLE = 1;
FEW_SEATS_AVAILABLE = 2;
STANDING_ROOM_ONLY = 3;
CRUSHED_STANDING_ROOM_ONLY = 4;
FULL = 5;
NOT_ACCEPTING_PASSENGERS = 6;
}
optional .transit_realtime.TripDescriptor trip = 1;
optional .transit_realtime.VehicleDescriptor vehicle = 8;
optional .transit_realtime.Position position = 2;
optional uint32 current_stop_sequence = 3;
optional string stop_id = 7;
optional .transit_realtime.VehiclePosition.VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];
optional uint64 timestamp = 5;
optional .transit_realtime.VehiclePosition.CongestionLevel congestion_level = 6;
optional .transit_realtime.VehiclePosition.OccupancyStatus occupancy_status = 9;
extensions 1000 to 1999;
}
So the message will be like
RProtoBuf::new(transit_realtime.VehiclePosition,
current_status = 1,
congestion_level = 0,
stop_id = "7",
current_stop_sequence = 1)
Upvotes: 1