Geofence: Add mission-planning geofence editor#2808
Conversation
Automated PR Review (Claude)0. SummaryVerdict: MINOR SUGGESTIONS Critical items to address: 6.1 This PR adds a full geofence planning editor to the Mission Planning view: polygon and circle fences (inclusion/exclusion), breach return point, autopilot parameter editing (ArduPilot & PX4), fence upload/download/clear via the MAVLink mission micro-service, 1. Correctness & Implementation Bugs1.1 ( 1.2 ( 1.3 ( 1.4 ( 2. AGENTS.md Adherence — ✅3. Security — ✅4. Performance4.1 ( 4.2 ( 5. UI / UX — ✅6. Code Quality & Style6.1 ( 6.2 ( 6.3 ( 6.4 ( 7. Commit Hygiene7.1 ( 8. Tests — ✅9. Documentation — ✅10. Nitpicks / Optional10.1 ( 10.2 ( Generated by Claude. This is advisory; a human reviewer must still approve. |
9959d71 to
a1f52a9
Compare
|
/review |
Automated PR Re-review 2 (Claude)Comparing Previous findings status
Notes on key resolutions:
New findings0. SummaryVerdict: MINOR SUGGESTIONS This re-review covers the delta from the first review. The three substantive findings (1.2 vehicle-listener stale binding, 4.1 aggressive polling, 6.1 file-size / extraction) have all been properly addressed. The new 1. Correctness & Implementation Bugs1.5 ( 2. AGENTS.md Adherence — ✅3. Security — ✅4. Performance — ✅5. UI / UX — ✅6. Code Quality & Style6.5 ( 7. Commit Hygiene — ✅8. Tests — ✅9. Documentation — ✅10. Nitpicks / Optional — ✅Generated by Claude. This is advisory; a human reviewer must still approve. |
a1f52a9 to
21bf45f
Compare
21bf45f to
2ccfbeb
Compare
Adds the runtime types backing the new geofencing flow: FenceLatLng, FencePolygon (with inclusion flag and vertex list), FenceCircle, BreachReturnPoint, and the Cockpit-level GeoFencePlan, plus the instanceOfGeoFencePlan guard that inspects only the outer discriminator + version so deeper validation stays at the call site that knows the schema.
On vehicle bring-up, send MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES and cache the bitmask received via the AUTOPILOT_VERSION message. Exposes a `capabilities()` accessor and a new `onCapabilities` signal so consumers can react when the bitmask first arrives. Failures are logged at warn level and gracefully fall back to "optimistic" capability reporting (consumers default to enabling features when no AUTOPILOT_VERSION has been seen yet).
Adds two helpers that turn the existing PARAM_REQUEST_READ / PARAM_VALUE round-trip into something callers can actually \`await\`: - \`requestParameter(name)\`: fires a single PARAM_REQUEST_READ for the given parameter id; the reply still bubbles up through \`onParameter\` for code that wants to keep listening passively. - \`requestParameterValue(name, timeoutMs)\`: subscribes a one-shot listener that resolves with the value as soon as the matching PARAM_VALUE arrives (or undefined on timeout). Both the listener and the timeout handle are cleared as soon as the promise settles to avoid stray callbacks. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Wires geofence support into the existing MAVLink mission micro-service: - geofence-conversion.ts: pure helpers that translate between a Cockpit GeoFencePlan and a flat list of MissionItemInt[]. Polygons are emitted vertex-per-item with a shared param1=vertex_count; circles use param1 for the radius; the optional breach return point goes last as a MAV_FRAME_GLOBAL_RELATIVE_ALT item. The reverse path detects bad/incomplete polygon item streams from the autopilot and surfaces a descriptive error. - vehicle.ts: extracts _fetchMissionItems / _uploadMissionItems from the mission code so fence and mission paths share the handshake, then layers uploadFence / fetchFence / clearFence on top using MAV_MISSION_TYPE_FENCE. uploadFence also calls _ensureArduPilotPolygonFenceTypeBit to set the Polygon bit (4) of FENCE_TYPE on ArduPilot — without it the autopilot silently ignores the uploaded polygons/circles. Other FENCE_TYPE bits are preserved. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Surfaces the new MAVLink capability and fence APIs through the existing main-vehicle Pinia store so consumers don't need to reach into the underlying MAVLinkVehicle instance: - \`capabilities\` ref + \`onCapabilities\` subscription, kept in sync as AUTOPILOT_VERSION arrives. - \`uploadFence\` / \`fetchFence\` / \`clearFence\` proxy actions, mirroring the existing mission helpers (and emitting the same "Geofence deleted from vehicle" snackbar on clear). - \`requestParameter\` proxy so other stores (notably the upcoming geo-fence store) can pull individual parameter values without duplicating the MAVLink boilerplate. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Framework-agnostic geofence geometry extracted so it stays unit-testable and reusable outside the store: WGS84 metric offsetting for default shape sizing, turf-backed point-in-polygon and haversine distance, plan/vertex deep-clone helpers, and detectMissionBreaches, which flags waypoints that fall outside every inclusion shape or inside any exclusion shape. Also houses the shared placement constants (default/max polygon half-side and circle radius) consumed by both the store and the editor draft.
Pinia store that owns the persisted editor-side geofencing state and vehicle sync, delegating pure geometry to libs/geo-fence and transient draw/interaction state to the useGeoFenceEditorDraft composable: - Reactive polygons, circles and breach-return point with `cockpit-draft-fence` (in-progress) and `cockpit-vehicle-fence` (last uploaded) persistence so the user doesn't lose work across reloads. - Vehicle sync: `uploadToVehicle` (auto-enables FENCE_ENABLE and FENCE_AUTOENABLE on ArduPilot once the upload completes), `downloadFromVehicle`, `clearOnVehicle`, plus `setFenceEnabled` / `setFenceAutoEnable` that write the parameters through the vehicle. - `FENCE_ENABLE` polling watch (10s) tied to ArduPilot + a loaded plan so the Map widget toggle reflects autopilot-side flips (e.g. takeoff-time activation) the autopilot doesn't broadcast. - Capability gate via `isFenceSupported` (`MISSION_FENCE` bit) and a `detectMissionBreaches` wrapper that picks the editor plan (or the last uploaded plan as fallback) so the UI can warn before mission upload.
…rop] Bail from _ensureArduPilotPolygonFenceTypeBit when the FENCE_TYPE read returns undefined (timeout) instead of assuming 0 and writing bit 4 alone, which would wipe the user's AltMax/AltMin/Circle bits. Logically belongs folded into "lib: vehicle-mavlink: add fence upload, fetch and clear" (0008163); kept separate because folding it would rewrite the stacked base and force a rebuild of the bluerobotics#2808/bluerobotics#2809 [drop] chains — do that explicitly, not autonomously.
Move emptyGeoFencePlan into libs/geo-fence and reuse it for the cockpit-draft-fence default and the MAVLink conversion re-export so the empty-plan literal is defined once. Addresses nit 10.3 from the local all-threshold review; logically folds into the geo-fence libs commit on a stack reshape.
The map container `<div>` carried `ref="planningMap"` while the setup
script also declares `const planningMap = shallowRef<Map | undefined>()`
that is later assigned in `onMounted` from `L.map('planningMap', ...)`.
Vue's ref-binding transiently writes the raw `HTMLDivElement` into the
same `shallowRef`, so any reactive consumer that observes the ref during
that window sees a DOM node instead of a Leaflet map and blows up when
it calls `.addLayer`, `.getCenter`, `.on`, etc. Drop the unused template
ref (the element is already reachable by id from `L.map`) and remove the
now-dead self-healing watcher that only existed to paper over the same
collision.
… row container Wrap the three independently absolute-positioned bottom-right buttons (Switch to Flight mode, Download tiles, Center-on-target speed dial) into a single flex-row container (`planning-bottom-buttons`, `gap: 10px`), mirroring the equivalent change to the Map widget. The Leaflet scale offset is updated from 293px to 278px to track the new container layout. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Move the shared screen-bounds and clamp-inside-viewport helpers that position the survey polygon confirm button into a dedicated libs module, where the upcoming geofence drawing action buttons can reuse them without further inflating the planning view.
Encapsulates the in-progress fence drawing state for the planning map — polygon vertex markers, edge "+"-markers, the dashed live polygon, the area pill at the centroid, and the two-click circle drawing primitives — behind a small composable. Mirrors the survey-polygon UX in the orange fence palette while letting the planning view stay the single owner of the Leaflet map and the measure-pane plumbing through injected deps.
Render the geofence plan (polygons, circles, breach-return point) as a Leaflet overlay driven by the geofence store, with a readonly mode for the flight-map live view and an interactive mode for the planning editor. Nested under a new src/components/geofence/ folder so every geofence-related component lives under a single domain root.
Isolate the floating confirm and discard buttons that hover next to the in-progress fence polygon into their own component. Owns the anchor-and-clamp positioning so the planning view no longer carries per-fence layout state, and reuses the shared confirm-button placement helpers so the survey and fence anchors follow the same geometry rules.
Expose the autopilot-side geofence parameters (FENCE_ACTION, FENCE_ENABLE, radius/altitude limits) as a collapsible panel that reads and writes them over MAVLink. Placed under the shared components/geofence/ folder alongside the rest of the geofence surface.
Bundle the polygon/circle CRUD, breach-return editor, upload and clear controls, and the parameters panel into a single sidebar shell so the planning view only mounts one component to expose the whole geofence authoring surface. Imports the params panel from its new geofence/ sibling location.
Wrap the collapsible left-side panel, the Mission/GeoFence tab switcher and the geofence editor mount in one shell so the planning view no longer manages tab styling and modal geometry inline. The mission editing surface stays in the planning view and renders through a named slot to keep behaviour identical.
Wire the mission planning view to the geofence stack through the new sidebar shell, drawing action buttons, and live map layer components, and add the composables that own fence drawing state and the fence subset of map click plus keyboard handling. Delegate mission upload to a fence-breach guard that surfaces a confirm dialog when any waypoint falls outside an inclusion fence or inside an exclusion fence, so the planning view stays the only place that couples mission and fence concerns. Add `useFenceMapInteraction` in composables/mission-planning to encapsulate the fence-mode keyboard shortcuts and map-click branching that used to live inline, and expose it alongside the existing `useFenceDrawing` composable so the planning view's setup shrinks to the wiring instead of the logic.
Bail from _ensureArduPilotPolygonFenceTypeBit when the FENCE_TYPE read returns undefined (timeout) instead of assuming 0 and writing bit 4 alone, which would wipe the user's AltMax/AltMin/Circle bits. Logically belongs folded into "lib: vehicle-mavlink: add fence upload, fetch and clear" (0008163); kept separate because folding it would rewrite the stacked base and force a rebuild of the bluerobotics#2808/bluerobotics#2809 [drop] chains — do that explicitly, not autonomously.
2ccfbeb to
3dff039
Compare
FENCE_ACTION,FENCE_ALT_*,FENCE_MARGIN,FENCE_AUTOENABLE; PX4GF_ACTION,GF_MAX_HOR_DIST,GF_MAX_VER_DIST,GF_PREDICT)..cfp, or the MAVLink-ecosystem.plan(mission + fence) so the same plan opens in other ground stations.Diff excluding the borrowed$\color{green}\pmb{+2{,}342}$ $\color{red}\pmb{-132}$
[drop]commits:Screenshare.-.2026-05-07.11_23_36.AM.mp4
Second of three sequential PRs splitting #2671:
To be merged after #2807