Skip to content

Navigation Service

Notice: using navigation service directly is a legacy way to leverage the ability of the TA SDK. It's recommended to use drive session instead. Refer to the guide of drive session for more information.

Overview

Based on the route in navigation and location information provided by position engine, navigation service can output vehicle current status, road properties that vehicle is on, dynamic predictions and statistics, and along route traffic information.

Key Concepts

Basic Information During Navigation
Information Type Content
vehicle status
  • whether it's on route or not
  • map matched location
  • bearing
  • speed
road properties
  • driving side
  • speed limit
  • time zone
  • country code
  • road types
  • road names
  • unique ID of road segments
on route information
  • indices to locate vehicle on route progress
  • distance to forward turn
  • whether next turn is a tight turn
travel information
  • forward waypoint
  • estimated travel time to forward waypoints and destination
  • traveled distance and time in current session
POI related information
  • whether in a service area
  • whether in a parking lot
  • whether nearby a planned charging station
events triggered by various causes
  • turn-by-turn list update
  • along route traffic update
  • waypoint or destination arrived
  • approaching or leaving a junction
  • timed restrictions detected
  • charging station not reachable

Setup a navigation service to create navigation sessions and getting junction view render.

tn::navigation::NavigationServiceDependencies dependencies;
// mapContent instance is created for sharing in the whole SDK
// must be set to dependencies to make navigation session work properly
dependencies.mapContent = mapContent;

// positionEngine instance is created for sharing in drive session services
// must be set to dependencies to make navigation session work properly
dependencies.positionEngine = positionEngine;

// directionService instance is created for sharing in the whole SDK
// must be set to dependencies to make navigation session work properly
dependencies.directionService = directionService;

// audioGuidanceService instance is created for sharing in drive session services
// must set if audio guidance service should work for route in navigation, otherwise could be not set
dependencies.audioGuidanceService = audioGuidanceService;

// alertService instance is created for sharing in drive session services
// must set if alert service should work for route in navigation, otherwise could be not set
dependencies.alertService = alertService;

// adasService instance is created for sharing in drive session services
// must set if ADAS service should work for route in navigation, otherwise could be not set
dependencies.adasService = adasService;

// system instance is created for sharing in the whole SDK
// settings instance should be created if any default setting does not meet the requirements, could be nullptr if default values are good enough
auto service = tn::navigation::NavigationServiceFactory::createService(system, settings, dependencies);

Create a navigation session from navigation service with default components.

1
2
3
4
5
// notice: session is created and maintained by navigation service
// client only holds the native pointer to the session to access it
// MUST never deleting it. 
// MUST never accessing it after it's stopped.
auto* session = service->createNavigationSession();

Create a navigation session from navigation service with customized options.

1
2
3
4
5
6
7
8
9
tn::navigation::NavigationSessionOptions options;
options.enable_alert = true;
options.enable_audio = true;

// notice: session is created and maintained by navigation service
// client only holds the native pointer to the session to access it
// MUST never deleting it. 
// MUST never accessing it after it's stopped.
auto* session = service->createNavigationSession(options);

Start navigation with a route.

// make a customized navigation status observer to handle navigation status changes
auto listener = tn::make_shared<NavigationObserver>();
session->addListener(listener);

// set route to navigate on
// route is retrieved from direction service
session->updateRoute(route);

// start navigation
session->startNavigation();

Stop navigation and remove listener when it's not needed anymore.

1
2
3
4
5
// remove listener
session->removeListener(listener);

// stop session
session->stopNavigation();

