Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions docs/Navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,70 @@ PID meaning:
* POS - translated position error to desired velocity, uses P term only
* POSR - translates velocity error to desired acceleration

## Marker Guidance Target Consumer (MSP)

INAV can consume externally computed marker offsets over MSP and use them for:
1. precision landing alignment
2. marker-relative position hold in POSHOLD
3. marker-relative containment (indoor limiter behavior)

### Build-time availability
This feature is compiled only when `USE_MARKER_GUIDANCE` is enabled for the target.
On flash-constrained targets, it can be excluded at build time to preserve headroom.

### MSP payload
`MSP2_INAV_SET_MARKER_GUIDANCE_TARGET` request payload is 4 bytes:
* `int16_t offsetForwardCm`
* `int16_t offsetRightCm`

* every received packet is treated as a fresh target sample
* target freshness is based on FC receive time (`nav_marker_guidance_max_target_age_ms`)

### Mode gating
Marker guidance can influence navigation only when:
* active profile is MC/VTOL-hover-capable
* `nav_marker_guidance_mode` is not `OFF`

Outside those contexts, updates may still be cached but do not affect navigation loops.

### POSHOLD behavior
When `nav_marker_guidance_mode = PL`:
* FC uses marker offsets to center above the target in POSHOLD.

When `nav_marker_guidance_mode = CONTAINMENT`:
* FC uses marker-relative hold target:
* `nav_marker_containment_hold_north_cm`
* `nav_marker_containment_hold_east_cm`
* FC applies containment behavior with `nav_marker_guidance_radius_cm`:
* inside radius: no correction
* outside radius: FC corrects back toward allowed boundary

### LAND behavior
When `nav_marker_guidance_mode = PL` and target is fresh:
* FC performs precision horizontal alignment to marker center during LAND
* vertical descent profile remains normal LAND behavior (`nav_land_*`)

With stale/lost target:
* FC enters hold for `nav_marker_guidance_lost_hold_time_ms`
* optionally performs climb-and-retry up to `nav_marker_guidance_retry_count`
* then falls back to normal LAND behavior

Retry safety rule:
* retry is only entered if target was acquired at least once in the current LAND context
* if no target was ever acquired in that LAND context, no retry is performed

### Shared radius setting
`nav_marker_guidance_radius_cm` is used by both modes:
* `PL`: center-alignment deadband around marker center
* `CONTAINMENT`: allowed radius around marker-containment hold target
* `0`: continuous correction (no deadband/boundary allowance)

### Core safety semantics
* new packet == fresh target sample
* no packet inside timeout window == target lost
* horizontal marker-guidance correction is capped by current active navigation speed limit (`getActiveSpeed()`)
* no dynamic allocation in the runtime path

## NAV RTH - return to home mode

Home for RTH is the position where vehicle was first armed. This position may be offset by the CLI settings `nav_rth_home_offset_distance` and `nav_rth_home_offset_direction`. This position may also be overridden with Safehomes. RTH requires accelerometer, compass and GPS sensors.
Expand Down
113 changes: 112 additions & 1 deletion docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4434,6 +4434,118 @@ If GPS fails wait for this much seconds before switching to emergency landing mo

---

### nav_marker_guidance_mode

Marker-guidance mode selector (master enable gate). `OFF` disables marker guidance.

| Allowed Values | |
| --- | --- |
| OFF | Default |
| PL | |
| CONTAINMENT | |

---

### nav_marker_guidance_radius_cm

Marker-guidance radius [cm]. In PL, this is the center-alignment deadband around marker center. In CONTAINMENT, this is the allowed radius around marker-containment hold target. Set 0 for continuous correction.

| Default | Min | Max |
| --- | --- | --- |
| 80 | 0 | 5000 |

---

### nav_marker_guidance_lost_hold_time_ms

Hold duration after target loss before falling back to normal LAND behavior [ms].

