Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3779acb1d9 | |||
| 2828162f72 | |||
| 76eca4b7a4 | |||
| 0b621009d5 | |||
| 56c69f4c07 | |||
| c7295c8a4f | |||
| 3ba440c332 | |||
| b04518c0bc | |||
| 45abdb14b3 | |||
| 701ac9b257 | |||
| 6db00a2326 | |||
| 935a21d05c | |||
| d2e3668ad9 | |||
| 541ee6f81d | |||
| 8b870e364e | |||
| b142342c3a | |||
| f444402e6c | |||
| 0d18be5049 | |||
| 197a1a6214 | |||
| 93955bd313 | |||
| 65c96fb2bf | |||
| f4c820c7e1 | |||
| c260794122 | |||
| 61f08771a7 | |||
| 4d4d814d19 | |||
| 14086c6f2e | |||
| 2e0000c8fa | |||
| 757be36ac2 | |||
| 106907bfd4 | |||
| 7d392394dd | |||
| 94580ab1e5 | |||
| 4cbdc3dec6 | |||
| 5568c66959 | |||
| a09c76d30d | |||
| 4b6cd37a23 | |||
| ffa10ab362 | |||
| e253c1e20c | |||
| c149bad4f2 | |||
| 8170e113fd | |||
| 7f59e5dc16 | |||
| b2a75fcc0f | |||
| 654306e9ed | |||
| 7b8fc2efaf | |||
| 0deb6b33ee | |||
| 0e63f41642 | |||
| b243398231 | |||
| 1d80fc317e | |||
| 01dd41b7e8 | |||
| 4f2918ee3b | |||
| f46609ac8b | |||
| 62b94fa73e | |||
| 1e769a76d6 | |||
| 1856933bac | |||
| eb029e6920 | |||
| d5d2ce26d7 | |||
| 1d81ecb08d | |||
| b48f3ef6f7 | |||
| d24d4a4fc4 | |||
| 710adefb4c | |||
| d4e60cb1dc | |||
| 45659d36aa | |||
| c2c811072e | |||
| 7584f7567f | |||
| 693b3111ca | |||
| 6c775c5a81 | |||
| b5cc93cebc | |||
| 9784fcbb8e | |||
| 274e9e3ee8 | |||
| 2ffc643390 | |||
| e4e3795cad | |||
| 5a4c13fc23 | |||
| 565781e688 | |||
| 6b17795aa4 | |||
| f573dec0d9 | |||
| 1bef6390f2 | |||
| 80815bba4a | |||
| b82894143e | |||
| 63c77734f7 | |||
| 72bcbdc1bb | |||
| ecd553da6a | |||
| 4a48525e45 | |||
| c7aa01bc80 | |||
| 5d26d7126a | |||
| d617971b3e | |||
| 596bb23bb9 | |||
| 873ee61d57 | |||
| 30bbd6ecd4 | |||
| 860505fc05 | |||
| 8d4a5cc76c | |||
| 1639c7f9c6 | |||
| 3f180ac42d | |||
| f003fc39cb | |||
| 53bec94205 | |||
| 552262f14f | |||
| 17bf9ccb5d | |||
| 782e9b8b04 | |||
| 02a31d0293 | |||
| 36006b6d70 | |||
| ffd670b54c | |||
| 7922ecbed2 | |||
| e9a04ed755 | |||
| 424f544c6d | |||
| 962db50ce7 | |||
| 882bee610d | |||
| abdde3e206 | |||
| c333688700 |
@@ -0,0 +1,207 @@
|
||||
---
|
||||
name: review-pr
|
||||
description: Review a pull request with structured, domain-aware feedback
|
||||
argument-hint: "<PR number or URL>"
|
||||
allowed-tools: Bash, Read, Glob, Grep, Agent
|
||||
---
|
||||
|
||||
# PX4 Pull Request Review
|
||||
|
||||
Review a pull request with domain-aware checks based on which files are changed.
|
||||
|
||||
**No Claude attribution anywhere.**
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Fetch PR context.** Run these in parallel:
|
||||
- `gh pr view <PR> --json number,title,body,baseRefName,headRefName,files,commits,reviewRequests,reviews,author`
|
||||
- `gh pr checks <PR>` (exit code 8 means some checks are pending, this is normal, not an error)
|
||||
- `gh pr diff <PR>` -- if this fails with HTTP 406 (300+ files), do NOT retry. Instead use `gh api repos/OWNER/REPO/pulls/NUMBER/files --paginate` to get the full file list in one call, then fetch patches for key infrastructure files individually and sample representative changes from each domain touched.
|
||||
- `gh api repos/OWNER/REPO/pulls/NUMBER/comments --paginate --jq '.[] | {user: .user.login, body: .body, path: .path, created_at: .created_at}'` to get inline review comments
|
||||
- `gh api repos/OWNER/REPO/issues/NUMBER/comments --paginate --jq '.[] | {user: .user.login, body: .body, created_at: .created_at}'` to get PR conversation comments
|
||||
|
||||
From the PR metadata, note:
|
||||
- **Assigned reviewers**: who has been requested to review (from `reviewRequests`)
|
||||
- **Existing reviews**: who has already reviewed and their verdict (from `reviews` -- approved, changes_requested, commented, dismissed)
|
||||
- **PR comments and inline comments**: read all existing feedback to avoid duplicating points already raised by other reviewers, and to build on their discussion rather than ignoring it
|
||||
|
||||
2. **Check CI status.** From the `gh pr checks` output in step 1, summarize pass/fail/pending. If there are failures, fetch logs with `gh run view <run-id> --log-failed`. Include CI status in the output.
|
||||
|
||||
3. **Recommend merge strategy.** Analyze the commit history and recommend squash or rebase merge. This decision informs all subsequent commit hygiene feedback.
|
||||
|
||||
**Recommend rebase merge** when:
|
||||
- Commits are atomic, each builds/works independently
|
||||
- Each commit has a proper `type(scope): description` message
|
||||
- The PR intentionally separates logical changes (e.g., refactor + feature, or one commit per module)
|
||||
- The commit history tells a useful story that would be lost by squashing
|
||||
|
||||
**Recommend squash merge** when:
|
||||
- There are WIP, fixup, or review-response commits
|
||||
- Commit messages are messy or inconsistent
|
||||
- The PR is a single logical change spread across multiple commits
|
||||
- There are "oops" or "make format" commits mixed in
|
||||
|
||||
Include the recommendation in the output. If recommending rebase, flag any commits that break atomicity or have bad messages. If recommending squash, don't bother flagging individual commit messages (they'll be discarded) but ensure the PR title is correct since it becomes the squash commit message.
|
||||
|
||||
4. **Check conventional commit title.** Verify the PR title follows `type(scope): description` per CONTRIBUTING.md. The PR title becomes the commit message on squash-merge, so it must be accurate and descriptive. Verify the scope matches the primary area of changed files. If the PR introduces breaking changes, the title must include `!` before the colon. If rebase merge was recommended in step 3, also scan individual commit messages for anti-patterns: vague messages ("fix", "update"), missing type prefix, review-response noise ("apply suggestions from code review", "do make format"), or WIP markers. Flag these for rewording.
|
||||
|
||||
5. **Identify domains touched.** Classify changed files into domains based on paths (a PR may touch multiple):
|
||||
- **Estimation**: `src/modules/ekf2/`, `src/lib/wind_estimator/`, `src/lib/world_magnetic_model/`
|
||||
- **Control**: `src/modules/mc_*control*/`, `src/modules/fw_*control*/`, `src/modules/flight_mode_manager/`, `src/lib/rate_control/`, `src/lib/npfg/`, `src/modules/vtol_att_control/`
|
||||
- **Drivers/CAN**: `src/drivers/`, `src/modules/cyphal/`, `src/drivers/uavcan*/`
|
||||
- **Simulation**: `src/modules/simulation/`, `Tools/simulation/`
|
||||
- **System**: `src/modules/commander/`, `src/modules/logger/`, `src/systemcmds/`, `platforms/`, `src/modules/dataman/`
|
||||
- **Board Addition**: `boards/{manufacturer}/{board}/` (new directories only, not modifications to existing boards)
|
||||
- **CI/Build**: `.github/`, `CMakeLists.txt`, `Makefile`, `cmake/`, `Tools/`, `Kconfig`
|
||||
- **Messages/Protocol**: `msg/`, `src/modules/mavlink/`, `src/modules/uxrce_dds_client/`
|
||||
|
||||
6. **Apply core checks** (always):
|
||||
- **Correctness**: logic errors, off-by-ones, unhandled edge cases
|
||||
- **Type safety**: int16 overflow, float/double promotion, unsigned subtraction, use `uint64_t` for absolute time
|
||||
- **Initialization**: uninitialized variables, missing default construction
|
||||
- **Buffer safety**: unchecked array access, stack allocation of large buffers, snprintf bounds
|
||||
- **Magic numbers**: every numeric literal needs a named constant or justification
|
||||
- **Framework reuse**: use PX4_ERR/WARN/INFO, existing libraries (AlphaFilter, SlewRate, RateControl), MAVLink constants from the library
|
||||
- **Naming**: accurate, no unjustified abbreviations, current terminology (GPS -> GNSS for new code)
|
||||
- **Unnecessary complexity**: can code be removed instead of added? Is there a simpler pattern?
|
||||
- **Test coverage**: new features should include unit or integration tests; bug fixes should include regression tests where practical. When automated testing is infeasible (hardware-specific), require a flight log link from https://logs.px4.io or bench test evidence.
|
||||
- **PR hygiene**: focused scope, no unrelated formatting, no stale submodule changes. Commits should be atomic and independently revertable. Multiple WIP or review-response commits should be squashed. Clean, logical commits will be preserved individually on main via rebase merge. **Do NOT assume PRs are squash-merged. Both squash and rebase merge are enabled; merge commits are disabled.** Verify the PR targets `main` unless it is a backport or release-specific fix.
|
||||
- **Formatting**: `make format` / `make check_format` (astyle) for C/C++ files; `clang-tidy` clean. Python files checked with `mypy` and `flake8`. PRs failing CI format or lint checks will not be merged.
|
||||
- **Coding style**: C/C++ must follow the [PX4 coding style](https://docs.px4.io/main/en/contribute/code.html)
|
||||
- **Necessity**: challenge every addition with "Why?" Is this actually needed or just copied? Can we change a default instead of adding runtime detection?
|
||||
- **Root cause vs symptom**: is this fixing the real problem or masking it?
|
||||
- **Ecosystem impact**: what does this change mean for QGC users, log analysis tools, and third-party integrations?
|
||||
- **Sustainability**: who will maintain this? Does it create long-term burden?
|
||||
- **Architecture fit**: does the code live in the module that naturally owns the data? Are there unnecessary cross-module dependencies?
|
||||
- **End user impact**: will parameters confuse less-technical users? Are error messages actionable in QGC?
|
||||
|
||||
7. **Apply domain checks** based on step 5:
|
||||
|
||||
**Estimation:**
|
||||
- Singularities in aerospace math (euler angles near gimbal lock, sideslip at low airspeed)
|
||||
- Aliasing from downsampling sensor data without filtering
|
||||
- Kalman filter correctness (Joseph form, innovation variance, covariance symmetry)
|
||||
- CPU cost on embedded targets (avoid unnecessary sqrt, limit fusion rate)
|
||||
- Frame/coordinate system correctness (FRD vs NED, body vs earth)
|
||||
|
||||
**Control:**
|
||||
- Phase margin: output filters consume margin for no benefit; prefer adjusting gyro/d-gyro cutoffs
|
||||
- Circular dependencies: sensor data feeding back into its own control loop (e.g., throttle-based airspeed in TECS)
|
||||
- NaN propagation in flight-critical math; check `PX4_ISFINITE` before magnitude checks
|
||||
- Setpoint generation vs output-stage hacks: prefer proper setpoint smoothing over controller output filtering
|
||||
- Yaw control edge cases: heading lock, drift, setpoint propagation
|
||||
- Flight task inheritance chain: correct base class for the desired behavior
|
||||
- Control allocation: actuator function ordering, motor index mapping
|
||||
|
||||
**Drivers/CAN:**
|
||||
- CAN bus devices behave differently from serial/SPI; check driver assumptions
|
||||
- ESC index mapping: telemetry index != channel when motors are disabled
|
||||
- ESC hardware quirks: 4-in-1 ESCs may report current on only one channel
|
||||
- device_id correctness and I2CSPIDriver patterns
|
||||
- Time representation: prefer `hrt_abstime` over iteration counts
|
||||
|
||||
**Simulation:**
|
||||
- Physics fidelity: noise models should match reality (GPS noise is not Gaussian)
|
||||
- Keep gz_bridge generic; vehicle-specific logic belongs in plugins
|
||||
- Prefer gz-transport over ROS2 dependencies when possible
|
||||
- Wrench commands for physics correctness vs kinematic constraints
|
||||
- Library generic/specific boundary: only base classes in common libs
|
||||
|
||||
**System:**
|
||||
- Race conditions and concurrency: no partial fixes, demand complete solutions
|
||||
- Semaphore/scheduling edge cases; understand RTOS guarantees
|
||||
- State machine sequential-logic bugs (consecutive RTL, armed/disarmed alternation)
|
||||
- uORB-driven scheduling (`SubscriptionCallback`), not extra threads
|
||||
- param_set triggers auto-save; no redundant param_save_default
|
||||
- Flash/memory efficiency: avoid `std::string` on embedded, minimize SubscriptionData usage
|
||||
- Constructor initialization order matters
|
||||
|
||||
**CI/Build:**
|
||||
- Pipeline race conditions (tag + branch push double-trigger, git describe correctness)
|
||||
- Container image size (check layer bloat)
|
||||
- Ubuntu LTS support policy (latest + one prior only)
|
||||
- Build time impact
|
||||
- CMake preferred over Makefiles
|
||||
|
||||
**Messages/Protocol:**
|
||||
- Backwards compatibility: will this break QGC, post-flight tools, or uLog parsers?
|
||||
- uORB: `timestamp` for publication metadata, `timestamp_sample` close to physical sample, include `device_id`
|
||||
- Don't version messages unless strictly needed
|
||||
- Parameter UX: will this confuse users in a GCS? Every new param is a configuration burden
|
||||
- MAVLink: use library constants, don't implement custom stream rates
|
||||
|
||||
**Board Addition:**
|
||||
- **Flight logs**: require a link to https://logs.px4.io demonstrating basic operation for the vehicle type (hover for multicopters, stable flight for fixed-wing, driving for rovers, etc.); short bench-only logs are insufficient
|
||||
- **Documentation**: require a docs page in `docs/en/flight_controller/` with pinout, where-to-buy, connector types, version badge, and manufacturer-supported notice block
|
||||
- **USB VID/PID**: must not reuse another manufacturer's Vendor ID; manufacturer must use their own
|
||||
- **Board naming**: directory is `boards/{manufacturer}/{board}/`, both lowercase, hyphens for board name
|
||||
- **Unique board_id**: registered in `boards/boards.json`, no collisions
|
||||
- **Copied code cleanup**: check for leftover files, configs, or comments from the template board; "Is this real or leftover?"
|
||||
- **RC configuration**: prefer `CONFIG_DRIVERS_COMMON_RC` over legacy `CONFIG_DRIVERS_RC_INPUT`
|
||||
- **No board-specific custom modules**: reject copy-pasted drivers (e.g., custom heater) when existing infrastructure works
|
||||
- **Bootloader**: expect a bootloader defconfig (`nuttx-config/bootloader/defconfig`) or explanation of shared bootloader
|
||||
- **CI integration**: board must be added to CI compile workflows so it builds on every PR
|
||||
- **Flash constraints**: verify enabled modules fit in flash; we are running low across all board targets
|
||||
- **Port labels**: serial port labels must match what is physically printed on the board
|
||||
- **Hardware availability**: for unknown manufacturers, verify the product exists and is purchasable (no vaporware)
|
||||
|
||||
8. **Format output** as:
|
||||
- **CI status**: pass/fail summary, link to failed runs if any
|
||||
- **Merge strategy**: recommend squash or rebase merge with reasoning
|
||||
- **Title check**: pass/fail with suggestion
|
||||
- **Review status**: list assigned reviewers and any existing reviews (who approved, who requested changes, key points already raised). Note if your review would duplicate feedback already given.
|
||||
- **Domains detected**: list which domain checks were applied
|
||||
- **Summary**: one paragraph on what the PR does and whether the approach is sound
|
||||
- **Issues**: numbered list, each with file:line, severity (blocker/warning/nit), and explanation. Skip issues already raised by other reviewers unless you have something to add.
|
||||
- **Verdict**: approve, request changes, or needs discussion
|
||||
|
||||
After the structured output, also display a **draft PR comment** formatted using the PR comment formatting rules from step 9. This gives the user a preview of what would be posted.
|
||||
|
||||
9. **Interactive dialog.** After displaying the review, present the user with these options:
|
||||
|
||||
Present options based on the verdict:
|
||||
|
||||
If verdict is **approve**:
|
||||
```
|
||||
What would you like to do?
|
||||
1. Chat about this PR (ask questions, explore code) [default]
|
||||
2. Approve this PR and post the review comment
|
||||
3. Adjust the review or draft (tell me what to change)
|
||||
4. Done for now
|
||||
```
|
||||
|
||||
If verdict is **request changes**:
|
||||
```
|
||||
What would you like to do?
|
||||
1. Chat about this PR (ask questions, explore code) [default]
|
||||
2. Request changes on this PR and post the review comment
|
||||
3. Adjust the review or draft (tell me what to change)
|
||||
4. Done for now
|
||||
```
|
||||
|
||||
If verdict is **needs discussion**:
|
||||
```
|
||||
What would you like to do?
|
||||
1. Chat about this PR (ask questions, explore code) [default]
|
||||
2. Post the review as a comment (no approval or rejection)
|
||||
3. Adjust the review or draft (tell me what to change)
|
||||
4. Done for now
|
||||
```
|
||||
|
||||
Wait for the user to choose before proceeding. If they pick:
|
||||
- **1 (chat)**: enter a free-form conversation about the PR. The user can ask about specific files, code paths, or decisions. When done, loop back to the options. This is the default if the user just presses enter.
|
||||
- **2 (submit)**: use the draft PR comment already shown. Before posting, check if you have review permissions: run `gh api repos/OWNER/REPO/collaborators/$(gh api user --jq .login)/permission --jq .permission` -- if `admin` or `write`, submit as a formal review with `gh pr review <PR> --approve --body "..."` or `gh pr review <PR> --request-changes --body "..."` based on the verdict. If no write access, fall back to `gh pr comment <PR> --body "..."`. Always confirm with the user before posting.
|
||||
- **3 (adjust)**: ask what to change, update the review and draft, then loop back to the options.
|
||||
- **4 (done)**: stop.
|
||||
|
||||
**PR comment formatting rules** (for the draft):
|
||||
When writing the GitHub comment, rewrite the review to sound like a human reviewer, not a structured report. Do NOT include the full skill output. Instead:
|
||||
- Drop most meta-sections (CI status, title check, domains detected, severity labels) but keep the merge strategy recommendation (e.g., "I'd suggest a rebase merge here since the commits are clean and atomic" or "This should be squash-merged, the commit history is messy")
|
||||
- Write conversationally: "Nice work on this. A few things I noticed:" not "Issues: 1. file:line (warning):"
|
||||
- Lead with a brief take on the overall change (1-2 sentences)
|
||||
- List only actionable feedback as natural review comments, not numbered checklists
|
||||
- Skip nits unless they are particularly useful
|
||||
- End with a clear stance: looks good to merge, needs a few changes, or let's discuss X
|
||||
- Post with `gh pr comment <PR> --body "$(cat <<'EOF' ... EOF)"`. Do not post without explicit confirmation.
|
||||
|
||||
If the user provided arguments, use them as context: $ARGUMENTS
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
applyTo: "boards/**"
|
||||
---
|
||||
|
||||
# Board Addition Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines, when reviewing new board additions:
|
||||
|
||||
- **Flight logs**: require a link to https://logs.px4.io demonstrating basic operation for the vehicle type (hover for multicopters, stable flight for fixed-wing, driving for rovers, etc.); short bench-only logs are insufficient
|
||||
- **Documentation**: require a docs page in `docs/en/flight_controller/` with pinout, where-to-buy, connector types, version badge, and manufacturer-supported notice block
|
||||
- **USB VID/PID**: must not reuse another manufacturer's Vendor ID; manufacturer must use their own
|
||||
- **Board naming**: directory is `boards/{manufacturer}/{board}/`, both lowercase, hyphens for board name
|
||||
- **Unique board_id**: registered in `boards/boards.json`, no collisions
|
||||
- **Copied code cleanup**: check for leftover files, configs, or comments from the template board. Ask "Is this real or leftover?"
|
||||
- **RC configuration**: prefer `CONFIG_DRIVERS_COMMON_RC` over legacy `CONFIG_DRIVERS_RC_INPUT`
|
||||
- **No board-specific custom modules**: reject copy-pasted drivers (e.g., custom heater) when existing infrastructure works
|
||||
- **Bootloader**: expect a bootloader defconfig (`nuttx-config/bootloader/defconfig`) or explanation of shared bootloader
|
||||
- **CI integration**: board must be added to CI compile workflows so it builds on every PR
|
||||
- **Flash constraints**: verify enabled modules fit in flash; we are running low across all board targets
|
||||
- **Port labels**: serial port labels must match what is physically printed on the board
|
||||
- **Hardware availability**: for unknown manufacturers, verify the product exists and is purchasable (no vaporware)
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: ".github/**,cmake/**,Makefile,CMakeLists.txt,Tools/**,**/Kconfig"
|
||||
---
|
||||
|
||||
# CI/Build Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Check for pipeline race conditions (tag + branch push double-trigger, git describe correctness)
|
||||
- Container image size: check for layer bloat
|
||||
- Ubuntu LTS support policy: only latest + one prior LTS version
|
||||
- Consider build time impact of changes
|
||||
- Prefer CMake over Makefiles
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
applyTo: "src/**,boards/**,platforms/**,msg/**,cmake/**,Makefile,CMakeLists.txt,Tools/**,.github/**"
|
||||
---
|
||||
|
||||
# PX4 Code Review Guidelines
|
||||
|
||||
## Conventions
|
||||
|
||||
- PR titles must follow conventional commits: `type(scope): description` (see CONTRIBUTING.md)
|
||||
- Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
|
||||
- Scope should match the primary area of changed files
|
||||
- Append `!` before the colon for breaking changes
|
||||
- Both squash merge and rebase merge are enabled; merge commits are disabled
|
||||
- Commits should be atomic and independently revertable
|
||||
- WIP or review-response commits should be squashed before merge
|
||||
|
||||
## Core Checks (always apply)
|
||||
|
||||
- **Correctness**: logic errors, off-by-ones, unhandled edge cases
|
||||
- **Type safety**: int16 overflow, float/double promotion, unsigned subtraction, use `uint64_t` for absolute time
|
||||
- **Initialization**: uninitialized variables, missing default construction
|
||||
- **Buffer safety**: unchecked array access, stack allocation of large buffers, snprintf bounds
|
||||
- **Magic numbers**: every numeric literal needs a named constant or justification
|
||||
- **Framework reuse**: use PX4_ERR/WARN/INFO, existing libraries (AlphaFilter, SlewRate, RateControl), MAVLink constants from the library
|
||||
- **Naming**: accurate, no unjustified abbreviations, current terminology (GPS -> GNSS for new code)
|
||||
- **Unnecessary complexity**: can code be removed instead of added? Is there a simpler pattern?
|
||||
- **Test coverage**: new features should include unit or integration tests; bug fixes should include regression tests where practical
|
||||
- **Formatting**: `make format` / `make check_format` (astyle) for C/C++ files; `clang-tidy` clean
|
||||
- **Coding style**: C/C++ must follow the PX4 coding style (https://docs.px4.io/main/en/contribute/code.html)
|
||||
- **Necessity**: challenge every addition. Is this actually needed or just copied?
|
||||
- **Architecture fit**: does the code live in the module that naturally owns the data? No unnecessary cross-module dependencies
|
||||
- **Ecosystem impact**: consider QGC users, log analysis tools, and third-party integrations
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
applyTo: "src/modules/mc_*control*/**,src/modules/fw_*control*/**,src/modules/flight_mode_manager/**,src/lib/rate_control/**,src/lib/npfg/**,src/modules/vtol_att_control/**"
|
||||
---
|
||||
|
||||
# Control Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Phase margin: output filters consume margin for no benefit; prefer adjusting gyro/d-gyro cutoffs
|
||||
- Check for circular dependencies: sensor data feeding back into its own control loop (e.g., throttle-based airspeed in TECS)
|
||||
- NaN propagation in flight-critical math; check `PX4_ISFINITE` before magnitude checks
|
||||
- Prefer proper setpoint smoothing over controller output filtering (setpoint generation vs output-stage hacks)
|
||||
- Check yaw control edge cases: heading lock, drift, setpoint propagation
|
||||
- Verify flight task inheritance chain uses the correct base class for desired behavior
|
||||
- Control allocation: verify actuator function ordering and motor index mapping
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: "src/drivers/**,src/modules/cyphal/**"
|
||||
---
|
||||
|
||||
# Drivers/CAN Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- CAN bus devices behave differently from serial/SPI; check driver assumptions
|
||||
- ESC index mapping: telemetry index != channel when motors are disabled
|
||||
- ESC hardware quirks: 4-in-1 ESCs may report current on only one channel
|
||||
- Verify device_id correctness and I2CSPIDriver patterns
|
||||
- Time representation: prefer `hrt_abstime` over iteration counts
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: "src/modules/ekf2/**,src/lib/wind_estimator/**,src/lib/world_magnetic_model/**"
|
||||
---
|
||||
|
||||
# Estimation Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Check for singularities in aerospace math (euler angles near gimbal lock, sideslip at low airspeed)
|
||||
- Flag aliasing from downsampling sensor data without proper filtering
|
||||
- Verify Kalman filter correctness (Joseph form, innovation variance, covariance symmetry)
|
||||
- Consider CPU cost on embedded targets (avoid unnecessary sqrt, limit fusion rate)
|
||||
- Verify frame/coordinate system correctness (FRD vs NED, body vs earth frame)
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: "msg/**,src/modules/mavlink/**,src/modules/uxrce_dds_client/**"
|
||||
---
|
||||
|
||||
# Messages/Protocol Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Backwards compatibility: will this break QGC, post-flight tools, or uLog parsers?
|
||||
- uORB: `timestamp` for publication metadata, `timestamp_sample` close to physical sample, include `device_id`
|
||||
- Don't version messages unless strictly needed
|
||||
- Parameter UX: will this confuse users in a GCS? Every new param is a configuration burden
|
||||
- MAVLink: use library constants, don't implement custom stream rates
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: "src/modules/simulation/**,Tools/simulation/**"
|
||||
---
|
||||
|
||||
# Simulation Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Physics fidelity: noise models should match reality (GPS noise is not Gaussian)
|
||||
- Keep gz_bridge generic; vehicle-specific logic belongs in plugins
|
||||
- Prefer gz-transport over ROS2 dependencies when possible
|
||||
- Use wrench commands for physics correctness vs kinematic constraints
|
||||
- Library generic/specific boundary: only base classes in common libs
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
applyTo: "src/modules/commander/**,src/modules/logger/**,src/systemcmds/**,platforms/**,src/modules/dataman/**"
|
||||
---
|
||||
|
||||
# System Review Guidelines
|
||||
|
||||
In addition to the core code review guidelines:
|
||||
|
||||
- Race conditions and concurrency: no partial fixes, demand complete solutions
|
||||
- Semaphore/scheduling edge cases; understand RTOS guarantees
|
||||
- State machine sequential-logic bugs (consecutive RTL, armed/disarmed alternation)
|
||||
- Use uORB-driven scheduling (`SubscriptionCallback`), not extra threads
|
||||
- `param_set` triggers auto-save; no redundant `param_save_default`
|
||||
- Flash/memory efficiency: avoid `std::string` on embedded, minimize SubscriptionData usage
|
||||
- Constructor initialization order matters
|
||||
@@ -268,4 +268,5 @@ jobs:
|
||||
files: |
|
||||
artifacts/*.px4
|
||||
artifacts/*.deb
|
||||
artifacts/**/*.sbom.spdx.json
|
||||
name: ${{ steps.upload-location.outputs.uploadlocation }}
|
||||
|
||||
@@ -46,6 +46,8 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Building [${{ matrix.check }}]
|
||||
env:
|
||||
PX4_SBOM_DISABLE: 1
|
||||
run: |
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
@@ -36,8 +36,8 @@ jobs:
|
||||
px4io/px4-dev-ros-melodic:2021-09-08 \
|
||||
bash -c '
|
||||
git config --global --add safe.directory /workspace
|
||||
make px4_sitl_default
|
||||
make px4_sitl_default sitl_gazebo-classic
|
||||
PX4_SBOM_DISABLE=1 make px4_sitl_default
|
||||
PX4_SBOM_DISABLE=1 make px4_sitl_default sitl_gazebo-classic
|
||||
./test/rostest_px4_run.sh \
|
||||
mavros_posix_test_mission.test \
|
||||
mission:=MC_mission_box \
|
||||
|
||||
@@ -36,8 +36,8 @@ jobs:
|
||||
px4io/px4-dev-ros-melodic:2021-09-08 \
|
||||
bash -c '
|
||||
git config --global --add safe.directory /workspace
|
||||
make px4_sitl_default
|
||||
make px4_sitl_default sitl_gazebo-classic
|
||||
PX4_SBOM_DISABLE=1 make px4_sitl_default
|
||||
PX4_SBOM_DISABLE=1 make px4_sitl_default sitl_gazebo-classic
|
||||
./test/rostest_px4_run.sh \
|
||||
mavros_posix_tests_offboard_posctl.test \
|
||||
vehicle:=iris
|
||||
|
||||
@@ -110,6 +110,8 @@ jobs:
|
||||
run: ccache -s
|
||||
|
||||
- name: Build PX4
|
||||
env:
|
||||
PX4_SBOM_DISABLE: 1
|
||||
run: make px4_sitl_default
|
||||
- name: ccache post-run px4/firmware
|
||||
run: ccache -s
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: SBOM License Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
- 'stable'
|
||||
paths:
|
||||
- '.gitmodules'
|
||||
- 'Tools/ci/license-overrides.yaml'
|
||||
- 'Tools/ci/generate_sbom.py'
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
paths:
|
||||
- '.gitmodules'
|
||||
- 'Tools/ci/license-overrides.yaml'
|
||||
- 'Tools/ci/generate_sbom.py'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify-licenses:
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: false
|
||||
|
||||
- name: Install PyYAML
|
||||
run: pip install pyyaml --break-system-packages
|
||||
|
||||
- name: Verify submodule licenses
|
||||
run: python3 Tools/ci/generate_sbom.py --verify-licenses --source-dir .
|
||||
@@ -0,0 +1,132 @@
|
||||
name: SBOM Monthly Audit
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# First Monday of each month at 09:00 UTC
|
||||
- cron: '0 9 1-7 * 1'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to audit (leave empty for current)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.branch || github.ref }}
|
||||
fetch-depth: 1
|
||||
submodules: recursive
|
||||
|
||||
- name: Install PyYAML
|
||||
run: pip install pyyaml --break-system-packages
|
||||
|
||||
- name: Run license verification
|
||||
id: verify
|
||||
continue-on-error: true
|
||||
run: |
|
||||
python3 Tools/ci/generate_sbom.py --verify-licenses --source-dir . 2>&1 | tee /tmp/sbom-verify.txt
|
||||
echo "exit_code=$?" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check for issues
|
||||
id: check
|
||||
run: |
|
||||
if grep -q "NOASSERTION" /tmp/sbom-verify.txt; then
|
||||
echo "has_issues=true" >> "$GITHUB_OUTPUT"
|
||||
# Extract NOASSERTION lines
|
||||
grep "NOASSERTION" /tmp/sbom-verify.txt | grep -v "skipped" > /tmp/sbom-issues.txt || true
|
||||
# Extract copyleft lines
|
||||
sed -n '/Copyleft licenses detected/,/^$/p' /tmp/sbom-verify.txt > /tmp/sbom-copyleft.txt || true
|
||||
else
|
||||
echo "has_issues=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Create issue if problems found
|
||||
if: steps.check.outputs.has_issues == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
const fullOutput = fs.readFileSync('/tmp/sbom-verify.txt', 'utf8');
|
||||
let issueLines = '';
|
||||
try {
|
||||
issueLines = fs.readFileSync('/tmp/sbom-issues.txt', 'utf8');
|
||||
} catch (e) {
|
||||
issueLines = 'No specific NOASSERTION lines captured.';
|
||||
}
|
||||
let copyleftLines = '';
|
||||
try {
|
||||
copyleftLines = fs.readFileSync('/tmp/sbom-copyleft.txt', 'utf8');
|
||||
} catch (e) {
|
||||
copyleftLines = '';
|
||||
}
|
||||
|
||||
const date = new Date().toISOString().split('T')[0];
|
||||
const branch = '${{ inputs.branch || github.ref_name }}';
|
||||
|
||||
// Check for existing open issue to avoid duplicates
|
||||
const existing = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: 'sbom-audit',
|
||||
state: 'open',
|
||||
});
|
||||
|
||||
if (existing.data.length > 0) {
|
||||
// Update existing issue with new findings
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: existing.data[0].number,
|
||||
body: `## Monthly audit update (${date})\n\nIssues still present:\n\n\`\`\`\n${issueLines}\n\`\`\`\n${copyleftLines ? `\n### Copyleft warnings\n\`\`\`\n${copyleftLines}\n\`\`\`` : ''}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: `chore(sbom): license audit found NOASSERTION entries on ${branch} (${date})`,
|
||||
labels: ['sbom-audit'],
|
||||
assignees: ['mrpollo'],
|
||||
body: [
|
||||
`## SBOM Monthly Audit -- ${branch} -- ${date}`,
|
||||
'',
|
||||
'The automated SBOM license audit found submodules with unresolved licenses.',
|
||||
'',
|
||||
'### NOASSERTION entries',
|
||||
'',
|
||||
'```',
|
||||
issueLines,
|
||||
'```',
|
||||
'',
|
||||
copyleftLines ? `### Copyleft warnings\n\n\`\`\`\n${copyleftLines}\n\`\`\`\n` : '',
|
||||
'### How to fix',
|
||||
'',
|
||||
'1. Check the submodule repo for a LICENSE file',
|
||||
'2. Add an override to `Tools/ci/license-overrides.yaml`',
|
||||
'3. Run `python3 Tools/ci/generate_sbom.py --verify-licenses --source-dir .` to confirm',
|
||||
'',
|
||||
'### Full output',
|
||||
'',
|
||||
'<details>',
|
||||
'<summary>Click to expand</summary>',
|
||||
'',
|
||||
'```',
|
||||
fullOutput,
|
||||
'```',
|
||||
'',
|
||||
'</details>',
|
||||
'',
|
||||
'cc @mrpollo',
|
||||
].join('\n'),
|
||||
});
|
||||
@@ -71,6 +71,7 @@ jobs:
|
||||
- name: Build PX4
|
||||
env:
|
||||
PX4_CMAKE_BUILD_TYPE: ${{matrix.config.build_type}}
|
||||
PX4_SBOM_DISABLE: 1
|
||||
run: make px4_sitl_default
|
||||
|
||||
- name: Cache Post-Run [px4_sitl_default]
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
name: Tag px4_msgs from PX4 release tags
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'PX4 tag to propagate (example: v1.17.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
tag_px4_msgs:
|
||||
if: github.repository == 'PX4/PX4-Autopilot'
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
env:
|
||||
TAG_NAME: ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.ref_name }}
|
||||
steps:
|
||||
- name: Checkout PX4 repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Setup git credentials
|
||||
run: |
|
||||
git config --global user.name "${{ secrets.PX4BUILDBOT_USER }}"
|
||||
git config --global user.email "${{ secrets.PX4BUILDBOT_EMAIL }}"
|
||||
|
||||
- name: Resolve release branch from tag
|
||||
id: tag_info
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ ! "${TAG_NAME}" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
echo "Tag format is not stable vX.Y.Z, skipping: ${TAG_NAME}"
|
||||
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
major="${BASH_REMATCH[1]}"
|
||||
minor="${BASH_REMATCH[2]}"
|
||||
release_branch="release/${major}.${minor}"
|
||||
|
||||
git show-ref --verify --quiet "refs/heads/${release_branch}" || {
|
||||
echo "PX4 branch ${release_branch} not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
tag_date="$(git for-each-ref --format='%(creatordate:iso8601)' "refs/tags/${TAG_NAME}")"
|
||||
if [[ -z "${tag_date}" ]]; then
|
||||
echo "Unable to resolve tag date for ${TAG_NAME}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "release_branch=${release_branch}" >> "$GITHUB_OUTPUT"
|
||||
echo "tag_date=${tag_date}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Clone px4_msgs repo
|
||||
if: steps.tag_info.outputs.should_run == 'true'
|
||||
run: |
|
||||
git clone https://${{ secrets.PX4BUILTBOT_PERSONAL_ACCESS_TOKEN }}@github.com/PX4/px4_msgs.git
|
||||
|
||||
- name: Checkout matching px4_msgs release branch
|
||||
if: steps.tag_info.outputs.should_run == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd px4_msgs
|
||||
|
||||
release_branch="${{ steps.tag_info.outputs.release_branch }}"
|
||||
if git show-ref --verify --quiet "refs/remotes/origin/${release_branch}"; then
|
||||
git checkout -B "${release_branch}" "origin/${release_branch}"
|
||||
else
|
||||
echo "px4_msgs branch ${release_branch} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify msg and srv trees are identical
|
||||
if: steps.tag_info.outputs.should_run == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_branch="${{ steps.tag_info.outputs.release_branch }}"
|
||||
git checkout "${release_branch}"
|
||||
|
||||
# Use the same synchronization logic as sync_to_px4_msgs.yml,
|
||||
# then verify there are no changes in px4_msgs.
|
||||
rm -f px4_msgs/msg/*.msg
|
||||
rm -f px4_msgs/msg/versioned/*.msg
|
||||
rm -f px4_msgs/srv/*.srv
|
||||
rm -f px4_msgs/srv/versioned/*.srv
|
||||
cp msg/*.msg px4_msgs/msg/
|
||||
cp msg/versioned/*.msg px4_msgs/msg/ || true
|
||||
cp srv/*.srv px4_msgs/srv/
|
||||
cp srv/versioned/*.srv px4_msgs/srv/ || true
|
||||
|
||||
if ! git -C px4_msgs diff --exit-code -- msg srv; then
|
||||
echo "Message/service definitions differ between PX4 ${release_branch} and px4_msgs ${release_branch}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create and push tag in px4_msgs
|
||||
if: steps.tag_info.outputs.should_run == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd px4_msgs
|
||||
|
||||
target="$(git rev-parse HEAD)"
|
||||
existing_target="$(git rev-parse "refs/tags/${TAG_NAME}^{}" 2>/dev/null || true)"
|
||||
|
||||
if [[ -n "${existing_target}" ]]; then
|
||||
if [[ "${existing_target}" == "${target}" ]]; then
|
||||
echo "Tag ${TAG_NAME} already exists on ${target}; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
echo "Tag ${TAG_NAME} already exists on ${existing_target}, expected ${target}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GIT_COMMITTER_DATE="${{ steps.tag_info.outputs.tag_date }}" \
|
||||
git tag -a "${TAG_NAME}" "${target}" \
|
||||
-m "PX4 msgs and srvs definitions matching PX4 stable release ${TAG_NAME#v}"
|
||||
|
||||
git push origin "refs/tags/${TAG_NAME}"
|
||||
@@ -112,3 +112,6 @@ keys/
|
||||
|
||||
# metadata
|
||||
_emscripten_sdk/
|
||||
|
||||
# virtual Python environment
|
||||
.venv
|
||||
|
||||
@@ -240,8 +240,15 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE ${PX4_BUILD_TYPE} CACHE STRING "Build type" FORCE)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BOARD_SUPPORT_FORTIFIED_TOOLCHAIN)
|
||||
set(PX4_DEBUG_OPT_LEVEL -Og)
|
||||
message(STATUS "fortified toolchain support enabled: PX4_DEBUG_OPT_LEVEL=${PX4_DEBUG_OPT_LEVEL}")
|
||||
else()
|
||||
set(PX4_DEBUG_OPT_LEVEL -O0)
|
||||
endif()
|
||||
|
||||
if((CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "Coverage"))
|
||||
set(MAX_CUSTOM_OPT_LEVEL -O0)
|
||||
set(MAX_CUSTOM_OPT_LEVEL ${PX4_DEBUG_OPT_LEVEL})
|
||||
elseif(CMAKE_BUILD_TYPE MATCHES "Sanitizer")
|
||||
set(MAX_CUSTOM_OPT_LEVEL -O1)
|
||||
elseif(CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
@@ -484,6 +491,7 @@ include(bloaty)
|
||||
|
||||
include(metadata)
|
||||
include(package)
|
||||
include(sbom)
|
||||
|
||||
# install python requirements using configured python
|
||||
add_custom_target(install_python_requirements
|
||||
|
||||
@@ -67,6 +67,16 @@ menu "Toolchain"
|
||||
help
|
||||
Enables Cmake Release for -O3 optimization
|
||||
|
||||
config BOARD_SUPPORT_FORTIFIED_TOOLCHAIN
|
||||
bool "Fortified toolchain support"
|
||||
default n
|
||||
help
|
||||
Enable compatibility with toolchains that define
|
||||
_FORTIFY_SOURCE.
|
||||
|
||||
This switches PX4_DEBUG_OPT_LEVEL from -O0 to -Og. Keep this
|
||||
disabled unless the fortified toolchain requires optimization.
|
||||
|
||||
config BOARD_ROMFSROOT
|
||||
string "ROMFSROOT"
|
||||
default "px4fmu_common"
|
||||
|
||||
@@ -162,6 +162,12 @@ else
|
||||
|
||||
endif
|
||||
|
||||
# Prefer the interpreter from an active Python virtual environment.
|
||||
# Otherwise leave PYTHON_EXECUTABLE unset and let CMake resolve Python.
|
||||
ifneq ($(strip $(VIRTUAL_ENV)),)
|
||||
PYTHON_EXECUTABLE ?= $(VIRTUAL_ENV)/bin/python
|
||||
endif
|
||||
|
||||
# Pick up specific Python path if set
|
||||
ifdef PYTHON_EXECUTABLE
|
||||
override CMAKE_ARGS += -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
|
||||
|
||||
@@ -18,6 +18,7 @@ param set-default SENS_EN_BAROSIM 1
|
||||
param set-default SENS_EN_MAGSIM 1
|
||||
|
||||
param set SIH_VEHICLE_TYPE 4
|
||||
param set-default MAV_TYPE 13
|
||||
|
||||
# Symmetric hexacopter X clockwise motor numbering
|
||||
param set-default CA_ROTOR_COUNT 6
|
||||
|
||||
@@ -633,7 +633,7 @@ else
|
||||
#
|
||||
# Start the VTX services.
|
||||
#
|
||||
if ! param compare VTX_SER_CFG 0
|
||||
if ! param compare -s VTX_SER_CFG 0
|
||||
then
|
||||
set RC_VTXTABLE ${R}etc/init.d/rc.vtxtable
|
||||
if [ -f ${RC_VTXTABLE} ]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# exit when any command fails
|
||||
set -e
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ $# -eq 0 ]] ; then
|
||||
exit 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Flash PX4 to a device running AuterionOS in the local network
|
||||
if [ "$1" == "-h" ] || [ "$1" == "--help" ] || [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 -f <firmware.px4|.elf> [-c <configuration_dir>] -d <IP/Device> [-u <user>] [-p <ssh_port>] [--revert]"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# This script is meant to be used by the build_all.yml workflow in a github runner
|
||||
# Please only modify if you know what you are doing
|
||||
set -e
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Copy a git diff between two commits if msg versioning is added
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate SPDX 2.3 JSON SBOM for a PX4 firmware build.
|
||||
|
||||
Produces one SBOM per board target containing:
|
||||
- PX4 firmware as the primary package
|
||||
- Git submodules as CONTAINS dependencies
|
||||
- Python build requirements as BUILD_DEPENDENCY_OF packages
|
||||
- Board-specific modules as CONTAINS packages
|
||||
|
||||
Requires PyYAML (pyyaml) for loading license overrides.
|
||||
"""
|
||||
import argparse
|
||||
import configparser
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
# Ordered most-specific first: all keywords must appear for a match.
|
||||
LICENSE_PATTERNS = [
|
||||
# Copyleft licenses first (more specific keywords prevent false matches)
|
||||
("GPL-3.0-only", ["GNU GENERAL PUBLIC LICENSE", "Version 3"]),
|
||||
("GPL-2.0-only", ["GNU GENERAL PUBLIC LICENSE", "Version 2"]),
|
||||
("LGPL-3.0-only", ["GNU LESSER GENERAL PUBLIC LICENSE", "Version 3"]),
|
||||
("LGPL-2.1-only", ["GNU Lesser General Public License", "Version 2.1"]),
|
||||
("AGPL-3.0-only", ["GNU AFFERO GENERAL PUBLIC LICENSE", "Version 3"]),
|
||||
# Permissive licenses
|
||||
("Apache-2.0", ["Apache License", "Version 2.0"]),
|
||||
("MIT", ["Permission is hereby granted"]),
|
||||
("BSD-3-Clause", ["Redistribution and use", "Neither the name"]),
|
||||
("BSD-2-Clause", ["Redistribution and use", "THIS SOFTWARE IS PROVIDED"]),
|
||||
("ISC", ["Permission to use, copy, modify, and/or distribute"]),
|
||||
("EPL-2.0", ["Eclipse Public License", "2.0"]),
|
||||
("Unlicense", ["The Unlicense", "unlicense.org"]),
|
||||
]
|
||||
|
||||
COPYLEFT_LICENSES = {
|
||||
"GPL-2.0-only", "GPL-3.0-only",
|
||||
"LGPL-2.1-only", "LGPL-3.0-only",
|
||||
"AGPL-3.0-only",
|
||||
}
|
||||
|
||||
def load_license_overrides(source_dir):
|
||||
"""Load license overrides and comments from YAML config file.
|
||||
|
||||
Returns (overrides, comments) dicts mapping submodule path to values.
|
||||
Falls back to empty dicts if the file is missing.
|
||||
"""
|
||||
yaml_path = source_dir / "Tools" / "ci" / "license-overrides.yaml"
|
||||
if not yaml_path.exists():
|
||||
return {}, {}
|
||||
|
||||
with open(yaml_path) as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
overrides = {}
|
||||
comments = {}
|
||||
for path, entry in (data.get("overrides") or {}).items():
|
||||
overrides[path] = entry["license"]
|
||||
if "comment" in entry:
|
||||
comments[path] = entry["comment"]
|
||||
|
||||
return overrides, comments
|
||||
|
||||
LICENSE_FILENAMES = ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "LICENCE.md", "COPYING", "COPYING.md"]
|
||||
|
||||
|
||||
def detect_license(submodule_dir):
|
||||
"""Auto-detect SPDX license ID from LICENSE/COPYING file in a directory.
|
||||
|
||||
Reads the first 100 lines of the first license file found and matches
|
||||
keywords against LICENSE_PATTERNS. Returns 'NOASSERTION' if no file
|
||||
is found or no pattern matches.
|
||||
"""
|
||||
for fname in LICENSE_FILENAMES:
|
||||
license_file = submodule_dir / fname
|
||||
if license_file.is_file():
|
||||
try:
|
||||
lines = license_file.read_text(errors="replace").splitlines()[:100]
|
||||
text = "\n".join(lines)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
text_upper = text.upper()
|
||||
for spdx_id_val, keywords in LICENSE_PATTERNS:
|
||||
if all(kw.upper() in text_upper for kw in keywords):
|
||||
return spdx_id_val
|
||||
|
||||
return "NOASSERTION"
|
||||
|
||||
return "NOASSERTION"
|
||||
|
||||
|
||||
def get_submodule_license(source_dir, sub_path, license_overrides):
|
||||
"""Return the SPDX license for a submodule: override > auto-detect."""
|
||||
if sub_path in license_overrides:
|
||||
return license_overrides[sub_path]
|
||||
return detect_license(source_dir / sub_path)
|
||||
|
||||
|
||||
def spdx_id(name: str) -> str:
|
||||
"""Convert a name to a valid SPDX identifier (letters, digits, dots, hyphens)."""
|
||||
return re.sub(r"[^a-zA-Z0-9.\-]", "-", name)
|
||||
|
||||
|
||||
def parse_gitmodules(source_dir):
|
||||
"""Parse .gitmodules and return list of {name, path, url}."""
|
||||
gitmodules_path = source_dir / ".gitmodules"
|
||||
if not gitmodules_path.exists():
|
||||
return []
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(str(gitmodules_path))
|
||||
|
||||
submodules = []
|
||||
for section in config.sections():
|
||||
if section.startswith("submodule "):
|
||||
name = section.split('"')[1] if '"' in section else section.split(" ", 1)[1]
|
||||
path = config.get(section, "path", fallback="")
|
||||
url = config.get(section, "url", fallback="")
|
||||
submodules.append({"name": name, "path": path, "url": url})
|
||||
|
||||
return submodules
|
||||
|
||||
|
||||
def get_submodule_commits(source_dir):
|
||||
"""Get commit hashes for all submodules via git ls-tree -r (works without init)."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "ls-tree", "-r", "HEAD"],
|
||||
cwd=str(source_dir),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return {}
|
||||
|
||||
commits = {}
|
||||
for line in result.stdout.splitlines():
|
||||
parts = line.split()
|
||||
if len(parts) >= 4 and parts[1] == "commit":
|
||||
commits[parts[3]] = parts[2]
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
def get_git_info(source_dir: Path) -> dict:
|
||||
"""Get PX4 git version and hash."""
|
||||
info = {"version": "unknown", "hash": "unknown"}
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "describe", "--always", "--tags", "--dirty"],
|
||||
cwd=str(source_dir),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
info["version"] = result.stdout.strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "HEAD"],
|
||||
cwd=str(source_dir),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
info["hash"] = result.stdout.strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
return info
|
||||
|
||||
|
||||
def parse_requirements(requirements_path):
|
||||
"""Parse pip requirements.txt into list of {name, version_spec}."""
|
||||
if not requirements_path.exists():
|
||||
return []
|
||||
|
||||
deps = []
|
||||
for line in requirements_path.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or line.startswith("-"):
|
||||
continue
|
||||
# Split on version specifiers
|
||||
match = re.match(r"^([a-zA-Z0-9_\-]+)(.*)?$", line)
|
||||
if match:
|
||||
deps.append({
|
||||
"name": match.group(1),
|
||||
"version_spec": match.group(2).strip() if match.group(2) else "",
|
||||
})
|
||||
return deps
|
||||
|
||||
|
||||
def read_module_list(modules_file, source_dir):
|
||||
"""Read board-specific module list from file.
|
||||
|
||||
Paths may be absolute; they are converted to relative paths under src/.
|
||||
Duplicates are removed while preserving order.
|
||||
"""
|
||||
if not modules_file or not modules_file.exists():
|
||||
return []
|
||||
|
||||
seen = set()
|
||||
modules = []
|
||||
source_str = str(source_dir.resolve()) + "/"
|
||||
|
||||
for line in modules_file.read_text().splitlines():
|
||||
path = line.strip()
|
||||
if not path or path.startswith("#"):
|
||||
continue
|
||||
# Convert absolute path to relative
|
||||
if path.startswith(source_str):
|
||||
path = path[len(source_str):]
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
modules.append(path)
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def make_purl(pkg_type: str, namespace: str, name: str, version: str = "") -> str:
|
||||
"""Construct a Package URL (purl)."""
|
||||
purl = f"pkg:{pkg_type}/{namespace}/{name}"
|
||||
if version:
|
||||
purl += f"@{version}"
|
||||
return purl
|
||||
|
||||
|
||||
def extract_git_host_org_repo(url):
|
||||
"""Extract host type, org, and repo from a git URL.
|
||||
|
||||
Returns (host, org, repo) where host is 'github', 'gitlab', or ''.
|
||||
"""
|
||||
match = re.search(r"github\.com[:/]([^/]+)/([^/]+?)(?:\.git)?$", url)
|
||||
if match:
|
||||
return "github", match.group(1), match.group(2)
|
||||
match = re.search(r"gitlab\.com[:/](.+?)/([^/]+?)(?:\.git)?$", url)
|
||||
if match:
|
||||
return "gitlab", match.group(1), match.group(2)
|
||||
return "", "", ""
|
||||
|
||||
|
||||
def generate_sbom(source_dir, board, modules_file, compiler, platform=""):
|
||||
"""Generate a complete SPDX 2.3 JSON document."""
|
||||
license_overrides, license_comments = load_license_overrides(source_dir)
|
||||
git_info = get_git_info(source_dir)
|
||||
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# Deterministic namespace using UUID5 from git hash + board
|
||||
ns_seed = f"{git_info['hash']}:{board}"
|
||||
doc_namespace = f"https://spdx.org/spdxdocs/{board}-{uuid.uuid5(uuid.NAMESPACE_URL, ns_seed)}"
|
||||
|
||||
doc = {
|
||||
"spdxVersion": "SPDX-2.3",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": f"PX4 Firmware SBOM for {board}",
|
||||
"documentNamespace": doc_namespace,
|
||||
"creationInfo": {
|
||||
"created": timestamp,
|
||||
"creators": [
|
||||
"Tool: px4-generate-sbom",
|
||||
"Organization: Dronecode Foundation",
|
||||
],
|
||||
"licenseListVersion": "3.22",
|
||||
},
|
||||
"packages": [],
|
||||
"relationships": [],
|
||||
}
|
||||
|
||||
# Primary package: PX4 firmware
|
||||
primary_spdx_id = f"SPDXRef-PX4-{spdx_id(board)}"
|
||||
doc["packages"].append({
|
||||
"SPDXID": primary_spdx_id,
|
||||
"name": board,
|
||||
"versionInfo": git_info["version"],
|
||||
"packageFileName": f"{board}.px4",
|
||||
"supplier": "Organization: Dronecode Foundation",
|
||||
"downloadLocation": "https://github.com/PX4/PX4-Autopilot",
|
||||
"filesAnalyzed": False,
|
||||
"primaryPackagePurpose": "FIRMWARE",
|
||||
"licenseConcluded": "BSD-3-Clause",
|
||||
"licenseDeclared": "BSD-3-Clause",
|
||||
"copyrightText": "Copyright (c) PX4 Development Team",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": make_purl(
|
||||
"github", "PX4", "PX4-Autopilot", git_info["version"]
|
||||
),
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
doc["relationships"].append({
|
||||
"spdxElementId": "SPDXRef-DOCUMENT",
|
||||
"relationshipType": "DESCRIBES",
|
||||
"relatedSpdxElement": primary_spdx_id,
|
||||
})
|
||||
|
||||
# Git submodules (filtered to those relevant to this board's modules)
|
||||
submodules = parse_gitmodules(source_dir)
|
||||
submodule_commits = get_submodule_commits(source_dir)
|
||||
modules = read_module_list(modules_file, source_dir)
|
||||
|
||||
def submodule_is_relevant(sub_path):
|
||||
"""A submodule is relevant if any board module path overlaps with it."""
|
||||
# NuttX platform submodules are only relevant for NuttX builds
|
||||
if sub_path.startswith("platforms/nuttx/"):
|
||||
return platform in ("nuttx", "")
|
||||
if not modules:
|
||||
return True # no module list means include all
|
||||
# Other platform submodules are always relevant
|
||||
if sub_path.startswith("platforms/"):
|
||||
return True
|
||||
for mod in modules:
|
||||
# Module is under this submodule, or submodule is under a module
|
||||
if mod.startswith(sub_path + "/") or sub_path.startswith(mod + "/"):
|
||||
return True
|
||||
return False
|
||||
|
||||
for sub in submodules:
|
||||
if not submodule_is_relevant(sub["path"]):
|
||||
continue
|
||||
sub_path = sub["path"]
|
||||
sub_path_id = sub_path.replace("/", "-")
|
||||
sub_spdx_id = f"SPDXRef-Submodule-{spdx_id(sub_path_id)}"
|
||||
commit = submodule_commits.get(sub_path, "unknown")
|
||||
license_id = get_submodule_license(source_dir, sub_path, license_overrides)
|
||||
|
||||
host, org, repo = extract_git_host_org_repo(sub["url"])
|
||||
download = sub["url"] if sub["url"] else "NOASSERTION"
|
||||
|
||||
# Use repo name from URL for human-readable name, fall back to last path component
|
||||
display_name = repo if repo else sub_path.rsplit("/", 1)[-1]
|
||||
|
||||
pkg = {
|
||||
"SPDXID": sub_spdx_id,
|
||||
"name": display_name,
|
||||
"versionInfo": commit,
|
||||
"supplier": f"Organization: {org}" if org else "NOASSERTION",
|
||||
"downloadLocation": download,
|
||||
"filesAnalyzed": False,
|
||||
"licenseConcluded": license_id,
|
||||
"licenseDeclared": license_id,
|
||||
"copyrightText": "NOASSERTION",
|
||||
}
|
||||
|
||||
comment = license_comments.get(sub_path)
|
||||
if comment:
|
||||
pkg["licenseComments"] = comment
|
||||
|
||||
if host and org and repo:
|
||||
pkg["externalRefs"] = [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": make_purl(host, org, repo, commit),
|
||||
}
|
||||
]
|
||||
|
||||
doc["packages"].append(pkg)
|
||||
doc["relationships"].append({
|
||||
"spdxElementId": primary_spdx_id,
|
||||
"relationshipType": "CONTAINS",
|
||||
"relatedSpdxElement": sub_spdx_id,
|
||||
})
|
||||
|
||||
# Python build dependencies
|
||||
requirements_path = source_dir / "Tools" / "setup" / "requirements.txt"
|
||||
py_deps = parse_requirements(requirements_path)
|
||||
|
||||
for dep in py_deps:
|
||||
dep_name = dep["name"]
|
||||
dep_spdx_id = f"SPDXRef-PyDep-{spdx_id(dep_name)}"
|
||||
version_str = dep["version_spec"] if dep["version_spec"] else "NOASSERTION"
|
||||
|
||||
doc["packages"].append({
|
||||
"SPDXID": dep_spdx_id,
|
||||
"name": dep_name,
|
||||
"versionInfo": version_str,
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": f"https://pypi.org/project/{dep_name}/",
|
||||
"filesAnalyzed": False,
|
||||
"primaryPackagePurpose": "APPLICATION",
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"copyrightText": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": f"pkg:pypi/{dep_name}",
|
||||
}
|
||||
],
|
||||
})
|
||||
doc["relationships"].append({
|
||||
"spdxElementId": dep_spdx_id,
|
||||
"relationshipType": "BUILD_DEPENDENCY_OF",
|
||||
"relatedSpdxElement": primary_spdx_id,
|
||||
})
|
||||
|
||||
# Board-specific modules (already read above for submodule filtering)
|
||||
for mod in modules:
|
||||
mod_path_id = mod.replace("/", "-")
|
||||
mod_spdx_id = f"SPDXRef-Module-{spdx_id(mod_path_id)}"
|
||||
|
||||
# Derive short name: strip leading src/ for readability
|
||||
display_name = mod
|
||||
if display_name.startswith("src/"):
|
||||
display_name = display_name[4:]
|
||||
|
||||
doc["packages"].append({
|
||||
"SPDXID": mod_spdx_id,
|
||||
"name": display_name,
|
||||
"versionInfo": git_info["version"],
|
||||
"supplier": "Organization: Dronecode Foundation",
|
||||
"downloadLocation": "https://github.com/PX4/PX4-Autopilot",
|
||||
"filesAnalyzed": False,
|
||||
"licenseConcluded": "BSD-3-Clause",
|
||||
"licenseDeclared": "BSD-3-Clause",
|
||||
"copyrightText": "NOASSERTION",
|
||||
})
|
||||
doc["relationships"].append({
|
||||
"spdxElementId": primary_spdx_id,
|
||||
"relationshipType": "CONTAINS",
|
||||
"relatedSpdxElement": mod_spdx_id,
|
||||
})
|
||||
|
||||
# Compiler as a build tool
|
||||
if compiler:
|
||||
compiler_spdx_id = f"SPDXRef-Compiler-{spdx_id(compiler)}"
|
||||
doc["packages"].append({
|
||||
"SPDXID": compiler_spdx_id,
|
||||
"name": compiler,
|
||||
"versionInfo": "NOASSERTION",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": False,
|
||||
"primaryPackagePurpose": "APPLICATION",
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"copyrightText": "NOASSERTION",
|
||||
})
|
||||
doc["relationships"].append({
|
||||
"spdxElementId": compiler_spdx_id,
|
||||
"relationshipType": "BUILD_TOOL_OF",
|
||||
"relatedSpdxElement": primary_spdx_id,
|
||||
})
|
||||
|
||||
return doc
|
||||
|
||||
|
||||
def verify_licenses(source_dir):
|
||||
"""Verify license detection for all submodules. Returns exit code."""
|
||||
license_overrides, _ = load_license_overrides(source_dir)
|
||||
submodules = parse_gitmodules(source_dir)
|
||||
if not submodules:
|
||||
print("No submodules found in .gitmodules")
|
||||
return 1
|
||||
|
||||
has_noassertion = False
|
||||
print(f"{'Submodule Path':<65} {'Detected':<16} {'Override':<16} {'Final'}")
|
||||
print("-" * 115)
|
||||
|
||||
for sub in submodules:
|
||||
sub_path = sub["path"]
|
||||
sub_dir = source_dir / sub_path
|
||||
|
||||
checked_out = sub_dir.is_dir() and any(sub_dir.iterdir())
|
||||
if not checked_out:
|
||||
detected = "(not checked out)"
|
||||
override = license_overrides.get(sub_path, "")
|
||||
final = override if override else "NOASSERTION"
|
||||
else:
|
||||
detected = detect_license(sub_dir)
|
||||
override = license_overrides.get(sub_path, "")
|
||||
final = override if override else detected
|
||||
|
||||
if final == "NOASSERTION" and checked_out:
|
||||
has_noassertion = True
|
||||
marker = " <-- NOASSERTION"
|
||||
elif final == "NOASSERTION" and not checked_out:
|
||||
marker = " (skipped)"
|
||||
else:
|
||||
marker = ""
|
||||
|
||||
print(f"{sub_path:<65} {str(detected):<16} {str(override) if override else '':<16} {final}{marker}")
|
||||
|
||||
# Copyleft warning (informational, not a failure)
|
||||
copyleft_found = []
|
||||
for sub in submodules:
|
||||
sub_path = sub["path"]
|
||||
sub_dir = source_dir / sub_path
|
||||
checked_out = sub_dir.is_dir() and any(sub_dir.iterdir())
|
||||
override = license_overrides.get(sub_path, "")
|
||||
if checked_out:
|
||||
final_lic = override if override else detect_license(sub_dir)
|
||||
else:
|
||||
final_lic = override if override else "NOASSERTION"
|
||||
for cl in COPYLEFT_LICENSES:
|
||||
if cl in final_lic:
|
||||
copyleft_found.append((sub_path, final_lic))
|
||||
break
|
||||
|
||||
print()
|
||||
if copyleft_found:
|
||||
print("Copyleft licenses detected (informational):")
|
||||
for path, lic in copyleft_found:
|
||||
print(f" {path}: {lic}")
|
||||
print()
|
||||
|
||||
if has_noassertion:
|
||||
print("FAIL: Some submodules resolved to NOASSERTION. "
|
||||
"Add an entry to Tools/ci/license-overrides.yaml or check the LICENSE file.")
|
||||
return 1
|
||||
|
||||
print("OK: All submodules have a resolved license.")
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate SPDX 2.3 JSON SBOM for PX4 firmware"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source-dir",
|
||||
type=Path,
|
||||
default=Path.cwd(),
|
||||
help="PX4 source directory (default: cwd)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verify-licenses",
|
||||
action="store_true",
|
||||
help="Verify license detection for all submodules and exit",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--board",
|
||||
default=None,
|
||||
help="Board target name (e.g. px4_fmu-v5x_default)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--modules-file",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Path to config_module_list.txt",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--compiler",
|
||||
default="",
|
||||
help="Compiler identifier (e.g. arm-none-eabi-gcc)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--platform",
|
||||
default="",
|
||||
help="PX4 platform (nuttx, posix, qurt). Filters platform-specific submodules.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Output SBOM file path",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verify_licenses:
|
||||
raise SystemExit(verify_licenses(args.source_dir))
|
||||
|
||||
if not args.board:
|
||||
parser.error("--board is required when not using --verify-licenses")
|
||||
if not args.output:
|
||||
parser.error("--output is required when not using --verify-licenses")
|
||||
|
||||
sbom = generate_sbom(
|
||||
source_dir=args.source_dir,
|
||||
board=args.board,
|
||||
modules_file=args.modules_file,
|
||||
compiler=args.compiler,
|
||||
platform=args.platform,
|
||||
)
|
||||
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(sbom, f, indent=2)
|
||||
f.write("\n")
|
||||
|
||||
pkg_count = len(sbom["packages"])
|
||||
print(f"SBOM generated: {args.output} ({pkg_count} packages)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Inspect a PX4 SPDX SBOM file.
|
||||
|
||||
Usage:
|
||||
inspect_sbom.py <sbom.spdx.json> # full summary
|
||||
inspect_sbom.py <sbom.spdx.json> search <term> # search packages by name
|
||||
inspect_sbom.py <sbom.spdx.json> ntia # NTIA minimum elements check
|
||||
inspect_sbom.py <sbom.spdx.json> licenses # license summary
|
||||
inspect_sbom.py <sbom.spdx.json> list <type> # list packages (Submodule|PyDep|Module|all)
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load(path):
|
||||
return json.loads(Path(path).read_text())
|
||||
|
||||
|
||||
def pkg_type(pkg):
|
||||
spdx_id = pkg["SPDXID"]
|
||||
for prefix in ("Submodule", "PyDep", "Module", "Compiler", "PX4"):
|
||||
if f"-{prefix}-" in spdx_id or spdx_id.startswith(f"SPDXRef-{prefix}"):
|
||||
return prefix
|
||||
return "Other"
|
||||
|
||||
|
||||
def summary(doc):
|
||||
print(f"spdxVersion: {doc['spdxVersion']}")
|
||||
print(f"name: {doc['name']}")
|
||||
print(f"namespace: {doc['documentNamespace']}")
|
||||
print(f"created: {doc['creationInfo']['created']}")
|
||||
print(f"creators: {', '.join(doc['creationInfo']['creators'])}")
|
||||
print()
|
||||
|
||||
types = Counter(pkg_type(p) for p in doc["packages"])
|
||||
print(f"Packages: {len(doc['packages'])}")
|
||||
for t, c in types.most_common():
|
||||
print(f" {t}: {c}")
|
||||
print()
|
||||
|
||||
rc = Counter(r["relationshipType"] for r in doc["relationships"])
|
||||
print(f"Relationships: {len(doc['relationships'])}")
|
||||
for t, n in rc.most_common():
|
||||
print(f" {t}: {n}")
|
||||
print()
|
||||
|
||||
primary = doc["packages"][0]
|
||||
print(f"Primary package:")
|
||||
print(f" name: {primary['name']}")
|
||||
print(f" version: {primary['versionInfo']}")
|
||||
print(f" purpose: {primary.get('primaryPackagePurpose', 'N/A')}")
|
||||
print(f" license: {primary['licenseDeclared']}")
|
||||
print()
|
||||
|
||||
noassert = [
|
||||
p["name"]
|
||||
for p in doc["packages"]
|
||||
if pkg_type(p) == "Submodule" and p["licenseDeclared"] == "NOASSERTION"
|
||||
]
|
||||
if noassert:
|
||||
print(f"WARNING: {len(noassert)} submodules with NOASSERTION license:")
|
||||
for n in noassert:
|
||||
print(f" - {n}")
|
||||
else:
|
||||
print("All submodule licenses mapped")
|
||||
|
||||
print(f"\nFile size: {Path(sys.argv[1]).stat().st_size // 1024}KB")
|
||||
|
||||
|
||||
def search(doc, term):
|
||||
term = term.lower()
|
||||
found = [p for p in doc["packages"] if term in p["name"].lower()]
|
||||
if not found:
|
||||
print(f"No packages matching '{term}'")
|
||||
return
|
||||
print(f"Found {len(found)} packages matching '{term}':\n")
|
||||
for p in found:
|
||||
print(json.dumps(p, indent=2))
|
||||
print()
|
||||
|
||||
|
||||
def ntia_check(doc):
|
||||
required = ["SPDXID", "name", "versionInfo", "supplier", "downloadLocation"]
|
||||
missing = []
|
||||
for p in doc["packages"]:
|
||||
for f in required:
|
||||
if f not in p or p[f] in ("", None):
|
||||
missing.append((p["name"], f))
|
||||
|
||||
if missing:
|
||||
print(f"FAIL: {len(missing)} missing fields:")
|
||||
for name, field in missing:
|
||||
print(f" {name}: missing {field}")
|
||||
else:
|
||||
print(f"PASS: All {len(doc['packages'])} packages have required fields")
|
||||
|
||||
print(f"\nCreators: {doc['creationInfo']['creators']}")
|
||||
print(f"Timestamp: {doc['creationInfo']['created']}")
|
||||
|
||||
rels = [r for r in doc["relationships"] if r["relationshipType"] == "DESCRIBES"]
|
||||
print(f"DESCRIBES relationships: {len(rels)}")
|
||||
|
||||
return len(missing) == 0
|
||||
|
||||
|
||||
def licenses(doc):
|
||||
by_license = {}
|
||||
for p in doc["packages"]:
|
||||
lic = p.get("licenseDeclared", "NOASSERTION")
|
||||
by_license.setdefault(lic, []).append(p["name"])
|
||||
|
||||
for lic in sorted(by_license.keys()):
|
||||
names = by_license[lic]
|
||||
print(f"\n{lic} ({len(names)}):")
|
||||
for n in sorted(names):
|
||||
print(f" {n}")
|
||||
|
||||
|
||||
def list_packages(doc, filter_type):
|
||||
filter_type = filter_type.lower()
|
||||
for p in sorted(doc["packages"], key=lambda x: x["name"]):
|
||||
t = pkg_type(p)
|
||||
if filter_type != "all" and t.lower() != filter_type:
|
||||
continue
|
||||
lic = p.get("licenseDeclared", "?")
|
||||
ver = p["versionInfo"][:20] if len(p["versionInfo"]) > 20 else p["versionInfo"]
|
||||
print(f" {t:10s} {p['name']:50s} {ver:20s} {lic}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
doc = load(sys.argv[1])
|
||||
cmd = sys.argv[2] if len(sys.argv) > 2 else "summary"
|
||||
|
||||
if cmd == "summary":
|
||||
summary(doc)
|
||||
elif cmd == "search":
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: inspect_sbom.py <file> search <term>")
|
||||
sys.exit(1)
|
||||
search(doc, sys.argv[3])
|
||||
elif cmd == "ntia":
|
||||
if not ntia_check(doc):
|
||||
sys.exit(1)
|
||||
elif cmd == "licenses":
|
||||
licenses(doc)
|
||||
elif cmd == "list":
|
||||
filter_type = sys.argv[3] if len(sys.argv) > 3 else "all"
|
||||
list_packages(doc, filter_type)
|
||||
else:
|
||||
print(f"Unknown command: {cmd}")
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,56 @@
|
||||
# SPDX license overrides for submodules where auto-detection fails or is wrong.
|
||||
# Each entry maps a submodule path to its SPDX license identifier and an
|
||||
# optional comment explaining why the override exists.
|
||||
#
|
||||
# Run `python3 Tools/ci/generate_sbom.py --verify-licenses` to validate.
|
||||
|
||||
overrides:
|
||||
src/modules/mavlink/mavlink:
|
||||
license: "LGPL-3.0-only AND MIT"
|
||||
comment: "Generator is LGPL-3.0; PX4 ships only MIT-licensed generated headers."
|
||||
|
||||
src/lib/cdrstream/cyclonedds:
|
||||
license: "EPL-2.0 OR BSD-3-Clause"
|
||||
comment: >-
|
||||
Dual-licensed. PX4 elects BSD-3-Clause.
|
||||
No board currently enables CONFIG_LIB_CDRSTREAM.
|
||||
|
||||
src/lib/cdrstream/rosidl:
|
||||
license: "Apache-2.0"
|
||||
|
||||
src/lib/crypto/monocypher:
|
||||
license: "BSD-2-Clause OR CC0-1.0"
|
||||
comment: >-
|
||||
Dual-licensed. LICENCE.md offers BSD-2-Clause with CC0-1.0 as
|
||||
public domain fallback.
|
||||
|
||||
src/lib/crypto/libtomcrypt:
|
||||
license: "Unlicense"
|
||||
comment: "Public domain dedication. Functionally equivalent to Unlicense."
|
||||
|
||||
src/lib/crypto/libtommath:
|
||||
license: "Unlicense"
|
||||
comment: "Public domain dedication. Functionally equivalent to Unlicense."
|
||||
|
||||
platforms/nuttx/NuttX/nuttx:
|
||||
license: "Apache-2.0"
|
||||
comment: >-
|
||||
Composite LICENSE (6652 lines) includes BSD/MIT/ISC sub-components.
|
||||
Primary license is Apache-2.0. NOTICE file contains FAT LFN patent warnings.
|
||||
|
||||
platforms/nuttx/NuttX/apps:
|
||||
license: "Apache-2.0"
|
||||
|
||||
boards/modalai/voxl2/libfc-sensor-api:
|
||||
license: "NOASSERTION"
|
||||
comment: >-
|
||||
No LICENSE file in repo. README describes it as public interface
|
||||
for proprietary sensor library.
|
||||
|
||||
boards/modalai/voxl2/src/lib/mpa/libmodal-json:
|
||||
license: "LGPL-3.0-only"
|
||||
comment: "LGPL-3.0 weak copyleft. Used via header includes in VOXL2 mpa library."
|
||||
|
||||
boards/modalai/voxl2/src/lib/mpa/libmodal-pipe:
|
||||
license: "LGPL-3.0-only"
|
||||
comment: "LGPL-3.0 weak copyleft. Used via header includes in VOXL2 mpa library."
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
mkdir artifacts
|
||||
cp **/**/*.px4 artifacts/ 2>/dev/null || true
|
||||
@@ -29,6 +29,8 @@ for build_dir_path in build/*/ ; do
|
||||
# Events
|
||||
mkdir -p artifacts/$build_dir/events/
|
||||
cp $build_dir_path/events/all_events.json.xz artifacts/$build_dir/events/ 2>/dev/null || true
|
||||
# SBOM
|
||||
cp $build_dir_path/*.sbom.spdx.json artifacts/$build_dir/ 2>/dev/null || true
|
||||
ls -la artifacts/$build_dir
|
||||
echo "----------"
|
||||
done
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# This script runs the fuzz tests from a given binary for a certain amount of time
|
||||
set -e
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Copy msgs and the message translation node into a ROS workspace directory
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z ${PX4_DOCKER_REPO+x} ]; then
|
||||
PX4_DOCKER_REPO="px4io/px4-dev:v1.17.0-beta1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Script to run ShellCheck (a static analysis tool for shell scripts) over a
|
||||
# script directory
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
NO_COLOR='\033[0m' # No Color
|
||||
|
||||
@@ -79,6 +79,13 @@ if [[ $INSTALL_SIM == "--sim-tools" ]]; then
|
||||
elif [[ $REINSTALL_FORMULAS == "--reinstall" ]]; then
|
||||
brew reinstall px4-sim
|
||||
fi
|
||||
|
||||
# jMAVSim requires a JDK (Java 17 LTS recommended)
|
||||
if ! brew ls --versions openjdk@17 > /dev/null; then
|
||||
echo "[macos.sh] Installing OpenJDK 17 (required for jMAVSim)"
|
||||
brew install openjdk@17
|
||||
sudo ln -sfn $(brew --prefix openjdk@17)/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[macos.sh] All set! The PX4 Autopilot toolchain was installed."
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Setup environment to make PX4 visible to Gazebo.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# run multiple instances of the 'px4' binary, with the gazebo SITL simulation
|
||||
# It assumes px4 is already built, with 'make px4_sitl_default sitl_gazebo-classic'
|
||||
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
#!/bin/bash
|
||||
# run multiple instances of the 'px4' binary, but w/o starting the simulator.
|
||||
# It assumes px4 is already built, with 'make px4_sitl_default'
|
||||
#!/usr/bin/env bash
|
||||
# Run multiple instances of the 'px4' binary, without starting an external simulator.
|
||||
# It assumes px4 is already built with the specified build target.
|
||||
#
|
||||
# Usage: ./Tools/simulation/sitl_multiple_run.sh [num_instances] [model] [build_target]
|
||||
# Examples:
|
||||
# ./Tools/simulation/sitl_multiple_run.sh 3 sihsim_quadx px4_sitl_sih
|
||||
# ./Tools/simulation/sitl_multiple_run.sh 2 gazebo-classic_iris px4_sitl_default
|
||||
# ./Tools/simulation/sitl_multiple_run.sh # defaults: 2 instances, gazebo-classic_iris, px4_sitl_default
|
||||
|
||||
# The simulator is expected to send to TCP port 4560+i for i in [0, N-1]
|
||||
# For example jmavsim can be run like this:
|
||||
#./Tools/simulation/jmavsim/jmavsim_run.sh -p 4561 -l
|
||||
|
||||
sitl_num=2
|
||||
[ -n "$1" ] && sitl_num="$1"
|
||||
sitl_num=${1:-2}
|
||||
sim_model=${2:-gazebo-classic_iris}
|
||||
build_target=${3:-px4_sitl_default}
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
src_path="$SCRIPT_DIR/../../"
|
||||
|
||||
build_path=${src_path}/build/px4_sitl_default
|
||||
build_path=${src_path}/build/${build_target}
|
||||
|
||||
echo "killing running instances"
|
||||
pkill -x px4 || true
|
||||
|
||||
sleep 1
|
||||
|
||||
export PX4_SIM_MODEL=gazebo-classic_iris
|
||||
export PX4_SIM_MODEL=${sim_model}
|
||||
|
||||
n=0
|
||||
while [ $n -lt $sitl_num ]; do
|
||||
|
||||
@@ -25,7 +25,14 @@ CONFIG_MODULES_COMMANDER=y
|
||||
CONFIG_MODULES_CONTROL_ALLOCATOR=y
|
||||
CONFIG_MODULES_DATAMAN=y
|
||||
CONFIG_MODULES_EKF2=y
|
||||
# CONFIG_EKF2_AUX_GLOBAL_POSITION is not set
|
||||
# CONFIG_EKF2_AUXVEL is not set
|
||||
# CONFIG_EKF2_BARO_COMPENSATION is not set
|
||||
# CONFIG_EKF2_DRAG_FUSION is not set
|
||||
# CONFIG_EKF2_EXTERNAL_VISION is not set
|
||||
# CONFIG_EKF2_GNSS_YAW is not set
|
||||
# CONFIG_EKF2_OPTICAL_FLOW is not set
|
||||
# CONFIG_EKF2_RANGE_FINDER is not set
|
||||
# CONFIG_EKF2_SIDESLIP is not set
|
||||
CONFIG_MODULES_FLIGHT_MODE_MANAGER=y
|
||||
CONFIG_MODULES_LAND_DETECTOR=y
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Run this from the px4 project top level directory
|
||||
docker run -it --rm --privileged -v `pwd`:/usr/local/workspace px4io/px4-dev-nuttx-focal:2022-08-12
|
||||
|
||||
@@ -47,7 +47,7 @@ set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
|
||||
set(CPACK_INSTALL_PREFIX "/usr")
|
||||
set(CPACK_SET_DESTDIR true)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libfc-sensor (>=1.0.10), voxl-px4-params (>=0.3.10), voxl3-system-image(>=0.0.2) | voxl2-system-image(>=1.5.4) | rb5-system-image(>=1.6.2), modalai-slpi(>=1.1.16) | modalai-adsp(>=1.0.2)")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libfc-sensor (>=1.0.10), voxl-px4-params (>=0.3.10), voxl3-system-image(>=0.0.2) | voxl2-system-image(>=1.5.4) | rb5-system-image(>=1.6.2), modalai-slpi(>=1.2.2) | modalai-adsp(>=1.0.5)")
|
||||
set(CPACK_DEBIAN_PACKAGE_CONFLICTS "px4-rb5-flight")
|
||||
set(CPACK_DEBIAN_PACKAGE_REPLACES "px4-rb5-flight")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "PX4 Autopilot for ModalAI VOXL2")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Create px4-* symlinks from px4-alias.sh
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Stop voxl-px4 service if running
|
||||
|
||||
@@ -4,11 +4,10 @@ After=sscrpcd.service
|
||||
Requires=sscrpcd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=/bin/sleep 2
|
||||
ExecStart=/usr/bin/voxl-px4
|
||||
ExecStopPost=/usr/bin/voxl-reset-slpi
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "*** Starting unified VOXL2 build (apps + SLPI) ***"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "*** Starting unified VOXL2 build (apps + SLPI) ***"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "*** Starting qurt slpi build ***"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Clean out the build artifacts
|
||||
# source /home/build-env.sh
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Push slpi image to voxl2
|
||||
adb push build/modalai_voxl2_slpi/platforms/qurt/libpx4.so /usr/lib/rfsa/adsp
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Push slpi image to voxl2
|
||||
adb push build/modalai_voxl2_slpi/platforms/qurt/libpx4.so /usr/lib/rfsa/adsp
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd Tools/simulation/gazebo-classic/sitl_gazebo-classic/src
|
||||
patch < ../../../../../boards/modalai/voxl2/gazebo-docker/patch/mavlink_interface.patch
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Run this from the px4 project top level directory
|
||||
docker run -it --rm -v `pwd`:/usr/local/workspace rb5-flight-px4-build-docker
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
################################################################################
|
||||
# Copyright 2023 ModalAI Inc.
|
||||
#
|
||||
|
||||
@@ -37,6 +37,8 @@ CONFIG_DRIVERS_MAGNETOMETER_ISENTEK_IST8310=y
|
||||
CONFIG_DRIVERS_MAGNETOMETER_QMC5883L=y
|
||||
CONFIG_DRIVERS_MAGNETOMETER_ST_IIS2MDC=y
|
||||
CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y
|
||||
CONFIG_DRIVERS_POWER_MONITOR_INA226=y
|
||||
CONFIG_DRIVERS_POWER_MONITOR_INA228=y
|
||||
CONFIG_DRIVERS_QSHELL_QURT=y
|
||||
CONFIG_DRIVERS_RC_CRSF_RC=y
|
||||
CONFIG_DRIVERS_VOXL2_IO=y
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CONFIG_FILE="/etc/modalai/voxl-px4.conf"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Make sure that the SLPI DSP test signature is there otherwise px4 cannot run
|
||||
# on the DSP
|
||||
|
||||
@@ -215,6 +215,12 @@ fi
|
||||
if [ "$POWER_MANAGER" == "VOXLPM" ]; then
|
||||
# APM power monitor
|
||||
qshell voxlpm start -X -b 2
|
||||
elif [ "$POWER_MANAGER" == "INA226" ]; then
|
||||
/bin/echo "Starting INA226 power monitor"
|
||||
qshell ina226 start -X -b 2
|
||||
elif [ "$POWER_MANAGER" == "INA228" ]; then
|
||||
/bin/echo "Starting INA228 power monitor"
|
||||
qshell ina228 start -X -b 2
|
||||
fi
|
||||
|
||||
if [ "$AIRSPEED_SENSOR" == "MS4525DO" ]; then
|
||||
|
||||
@@ -31,6 +31,8 @@ CONFIG_MODULES_EKF2=y
|
||||
# CONFIG_EKF2_DRAG_FUSION is not set
|
||||
# CONFIG_EKF2_EXTERNAL_VISION is not set
|
||||
# CONFIG_EKF2_GNSS_YAW is not set
|
||||
# CONFIG_EKF2_OPTICAL_FLOW is not set
|
||||
# CONFIG_EKF2_RANGE_FINDER is not set
|
||||
# CONFIG_EKF2_SIDESLIP is not set
|
||||
CONFIG_MODULES_FLIGHT_MODE_MANAGER=y
|
||||
CONFIG_MODULES_LAND_DETECTOR=y
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_MODULES_SIMULATION_GZ_BRIDGE=n
|
||||
CONFIG_MODULES_SIMULATION_GZ_MSGS=n
|
||||
CONFIG_MODULES_SIMULATION_GZ_PLUGINS=n
|
||||
@@ -52,10 +52,10 @@ endif()
|
||||
|
||||
# add code coverage build type
|
||||
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang"))
|
||||
set(CMAKE_C_FLAGS_COVERAGE "--coverage -ftest-coverage -fdiagnostics-absolute-paths -O0 -fprofile-arcs -fno-inline-functions"
|
||||
set(CMAKE_C_FLAGS_COVERAGE "--coverage -ftest-coverage -fdiagnostics-absolute-paths ${PX4_DEBUG_OPT_LEVEL} -fprofile-arcs -fno-inline-functions"
|
||||
CACHE STRING "Flags used by the C compiler during coverage builds" FORCE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE "--coverage -ftest-coverage -fdiagnostics-absolute-paths -O0-fprofile-arcs -fno-inline-functions -fno-elide-constructors"
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE "--coverage -ftest-coverage -fdiagnostics-absolute-paths ${PX4_DEBUG_OPT_LEVEL} -fprofile-arcs -fno-inline-functions -fno-elide-constructors"
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds" FORCE)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "-ftest-coverage -fdiagnostics-absolute-paths"
|
||||
@@ -63,11 +63,11 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}"
|
||||
|
||||
else()
|
||||
# Add -fprofile-abs-path for GCC v8/9 later on
|
||||
set(CMAKE_C_FLAGS_COVERAGE "--coverage -ftest-coverage -fprofile-arcs -O0 -fno-default-inline -fno-inline"
|
||||
set(CMAKE_C_FLAGS_COVERAGE "--coverage -ftest-coverage -fprofile-arcs ${PX4_DEBUG_OPT_LEVEL} -fno-default-inline -fno-inline"
|
||||
CACHE STRING "Flags used by the C compiler during coverage builds" FORCE)
|
||||
|
||||
# Add -fprofile-abs-path for GCC v8/9 later on
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE "--coverage -ftest-coverage -fprofile-arcs -O0 -fno-default-inline -fno-inline -fno-elide-constructors"
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE "--coverage -ftest-coverage -fprofile-arcs ${PX4_DEBUG_OPT_LEVEL} -fno-default-inline -fno-inline -fno-elide-constructors"
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds" FORCE)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage -ftest-coverage -lgcov"
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
#
|
||||
############################################################################
|
||||
|
||||
# Attach only matching test binaries to `test_results` when TESTFILTER is set.
|
||||
# `ctest -R` filters execution only; without this helper the build still
|
||||
# compiles every gtest target before running the filtered subset.
|
||||
function(add_filtered_test_dependencies TESTNAME)
|
||||
if(NOT TESTFILTER OR "${TESTNAME}" MATCHES "${TESTFILTER}")
|
||||
add_dependencies(test_results ${TESTNAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
# px4_add_unit_gtest
|
||||
@@ -74,7 +83,7 @@ function(px4_add_unit_gtest)
|
||||
WORKING_DIRECTORY ${PX4_BINARY_DIR})
|
||||
|
||||
# attach it to the unit test target
|
||||
add_dependencies(test_results ${TESTNAME})
|
||||
add_filtered_test_dependencies(${TESTNAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -133,6 +142,6 @@ function(px4_add_functional_gtest)
|
||||
COMMAND ${PX4_BINARY_DIR}/${TESTNAME})
|
||||
|
||||
# attach it to the unit test target
|
||||
add_dependencies(test_results ${TESTNAME})
|
||||
add_filtered_test_dependencies(${TESTNAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name PX4 nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
# SBOM - SPDX 2.3 JSON Software Bill of Materials generation
|
||||
|
||||
option(GENERATE_SBOM "Generate SPDX 2.3 SBOM" ON)
|
||||
|
||||
if(DEFINED ENV{PX4_SBOM_DISABLE})
|
||||
set(GENERATE_SBOM OFF)
|
||||
endif()
|
||||
|
||||
if(GENERATE_SBOM)
|
||||
|
||||
# Write board-specific module list for the SBOM generator
|
||||
set(sbom_module_list_file "${PX4_BINARY_DIR}/config_module_list.txt")
|
||||
get_property(module_list GLOBAL PROPERTY PX4_MODULE_PATHS)
|
||||
string(REPLACE ";" "\n" module_list_content "${module_list}")
|
||||
file(GENERATE OUTPUT ${sbom_module_list_file} CONTENT "${module_list_content}\n")
|
||||
|
||||
set(sbom_output "${PX4_BINARY_DIR}/${PX4_CONFIG}.sbom.spdx.json")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${sbom_output}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${PX4_SOURCE_DIR}/Tools/ci/generate_sbom.py
|
||||
--source-dir ${PX4_SOURCE_DIR}
|
||||
--board ${PX4_CONFIG}
|
||||
--modules-file ${sbom_module_list_file}
|
||||
--compiler ${CMAKE_C_COMPILER}
|
||||
--platform ${PX4_PLATFORM}
|
||||
--output ${sbom_output}
|
||||
DEPENDS
|
||||
${PX4_SOURCE_DIR}/Tools/ci/generate_sbom.py
|
||||
${PX4_SOURCE_DIR}/Tools/ci/license-overrides.yaml
|
||||
${PX4_SOURCE_DIR}/.gitmodules
|
||||
${PX4_SOURCE_DIR}/Tools/setup/requirements.txt
|
||||
${sbom_module_list_file}
|
||||
COMMENT "Generating SPDX SBOM for ${PX4_CONFIG}"
|
||||
)
|
||||
|
||||
add_custom_target(sbom ALL DEPENDS ${sbom_output})
|
||||
|
||||
endif()
|
||||
|
Before Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 354 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 160" width="520" height="160" font-family="Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif">
|
||||
<!-- Arrow marker -->
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 7" refX="10" refY="3.5" markerWidth="10" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M 0 0 L 10 3.5 L 0 7 z" fill="#4a5568"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- Left label: Actuator Outputs -->
|
||||
<text x="20" y="72" font-size="13" fill="#4a5568" font-weight="500" text-anchor="start">Actuator</text>
|
||||
<text x="20" y="90" font-size="13" fill="#4a5568" font-weight="500" text-anchor="start">Outputs</text>
|
||||
<text x="20" y="108" font-size="11" fill="#718096" text-anchor="start">(uORB)</text>
|
||||
|
||||
<!-- Left arrow -->
|
||||
<line x1="100" y1="80" x2="170" y2="80" stroke="#4a5568" stroke-width="2" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- SIH Module box -->
|
||||
<rect x="180" y="30" width="160" height="100" rx="8" ry="8" fill="#edf2f7" stroke="#4a5568" stroke-width="2"/>
|
||||
<text x="260" y="72" font-size="16" fill="#2d3748" font-weight="600" text-anchor="middle">SIH Module</text>
|
||||
<text x="260" y="96" font-size="12" fill="#718096" text-anchor="middle">C++ / uORB</text>
|
||||
|
||||
<!-- Right arrow -->
|
||||
<line x1="350" y1="80" x2="420" y2="80" stroke="#4a5568" stroke-width="2" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- Right label: Simulated Sensor Data -->
|
||||
<text x="432" y="72" font-size="13" fill="#4a5568" font-weight="500" text-anchor="start">Simulated</text>
|
||||
<text x="432" y="90" font-size="13" fill="#4a5568" font-weight="500" text-anchor="start">Sensor Data</text>
|
||||
<text x="432" y="108" font-size="11" fill="#718096" text-anchor="start">(uORB)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -171,6 +171,7 @@
|
||||
- [CUAV V5 nano (FMUv5)](flight_controller/cuav_v5_nano.md)
|
||||
- [CUAV V5 nano Wiring Quickstart](assembly/quick_start_cuav_v5_nano.md)
|
||||
- [CUAV X25 EVO](flight_controller/cuav_x25-evo.md)
|
||||
- [CUAV X25 EVO Wiring Quick Start](assembly/quick_start_cuav_x25_evo.md)
|
||||
- [CUAV X25 SUPER](flight_controller/cuav_x25-super.md)
|
||||
- [CubePilot Cube Orange+ (CubePilot)](flight_controller/cubepilot_cube_orangeplus.md)
|
||||
- [CubePilot Cube Orange (CubePilot)](flight_controller/cubepilot_cube_orange.md)
|
||||
@@ -466,6 +467,7 @@
|
||||
- [Plugins](sim_gazebo_gz/plugins.md)
|
||||
- [Gazebo Models Repository](sim_gazebo_gz/gazebo_models.md)
|
||||
- [Multi-Vehicle Sim](sim_gazebo_gz/multi_vehicle_simulation.md)
|
||||
- [SIH Simulation](sim_sih/index.md)
|
||||
- [Gazebo Classic Simulation](sim_gazebo_classic/index.md)
|
||||
- [Vehicles](sim_gazebo_classic/vehicles.md)
|
||||
- [Worlds](sim_gazebo_classic/worlds.md)
|
||||
@@ -565,6 +567,8 @@
|
||||
- [DistanceSensorModeChangeRequest](msg_docs/DistanceSensorModeChangeRequest.md)
|
||||
- [DronecanNodeStatus](msg_docs/DronecanNodeStatus.md)
|
||||
- [Ekf2Timestamps](msg_docs/Ekf2Timestamps.md)
|
||||
- [EscEepromRead](msg_docs/EscEepromRead.md)
|
||||
- [EscEepromWrite](msg_docs/EscEepromWrite.md)
|
||||
- [EscReport](msg_docs/EscReport.md)
|
||||
- [EscStatus](msg_docs/EscStatus.md)
|
||||
- [EstimatorAidSource1d](msg_docs/EstimatorAidSource1d.md)
|
||||
@@ -755,6 +759,7 @@
|
||||
- [VehicleLocalPositionV0](msg_docs/VehicleLocalPositionV0.md)
|
||||
- [VehicleStatusV0](msg_docs/VehicleStatusV0.md)
|
||||
- [VehicleStatusV1](msg_docs/VehicleStatusV1.md)
|
||||
- [VehicleStatusV2](msg_docs/VehicleStatusV2.md)
|
||||
- [MAVLink Messaging](mavlink/index.md)
|
||||
- [Adding Messages](mavlink/adding_messages.md)
|
||||
- [Streaming Messages](mavlink/streaming_messages.md)
|
||||
@@ -849,8 +854,9 @@
|
||||
- [Multi-Vehicle Sim with JMAVSim](sim_jmavsim/multi_vehicle.md)
|
||||
- [JSBSim Simulation](sim_jsbsim/index.md)
|
||||
- [AirSim Simulation](sim_airsim/index.md)
|
||||
- [HITL Simulation](simulation/hitl.md)
|
||||
- [Simulation-In-Hardware](sim_sih/index.md)
|
||||
- [Hardware Simulation](simulation/hardware.md)
|
||||
- [HITL Simulation](simulation/hitl.md)
|
||||
- [SIH on Hardware](sim_sih/hardware.md)
|
||||
- [Multi-vehicle simulation](simulation/multi-vehicle-simulation.md)
|
||||
- [Platform Testing and CI](test_and_ci/index.md)
|
||||
- [Test Flights](test_and_ci/test_flights.md)
|
||||
@@ -904,6 +910,7 @@
|
||||
- [Translation](contribute/translation.md)
|
||||
- [Terminology/Notation](contribute/notation.md)
|
||||
- [Licenses](contribute/licenses.md)
|
||||
- [SBOM](contribute/sbom.md)
|
||||
- [Releases](releases/index.md)
|
||||
- [Release Process](releases/release_process.md)
|
||||
- [main (alpha)](releases/main.md)
|
||||
|
||||
@@ -91,7 +91,7 @@ For FMUv6S, you need to route the PPS signal separately:
|
||||
|
||||
For ARK FMUv6X on the Jetson carrier board:
|
||||
|
||||
1. Connect your GNSS module using either the 10-pin or 6-pin GPS connector: [ARK PAB GPS1 Interface](../flight_controller/ark_pab#gps1)
|
||||
1. Connect your GNSS module using either the 10-pin or 6-pin GPS connector: [ARK PAB GPS1 Interface](../flight_controller/ark_pab.md#gps1)
|
||||
2. Connect the PPS signal to the **FMU_CAP** pin: [ARK PAB ADIO Interface](../flight_controller/ark_pab.md#adio)
|
||||
|
||||
## Verification
|
||||
|
||||
@@ -160,7 +160,7 @@ After the bootloader has updated you can [Load PX4 Firmware](../config/firmware.
|
||||
## FMUv2 Bootloader Update
|
||||
|
||||
If _QGroundControl_ installs the FMUv2 target (see console during installation), and you have a newer board, you may need to update the bootloader in order to access all the memory on your flight controller.
|
||||
This example explains how you can use [QGC Bootloader Update](qgc-bootloader-update-sys-bl-update) to update the bootloader.
|
||||
This example explains how you can use [QGC Bootloader Update](#qgc-bootloader-update-sys-bl-update) to update the bootloader.
|
||||
|
||||
::: info
|
||||
Early FMUv2 [Pixhawk-series](../flight_controller/pixhawk_series.md#fmu_versions) flight controllers had a [hardware issue](../flight_controller/silicon_errata.md#fmuv2-pixhawk-silicon-errata) that restricted them to using 1MB of flash memory.
|
||||
|
||||
@@ -27,6 +27,8 @@ Supported flight controllers include:
|
||||
|
||||
- [ARK Electronics ARKV6X](../flight_controller/ark_v6x.md)
|
||||
- [CUAV Pixhawk V6X](../flight_controller/cuav_pixhawk_v6x.md)
|
||||
- [CUAV X25 EVO](../flight_controller/cuav_x25-evo.md)
|
||||
- [CUAV X25 SUPER](../flight_controller/cuav_x25-super.md)
|
||||
- [Holybro Pixhawk 5X](../flight_controller/pixhawk5x.md)
|
||||
- [Holybro Pixhawk 6X](../flight_controller/pixhawk6x.md)
|
||||
- [RaccoonLab FMUv6X Autopilot](../flight_controller/raccoonlab_fmu6x.md)
|
||||
|
||||
@@ -9994,6 +9994,48 @@ When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC1
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FAIL10 (`INT32`) {#UAVCAN_EC_FAIL10}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 10 Failsafe Value.
|
||||
|
||||
This is the output value that is set when in failsafe mode.
|
||||
|
||||
When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC10).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FAIL11 (`INT32`) {#UAVCAN_EC_FAIL11}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 11 Failsafe Value.
|
||||
|
||||
This is the output value that is set when in failsafe mode.
|
||||
|
||||
When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC11).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FAIL12 (`INT32`) {#UAVCAN_EC_FAIL12}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 12 Failsafe Value.
|
||||
|
||||
This is the output value that is set when in failsafe mode.
|
||||
|
||||
When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC12).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FAIL2 (`INT32`) {#UAVCAN_EC_FAIL2}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10092,6 +10134,20 @@ When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC8
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FAIL9 (`INT32`) {#UAVCAN_EC_FAIL9}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 9 Failsafe Value.
|
||||
|
||||
This is the output value that is set when in failsafe mode.
|
||||
|
||||
When set to -1 (default), the value depends on the function (see UAVCAN_EC_FUNC9).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -1 | 8191 | | -1 | |
|
||||
|
||||
### UAVCAN_EC_FUNC1 (`INT32`) {#UAVCAN_EC_FUNC1}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10166,6 +10222,228 @@ The default failsafe value is set according to the selected function:
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_FUNC10 (`INT32`) {#UAVCAN_EC_FUNC10}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 10 Output Function.
|
||||
|
||||
Select what should be output on UAVCAN ESC 10.
|
||||
|
||||
The default failsafe value is set according to the selected function:
|
||||
|
||||
- 'Min' for ConstantMin
|
||||
- 'Max' for ConstantMax
|
||||
- 'Max' for Parachute
|
||||
- ('Max'+'Min')/2 for Servos
|
||||
- 'Disarmed' for the rest
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disabled
|
||||
- `1`: Constant Min
|
||||
- `2`: Constant Max
|
||||
- `101`: Motor 1
|
||||
- `102`: Motor 2
|
||||
- `103`: Motor 3
|
||||
- `104`: Motor 4
|
||||
- `105`: Motor 5
|
||||
- `106`: Motor 6
|
||||
- `107`: Motor 7
|
||||
- `108`: Motor 8
|
||||
- `109`: Motor 9
|
||||
- `110`: Motor 10
|
||||
- `111`: Motor 11
|
||||
- `112`: Motor 12
|
||||
- `201`: Servo 1
|
||||
- `202`: Servo 2
|
||||
- `203`: Servo 3
|
||||
- `204`: Servo 4
|
||||
- `205`: Servo 5
|
||||
- `206`: Servo 6
|
||||
- `207`: Servo 7
|
||||
- `208`: Servo 8
|
||||
- `301`: Peripheral via Actuator Set 1
|
||||
- `302`: Peripheral via Actuator Set 2
|
||||
- `303`: Peripheral via Actuator Set 3
|
||||
- `304`: Peripheral via Actuator Set 4
|
||||
- `305`: Peripheral via Actuator Set 5
|
||||
- `306`: Peripheral via Actuator Set 6
|
||||
- `400`: Landing Gear
|
||||
- `401`: Parachute
|
||||
- `402`: RC Roll
|
||||
- `403`: RC Pitch
|
||||
- `404`: RC Throttle
|
||||
- `405`: RC Yaw
|
||||
- `406`: RC Flaps
|
||||
- `407`: RC AUX 1
|
||||
- `408`: RC AUX 2
|
||||
- `409`: RC AUX 3
|
||||
- `410`: RC AUX 4
|
||||
- `411`: RC AUX 5
|
||||
- `412`: RC AUX 6
|
||||
- `420`: Gimbal Roll
|
||||
- `421`: Gimbal Pitch
|
||||
- `422`: Gimbal Yaw
|
||||
- `430`: Gripper
|
||||
- `440`: Landing Gear Wheel
|
||||
- `450`: IC Engine Ignition
|
||||
- `451`: IC Engine Throttle
|
||||
- `452`: IC Engine Choke
|
||||
- `453`: IC Engine Starter
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_FUNC11 (`INT32`) {#UAVCAN_EC_FUNC11}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 11 Output Function.
|
||||
|
||||
Select what should be output on UAVCAN ESC 11.
|
||||
|
||||
The default failsafe value is set according to the selected function:
|
||||
|
||||
- 'Min' for ConstantMin
|
||||
- 'Max' for ConstantMax
|
||||
- 'Max' for Parachute
|
||||
- ('Max'+'Min')/2 for Servos
|
||||
- 'Disarmed' for the rest
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disabled
|
||||
- `1`: Constant Min
|
||||
- `2`: Constant Max
|
||||
- `101`: Motor 1
|
||||
- `102`: Motor 2
|
||||
- `103`: Motor 3
|
||||
- `104`: Motor 4
|
||||
- `105`: Motor 5
|
||||
- `106`: Motor 6
|
||||
- `107`: Motor 7
|
||||
- `108`: Motor 8
|
||||
- `109`: Motor 9
|
||||
- `110`: Motor 10
|
||||
- `111`: Motor 11
|
||||
- `112`: Motor 12
|
||||
- `201`: Servo 1
|
||||
- `202`: Servo 2
|
||||
- `203`: Servo 3
|
||||
- `204`: Servo 4
|
||||
- `205`: Servo 5
|
||||
- `206`: Servo 6
|
||||
- `207`: Servo 7
|
||||
- `208`: Servo 8
|
||||
- `301`: Peripheral via Actuator Set 1
|
||||
- `302`: Peripheral via Actuator Set 2
|
||||
- `303`: Peripheral via Actuator Set 3
|
||||
- `304`: Peripheral via Actuator Set 4
|
||||
- `305`: Peripheral via Actuator Set 5
|
||||
- `306`: Peripheral via Actuator Set 6
|
||||
- `400`: Landing Gear
|
||||
- `401`: Parachute
|
||||
- `402`: RC Roll
|
||||
- `403`: RC Pitch
|
||||
- `404`: RC Throttle
|
||||
- `405`: RC Yaw
|
||||
- `406`: RC Flaps
|
||||
- `407`: RC AUX 1
|
||||
- `408`: RC AUX 2
|
||||
- `409`: RC AUX 3
|
||||
- `410`: RC AUX 4
|
||||
- `411`: RC AUX 5
|
||||
- `412`: RC AUX 6
|
||||
- `420`: Gimbal Roll
|
||||
- `421`: Gimbal Pitch
|
||||
- `422`: Gimbal Yaw
|
||||
- `430`: Gripper
|
||||
- `440`: Landing Gear Wheel
|
||||
- `450`: IC Engine Ignition
|
||||
- `451`: IC Engine Throttle
|
||||
- `452`: IC Engine Choke
|
||||
- `453`: IC Engine Starter
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_FUNC12 (`INT32`) {#UAVCAN_EC_FUNC12}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 12 Output Function.
|
||||
|
||||
Select what should be output on UAVCAN ESC 12.
|
||||
|
||||
The default failsafe value is set according to the selected function:
|
||||
|
||||
- 'Min' for ConstantMin
|
||||
- 'Max' for ConstantMax
|
||||
- 'Max' for Parachute
|
||||
- ('Max'+'Min')/2 for Servos
|
||||
- 'Disarmed' for the rest
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disabled
|
||||
- `1`: Constant Min
|
||||
- `2`: Constant Max
|
||||
- `101`: Motor 1
|
||||
- `102`: Motor 2
|
||||
- `103`: Motor 3
|
||||
- `104`: Motor 4
|
||||
- `105`: Motor 5
|
||||
- `106`: Motor 6
|
||||
- `107`: Motor 7
|
||||
- `108`: Motor 8
|
||||
- `109`: Motor 9
|
||||
- `110`: Motor 10
|
||||
- `111`: Motor 11
|
||||
- `112`: Motor 12
|
||||
- `201`: Servo 1
|
||||
- `202`: Servo 2
|
||||
- `203`: Servo 3
|
||||
- `204`: Servo 4
|
||||
- `205`: Servo 5
|
||||
- `206`: Servo 6
|
||||
- `207`: Servo 7
|
||||
- `208`: Servo 8
|
||||
- `301`: Peripheral via Actuator Set 1
|
||||
- `302`: Peripheral via Actuator Set 2
|
||||
- `303`: Peripheral via Actuator Set 3
|
||||
- `304`: Peripheral via Actuator Set 4
|
||||
- `305`: Peripheral via Actuator Set 5
|
||||
- `306`: Peripheral via Actuator Set 6
|
||||
- `400`: Landing Gear
|
||||
- `401`: Parachute
|
||||
- `402`: RC Roll
|
||||
- `403`: RC Pitch
|
||||
- `404`: RC Throttle
|
||||
- `405`: RC Yaw
|
||||
- `406`: RC Flaps
|
||||
- `407`: RC AUX 1
|
||||
- `408`: RC AUX 2
|
||||
- `409`: RC AUX 3
|
||||
- `410`: RC AUX 4
|
||||
- `411`: RC AUX 5
|
||||
- `412`: RC AUX 6
|
||||
- `420`: Gimbal Roll
|
||||
- `421`: Gimbal Pitch
|
||||
- `422`: Gimbal Yaw
|
||||
- `430`: Gripper
|
||||
- `440`: Landing Gear Wheel
|
||||
- `450`: IC Engine Ignition
|
||||
- `451`: IC Engine Throttle
|
||||
- `452`: IC Engine Choke
|
||||
- `453`: IC Engine Starter
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_FUNC2 (`INT32`) {#UAVCAN_EC_FUNC2}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10684,6 +10962,80 @@ The default failsafe value is set according to the selected function:
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_FUNC9 (`INT32`) {#UAVCAN_EC_FUNC9}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 9 Output Function.
|
||||
|
||||
Select what should be output on UAVCAN ESC 9.
|
||||
|
||||
The default failsafe value is set according to the selected function:
|
||||
|
||||
- 'Min' for ConstantMin
|
||||
- 'Max' for ConstantMax
|
||||
- 'Max' for Parachute
|
||||
- ('Max'+'Min')/2 for Servos
|
||||
- 'Disarmed' for the rest
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disabled
|
||||
- `1`: Constant Min
|
||||
- `2`: Constant Max
|
||||
- `101`: Motor 1
|
||||
- `102`: Motor 2
|
||||
- `103`: Motor 3
|
||||
- `104`: Motor 4
|
||||
- `105`: Motor 5
|
||||
- `106`: Motor 6
|
||||
- `107`: Motor 7
|
||||
- `108`: Motor 8
|
||||
- `109`: Motor 9
|
||||
- `110`: Motor 10
|
||||
- `111`: Motor 11
|
||||
- `112`: Motor 12
|
||||
- `201`: Servo 1
|
||||
- `202`: Servo 2
|
||||
- `203`: Servo 3
|
||||
- `204`: Servo 4
|
||||
- `205`: Servo 5
|
||||
- `206`: Servo 6
|
||||
- `207`: Servo 7
|
||||
- `208`: Servo 8
|
||||
- `301`: Peripheral via Actuator Set 1
|
||||
- `302`: Peripheral via Actuator Set 2
|
||||
- `303`: Peripheral via Actuator Set 3
|
||||
- `304`: Peripheral via Actuator Set 4
|
||||
- `305`: Peripheral via Actuator Set 5
|
||||
- `306`: Peripheral via Actuator Set 6
|
||||
- `400`: Landing Gear
|
||||
- `401`: Parachute
|
||||
- `402`: RC Roll
|
||||
- `403`: RC Pitch
|
||||
- `404`: RC Throttle
|
||||
- `405`: RC Yaw
|
||||
- `406`: RC Flaps
|
||||
- `407`: RC AUX 1
|
||||
- `408`: RC AUX 2
|
||||
- `409`: RC AUX 3
|
||||
- `410`: RC AUX 4
|
||||
- `411`: RC AUX 5
|
||||
- `412`: RC AUX 6
|
||||
- `420`: Gimbal Roll
|
||||
- `421`: Gimbal Pitch
|
||||
- `422`: Gimbal Yaw
|
||||
- `430`: Gripper
|
||||
- `440`: Landing Gear Wheel
|
||||
- `450`: IC Engine Ignition
|
||||
- `451`: IC Engine Throttle
|
||||
- `452`: IC Engine Choke
|
||||
- `453`: IC Engine Starter
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### UAVCAN_EC_MAX1 (`INT32`) {#UAVCAN_EC_MAX1}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10696,6 +11048,42 @@ Maxmimum output value (when not disarmed).
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MAX10 (`INT32`) {#UAVCAN_EC_MAX10}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 10 Maximum Value.
|
||||
|
||||
Maxmimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MAX11 (`INT32`) {#UAVCAN_EC_MAX11}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 11 Maximum Value.
|
||||
|
||||
Maxmimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MAX12 (`INT32`) {#UAVCAN_EC_MAX12}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 12 Maximum Value.
|
||||
|
||||
Maxmimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MAX2 (`INT32`) {#UAVCAN_EC_MAX2}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10780,6 +11168,18 @@ Maxmimum output value (when not disarmed).
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MAX9 (`INT32`) {#UAVCAN_EC_MAX9}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 9 Maximum Value.
|
||||
|
||||
Maxmimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 8191 | |
|
||||
|
||||
### UAVCAN_EC_MIN1 (`INT32`) {#UAVCAN_EC_MIN1}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10792,6 +11192,42 @@ Minimum output value (when not disarmed).
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_MIN10 (`INT32`) {#UAVCAN_EC_MIN10}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 10 Minimum Value.
|
||||
|
||||
Minimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_MIN11 (`INT32`) {#UAVCAN_EC_MIN11}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 11 Minimum Value.
|
||||
|
||||
Minimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_MIN12 (`INT32`) {#UAVCAN_EC_MIN12}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 12 Minimum Value.
|
||||
|
||||
Minimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_MIN2 (`INT32`) {#UAVCAN_EC_MIN2}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10876,6 +11312,18 @@ Minimum output value (when not disarmed).
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_MIN9 (`INT32`) {#UAVCAN_EC_MIN9}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
|
||||
UAVCAN ESC 9 Minimum Value.
|
||||
|
||||
Minimum output value (when not disarmed).
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 8191 | | 1 | |
|
||||
|
||||
### UAVCAN_EC_REV (`INT32`) {#UAVCAN_EC_REV}
|
||||
|
||||
<Badge type="warning" text="This parameter is only present on some boards." />
|
||||
@@ -10895,10 +11343,14 @@ Note: this is only useful for servos.
|
||||
- `5`: UAVCAN ESC 6
|
||||
- `6`: UAVCAN ESC 7
|
||||
- `7`: UAVCAN ESC 8
|
||||
- `8`: UAVCAN ESC 9
|
||||
- `9`: UAVCAN ESC 10
|
||||
- `10`: UAVCAN ESC 11
|
||||
- `11`: UAVCAN ESC 12
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0 | 255 | | 0 | |
|
||||
| | 0 | 4095 | | 0 | |
|
||||
|
||||
### UAVCAN_SV_DIS1 (`INT32`) {#UAVCAN_SV_DIS1}
|
||||
|
||||
@@ -18210,6 +18662,18 @@ disabled, warn only or deny arming.
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### COM_ARM_ON_BOOT (`INT32`) {#COM_ARM_ON_BOOT}
|
||||
|
||||
Arm automatically on boot.
|
||||
|
||||
When enabled, the vehicle arms automatically once all preflight checks pass after boot.
|
||||
The vehicle will not re-arm after a manual disarm.
|
||||
Has no effect if COM_ARMABLE is 0.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------- | -------- | -------- | --------- | ------------ | ---- |
|
||||
| ✓ | | | | Disabled (0) | |
|
||||
|
||||
### COM_ARM_SDCARD (`INT32`) {#COM_ARM_SDCARD}
|
||||
|
||||
Enable FMU SD card detection check.
|
||||
@@ -21013,7 +21477,7 @@ Required EPH to use GPS.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 2 | 100 | | 3.0 | m |
|
||||
| | 0.1 | 100 | | 3.0 | m |
|
||||
|
||||
### EKF2_REQ_EPV (`FLOAT`) {#EKF2_REQ_EPV}
|
||||
|
||||
@@ -21021,7 +21485,7 @@ Required EPV to use GPS.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 2 | 100 | | 5.0 | m |
|
||||
| | 0.1 | 100 | | 5.0 | m |
|
||||
|
||||
### EKF2_REQ_FIX (`INT32`) {#EKF2_REQ_FIX}
|
||||
|
||||
@@ -21093,6 +21557,49 @@ Maximum vertical drift speed to use GPS.
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0.1 | 1.5 | | 0.2 | m/s |
|
||||
|
||||
### EKF2_RNGBC_CTRL (`INT32`) {#EKF2_RNGBC_CTRL}
|
||||
|
||||
Ranging beacon fusion control.
|
||||
|
||||
Enable/disable ranging beacon fusion.
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disable ranging beacon fusion
|
||||
- `1`: Enable ranging beacon fusion
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### EKF2_RNGBC_DELAY (`FLOAT`) {#EKF2_RNGBC_DELAY}
|
||||
|
||||
Ranging beacon measurement delay relative to IMU measurements.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------- | -------- | -------- | --------- | ------- | ---- |
|
||||
| ✓ | 0 | 1000 | | 0 | ms |
|
||||
|
||||
### EKF2_RNGBC_GATE (`FLOAT`) {#EKF2_RNGBC_GATE}
|
||||
|
||||
Gate size for ranging beacon fusion.
|
||||
|
||||
Sets the number of standard deviations used by the innovation consistency test.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 1.0 | | | 5.0 | SD |
|
||||
|
||||
### EKF2_RNGBC_NOISE (`FLOAT`) {#EKF2_RNGBC_NOISE}
|
||||
|
||||
Measurement noise for ranging beacon fusion.
|
||||
|
||||
Used to lower bound or replace the uncertainty included in the message
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0.1 | 500.0 | | 30.0 | m |
|
||||
|
||||
### EKF2_RNG_A_HMAX (`FLOAT`) {#EKF2_RNG_A_HMAX}
|
||||
|
||||
Maximum height above ground allowed for conditional range aid mode.
|
||||
@@ -21794,7 +22301,7 @@ Also applies to flaperons if enabled in the mixer/allocation.
|
||||
|
||||
Trigger time.
|
||||
|
||||
Launch is detected when acceleration in body forward direction is above FW_LAUN_AC_THLD for FW_LAUN_AC_T seconds.
|
||||
Launch is detected when the norm of body acceleration is above FW_LAUN_AC_THLD for FW_LAUN_AC_T seconds.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
@@ -21804,7 +22311,7 @@ Launch is detected when acceleration in body forward direction is above FW_LAUN_
|
||||
|
||||
Trigger acceleration threshold.
|
||||
|
||||
Launch is detected when acceleration in body forward direction is above FW_LAUN_AC_THLD for FW_LAUN_AC_T seconds.
|
||||
Launch is detected when the norm of body acceleration is above FW_LAUN_AC_THLD for FW_LAUN_AC_T seconds.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ----- |
|
||||
@@ -22597,6 +23104,26 @@ This increment is added to TRIM_YAW when airspeed is FW_AIRSPD_MIN.
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -0.5 | 0.5 | 0.01 | 0.0 | |
|
||||
|
||||
### FW_FLAPS_MAN (`INT32`) {#FW_FLAPS_MAN}
|
||||
|
||||
Flap input in manual flight.
|
||||
|
||||
Chose source for manual setting of flaps in manual flight modes.
|
||||
|
||||
**Values:**
|
||||
|
||||
- `0`: Disabled
|
||||
- `1`: Aux1
|
||||
- `2`: Aux2
|
||||
- `3`: Aux3
|
||||
- `4`: Aux4
|
||||
- `5`: Aux5
|
||||
- `6`: Flaps channel
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | | | | 0 | |
|
||||
|
||||
### FW_GC_EN (`INT32`) {#FW_GC_EN}
|
||||
|
||||
Enable rate gain compression.
|
||||
@@ -22757,6 +23284,10 @@ Chose source for manual setting of spoilers in manual flight modes.
|
||||
- `0`: Disabled
|
||||
- `1`: Flaps channel
|
||||
- `2`: Aux1
|
||||
- `3`: Aux2
|
||||
- `4`: Aux3
|
||||
- `5`: Aux4
|
||||
- `6`: Aux5
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
@@ -28310,6 +28841,19 @@ clockwise, negative for counter-clockwise.
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | -10000 | 10000 | 0.5 | 80.0 | m |
|
||||
|
||||
### NAV_LTR_LAST_DL (`INT32`) {#NAV_LTR_LAST_DL}
|
||||
|
||||
Loiter at last GCS heartbeat position on data link loss.
|
||||
|
||||
When the data link is lost and this setting is enabled,
|
||||
the vehicle will loiter at the position where the last GCS
|
||||
heartbeat was received rather than at its current position.
|
||||
Only applies to Hold mode during failsafe actions.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------------ | ---- |
|
||||
| | | | | Disabled (0) | |
|
||||
|
||||
### NAV_MC_ALT_RAD (`FLOAT`) {#NAV_MC_ALT_RAD}
|
||||
|
||||
MC Altitude Acceptance Radius.
|
||||
@@ -39603,6 +40147,16 @@ This value is usually about few percent of the maximum thrust force.
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0.0 | | 0.05 | 0.1 | Nm |
|
||||
|
||||
### SIH_RNGBC_NOISE (`FLOAT`) {#SIH_RNGBC_NOISE}
|
||||
|
||||
Ranging beacon measurement noise standard deviation.
|
||||
|
||||
Gaussian noise added to simulated ranging beacon measurements. Set to 0 to disable noise.
|
||||
|
||||
| Reboot | minValue | maxValue | increment | default | unit |
|
||||
| ------ | -------- | -------- | --------- | ------- | ---- |
|
||||
| | 0.0 | 100.0 | | 30.0 | m |
|
||||
|
||||
### SIH_T_MAX (`FLOAT`) {#SIH_T_MAX}
|
||||
|
||||
Max propeller thrust force.
|
||||
|
||||
@@ -91,6 +91,28 @@ The feature is configured using the following timeouts.
|
||||
| <a id="COM_DISARM_LAND"></a>[COM_DISARM_LAND](../advanced_config/parameter_reference.md#COM_DISARM_LAND) | Time-out for auto disarm after landing. Default: 2s (-1 to disable). |
|
||||
| <a id="COM_DISARM_PRFLT"></a>[COM_DISARM_PRFLT](../advanced_config/parameter_reference.md#COM_DISARM_PRFLT) | Time-out for auto disarm if too slow to takeoff. Default: 10s (<=0 to disable). |
|
||||
|
||||
## Auto-Arming on Boot
|
||||
|
||||
The vehicle can be configured to arm automatically on boot once all preflight checks pass,
|
||||
using the `COM_ARM_ON_BOOT` parameter. For safety, PX4 enforces a minimum 5-second delay after boot before attempting to arm.
|
||||
|
||||
Once armed this way, the vehicle will not re-arm automatically after a manual disarm.
|
||||
|
||||
::: info
|
||||
The parameter value is read once at boot.
|
||||
Changing it while the system is running has no effect until the next reboot.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
Use with caution.
|
||||
A vehicle that arms automatically can spin up motors and actuators without any operator gesture.
|
||||
Ensure the vehicle is in a safe state before powering on.
|
||||
:::
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| <a id="COM_ARM_ON_BOOT"></a>[COM_ARM_ON_BOOT](../advanced_config/parameter_reference.md#COM_ARM_ON_BOOT) | Arm automatically once preflight checks pass after boot. Default: `0` (Disabled). |
|
||||
|
||||
## Pre-Arm Checks
|
||||
|
||||
To reduce accidents, vehicles are only allowed to arm certain conditions are met (some of which are configurable).
|
||||
|
||||
@@ -409,6 +409,7 @@ They recommend sensors, power systems, and other components from the same manufa
|
||||
- [CUAV Pixhawk V6X Wiring QuickStart](../assembly/quick_start_cuav_pixhawk_v6x.md)
|
||||
- [CUAV V5+ Wiring Quickstart](../assembly/quick_start_cuav_v5_plus.md)
|
||||
- [CUAV V5 nano Wiring Quickstart](../assembly/quick_start_cuav_v5_nano.md)
|
||||
- [CUAV X25 EVO Wiring Quickstart](../assembly/quick_start_cuav_x25_evo.md)
|
||||
- [Holybro Pixhawk 6C Wiring Quickstart](../assembly/quick_start_pixhawk6c.md)
|
||||
- [Holybro Pixhawk 6X Wiring Quickstart](../assembly/quick_start_pixhawk6x.md)
|
||||
- [Holybro Pixhawk 5X Wiring Quickstart](../assembly/quick_start_pixhawk5x.md)
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
# CUAV X25 EVO Wiring Quick Start
|
||||
|
||||
::: warning
|
||||
PX4 does not manufacture this (or any) autopilot.
|
||||
Contact the [manufacturer](https://store.cuav.net/) for hardware support or compliance issues.
|
||||
:::
|
||||
|
||||
This quick start guide shows how to power the [X25 EVO](../flight_controller/cuav_x25-evo.md) flight controller and connect its most important peripherals.
|
||||
|
||||
::: info
|
||||
The following flight controller models are applicable to this quick start guide.
|
||||
[CUAV X25 SUPER](../flight_controller/cuav_x25-super.md)
|
||||
:::
|
||||
|
||||
## Wiring Chart Overview
|
||||
|
||||
The image below shows how to connect the most important sensors and peripherals (except the motor and servo outputs).
|
||||
We'll go through each of these in detail in the following sections.
|
||||
|
||||

|
||||
|
||||
| Interface | **Function** |
|
||||
| :------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| POWER C1/C2 | Connect the PMU2 Lite to this port; this port is used for connecting the DroneCAN power module |
|
||||
| M1 ~ M16 | PWM signal output ports, usable for controlling motors or servos; support 3.3V/5V PWM configuration |
|
||||
| RC IN | Connect remote controller receivers with one-way protocols (e.g., SBUS/DSM/PPM). Note: ELRS/CRSF receivers should be connected to any serial port, not RC IN |
|
||||
| RSSI | For connecting signal strength feedback modules |
|
||||
| GPS&SAFETY | Connect Neo-series GPS or C-RTK-series RTK; this port includes interfaces for GPS, safety switch, and buzzer |
|
||||
| GPS2 | Usable for connecting additional GPS/RTK modules |
|
||||
| DEBUG (DSU) | For FMU chip debugging and reading debug device information; with ArduPilot firmware, it can be configured for other serial port functions |
|
||||
| ADC3V3 | For analog level signal detection; the maximum detectable level signal is 3.3V |
|
||||
| ADC6V6 | For analog level signal detection; the maximum detectable level signal is 6.6V (PX4 is not supported.) |
|
||||
| TF CARD | Insert an SD card here to enable log storage functionality |
|
||||
| ETH | Ethernet port, usable for connecting Ethernet devices such as companion computers |
|
||||
| I2C1/2/3 | Connect external I2C devices (e.g., external compasses) for communication between the controller and I2C devices |
|
||||
| TELEM1/TELEM2 | Connect telemetry modules (for data transmission) to enable MAVLINK data interaction |
|
||||
| CAN1/2 | For communication between the controller and DroneCAN devices (e.g., connecting NEO4 SE GPS) |
|
||||
| TYPE C | USB port of the controller, usable for connecting to the ground station, flashing firmware, and other operations |
|
||||
| SPI6 | SPI port for external expansion; generally not used |
|
||||
|
||||
## Vehicle Front
|
||||
|
||||
::: info
|
||||
If the controller cannot be mounted in the recommended/default orientation (e.g. due to space constraints) you will need to configure the autopilot software with the orientation that you actually used: [Flight Controller Orientation](../config/flight_controller_orientation.md).
|
||||
:::
|
||||
|
||||

|
||||
|
||||
## GPS + Compass + Buzzer + Safety Switch + LED
|
||||
|
||||
We recommend using a CAN GPS/RTK (such as [Neo 4SE](https://store.cuav.net/shop/cuav-neo-4-se-gps-module/)); simply connect it to the **CAN 1** or **CAN 2** port.
|
||||
|
||||
You can also use a standard GPS/RTK module(such as [NEO3 GPS](https://store.cuav.net/shop/neo-3/) (10-pin connector)) by connecting it to the **GPS&SAFETY** port.
|
||||
Most commonly used GPS modules today integrate GPS, compass, safety switch, buzzer, and LED status light.
|
||||
|
||||
If you need to use assisted GPS, connect to the **GPS2** port.
|
||||
|
||||
The GPS/compass should be [mounted on the frame](../assembly/mount_gps_compass.md) as far away from other electronics as possible (separating the compass from other electronics will reduce interference), with the direction markings towards the front of the vehicle (the arrow on the NEO GPS should match the arrow on the flight controller).
|
||||
|
||||

|
||||
|
||||
::: info
|
||||
The GPS module's integrated safety switch is enabled _by default_ (when enabled, PX4 will not let you arm the vehicle).
|
||||
To disable the safety, press and hold the safety switch for 1 second.
|
||||
You can press the safety switch again to enable safety and disarm the vehicle (this can be useful if, for whatever reason, you are unable to disarm the vehicle from your remote control or ground station).
|
||||
:::
|
||||
|
||||
## Radio Control
|
||||
|
||||
A remote control (RC) radio system is required if you want to _manually_ control your vehicle (PX4 does not require a radio system for autonomous flight modes).
|
||||
|
||||
You will need to [select a compatible transmitter/receiver](../getting_started/rc_transmitter_receiver.md) and then _bind_ them so that they communicate (read the instructions that come with your specific transmitter/receiver).
|
||||
|
||||
Connection methods vary by remote controller and receiver type:
|
||||
|
||||
### Android Remote Controllers
|
||||
|
||||
Take the H16 as an example:
|
||||
|
||||

|
||||
|
||||
Connect **TELEM1/TELEM2** to the UART0 port of the H16 remote controller, and link the H16’s SBUS pin to the **RC IN** port.
|
||||
|
||||
### SBUS/DSM/PPM Protocol Receivers
|
||||
|
||||

|
||||
|
||||
Use wires to connect the receiver to the **RC IN** port at the rear of the controller.
|
||||
|
||||
### ELRS/CRSF Receivers
|
||||
|
||||

|
||||
|
||||
Connect the [ELRS/CRSF](../telemetry/crsf_telemetry.md) receiver to any UART serial port of the X25 EVO (e.g., **TELEM2**).
|
||||
|
||||
## Power
|
||||
|
||||
The X25 EVO comes standard with the PMU2 Lite power module, which supports 20–70V input and can measure a maximum current of 220A.
|
||||
It can be directly connected to the **Power C1/C2** port of the X25 EVO and is plug-and-play (no configuration required).
|
||||
|
||||

|
||||
|
||||
## Telemetry (Radio) System
|
||||
|
||||
[Telemetry system](../telemetry/index.md) allows you to communicate with the unmanned system via ground station software, enabling you to monitor and control the UAV’s status during flight. Connect the on-board unit of the telemetry system to the **TELEM1** or **TELEM2** port.
|
||||
|
||||
You can also purchase telemetry radios from the [CUAV store](https://store.cuav.net/uav-telemetry-module/).
|
||||
|
||||

|
||||
|
||||
## SD Card
|
||||
|
||||
SD cards are highly recommended as they are required for [recording and analyzing flight details](../getting_started/flight_reporting.md), running tasks and using UAVCAN bus hardware.
|
||||
An SD card is already installed on X25 EVO when it leaves the factory.
|
||||
|
||||
::: tip
|
||||
For more information see [Basic Concepts > SD Cards (Removable Memory)](../getting_started/px4_basic_concepts.md#sd-cards-removable-memory).
|
||||
:::
|
||||
|
||||
## Motors/Servo
|
||||
|
||||
Motors/servos are connected to the **M1~M16** ports in the order specified for your vehicle in the [Airframe Reference](../airframes/airframe_reference.md).
|
||||
|
||||

|
||||
|
||||
## Servo Power Supply
|
||||
|
||||
The X25 EVO does not supply power to servos. If you need to power servos:
|
||||
|
||||
1. Connect a BEC to the positive and negative terminals of any column among **M1 ~ M16** (the positive and negative terminals of **M1 ~ M16** are interconnected).
|
||||
2. Then connect the servos to the same column.
|
||||
|
||||

|
||||
|
||||
::: info
|
||||
The power rail voltage must be appropriate for the servo being used!
|
||||
:::
|
||||
|
||||
## Other Peripherals
|
||||
|
||||
The wiring and configuration of optional/less common components is covered within the topics for individual [peripherals](../peripherals/index.md).
|
||||
|
||||
## Configuration
|
||||
|
||||
General configuration information is covered in: [Autopilot Configuration](../config/index.md).
|
||||
|
||||
QuadPlane-specific configuration is covered here: [QuadPlane VTOL Configuration](../config_vtol/vtol_quad_configuration.md)
|
||||
|
||||
## Further information
|
||||
|
||||
- [CUAV Docs](https://doc.cuav.net/) (CUAV)
|
||||
- [X25 EVO](../flight_controller/cuav_x25-evo.md) (PX4 Doc Overview page)
|
||||
- [X25 SUPER](../flight_controller/cuav_x25-super.md) (PX4 Doc Overview page)
|
||||
@@ -37,7 +37,7 @@ The wiring for CAN networks is the same for both DroneCAN and Cyphal/CAN (in fac
|
||||
Devices within a network are connected in a _daisy-chain_ in any order (this differs from UARTs peripherals, where you attach just one component per port).
|
||||
|
||||
:::warning Don't connect each CAN peripheral to a separate CAN port!
|
||||
Unlike UARTs, CAN peripherals are designed to be daisy chained, with additional ports such as `CAN2` used for [redundancy](redundancy).
|
||||
Unlike UARTs, CAN peripherals are designed to be daisy chained, with additional ports such as `CAN2` used for [redundancy](#redundancy).
|
||||
:::
|
||||
|
||||
At either end of the chain, a 120Ω termination resistor should be connected between the two data lines.
|
||||
@@ -83,7 +83,7 @@ You only _need_ one CAN port to support an arbitrary number of CAN devices using
|
||||
Don't connect each CAN peripheral to a separate CAN port!
|
||||
:::
|
||||
|
||||
Generally you'll daisy all CAN peripherals off a single port, and if there is more than one CAN port, use the second one for [redundancy](redundancy).
|
||||
Generally you'll daisy all CAN peripherals off a single port, and if there is more than one CAN port, use the second one for [redundancy](#redundancy).
|
||||
If three are three ports, you might use the remaining network for devices that support another CAN protocol.
|
||||
|
||||
The documentation for your flight controller should indicate which ports are supported/enabled.
|
||||
|
||||