Make a customized navigation observer to handle navigation status updates.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        // vehicle status is always updated
        const auto vehicleLocation = navStatus.getVehicleLocation();
        const auto vehicleBearing = navStatus.getVehicleHeading();
        const auto vehicleSpeed = navStatus.getVehicleSpeed();

        const auto vehicleStatus = navStatus.getStatus();
        // get on-route information when vehicle is on route
        if (vehicleStatus == tn::navigation::NavStatus::eNavStatus::E_NAV_STATUS_NORMAL)
        {
            const auto route = navStatus.route();
            const auto legIndex = navStatus.getCurrentLegIndex();
            const auto stepIndex = navStatus.getCurrentStepIndex();
            const auto edgeIndex = navStatus.getCurrentEdgeIndex();
            const auto edgePointIndex = navStatus.getCurrentEdgePointIndex();
            const auto edgePointRange = navStatus.getCurrentEdgePointRange();
            const auto distanceToTurn = navStatus.getDistanceToTurn();
            const auto isNextTurnTight = navStatus.isNextStepTightTurn();
        }

        // get road properties when vehicle is not off-road
        if (vehicleStatus != tn::navigation::NavStatus::eNavStatus::E_NAV_STATUS_OFF_ROAD)
        {
            const auto drivingSide = navStatus.getDriveSide();
            const auto speedLimit = navStatus.getSpeedLimit();
            const auto timeZone = navStatus.getTimeZone();
            const auto countryCode = navStatus.getCountryCode();
            const auto roadType = navStatus.getRoadTypeInfo();
            const auto roadSubType = navStatus.getRoadSubtypeInfo();
            const auto edgeId = navStatus.getEdgeID();
            const auto roadNames = navStatus.getRoadName();
            const auto isInServiceArea = navStatus.isInServiceArea();
            const auto isInParkingLot = navStatus.isInParkingLot();
        }
    }
};

Travel Estimation

The TA SDK will estimate remaining time to reach the waypoint or destination.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto index = navStatus.getForwardWaypointIndex();

        // use navStatus.getAllTravelEstimations() to get estimations for all remaining waypoints and destination
        const auto estimation = navStatus.getForwardTravelEstimation();

        // show estimated remaining distance and time to forward waypoint / destination
        const auto distance = estimation.distance;
        const auto time = estimation.time;
        const auto delay = estimation.traffic_delay;

        // show estimated arrival time in local time zone
        const auto timeZone = estimation.time_zone;
        const auto arrivalTime = estimate.arrival_time;
    }
};
Statistics

The TA SDK will count how much distance and time has been driven.

1
2
3
4
5
6
7
8
9
class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto traveledDistance = navStatus.getTraveledDistance();
        const auto traveledTime = navStatus.getTraveledTime();
    }
};
Turn by Turn List

During navigation, the TA SDK will provide next road names in turn order to guide user in the right direction.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto signals = navStatus.getNavigationSignal();
        for (const auto& signal : signals)
        {
            if (signal->getSignal() == tn::navigation::NavigationSignal::eNavigationSignal::NAV_SIGNAL_UPDATE_TURN_BY_TURN_LIST)
            {
                auto tbtSignal = tn::dynamic_pointer_cast<const tn::navigation::NavigationSignalUpdateTurnByTurnList>(signal);
                const auto turnList = tbtSignal->getTurnByTurnList();
                for (const auto& turn : turnList)
                {
                    // best name for next road
                    const auto nextRoadName = turn.road_name;

                    // turn actions to determine the action icon used for the turn
                    const auto turnAction = turn.turn_action;
                    const auto turnAssistantAction = turn.turn_assistant_action;

                    for (const auto& shield : turn.shield_info)
                    {
                        // render shield icon (bitmap in ARGB32 format)
                        auto image = shield->iconImage(60, 48);
                    }

                    // add one turn to show in turn list on HMI
                }
            }
        }
    }
};
Arrival Reminder

There are 2 kinds of reminders: normal road arrival and off-road arrival (e.g., parking lot area). In normal road arrival mode, the default advance reminder distance for highways is 100m and 60m for non-highway. The value is configurable.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto signals = navStatus.getNavigationSignal();
        for (const auto& signal : signals)
        {
            if (signal->getSignal() == tn::navigation::NavigationSignal::eNavigationSignal::NAV_SIGNAL_REACH_WAYPOINT)
            {
                auto arrivalSignal = tn::dynamic_pointer_cast<const tn::navigation::NavigationSignalReachWaypoint>(signal);

                const auto index = arrivalSignal->getWaypointIndex();
                const auto position = arrivalSignal->getWaypointLocation();
                // show notification on arrival of the (index)th waypoint and the position along route
            }
        }
    }
};
// arrival signals are generated before vehicle actually hits the waypoint location for the reason of leaving some time for 
// audio guidance to play the sentence.
// the distance can be configured at service creation time
auto settings = tn::foundation::Settings::Builder()
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_WAYPOINT_LOCAL_ARRIVAL_DISTANCE, "40")
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_WAYPOINT_HIGHWAY_ARRIVAL_DISTANCE, "120")
    .build();

