Missions: Add geo fencing#2671
Conversation
Replace the per-key "if undefined ..." chain in onBeforeMount with a single spread merge of a defaultOptions object over the persisted options. Aligns the Map widget with the convention documented in AGENTS.md (and used in Plotter.vue) so future option additions are a one-liner instead of another conditional branch. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Replace the three independently absolute-positioned bottom-right buttons (Edit mission, Download tiles, Center-on-target speed dial) with a single flex-row container (`map-bottom-buttons`, `gap: 10px`). Lays the groundwork for additional map overlay buttons to slot in without reshuffling right-offsets, and keeps the existing Leaflet scale offset untouched. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
… 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>
Adds the runtime types backing the new geofencing flow: FenceLatLng, FencePolygon (with inclusion flag and vertex list), FenceCircle, BreachReturnPoint, the Cockpit-level GeoFencePlan, the on-disk CockpitFencePlanFile (.cfp) envelope, and the MavlinkPlanFile envelope that lets fence (and mission) plans round-trip with other ground stations through the de-facto MAVLink-ecosystem .plan JSON format. Type guards (instanceOfGeoFencePlan, instanceOfCockpitFencePlanFile, instanceOfMavlinkPlanFile) only inspect the outer discriminator + version so deeper validation stays at the call site that knows the schema. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
On vehicle bring-up, send MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES and cache the bitmask received via the AUTOPILOT_VERSION message. Exposes `capabilities()` / `hasCapability(bit)` accessors, 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). Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
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>
Pinia store that owns all editor-side geofencing state: - 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. - Plan import/export between Cockpit's runtime shape, the .cfp envelope and the de-facto MAVLink-ecosystem .plan file. - Vehicle sync: \`uploadToVehicle\` (auto-enables FENCE_ENABLE and FENCE_AUTOENABLE on ArduPilot once the upload completes), \`downloadFromVehicle\`, \`clearOnVehicle\`, plus \`setFenceEnabled\` / \`setFenceAutoEnable\` that talk to the new MAVLink helpers. - \`FENCE_ENABLE\` polling watch (3 s) 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\` helper that flags mission waypoints which fall outside an inclusion fence or inside an exclusion fence so the UI can warn before mission upload. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Leaflet layer responsible for rendering all geofence shapes — both during interactive editing in MissionPlanningView and as the read-only overlay on the Map widget. - Polygons render with a 45-degree striped SVG pattern for exclusion zones and a translucent blue fill for inclusion zones, with a stripe pattern that's dimmed by 50% when \`readonly\` so the live overlay stays visually quieter than the editor. - Vertex / center / "+" handles drive polygon shape edits in editor mode (move cursor on draggable handles, copy cursor on midpoint add-vertex handles); circles get a center handle plus a draggable edge handle with a live distance tooltip. Breach-return drag reads its altitude back from the store on dragend so altitude edits made between marker creation and drag aren't overwritten. - \`L.Layer | null\` types kept loose where Leaflet's typings would otherwise fight us. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Collapsed-by-default ExpansiblePanel that exposes the curated set of autopilot-side fence parameters. ArduPilot lists FENCE_ACTION / FENCE_ALT_MAX / FENCE_ALT_MIN / FENCE_MARGIN / FENCE_AUTOENABLE; PX4 lists GF_ACTION / GF_MAX_HOR_DIST / GF_MAX_VER_DIST / GF_PREDICT. Per-parameter info icons open a click-triggered tooltip with the full description so we don't drown the panel in inline text. The PARAM_VALUE listener is captured in a named handler and removed in onBeforeUnmount to avoid accumulating listeners on remount; failed param writes surface as a snackbar instead of failing silently. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Sidebar component that drives all editor-side geofence interactions: - Compact "Add fence" row with polygon and circle buttons that match the Add survey / Add simple path styling; new fences live in expansible panels and the cards expose a clickable inclusion/exclusion tag plus a scaled-down on/off switch. - Breach-return section with an "Add breach return point" button (info icon on the right) and an "Auto enable fence on takeoff" switch (defaults on; flips FENCE_AUTOENABLE on ArduPilot). - Vehicle controls: upload to vehicle, clear on vehicle, and import / export of both Cockpit-native .cfp files and the de-facto MAVLink ecosystem .plan files. clearOnVehicle and parameter writes are wrapped in try/catch so failures surface as a dialog or snackbar instead of failing silently. - Embeds the GeoFenceParametersPanel for autopilot-side fence parameters. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
Wires the geofencing flow into the planning view: - A compound "Mission / GeoFence" planning-mode switcher; the sidebar swaps between mission editing controls and the new GeoFenceEditor. - Cruise-speed input + "Add survey" / "Add simple path" buttons gated on planningMode === "mission" so they disappear in geofence mode. - Click-to-draw flow for polygon and circle fences, mirroring the survey-polygon mechanics (crosshair cursor, live edge measurement, add-vertex midpoints, vertex dragging) plus a click-to-set-center / drag-to-set-radius flow for circles. Confirm/delete buttons hover near the shape, no inline distance fields. - Pre-upload safety net: confirmMissionFenceBreachIfNeeded runs fenceStore.detectMissionBreaches against the planned waypoints and, if any waypoint is outside an inclusion fence or inside an exclusion fence, prompts the user with "Back to mission planning" / "Upload to vehicle anyway" before letting the upload proceed. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
- Renders the last uploaded fence read-only on the map widget via GeoFenceMapLayer. The overlay is mounted only while enforcement is on (and a fence is loaded) so toggling enforcement off also hides the fence polygons/circles and the breach-return marker; turning it back on re-renders them automatically. - Adds a fence enforcement speed-dial to the bottom-right buttons row (visible only on ArduPilot once a fence is loaded). The shield activator opens the dial on click and turns the same orange as exclusion zones whenever the fence is active; double-clicking it toggles FENCE_ENABLE directly through fenceStore.setFenceEnabled without leaving the map. The dial exposes a toggle item and a reload item that triggers a fresh fence download from the vehicle. - Adjusts the Leaflet scale offset from 293px to 319px to track the extra width the fence speed-dial adds to the bottom-right flex row. Signed-off-by: Arturo Manzoli <arturomanzoli@gmail.com>
0fde676 to
1015db7
Compare
Automated PR Review (Claude)0. SummaryVerdict: MINOR SUGGESTIONS Minor items to address: 1.1, 1.2, 1.3, 4.1, 4.2, 6.1, 6.2. This PR adds a comprehensive geofence planning module to Cockpit's Mission Planning view. It introduces polygon and circle fence shapes (inclusion/exclusion), a breach return point, fence parameter management (ArduPilot + PX4), MAVLink upload/download via the fence mission micro-service, live fence overlay on the flight Map widget, fence enforcement toggling, waypoint-vs-fence breach checking before mission upload, and 1. Correctness & Implementation Bugs1.1 (minor) 1.2 (minor) 1.3 (minor) sourcePolygons().map((p) => ({
id: p.id,
inclusion: p.inclusion,
vertices: p.vertices.map((v) => `${v[0]},${v[1]}`),
})),With 1.4 (nit) 2. AGENTS.md Adherence2.1 (nit) Comment policy (explain "why" not "what"): Several new comments describe "what" rather than "why", e.g. 2.2 (pass) Existing dependencies: 2.3 (pass) 2.4 (pass) Widget options default-merging pattern: The Map widget's 2.5 (pass) JSDoc completeness: All new public functions and interfaces have JSDoc with typed 2.6 (pass) Optional chaining: Used consistently throughout (e.g. 3. Security3.1 (pass) No obfuscated or intentionally unreadable code detected. 3.2 (pass) No suspicious base64/hex/long-encoded blobs, binary-like strings, or unusually large encoded constants. 3.3 (pass) No hidden Unicode, zero-width characters, right-to-left overrides, or homoglyph attacks detected. All identifiers use standard ASCII. 3.4 (pass) No unexpected network calls. All communication goes through the existing MAVLink message pipeline ( 3.5 (pass) No changes to build scripts, 3.6 (pass) No new environment variables, tokens, credentials, weakened CORS/CSP, 3.7 (pass) No new dependencies added to 3.8 (pass) No patterns suggesting malicious behavior. File I/O is limited to user-initiated file picker ( 4. Performance4.1 (minor) 4.2 (minor) 4.3 (nit) 5. UI / UX5.1 (nit) The fence speed-dial on the Map widget is gated by 5.2 (nit) The "Finish polygon fence" confirm button uses 5.3 (nit) In the sidebar, when 6. Code Quality & Style6.1 (minor) const onTogglePolygonInteractive = (id: string): void => {
fenceStore.setInteractive(fenceStore.interactiveShapeId === id ? undefined : id)
}
const onToggleCircleInteractive = (id: string): void => {
fenceStore.setInteractive(fenceStore.interactiveShapeId === id ? undefined : id)
}These could be a single 6.2 (minor) 6.3 (nit) const param_id = [...paramName.padEnd(16, '\0')]6.4 (nit) 7. TestsNo new tests are added for the geofence functionality. Given the complexity of the feature (MAVLink encoding/decoding in
This is noted as a suggestion rather than a blocker, since the existing codebase test coverage appears minimal and this PR is consistent with current practice. 8. DocumentationNo README updates. Per AGENTS.md, if a feature differs between Standalone (Electron) and Lite (Web), the limitations should be documented in the README table. The geofence feature appears to work identically in both modes (all MAVLink, no Electron-specific APIs), so no README update is needed. The in-code JSDoc is thorough across all new files. The PR description is detailed and includes a demo video. 9. Nitpicks / Optional9.1 (nit) 9.2 (nit) 9.3 (nit) Consider extracting the dialog confirmation pattern (used in 9.4 (nit) Generated by Claude. This is advisory; a human reviewer must still approve. |
This PR was split into thee others to ease the review:
#2807 - Add geofence vehicle sync and plan types
#2808 - Mission Planning: Add geofence planning editor
#2809 - Add live geofence map overlay