Mission Nav2 (NavigateThroughPoses)
Description
The nav2 adapter of the Mission Measurement for nav2's NavigateThroughPoses action -- the
action a deployment issues when a mission is a single job through several hard-constraint poses
in one call, rather than a chain of separate NavigateToPose goals (that sibling adapter is
mission_nav2, #387). Emits a mission_start Record when a goal is first observed and a
mission_end Record once it reaches a terminal state, in the same Record schema #387 defines,
with mission_type: "navigate_through_poses".
This Measurement is a passive observer of the action server's single active goal. It
never sends a goal itself. Instead it subscribes to the action's own
_action/status and _action/feedback topics and calls its _action/get_result service
directly for whichever goal_id just reached a terminal status -- the same standard per-action
topics/services every rclcpp_action::Server (nav2's bt_navigator included) exposes. Whatever
in the deployment actually dispatches missions (a BT navigator, a fleet orchestrator, an
operator command) keeps doing so exactly as before; this Measurement only watches.
Two Records per mission:
- a
mission_startRecord, the first time a goal_id is observed on the action's status topic. - a
mission_endRecord, once that goal_id reaches a terminal status (SUCCEEDED,CANCELED, orABORTED) and its result has been fetched.
outcome on the end Record is one of succeeded, failed, cancelled, aborted:
CANCELED maps to cancelled, ABORTED to aborted (both carrying nav2's own
error_msg/error_code as reason/error_code), and SUCCEEDED maps to succeeded unless
NavigateThroughPoses::Result.error_code is non-zero, in which case it is failed -- an
application-level failure nav2 reported without aborting the goal status itself.
recoveries (from NavigateThroughPoses::Feedback.number_of_recoveries, when feedback was seen
before completion) is carried on the end Record when available.
No per-waypoint outcome is reported. The acceptance criteria this Measurement was built
against ask for the final waypoint_statuses (which poses in the job succeeded versus failed) to
be represented on mission_end, following an upstream nav2 NavigateThroughPoses.action result
field of that name. That field does not exist on the nav2 release this repository actually
builds against (nav2_msgs on the jazzy branch of ros-navigation/navigation2 -- verified
directly, not assumed): its NavigateThroughPoses::Result carries only error_code/error_msg,
the same shape as NavigateToPose::Result. It was present in an earlier implementation of this
plugin (written against the upstream default branch without checking the pinned distro branch
first) and removed once CI's real Jazzy build caught the mismatch (fatal error: nav2_msgs/msg/waypoint_status.hpp: No such file or directory). Adding it back is a follow-up for
whenever nav2 backports per-waypoint result reporting to a distro this repository targets, not
something this Measurement can honestly do today.
A mission still running when collection stops simply never gets a matching mission_end Record:
nothing downstream can average an interval that was never closed as a zero, because there is no
mission_end Record to average. sequence is a monotonically increasing counter across every
Record this Measurement instance emits (start and end alike, not per mission_id), so a dropped
Record shows up as a gap rather than silently corrupting a duration or a mission-success-rate
denominator.
Parameters
| Parameter | Default | Description |
|---|---|---|
action_name | navigate_through_poses | The NavigateThroughPoses action to watch. Its _action/status, _action/feedback, and _action/get_result endpoints are subscribed/called directly. |
Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MissionNav2ThroughPoses",
"properties": {
"event": { "type": "string", "enum": ["mission_start", "mission_end"] },
"mission_id": { "type": "string" },
"mission_type": { "type": "string" },
"sequence": { "type": "integer", "minimum": 1 },
"outcome": { "type": "string", "enum": ["succeeded", "failed", "cancelled", "aborted"] },
"reason": { "type": "string" },
"error_code": { "type": "integer", "minimum": 0 },
"duration_sec": { "type": "number", "minimum": 0 },
"recoveries": { "type": "integer", "minimum": 0 }
},
"required": ["event", "mission_id", "sequence"],
"type": "object"
}
Configuration
...
mission_nav2_through_poses:
plugin: "dc_measurements/MissionNav2ThroughPoses"
topic_output: "/dc/measurement/mission_nav2_through_poses"
group_key: "mission"
action_name: "navigate_through_poses"
Example output
Start:
{
"event": "mission_start",
"mission_id": "3f2504e04f8911d39a0c0305e82c3301",
"mission_type": "navigate_through_poses",
"sequence": 7
}
and end (succeeded):
{
"event": "mission_end",
"mission_id": "3f2504e04f8911d39a0c0305e82c3301",
"mission_type": "navigate_through_poses",
"sequence": 8,
"outcome": "succeeded",
"duration_sec": 96.4,
"recoveries": 1
}
and end (aborted):
{
"event": "mission_end",
"mission_id": "9f86d081884c7d659a2feaa0c55ad015",
"mission_type": "navigate_through_poses",
"sequence": 10,
"outcome": "aborted",
"reason": "tf timeout",
"error_code": 9102,
"duration_sec": 12.1
}