// create navigation service with customized settings
// all navigation sessions created from this service will have customized settings enabled
auto service = tn::navigation::NavigationServiceFactory::createService(system, settings, dependencies);
Real-time Traffic Along the Route

The TA SDK will provide real-time traffic along the route.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto signals = navStatus.getNavigationSignal();
        for (const auto& signal : signals)
        {
            if (signal->getSignal() == tn::navigation::NavigationSignal::eNavigationSignal::NAV_SIGNAL_ALONG_ROUTE_TRAFFIC_UPDATE)
            {
                auto trafficSignal = tn::dynamic_pointer_cast<const tn::navigation::NavigationSignalAlongRouteTraffic>(signal);

                auto incidents = trafficSignal->getAlongRouteTrafficIncidents();
                for (const auto& incident : incidents)
                {
                    const auto incidentLocation = incident.location;

                    const auto incidentInfo = incident.info;
                    const auto eventCode = incidentInfo.event_code;
                    const auto incidentType = incidentInfo.type;

                    // update incident along route
                }

                auto flows = trafficSignal->getAlongRouteTrafficFlows();
                for (const auto& flow : flows)
                {
                    const auto beginLocation = flow.begin_location;
                    const auto endLocation = flow.end_location;
                    const auto flowInfo = flow.info;
                    const auto flowLevel = flowInfo.lowest_level;

                    // update flow along route
                }
            }
        }
    }
};

Client can configure the range of traffic to fetch along the route (default 1 hour, minimum 1 s).

1
2
3
4
5
6
7
8
// customize traffic fetch range
const auto settings = tn::foundation::Settings::Builder()
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_TRAFFIC_FETCH_RANGE, "1800")
    .build();

// create navigation service with customized settings
// all navigation sessions created from this service will have customized settings enabled
auto service = tn::navigation::NavigationServiceFactory::createService(system, settings, dependencies);
Junction View

In highway scenarios, entering junction event is triggered within 700 meters by default.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto signals = navStatus.getNavigationSignal();
        for (const auto& signal : signals)
        {
            if (signal->getSignal() == tn::navigation::NavigationSignal::eNavigationSignal::NAV_SIGNAL_UPDATE_JUNCTION_VIEW)
            {
                auto junctionSignal = tn::dynamic_pointer_cast<const tn::navigation::NavigationSignalUpdateJunctionView>(signal);

                const auto status = junctionSignal->getJunctionViewStatus();
                if (status == tn::navigation::NavigationSignalUpdateJunctionView::eJunctionViewStatus::ENTERED ||
                    status == tn::navigation::NavigationSignalUpdateJunctionView::eJunctionViewStatus::IN_TRANSITION)
                {
                    const auto route = navStatus->route();
                    const auto legIndex = junctionSignal->getLegIndex();
                    const auto stepIndex = junctionSignal->getStepIndex();
                    auto* render = service->getJunctionViewRender();
                    auto image = render->getJunctionViewImage(route, legIndex, stepIndex, 400, 480);
                    // show image (bitmap in ARGB32 format) on HMI
                }
                else
                {
                    // dismiss the previously shown junction view image
                }
            }
        }
    }
};
// junction signals are generated before vehicle actually hits the junction location for the reason of leaving some time for 
// drive to take actions.
// the distance can be configured at service creation time
auto settings = tn::foundation::Settings::Builder()
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_JUNCTION_HIGHWAY_DISPLAY_DISTANCE, "1000")
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_JUNCTION_LOCAL_STREET_DISPLAY_DISTANCE, "250")
    .build();

// create navigation service with customized settings
// all navigation sessions created from this service will have customized settings enabled
auto service = tn::navigation::NavigationServiceFactory::createService(system, settings, dependencies);
Timed Restriction

The TA SDK will prompt if there is a timed restriction within 50km detected.

class NavigationObserver : public tn::navigation::NavigationSessionListener 
{
public:
    void onUpdateNavStatus(const tn::navigation::NavStatus& navStatus) override
    {
        const auto signals = navStatus.getNavigationSignal();
        for (const auto& signal : signals)
        {
            if (signal->getSignal() == tn::navigation::NavigationSignal::eNavigationSignal::NAV_SIGNAL_TIMED_RESTRICTION)
            {
                auto restrictionSignal = tn::dynamic_pointer_cast<const tn::navigation::NavigationSignalTimedRestriction>(signal);

                const auto& edges = restrictionSignal->getTimedRestrictionEdges();

                // show timed restriction affected edges along the route
            }
        }
    }
};
// timed restriction signals are generated if the TA SDK estimates that vehicle may be on a road that will have timed restrictions
// effective in the future.
// the distance can be configured at service creation time
auto settings = tn::foundation::Settings::Builder()
    .setString(tn::navigation::SettingConstants::SETTING_KEY_NAME_TIMED_RESTRICTION_DETECT_RANGE, "10000")
    .build();

