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 exists on the nav2 this repository actually builds against
(nav2_msgs from navigation2's main branch, pinned in ros2_data_collection.repos -- its
NavigateThroughPoses::Result carries WaypointStatus[] waypoint_statuses) but this Measurement
does not surface it yet: an earlier implementation reported it, and was trimmed when the
repository tracked a distro branch whose NavigateThroughPoses::Result had no such field
(fatal error: nav2_msgs/msg/waypoint_status.hpp: No such file or directory). Surfacing it again
against the current pin is a follow-up, not something this Measurement does 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
}