Update User Location
Update user location
This tutorial shows how to update user location via navigation service and get feedback from it.
Get started
Before updating user location to navigation service, make sure GPS location is available,
and it's recommended to use a dead reckoning module to get a high-precision location for some scenarios like tunnels.
Update location
Make a customized location observer.
| class LocationObserver : public tn::drive::api::PositionEventListener
{
public:
void onPositionIndicatorUpdated(const tn::drive::models::v1::Indicator& indicator) override
{
// ...
}
};
|
Register the location observer to navigation service.
| const auto locationObserver = tn::make_shared<LocationObserver>();
navigationService->addPositionEventListener(locationObserver);
|
Unregister the location observer before shutdown navigation service.
| navigationService->removePositionEventListener(locationObserver);
navigationService->shutdown();
|
Construct a location input and feed it to the navigation service.
Location inputs are recommended to be provided at a frequency no greater than 15 Hz.
Too frequent inputs will cause some of them to be ignored by the navigation service.
For some important location updates, you are recommended to set epoch_flag to true
to ensure it will get handled in the navigation service.
| tn::foundation::VehicleLocation inputLocation;
// when epoch_flag is set to true, the location input will be handled in navigation service
// for example a location input with high confidence
inputLocation.epoch_flag = true;
// elapsed time could be used as a key to match input and output locations
inputLocation.elapsed_time = std::chrono::duration<uint32_t, std::milli>(std::chrono::steady_clock::now() - getSystemStartTimePoint());
// bearing is strongly recommended to be set to increase map matching quality
inputLocation.bearing = getVehicleBearing();
// speed is strongly recommended to be set to increase map matching quality
inputLocation.speed = getVehicleSpeed();
// GPS location is must to have for an input location
inputLocation.coordinate = getVehicleGpsLocation();
// get location provider from foundation system
auto locationProvider = system->locationProvider();
locationProvider->updateLocation(inputLocation);
|
Handle map matching feedback
Handle map matching feedback.
| void LocationObserver::onPositionIndicatorUpdated(const tn::drive::models::v1::Indicator& indicator)
{
// location information is always available
const auto location = indicator.location.matched_location;
showVehicleLocationOnMap(location);
if (indicator.matched_road.has_value())
{
const auto& roadInfo = indicator.matched_road.value();
showSpeedLimit(roadInfo.speed_limit);
const auto parking_lot = roadInfo.parking_lot;
if (parking_lot)
{
// do something in the parking lot ...
}
// show combined road name if there are multiple names for the road
showRoadNames(roadInfo.combined_name);
// show the best name for the road even if there are multiple names for the road
const auto roadName = parseRoadName(roadInfo.road_name);
showRoadName(roadName);
}
if (indicator.regional.has_value())
{
const auto& regionalInfo = indicator.regional.value();
showLocalTime(regionalInfo.time_zone);
}
// use map matching feedback to adjust dead reckoning locations
if (indicator.feedback.has_value())
{
const auto& feedback = indicator.feedback.value();
if (feedback.on_road)
{
// handle fields valid only on road, including:
// oneway, right_hand, ferry, in_service_area, in_parking_lot, in_tunnel,
// lane_count, dist_from_bifurcation_behind, dist_to_bifurcation_ahead
// NOTICE: these fields may not be related to matched road
// omit code here ...
}
// feedback location may be different from map matched location
const auto location = feedback.location;
// use timestamp to match location input and output
const auto elapsed_time = feedback.timestamp;
}
}
|
Parse name string for road names
Name string is an encoded format to represent various names in one unified format.
To decode the string, check the string format and use corresponding utility functions to get the real name.
| std::string parseRoadName(const tn::mapcontent::models::v1::NameString& name)
{
std::string parsedName;
switch (name.format)
{
case tn::mapcontent::models::v1::NameString::Format::Name:
case tn::mapcontent::models::v1::NameString::Format::ExitName:
case tn::mapcontent::models::v1::NameString::Format::ExitNumber:
{
const auto ordinaryName = tn::mapcontent::models::v1::NameString::Utility::asOrdinaryName(name);
parsedName = (ordinaryName.has_value() ? ordinaryName->orthography.content : "");
break;
}
case tn::mapcontent::models::v1::NameString::Format::RoadNumber:
{
const auto roadNumber = tn::mapcontent::models::v1::NameString::Utility::asRoadNumberName(name);
parsedName = (roadNumber.has_value() ? roadNumber->ordinary.orthography.content : "");
break;
}
default:
break;
}
return parsedName;
}
|
Next steps