// create navigation service with customized settings
// all navigation sessions created from this service will have customized settings enabled
auto service = tn::navigation::NavigationServiceFactory::createService(system, settings, dependencies);
Better Route Detection

The TA SDK will search for better routes during navigation. There are 2 kinds of better route searching: one is that a better route must be searched since the current route is no longer valid, the other is that a better route will save the user time to reach the destination.

Meeting any of the following conditions will definitely trigger better route searching:

  1. the vehicle deviates from the current route in the navigation
  2. there's blocking traffic incidents or flows ahead
  3. timed restriction detected ahead
  4. map data version changed
  5. guidance information for the current route in navigation needs an update
  6. the remaining battery is not sufficient to reach the next planned charging station or destination (EV only)
// make a customized better route observer
auto listener = tn::make_shared<BetterRouteObserver>();

// get better route detector from navigation session
// better route detector is created and maintained in navigation session
// client MUST NOT delete it or access it after session is stopped
auto* detector = session->getBetterRouteDetector();

// register listener
detector->addListener(listener);
// remove better route observer when it's not needed anymore
detector->removeListener(listener);
// make a customized better route observer to handle better route switching progress
class BetterRouteObserver : public tn::navigation::BetterRouteListener
{
public:
    void onBetterRouteUpdating(const tn::shared_ptr<BetterRouteUpdateProgress>& progress) override
    {
        const auto status = progress->getRouteUpdateStatus();
        const auto reason = progress->getRouteUpdateReason();
        if (reason == tn::navigation::BetterRouteUpdateProgress::RouteUpdateReason::E_DEVIATION) 
        {
            if (status == tn::navigation::BetterRouteUpdateProgress::RouteUpdateStatus::E_STARTED)
            {
                requestAudio(tn::audio::AudioRequest::Type::kDeviation);
                requestAudio(tn::audio::AudioRequest::Type::kRerouting);
            }
            else (status == tn::navigation::BetterRouteUpdateProgress::RouteUpdateStatus::E_SUCCEEDED)
            {
                requestAudio(tn::audio::AudioRequest::Type::kFinishReroute);
                const auto currentRoute = progress->getRoute();
                const auto context = progress->getContext();
                const auto previousRoute = context->route();
                // update current route to necessary components in navigation application
                // it's already in navigation state inside the TA SDK services
            }
        }
        // handle other reasons
        // ...
    }

private:
    void requestAudio(tn::audio::AudioRequest::Type type)
    {
        tn::audio::AudioRequest request(type);
        const auto data = audioService->requestAudio(request);

        assert(data.audioType().isRequest());
        const auto& content = data.audioContent();
        tts.say(content.sentence);
    }
};

Meeting any of the following conditions will optionally trigger better route searching:

  1. traffic delay on current route is long enough
  2. timer to try searching for better route triggered
  3. next planned charging station is not available (EV only)
// make a customized better route observer to handle better route candidate
class BetterRouteObserver : public tn::navigation::BetterRouteListener
{
public:
    void onBetterRouteDetected(const tn::shared_ptr<BetterRouteCandidate>& candidate) override
    {
        const auto status = candidate->getStatus();
        if (status == tn::navigation::BetterRouteStatus::E_NEW_ROUTE)
        {
            const auto reason = candidate->getReason();
            if (reason == tn::navigation::BetterRouteReason::E_SAVE_TIME)
            {
                const auto betterRoute = candidate->route();
                const auto context = candidate->getContextInfo();
                const auto currentRoute = context->route();
                const auto savedTime = context->getSavedTime();

                if (savedTime > 60) // saved more than one minute
                {
                    candidate->accept(true);
                }
            }
        }
    }
};

During better route searching, the routing preferences used for current route in navigation will be preserved. Besides, route source (calculated on cloud or on board) will be preserved as well if possible.