Create multi-destination trips

This document describes how to create a multi-destination trip, set the correct fields, and assign it to a vehicle to fulfill. It assumes you have set up Fleet Engine, you have created vehicles, have a working driver app, and optionally, a consumer app. You should also be familiar with the various trip scenarios available for on-demand trips. See the following related guides for that:

Trip creation basics

This section describes the request details necessary for creating a trip in Fleet Engine. You issue a creation request using either gRPC and REST.

  • CreateTrip() method: gRPC or REST
  • CreateTripRequest message: gRPC only

Trip Fields

Use the following fields to create a trip in Fleet Engine. You can use different fields for the different kinds of trips: single- or multi-destination, back-to-back, or shared pooling trips. You can supply the optional fields when you create the trip, or you can set them later when you update the trip.

Trip fields
Name Required? Description
parent Yes A string that includes the project ID. This ID must be the same ID used across your entire Fleet Engine integration, with the same service account roles.
trip_id Yes A string that you create that uniquely identifies this trip. Trip IDs have certain restrictions, as indicated in the reference.
trip_type Yes Set the TripType to the following values for the trip type you're creating:
  • Single destination: Set to SHARED or EXCLUSIVE.
  • Multi-destination: Set to EXCLUSIVE.
  • Back-to-back: Set to EXCLUSIVE.
  • Shared pooling: Set to SHARED.
pickup_point Yes The trip's point of origin.
Intermediate destinations Yes

Multi-destination trips only: The list of intermediate destinations that the driver visits in between pickup and drop-off. As with dropoff_point, this field can also be set later by calling UpdateTrip, but a multi-destination trip by definition contains intermediate destinations.

vehicle_waypoints Yes

Shared-pooling trips only: This field supports interleaving the waypoints from multiple trips. It contains all of the remaining waypoints for the assigned vehicle, as well as the pickup and drop-off waypoints for this trip. You can set this field by calling CreateTrip or UpdateTrip. You can also update vehicle waypoints through the waypoints field with a call to UpdateVehicle. The service does not return this information on GetTrip calls due to privacy reasons.

number_of_passengers No The number of passengers on the trip.
dropoff_point No The trip's destination.
vehicle_id No The ID of the vehicle assigned to the trip.

Example: create a multi-destination trip

The following demonstrates how to create an exclusive multi-destination trip that has a pickup point, a drop-off point, and one intermediate destination.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// Trip initial settings.
String parent = "providers/" + PROJECT_ID;

Trip trip = Trip.newBuilder()
    .setTripType(TripType.EXCLUSIVE)
    .setPickupPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.195139).setLongitude(106.820826)))
    .setNumberOfPassengers(1)
    .setDropoffPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.1275).setLongitude(106.6537)))
    // Add the list of intermediate destinations.
    .addAllIntermediateDestinations(
        ImmutableList.of(
            TerminalLocation.newBuilder().setPoint(
                LatLng.newBuilder()
                    .setLatitude(-6.195139).setLongitude(106.820826)).build()))
    .build();

// Create the Trip request.
CreateTripRequest createTripRequest = CreateTripRequest.newBuilder()
    .setParent(parent)
    .setTripId(TRIP_ID)  // Trip ID assigned by the Provider server.
    .setTrip(trip)       // Initial state is NEW.
    .build();

// Error handling.
try {
  Trip createdTrip =
      tripService.createTrip(createTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:  // Trip already exists.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

Update a multi-destination trip

You must configure the trip with a vehicle ID so that the Fleet Engine can track the vehicle along its route. For details on updating a trip, see Update trips and manage their state.

If you don't specify a drop-off or intermediate destinations when you create the trip, you can always do it at this point.

Example trip update

The following demonstrates how to update a trip to add a list of intermediate destinations and set a vehicle ID.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// The trip settings to be updated.
Trip trip = Trip.newBuilder()
    // Add the list of intermediate destinations.
    .addAllIntermediateDestinations(
        ImmutableList.of(
            TerminalLocation.newBuilder().setPoint(
                LatLng.newBuilder()
                    .setLatitude(-6.195139).setLongitude(106.820826)).build()))
    .setVehicleId("8241890")
    .build();

// The trip update request.
UpdateTripRequest updateTripRequest = UpdateTripRequest.newBuilder()
    .setName(tripName)
    .setTrip(trip)
    .setUpdateMask(
        FieldMask.newBuilder()
            .addPaths("intermediate_destinations")
            .addPaths("vehicle_id")
            .build())
    .build();

// Error handling.
try {
  Trip updatedTrip =
      tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:            // The trip doesn't exist.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

Manage trip state for multi-destination trips

You specify the state of a trip using one of the TripStatus enumeration values. When a trip's state changes, for example from ENROUTE_TO_PICKUP to ARRIVED_AT_PICKUP, you must update the trip state in Fleet Engine. Trip state always begins with a value of NEW, and ends with a value of either COMPLETE or CANCELED.

For a multi-destination trip, in addition to updating the trip state as you would for a single destination trip, you must also update the following every time your vehicle reaches an intermediate destination:

  • intermediateDestinationIndex
  • intermediateDestinationsVersion

To do this, use the following values from the TripStatus enumeration.

  • ENROUTE_TO_PICKUP
  • ARRIVED_AT_PICKUP
  • ENROUTE_TO_INTERMEDIATE_DESTINATION
  • ARRIVED_AT_INTERMEDIATE_DESTINATION
  • ENROUTE_TO_DROPOFF
  • COMPLETE

Example trip with intermediate destinations

The following shows how to create a multi-destination trip that has passed its pickup point, and is now en route to its first intermediate destination.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

// Get the trip object from either the Fleet Engine or storage.
Trip trip = …;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// The trip settings to be updated.
Trip trip = Trip.newBuilder()
    // Trip status cannot return to a previous state once it has passed.
    .setTripStatus(TripStatus.ENROUTE_TO_INTERMEDIATE_DESTINATION)

    // Enroute to the first intermediate destination.
    .setIntermediateDestinationIndex(0)

    // You must provide an intermediate_destinations_version to ensure that you
    // have the same intermediate destinations list as the Fleet Engine.
    .setIntermediateDestinationsVersion(
         trip.getIntermediateDestinationsVersion())
    .build();

// The trip update request.
UpdateTripRequest updateTripRequest = UpdateTripRequest.newBuilder()
    .setName(tripName)
    .setTrip(trip)
    .setUpdateMask(
        FieldMask.newBuilder()
            .addPaths("trip_status")
            .addPaths("intermediate_destination_index")
            // intermediate_destinations_version must not be in the update mask.
            .build())
    .build();

// Error handling.
try {
  Trip updatedTrip =
      tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:            // The trip doesn't exist.
      break;
    case FAILED_PRECONDITION:  // Either the trip status is invalid, or the
                               // intermediate_destinations_version doesn't
                               // match Fleet Engine's.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

What's next