| Default | Min | Max |
| --- | --- | --- |
| 1500 | 100 | 10000 |

---

### nav_marker_containment_hold_north_cm

Marker-relative hold target for vehicle North position [cm], relative to marker. Positive means vehicle should stay North of marker.

| Default | Min | Max |
| --- | --- | --- |
| 0 | -5000 | 5000 |

---

### nav_marker_containment_hold_east_cm

Marker-relative hold target for vehicle East position [cm], relative to marker. Positive means vehicle should stay East of marker.

| Default | Min | Max |
| --- | --- | --- |
| 0 | -5000 | 5000 |

---

### nav_marker_guidance_max_offset_cm

Maximum allowed horizontal target offset magnitude. Larger offsets are rejected [cm]. Set 0 to disable this check.

| Default | Min | Max |
| --- | --- | --- |
| 1500 | 0 | 5000 |

---

### nav_marker_guidance_max_target_age_ms

Maximum age of cached marker data [ms]. If no fresh packet arrives inside this window, target becomes stale/lost and marker guidance stops affecting navigation.

| Default | Min | Max |
| --- | --- | --- |
| 500 | 50 | 5000 |

---

### nav_marker_guidance_retry_altitude_cm

Climb distance for each retry attempt after target loss in PL mode LAND context [cm].

| Default | Min | Max |
| --- | --- | --- |
| 200 | 50 | 2000 |

---

### nav_marker_guidance_retry_count

Maximum number of climb-and-retry attempts after target loss in PL mode LAND context.

| Default | Min | Max |
| --- | --- | --- |
| 2 | 0 | 10 |

---

### nav_marker_guidance_retry_timeout_ms

Timeout for each climb-and-retry phase in PL mode LAND context [ms]. Set to 0 for AUTO mode (computed as 2 x nav_marker_guidance_lost_hold_time_ms).

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 60000 |

---

### nav_marker_guidance_source

Marker-guidance target source.

| Allowed Values | |
| --- | --- |
| MSP | Default |

---

### nav_rth_abort_threshold

RTH sanity checking feature will notice if distance to home is increasing during RTH and once amount of increase exceeds the threshold defined by this parameter, instead of continuing RTH machine will enter emergency landing, self-level and go down safely. Default is 500m which is safe enough for both multirotor machines and airplanes. Set to 0 to disable. [cm]
Expand Down Expand Up @@ -7127,4 +7239,3 @@ Defines rotation rate on YAW axis that UAV will try to archive on max. stick def
| 20 | 1 | 180 |

---

