Lane Guidance
Lane guidance
This tutorial shows how to handle lane guidance instructions.
Get started
The navigation service provides lane guidance information for lane level navigation experience.
In free mode, it only provides static lane information, including lane types and lane turn types, along the most possible path (MPP).
In navigation mode, it also provides lane level navigation guidance instructions to indicate whether a lane is preferred
to make the turn on the route in navigation.
Lane guidance requires the alert component to be enabled at the creation of a navigation service.
A navigation service created with the alert component enabled will have lane guidance turned off by default.
| // enable alert component
tn::drive::NavigationServiceOptions options;
options.enable_alert = true;
const auto navigationService = tn::drive::api::NavigationServiceFactory::createNavigationService(
options, system, settings, mapContent, directionService);
|
Turn it on if lane guidance is needed.
Once turned on, you will receive lane guidance notification including lane merge, lane fork, lane type change
and lane guidance instructions for junctions.
| // turn on lane guidance
navigationService->enableLaneGuidanceDetection(true);
|
Make a customized alert listener to handle lane guidance updates.
| class AlertObserver : public tn::drive::api::AlertEventListener
{
public:
void onLaneGuidanceInfoUpdated(const tn::drive::models::v1::LaneGuidanceInfo& laneGuidance) override
{
// the lane guidance is given in the order of nearest to furthest regarding vehicle location
for (const auto& guidanceInfo : laneGuidance)
{
// Get the route step index information.
// In AGV mode, displaying different lane turn types and turn maneuver information may confuse users.
// It is suggested to only show the lane guidance information in the current route step.
// If the step index is not aligned with the current direction step, it should be skipped.
const auto routeStepInfo = guidanceInfo.routeStepInfo;
const auto lanesBeforeChange = generateLanesImage(guidanceInfo.prevLanes);
const auto lanesAfterChange = generateLanesImage(guidanceInfo.nextLanes);
switch (guidanceInfo.type)
{
case tn::drive::models::v1::LaneGuidanceType::LaneMerge:
{
if (guidanceInfo.mergeType.has_value())
{
/*
* Following is the illustration of merge types:
* | | | | | | | |
* / | | \ / \
* / | | | | \ / \
* / | | \ / \
* / | | | | | | | | | |
* | | | | | |
* | | | | | | | | | | |
* MergeIntoRight MergeIntoLeft NoPriority
* NoPriority means there is no obvious priority between lanes.
*/
// align image for lanes before and after change according to merge type
const auto alignedImage = alignLaneImages(
lanesBeforeChange, lanesAfterChange, guidanceInfo.mergeType.value());
}
break;
}
case tn::drive::models::v1::LaneGuidanceType::LaneFork:
{
if (guidanceInfo.forkType.has_value())
{
/*
* Following is the illustration of fork types:
* | | | | | | | | | | | |
* | | | | | |
* \ | | | | | | | | | | |
* \ | | / \ /
* \ | | | | / \ /
* \ | | / \ /
* | | | | | | | |
* ForkOnLeft ForkOnRight ForkOnBothSides
*/
// align image for lanes before and after change according to fork type
const auto alignedImage = alignLaneImages(
lanesBeforeChange, lanesAfterChange, guidanceInfo.forkType.value());
}
break;
}
case tn::drive::models::v1::LaneGuidanceType::LaneTypeChange:
{
// align image for lanes before and after change
const auto alignedImage = alignLaneImages(lanesBeforeChange, lanesAfterChange);
break;
}
case tn::drive::models::v1::LaneGuidanceType::Junction:
{
// what matters for lane guidance at junction is the lane and direction to take before the junction
// so lane image before change is necessary, those after does not have to be shown
const auto alignedImage = lanesBeforeChange;
break;
}
default:
{
break;
}
}
}
}
};
// generate any image format that can be displayed in HMI
// take tn::foundation::Bitmap for example, it represents an image in ARGB32 format
tn::shared_ptr<tn::foundation::Bitmap> generateLanesImage(const std::vector<tn::drive::models::v1::LaneInfo>& lanes)
{
std::vector<tn::shared_ptr<tn::foundation::Bitmap>> laneImages;
for (const auto& lane : lanes)
{
// generate lane turn icon according to turn type
// no direction: | |
// straight: | ↑ |
// left: | ↰ |
// right: | ↱ |
// u-turn left: | ↶ |
// u-turn right: | ↷ |
// a lane may have multiple turn types
// for example, a lane can make left and right turns, so the icon should be a combination of left and right turn arrows
// in free mode, lane does not have applicable turn direction since we don't know which direction is driver going
// in navigation mode, lane will have applicable turn direction to indicate with direction should be taken for multiple turn directions
// besides, in navigation mode, a lane may be preferred if it's the best choice in all applicable lanes
// lane turn icon for multiple directions should consider if one of them is applicable and preferred to highlight that direction
tn::shared_ptr<tn::foundation::Bitmap> turnIcon = generateLaneTurnIcon(lane.turns, lane.applicableTurn, lane.preferred);
// generate lane icon according to lane type
// not specified: | |
// regular lane: | |
// HOV lane: | ♢ |
// express lane: | EXPRS |
// bicycle lane: | 🚲 |
// bus lane: | 🚌 |
// reversible lane: | ⇅ |
tn::shared_ptr<tn::foundation::Bitmap> laneIcon = generateLaneIcon(lane.types);
// put lane turn icon above lane icon to construct a lane image
// for example:
// a HOV lane go straight: | ↑ |
// | ♢ |
laneImages.push_back(generateLaneImage(turnIcon, laneIcon));
}
// append lane images one by one to generate a list of lanes
// for example:
// | ↶ | ↰ | ↑ | ↑ | ↱ | |
// | | | ♢ | | 🚌 |🚲|
tn::shared_ptr<tn::foundation::Bitmap> result;
for (const auto& image : laneImages)
{
result = appendLaneImage(result, image);
}
return result;
}
|
Register the listener after creation of navigation service.
| const auto listener = tn::make_shared<AlertObserver>();
navigationService->addAlertEventListener(listener);
|
Unregister it when not needed.
| navigationService->removeAlertEventListener(listener);
|
Customize lane guidance detection distance
Lane guidance detection distances can be configured to adjust performance.
These detection distances are shared for the detection of lane type, lane turn type, lane merge, lane fork, lane merge,
and lane instruction at the junction.
The detection distance should be less than
detection distance configured for road graph builder.
| const std::string laneDetectionSettings = R"json(
{
// Following configuration shows the default values for the detection distances
"LaneGuidance":
{
// Max ahead lane info detect distance on local road, unit: meter.
// Note that if this value is larger than actual forward detect route length,
// it will not incur extra road detection.
"AheadDetectDistanceOnLocalRoad": 700,
// Max ahead lane info detect distance on highway, unit: meter.
// Note that if this value is larger than actual forward detect route length,
// it will not incur extra road detection.
"AheadDetectDistanceOnHighway": 1000,
// The min distance for detecting lane guidance info in streaming mode, unit: meter.
// If the streaming data within this distance is not ready, will report the data failure to MapContent.
"MinDemandDistanceForStreaming": 1000
}
}
)json";
const auto settings = tn::foundation::Settings::Builder()
.setString(tn::drive::api::SettingConstants::SETTING_ALERT_JSON_CONTENT, laneDetectionSettings)
.build();
// enable alert component at the creation of a navigation service to make customized lane guidance detection settings effective
tn::drive::NavigationServiceOptions options;
options.enable_alert = true;
const auto navigationService = tn::drive::api::NavigationServiceFactory::createNavigationService(
options, system, settings, mapContent, directionService);
|