22 changes: 21 additions & 1 deletion docs/development/msp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ When the MSP JSON specification changes, bump `msp_messages.json` version:
[8731 - MSP2_INAV_NAV_TARGET](#msp2_inav_nav_target)
[8736 - MSP2_INAV_FULL_LOCAL_POSE](#msp2_inav_full_local_pose)
[8737 - MSP2_INAV_SET_WP_INDEX](#msp2_inav_set_wp_index)
[8753 - MSP2_INAV_SET_MARKER_GUIDANCE_TARGET](#msp2_inav_set_marker_guidance_target)
[8739 - MSP2_INAV_SET_CRUISE_HEADING](#msp2_inav_set_cruise_heading)
[12288 - MSP2_BETAFLIGHT_BIND](#msp2_betaflight_bind)
[12289 - MSP2_RX_BIND](#msp2_rx_bind)
Expand Down Expand Up @@ -4698,6 +4699,26 @@ When the MSP JSON specification changes, bump `msp_messages.json` version:

**Notes:** Returns error if the aircraft is not armed, `NAV_WP_MODE` is not active, or the index is outside the valid mission range (`startWpIndex` to `startWpIndex + waypointCount - 1`). On success, sets `posControl.activeWaypointIndex` to the requested index and fires `NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_JUMP`, transitioning the navigation FSM back to `NAV_STATE_WAYPOINT_PRE_ACTION` so the flight controller re-initialises navigation for the new target.

## <a id="msp2_inav_set_marker_guidance_target"></a>`MSP2_INAV_SET_MARKER_GUIDANCE_TARGET (8753 / 0x2231)`
**Description:** Updates the external marker target sample used by marker-guidance NAV correction. This message does not arm/disarm, does not switch flight modes, and does not start landing by itself.

**Request Payload:**
|Field|C Type|Size (Bytes)|Units|Description|
|---|---|---|---|---|
| `offset_forward_cm` | `int16_t` | 2 | cm | Marker offset forward from vehicle body origin |
| `offset_right_cm` | `int16_t` | 2 | cm | Marker offset right from vehicle body origin |

**Reply Payload:**
|Field|C Type|Size (Bytes)|Description|
|---|---|---|---|
| `accepted` | `uint8_t` | 1 | Payload accepted into target-processing path |
| `used_now` | `uint8_t` | 1 | Target is currently influencing navigation correction |
| `nav_guidance_state` | `uint8_t` | 1 | Internal marker-guidance state |
| `reason` | `uint8_t` | 1 | Result reason (`OK`, `NOT_ENABLED`, `STALE`, `OFFSET_TOO_LARGE`, `NOT_MC_PROFILE`, `NOT_IN_POSHOLD_OR_LAND`, etc.) |
| `retry_count` | `uint8_t` | 1 | Current retry-attempt counter in PL LAND retry flow |

**Notes:** Hard break: request payload is now fixed at **4 bytes** (`int16_t`, `int16_t`). Legacy request fields `valid`, `confidence`, `frame`, `timestamp_ms`, and `distance_cm` were removed. Companion implementations must migrate to the new layout. Available only when firmware is built with `USE_MARKER_GUIDANCE`. Corrections are mode-gated to MC/VTOL-hover-capable POSHOLD/LAND contexts; outside those contexts updates may still be cached (`used_now = 0`). Freshness is evaluated using FC receive time.

## <a id="msp2_inav_set_cruise_heading"></a>`MSP2_INAV_SET_CRUISE_HEADING (8739 / 0x2223)`
**Description:** Sets the course heading target while Cruise or Course Hold mode is active, causing the aircraft to turn to and maintain the new heading.

Expand Down Expand Up @@ -4735,4 +4756,3 @@ When the MSP JSON specification changes, bump `msp_messages.json` version:
| `reserved_for_custom_use` | `uint8_t[3]` | 3 | Reserved for custom use |

**Notes:** Requires a receiver using MSP as the protocol, sends MSP2_RX_BIND to the receiver.

60 changes: 58 additions & 2 deletions docs/development/msp/msp_messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": {
"major": 2,
"minor": 0,
"patch": 0
"patch": 1
},
"messages": {
"MSP_API_VERSION": {
Expand Down Expand Up @@ -11260,6 +11260,62 @@
"notes": "Returns error if the aircraft is not armed, `NAV_WP_MODE` is not active, or the index is outside the valid mission range (`startWpIndex` to `startWpIndex + waypointCount - 1`). On success, sets `posControl.activeWaypointIndex` to the requested index and fires `NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_JUMP`, transitioning the navigation FSM back to `NAV_STATE_WAYPOINT_PRE_ACTION` so the flight controller re-initialises navigation for the new target.",
"description": "Jumps to a specific waypoint during an active waypoint mission, causing the aircraft to immediately begin navigating toward the new target waypoint."
},
"MSP2_INAV_SET_MARKER_GUIDANCE_TARGET": {
"code": 8753,
"mspv": 2,
"request": {
"payload": [
{
"name": "offset_forward_cm",
"ctype": "int16_t",
"desc": "Marker forward offset relative to vehicle body frame.",
"units": "cm"
},
{
"name": "offset_right_cm",
"ctype": "int16_t",
"desc": "Marker right offset relative to vehicle body frame.",
"units": "cm"
}
]
},
"reply": {
"payload": [
{
"name": "accepted",
"ctype": "uint8_t",
"desc": "Payload accepted by marker-guidance target consumer.",
"units": ""
},
{
"name": "used_now",
"ctype": "uint8_t",
"desc": "Target is currently influencing navigation correction.",
"units": ""
},
{
"name": "nav_guidance_state",
"ctype": "uint8_t",
"desc": "Current internal marker-guidance state.",
"units": "enum"
},
{
"name": "reason",
"ctype": "uint8_t",
"desc": "Processing reason/result code.",
"units": "enum"
},
{
"name": "retry_count",
"ctype": "uint8_t",
"desc": "Current retry-attempt counter in PL LAND retry flow.",
"units": ""
}
]
},
"notes": "Hard-break payload format: request size is now exactly 4 bytes (`int16_t`, `int16_t`). Legacy fields (`valid`, `confidence`, `frame`, `timestamp_ms`, `distance_cm`) were removed. Every received packet is treated as a fresh target sample; freshness timeout is evaluated using FC receive time. This message updates marker target cache only. It does not arm/disarm, does not switch modes, and does not trigger landing by itself. Available only when firmware is built with USE_MARKER_GUIDANCE. Navigation correction influence is mode-gated to MC/VTOL-hover-capable POSHOLD/LAND contexts.",
"description": "Updates the external marker-relative target sample consumed by marker-guidance NAV correction."
},
"MSP2_INAV_SET_CRUISE_HEADING": {
"code": 8739,
"mspv": 2,
Expand Down Expand Up @@ -11354,4 +11410,4 @@
"description": "Initiates binding for MSP receivers (mLRS)."
}
}
}
}
2 changes: 2 additions & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ main_sources(COMMON_SRC
navigation/navigation_fw_launch.c
navigation/navigation_geo.c
navigation/navigation_multicopter.c
navigation/marker_guidance.c
navigation/marker_guidance.h
navigation/navigation_pos_estimator.c
navigation/navigation_pos_estimator_private.h
navigation/navigation_pos_estimator_agl.c
Expand Down
31 changes: 31 additions & 0 deletions src/main/fc/fc_msp.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@

#include "navigation/navigation.h"
#include "navigation/navigation_private.h" //for MSP_SIMULATOR
#ifdef USE_MARKER_GUIDANCE
#include "navigation/marker_guidance.h"
#endif
#include "navigation/navigation_pos_estimator_private.h" //for MSP_SIMULATOR

#include "rx/rx.h"
Expand Down Expand Up @@ -4367,6 +4370,34 @@ bool mspFCProcessInOutCommand(uint16_t cmdMSP, sbuf_t *dst, sbuf_t *src, mspResu
break;
#endif

#ifdef USE_MARKER_GUIDANCE
case MSP2_INAV_SET_MARKER_GUIDANCE_TARGET:
if (dataSize != (2 * sizeof(int16_t))) {
*ret = MSP_RESULT_ERROR;
break;
}
{
markerGuidanceTargetUpdate_t update = {
.offsetForwardCm = (int16_t)sbufReadU16(src),
.offsetRightCm = (int16_t)sbufReadU16(src),
};

markerGuidanceMspResponse_t response = { 0 };
if (!markerGuidanceHandleMspTargetUpdate(&update, &response)) {
*ret = MSP_RESULT_ERROR;
break;
}

sbufWriteU8(dst, response.accepted);
sbufWriteU8(dst, response.usedNow);
sbufWriteU8(dst, response.navGuidanceState);
sbufWriteU8(dst, response.reason);
sbufWriteU8(dst, response.retryCount);
*ret = MSP_RESULT_ACK;
}
break;
#endif

case MSP2_INAV_SET_LOCAL_TARGET:
if (dataSize != 3 * sizeof(int32_t) || !isGCSValid()) {
*ret = MSP_RESULT_ERROR;
Expand Down
Loading