Commit Graph

49957 Commits

Author SHA1 Message Date
Jacob Dahl
1435fe2b30 ci(flash-analysis): always post PR comment regardless of diff size (#27473) 2026-05-28 16:12:58 -06:00
ZeroOne-Aero
02b41f81d9 feat(boards/zeroone): Add IIM42652 and BMP581 support for ZeroOneX6 Series V2 (#27475)
* Add TDK IIM42652 IMU and Bosch BMP581 Baro support for ZeroOneX6 Series V2 board
2026-05-28 18:03:43 -04:00
PX4BuildBot
3445a60c38 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 20:03:45 +00:00
Hamish Willee
0b479adb26 docs(docs): Dynamically fetched navbar (#27489) 2026-05-29 05:56:21 +10:00
PX4BuildBot
28ec0e51b3 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 16:53:47 +00:00
0xDI
66058d48b8 fix(simulation): revert SIH wind sign regression from #27376 2026-05-28 18:46:14 +02:00
PX4BuildBot
be1a84440d docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 14:17:37 +00:00
Michael Fritsche
322305b339 fix(failsafe): Inform user about every failsafe triggered (#27273)
* always warn about new less severe failsafes as warning

* Prevent notification of disabled failsafes

---------

Co-authored-by: Matthias Grob <maetugr@gmail.com>
2026-05-28 16:09:57 +02:00
alexcekay
7f48958769 platform(nuttx): update to newest version 2026-05-28 13:42:46 +02:00
mahima-yoga
2e59c98b7c fix(fw_mode_manager): guard course guidance on GUIDED_COURSE nav state
This prevents zero-initialized course setpoints from overriding GCS commanded auto-modes.
2026-05-28 13:35:51 +02:00
PX4BuildBot
5f19d86074 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 07:57:49 +00:00
Hamish Willee
6909ea345f docs(docs): PX4 v1.17 now stable changes (#27485) 2026-05-28 17:50:44 +10:00
PX4BuildBot
240908caea docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 02:28:54 +00:00
Julian Oes
ec8718f05e feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237)
* feat(secure_bootloader): add ed25519 key and signing helpers

Scaffolding for PX4 secure-boot firmware signing, split into two
self-contained scripts:

- generate_signing_keys.py: produces <name>.json (private+public hex)
  for use by sign_firmware.py and <name>.pub (C-array public key)
  for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn.
  Refuses to overwrite existing private-key files.

- sign_firmware.py: pads an input .bin to a 4-byte boundary and
  appends a 64-byte ed25519 signature, producing a file that drops
  directly into the flash slot described by the image TOC.
  Optionally appends an R&D certificate binary after the signature.

Replaces the signing path of the old Tools/cryptotools.py that was
removed along with the log-encryption cleanup; the new layout keeps
bootloader-signing tooling separate from log encryption to avoid
confusing the two independent crypto surfaces.

* fix(bootloader): panic if px4_get_secure_random is ever called

sw_crypto's crypto_open() unconditionally references
px4_get_secure_random from its XCHACHA20 path, so even a bootloader
that only performs ed25519 signature verification (and never touches
stream ciphers) pulls in an undefined symbol at link time.

The app build resolves it through nuttx_random.c, which is gated
behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the
NuttX random pool is enabled. That config isn't on in the tiny
bootloader NuttX defconfig, and enabling it would pull in a pile
of kernel code the bootloader doesn't need.

Supply the symbol locally, but make it call up_assert() instead of
returning zeros. Silently handing out predictable bytes would be a
serious security bug if anyone later enables the XCHACHA20 path in
the bootloader without wiring up a real RNG. Aborting makes the
mistake impossible to miss.

* fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check

Today a signed-boot failure is invisible to the uploader: verify_app()
runs inside jump_to_app() after PROTO_BOOT has already rebooted the
chip, so the host sees a successful upload followed by the device
silently staying in the bootloader. There is no protocol-level signal
that the image that was just written is not going to run.

Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run
find_toc() + verify_app(0) *before* the reboot and get a concrete
OK / FAILED / INVALID answer back over the still-open USB connection.
The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built
without secure boot return cmd_bad (INSYNC/INVALID) so an uploader
can tell "I don't know this command" apart from "verification failed".

Two subtleties required care:

1. PROG_MULTI deliberately defers the very first word of the app
   image to a RAM variable (first_word) and only commits it to flash
   inside PROTO_BOOT, so a partial upload can never become bootable.
   But verify_app() reads directly from flash, so if we verified
   before committing first_word, even a valid image would always
   fail (the first four bytes at APP_LOAD_ADDRESS would still be
   0xffffffff). The handler therefore mirrors the first half of the
   PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the
   deferred first word, then run the crypto check.

2. On failure we deliberately do not try to "undo" the first-word
   write — H7 flash programming granularity makes it impossible to
   revert in place, and the device was going to end up in the same
   reject state at the next boot either way. The improvement is
   purely that the uploader sees the failure before REBOOT instead
   of after.

Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and
0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which
an AP-compatible uploader might.

ArduPilot also has bootloader secure boot (monocypher ed25519, like
us) but their verification runs at boot time, not upload time — so
neither project currently solves the "upload silently wrote a bad
image" problem. This puts PX4 ahead on that.

* feat(Tools): add --image_signed to mark signed firmware for uploader

px_uploader.py only needs to run signature verification over USB for
images that actually carry a signature — asking the bootloader to
verify an unsigned image would always fail, and the extra round trip
is wasted time for the common unsigned case. It therefore needs a
reliable way to tell the two apart.

We cannot tell by inspecting the bytes: a sign_firmware.py output is
just the raw .bin with 64 bytes of ed25519 signature glued on the
end, indistinguishable in content from an unsigned image of the same
padded length. The natural place to put the flag is the .px4 JSON
envelope, which already carries board_id / version / summary / etc.

Add --image_signed to px_mkfw.py, which sets "image_signed": true
in the emitted JSON. The flag has no effect on what bytes actually
end up on the device — it just tells the uploader "this blob has a
signature, please verify it before booting".

* feat(Tools): verify firmware signature before reboot

After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to
the bootloader to check the ed25519 signature over the freshly
flashed image *before* sending REBOOT. This way a signature failure
is reported as a clean error from the uploader script, instead of a
silent "device stays in bootloader after reboot" that leaves the user
guessing.

The uploader always probes VERIFY_SIG. The bootloader is the source
of truth for whether secure boot is enabled:

- INSYNC/OK         -> verification passed, proceed to REBOOT
- INSYNC/FAILED     -> raise; "Signature does not verify against any
                       trusted key" if the firmware claims to be signed,
                       "Secure bootloader rejected an unsigned image"
                       otherwise (= helpful guidance for the common
                       misconfiguration of uploading default firmware
                       to a secureboot bootloader)
- INSYNC/INVALID    -> bootloader has no secure boot. Quietly proceed
                       unless the firmware metadata says image_signed,
                       in which case raise.
- recv timeout      -> assume a pre-VERIFY_SIG bootloader, proceed.

Surfaces a "Verifying image signature... passed" line on the upload
status path when the firmware is marked signed, so users get a clear
positive signal that the secure-boot pipeline ran end-to-end.

Also drop the redundant logger.error in the upload() loop, which was
duplicating the error message printed by the top-level handler in
main() for every UploadError path (not specific to verify_signature,
but only became obvious once these clean error messages started
firing in normal usage).

* fix(cmake): fix .px4board variant resolution to require exact match

px4_config.cmake matched the requested CONFIG against each candidate
.px4board with `MATCHES`, which is a regex partial match. For a
config like `px4_fmu-v6x_bootloader_secureboot`, the iteration over
.px4board files (alphabetical glob order) would match
`bootloader.px4board` first — because "px4_fmu-v6x_bootloader" is a
prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently
selecting the wrong board config.

Use `STREQUAL` instead so each candidate has to match the full
requested CONFIG. Existing single-label cases (e.g. exact match on
`px4_fmu-v2_default` or `px4_fmu-v2`) are unaffected because they
were already exact in practice; this just plugs the prefix-match
hole that any future `<label>_<suffix>` variant would trip over.

* fix(nuttx): support bootloader_<variant> labels

Boards can ship bootloader variants beyond the default `bootloader`
label — e.g. a `bootloader_secureboot` that adds crypto + keystore
Kconfig on top of the same source tree. Two pieces of build glue
were hardcoded to the exact label `bootloader` and need to relax to
match any `bootloader_*` label:

1. platforms/nuttx/CMakeLists.txt picked the bootloader linker
   script and bootloader-specific library list only when the label
   was exactly `bootloader`. Any other label (including
   `bootloader_secureboot`) silently fell through to the app build,
   producing nonsensical link flags. Match `^bootloader` instead,
   and explicitly set SCRIPT_PREFIX to `bootloader_` so all
   bootloader variants share the single existing linker script
   regardless of their full label.

2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config
   subdirectory by exact label match, falling back to `nsh` when no
   matching directory exists. For `bootloader_secureboot` that fell
   through to `nsh`, dragging in a full app-style NuttX with cromfs,
   networking, and the full heap subsystem — a 128 KB bootloader
   sector overflowed by ~50 KB. Add an intermediate fallback: if the
   label starts with `bootloader` and a `bootloader/` subdir exists,
   use that instead of `nsh`.

Both changes are backward-compatible: existing single-label
`bootloader` builds take exactly the same path as before. They only
gain the ability for boards to add `bootloader_<suffix>.px4board`
files without duplicating bootloader build wiring.

* feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT

Add a Kconfig pair that boards can opt into:

  CONFIG_BOARD_SECUREBOOT      -- bool: sign the .px4 with ed25519
  CONFIG_BOARD_SECUREBOOT_KEY  -- string: path to JSON private key
                                  (default: Tools/test_keys/test_keys.json)

When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py
step between the unsigned .bin and px_mkfw.py, and passes --image_signed
so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG
step. The unsigned .bin is still produced alongside the .px4, so users
can sign with their own key out-of-tree if they prefer.

A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path
at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn
in stub_keystore. This makes release builds practical:

  BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot

Relative paths in the Kconfig are resolved against the repo root (not
the build directory) so the same value works regardless of where the
build runs from.

Default builds are byte-identical to before; the new code path is gated
on CONFIG_BOARD_SECUREBOOT being set.

* feat(boards): add secureboot demo variant + docs

Two coordinated build variants demonstrate end-to-end secure boot
on px4_fmu-v6x without touching the default builds:

  px4_fmu-v6x_secureboot              -- the app, with TOC + signing
  px4_fmu-v6x_bootloader_secureboot   -- the matching secure bootloader

App side (secureboot.px4board):
  - Selects nuttx-config/scripts/secureboot-script.ld via
    CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default
    layout plus a fixed 0x800 reservation past the vector table for
    the image TOC, and an empty .signature section at end-of-FLASH
    so sign_firmware.py knows where the appended ed25519 signature
    will land.
  - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the
    layout used elsewhere in the tree) into drivers_board, gated on
    PX4_BOARD_LABEL == secureboot so the default build still
    produces the existing layout.
  - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the
    image with the upstream test key by default.

Bootloader side (bootloader_secureboot.px4board):
  - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE,
    which links monocypher and the stub keystore into the bootloader.
  - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired
    with the test_keys.json the app variant signs with.
  - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM
    (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO,
    so they only activate in this variant.

Together the two variants implement the workflow:

  make px4_fmu-v6x_bootloader_secureboot     # build + flash via SWD once
  make px4_fmu-v6x_secureboot upload         # signs with test key, verifies

Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections
stripping the unused libtomcrypt code; nothing in the bootloader
binary depends on monocypher beyond the ed25519 verifier.

Replace the bundled test key for production with
Tools/secure_bootloader/generate_signing_keys.py output and update
both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) —
see docs/en/advanced_config/bootloader_secure_boot.md.

* fix(boards): cap H7 bootloader linker scripts at 128 KB

Roughly half of the H7 boards in tree had `LENGTH = 2048K` for the
bootloader sector in their bootloader_script.ld, even though the
matching app linker script places APP_LOAD_ADDRESS at 0x08020000 —
i.e. the bootloader actually only owns the first 128 KB sector.

The 2048K constraint is wrong: it lets a bootloader that grew past
the 128 KB sector silently overflow into the app sector at link
time and corrupt the start of the app on flash. The linker should
fail the build instead.

The current default bootloader is ~46 KB, well under 128 KB on every
affected board, so this change is a no-op for default builds. It
just plugs a footgun for anyone adding bootloader features (secure
boot, extra UI, network boot, ...) that would have otherwise
silently grown into the app's flash range.

Boards fixed:

  3dr-style H7 reference boards: cubepilot/cubeorange,
    cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7
  vendor variants: corvon/743v1, cuav/nora, cuav/x7pro,
    gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1,
    matek/h743, matek/h743-mini, matek/h743-slim,
    micoair/h743, micoair/h743-aio, micoair/h743-lite,
    micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2

Boards already correct (LENGTH = 128K) are unchanged.

* fix(ci): add pynacl to Python requirements

Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519
signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT
calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot).
Without pynacl in the dev requirements, those builds fail in CI and
fresh dev setups.

* docs(update): Subedit

* docs(update): Fix example error I made

* fix(docs): document BOOT and SIG1 regions

* fix(platforms): style fix

* fix(ci): workaround to get pip dependency

* fix(ci): fall back to plain pip on older build containers

The voxl2 build image ships a pip that predates --break-system-packages
(added in pip 23.0.1), so the install step blew up with "no such option".
Modern containers enforce PEP 668 and need the flag; older ones don't
support it but also don't enforce PEP 668, so plain pip works there.
Try the modern flag first, fall back if pip rejects it.

Signed-off-by: Julian Oes <julian@oes.ch>

* fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build

cmake-build was passing the full build-dir name (including any
BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which
the board-lookup in cmake/px4_config.cmake then tried to match
against <vendor>_<model>_<label> .px4board files. That used to work
by accident because px4_config.cmake matched with regex MATCHES, but
since the switch to STREQUAL (needed to disambiguate
bootloader_secureboot from bootloader) the suffixed CONFIG no longer
matches anything and LABEL ends up empty, tripping a CMake error in
kconfig.cmake.

Pass the bare CONFIG and keep the suffix only on the build dir so
both concerns are independent.

Signed-off-by: Julian Oes <julian@oes.ch>

---------

Signed-off-by: Julian Oes <julian@oes.ch>
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
2026-05-27 20:21:49 -06:00
PX4BuildBot
0acdaacf86 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 01:59:55 +00:00
Jonas Perolini
29903b1a63 docs(vte): fix rendering in equations (#27471) 2026-05-28 11:51:52 +10:00
PX4BuildBot
788172984d docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 01:03:58 +00:00
Hamish Willee
dfc08eed28 docs(docs): Link fixes, _sidebar, uorb docs generator tweak (#27482) 2026-05-28 10:44:16 +10:00
PX4BuildBot
19b2d01fd1 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-28 00:38:25 +00:00
Hamish Willee
ac5a6a9602 chore(update): Mavlink update (#27476) 2026-05-28 12:30:48 +12:00
PX4BuildBot
0390c5473b docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 21:52:50 +00:00
PX4 Build Bot
23892992aa docs(i18n): PX4 guide translations (Crowdin) - zh-CN (#27479)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-05-28 07:44:55 +10:00
PX4 Build Bot
091ab6f978 docs(i18n): PX4 guide translations (Crowdin) - uk (#27450)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-05-28 07:36:47 +10:00
PX4BuildBot
816958245e docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 13:02:07 +00:00
Balduin
fb4f564f69 fix(fw_latlon_control): compensate TECS min airspeed for load factor (#27441)
* fix(fw_latlon_control): compensate TECS min airspeed for load factor

TECS was given the load factor but not the minimum airspeed, derived
from the performance model.

TECS itself does the eas/tas conversion (altitude compensation) but not
load factor or weight compensation, which is the responsibility of the
performance model.

Use set_equivalent_airspeed_min to update the latter, compensated for
load factor, whenever attitude updates. Currently it is only called on
param change, so TECS has a min airspeed based on outdated load factor
and flap setpoint.

* fix(fw_latlon_control): do not update tecs min airspeed on param update

As we are updating it on every attitude sample now we can and should
remove this -- as this calculates the load factor based on the attitude
setpoint but the newly added continuous update is based on the actual
attitude, the two would conflict and introduce spikes.
2026-05-27 14:40:54 +02:00
PX4BuildBot
9720b797aa docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 10:42:32 +00:00
Silvan Fuhrer
cd89fe9967 docs(docs): MC remove mention of removed smoothVel POS_MODE (#25913) 2026-05-27 20:34:51 +10:00
gguidone
52cf7f3918 fix(fmu-v5x): use single EKF on Skynode 2026-05-27 11:44:47 +02:00
PX4BuildBot
e0f7f2129c docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 09:23:30 +00:00
Matthias Grob
b76ff83576 docs(rover): fix rover simulation command (#27423) 2026-05-27 19:13:32 +10:00
PX4BuildBot
440ff999fa docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 08:59:41 +00:00
mahima-yoga
963d837c33 docs: add docs on new guided course mode 2026-05-27 10:51:55 +02:00
mahima-yoga
8b3ef1cf9e feat(navigator): add Guided Course mode for fixed-wing
Implements a new GUIDED_COURSE navigator mode that maintains a constant
ground-track bearing, altitude, and airspeed without manual stick input.
The mode is activated via MAVLink and accepts real-time in-flight updates:
  - MAV_CMD_GUIDED_CHANGE_HEADING (HEADING_TYPE_COURSE_OVER_GROUND): set course
  - MAV_CMD_DO_CHANGE_ALTITUDE: adjust target altitude
  - MAV_CMD_DO_CHANGE_SPEED: adjust target airspeed

On activation the vehicle captures its current velocity vector as the
initial course bearing. A valid horizontal velocity estimate (GPS or
dead-reckoning) is required; course commands are rejected if unavailable.
2026-05-27 10:51:55 +02:00
PX4BuildBot
e89d7a2dd2 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 07:55:33 +00:00
Hamish Willee
ac4efcf83e docs(docs): Ark6s shrink images (#27477) 2026-05-27 17:47:37 +10:00
PX4BuildBot
be784e21f7 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-27 02:57:43 +00:00
Eurus
b52464059e fix(mavlink): preserve invalid battery values on receive (#27467) 2026-05-26 20:50:55 -06:00
Hamish Willee
b6ca5d8c77 docs(tools): Fixes for uorb docs generation (#27474)
* docs(tools): uORB parser: Comma separate multiple enums
* docs(tools): uORB parser: Backlink from enum to field
* docs(tools): uORB parser: index.md section for historic versions
* docs(tools): uORB parser: summary fragment to ease updates
2026-05-27 10:59:44 +10:00
PX4BuildBot
cd286ee1fe docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-26 22:57:32 +00:00
Andrii Anoshyn
9b25102c2c fix(mavlink): don't derive multicopter yaw from LOITER_TIME param4 (#27455)
For MAV_CMD_NAV_LOITER_TIME the parser used param4 both as the loiter
exit cross-track flag and as a multicopter yaw setpoint
(wrap_2pi(radians(param4))). Per the MAVLink spec param4 only selects the
loiter-circle exit behavior for forward-only vehicles and is not a yaw
field, so a ground station following the spec (e.g. param4=1 to request a
tangent exit) unintentionally forced a multicopter heading and could trip
the yaw-reached timeout.

Set yaw to NAN instead, so multicopters keep their current heading and no
heading is enforced; get_yaw_to_be_accepted() already treats a non-finite
yaw as reached. The exit cross-track flag is unchanged, and fixed-wing
behavior is unaffected (yaw is always considered reached there). The
download path already maps param4 to the exit cross-track flag, so it
stays consistent.

Fixes #27287

Signed-off-by: Andrii Anoshyn <anoshyn.andrii@gmail.com>
2026-05-26 16:50:15 -06:00
PX4BuildBot
92f0836605 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-26 20:30:37 +00:00
Jacob Dahl
773967b547 docs(arkv6s): add flight controller documentation (#27383)
* docs(arkv6s): add flight controller documentation

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

* docs(arkv6s): add product photo and note single-IMU variant

Drop in docs/assets/flight_controller/arkv6s/ark_v6s_front.jpg
so the page renders the board photo it already references, and
align the intro with the upstream description by spelling out
that the V6S is the single-IMU variant of the V6X.

* docs(arkv6s): add bootloader UART note, fix arkv6x RAM typo

Add the bootloader serial port note (TELEM1-only in bootloader mode)
to the ARKV6S docs, matching the ARKV6X docs. Also fix the ARKV6X
MCU spec listing "1MB Flash" instead of "1MB RAM".

---------

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-05-26 14:23:11 -06:00
PX4BuildBot
5f28520527 docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-26 20:05:00 +00:00
Jacob Dahl
c894945f15 fix(optical_flow): report actual integration timespan in PAW3902/PAA3905 (#27418)
* fix(optical_flow): report actual integration timespan in PAW3902/PAA3905

The chip accumulates delta_x/delta_y in its burst registers until the
Motion_Burst register is read, which clears the accumulator. The drivers
previously reported a hardcoded mode-dependent SAMPLE_INTERVAL_MODE_X as
the integration timespan regardless of how long ago the last burst read
happened.

This is wrong any time reads span more than one frame period - most
commonly when the Motion DRDY pin doesn't fire (chip detected no motion)
and the backup watchdog fires the read kBackupScheduleIntervalUs (20 ms)
later instead of every frame.

Downstream, VehicleOpticalFlow uses integration_timespan_us to size the
gyro integration window used for body-rate compensation, and ekf2's
_flow_gyro_bias estimator compares that gyro against the IMU at the
matched delayed time. A wrong window length misaligns the gyro
compensation with what the chip actually saw, and slowly biases
_flow_gyro_bias - contaminating motion-reported fusions on the
correctly-timed DRDY path too.

Replace the hardcoded value with the actual interval between consecutive
successful burst reads (clamped to a sane range). _timestamp_sample_last
is reset on driver Reset() and updated on every successful burst read
regardless of publish, since the chip clears its accumulator on every
read.

* refactor(optical_flow): use _ms literals for integration_timespan_us clamp

Replace raw 1000/200000 microsecond bounds with 1_ms/200_ms to match
the existing time_literals convention already used elsewhere in these
drivers. No behavior change.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

---------

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-05-26 13:53:59 -06:00
Jacob Dahl
659ab6b400 fix(dshot): pick bit width per timer clock for accurate rate (#27402)
Auto-selects DSHOT_MOTOR_PWM_BIT_WIDTH per timer clock at compile time
so ARK FPV emits DSHOT at the same bit period as the rest of the fleet.
The hardcoded WIDTH=20 truncates the prescaler on ARK FPV's 160 MHz APB1
(PLL1N=40, floor(160e6/600e3)=266 not divisible by 20), giving a 1.706us
bit period and 66.7%/33.3% duty cycles (vs DSHOT600 spec 75%/37.5%).

The new ladder tries WIDTH in {20, 19, 18} and picks the first that
divides cleanly. ARK FPV lands on W=19, matching the 1.75us bit period
of the 240 MHz boards. Duty cycles improve to 70%/35%. 240/96/108/84 MHz
boards keep W=20 (unchanged). 200 MHz boards (CubeOrange/Orange+,
h7extreme) fall through to W=20 (unchanged, fix needs W=22 with scaled
BIT_1/BIT_0 -- out of scope).

A #pragma message (not #warning, which -Werror=cpp would treat as an
error) flags boards where APB1 and APB2 timer clocks would emit DSHOT
at different rates -- currently only fmu-v4pro (APB1=90, APB2=180 MHz).
The whole block is guarded on STM32_APB2_TIM8_CLKIN so STM32F1 IO
co-processor boards (no TIM8, header still pulled in by io_timer.c)
keep W=20 silently.

Supersedes #27401.
2026-05-26 13:53:31 -06:00
Jacob Dahl
3ebc6d6a40 fix(ekf2): publish HAGL variance in dist_bottom_var (#27349)
* fix(ekf2): report HAGL variance for dist_bottom_var

dist_bottom_var was published as P(terrain, terrain) only. When the
range finder is the EKF height reference (EKF2_HGT_REF=2), the terrain
state is reset to 0 and not directly observed, so this variance does
not represent the actual uncertainty of dist_bottom (HAGL).

Use ComputeHaglInnovVar(P, 0) to report the proper HAGL variance,
which accounts for terrain state, vertical position state, and their
covariance.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

* fix(ekf2): clamp HAGL variance to non-negative

H*P*H^T should be >= 0 for a valid covariance, but float drift or
mildly non-PSD P can produce a tiny negative result. Clamp at the
accessor so consumers of lpos.dist_bottom_var never see a negative
variance.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

---------

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-05-26 13:52:17 -06:00
Jacob Dahl
ad26499a36 refactor(ina226): rewrite driver for robustness and clarity (#27364)
* refactor(ina226): rewrite driver for robustness and clarity

Mirrors the INA238 rewrite (#27359):

- Non-blocking UNINITIALIZED -> RESET -> CONFIGURE -> MEASURE state
  machine. Each transition is its own RunImpl tick with an explicit
  ScheduleDelayed; init failures retry without losing the driver
  instance.
- Tolerate ~2 s of consecutive collect() failures
  (MAX_CONSECUTIVE_FAILURES = DISCONNECT_DEBOUNCE_US / SAMPLE_INTERVAL_US)
  before a full reinit. Isolated I2C glitches just skip a cycle instead
  of dropping battery_status.
- SAMPLE_INTERVAL_US = 100 ms, comfortably above the default ADC period
  of ~75.3 ms (588 us * 2 channels * 64 avg). MEASURE compensates for
  in-tick I2C time so each tick is exactly one interval apart.
- CONFIGURE waits SAMPLE_INTERVAL_US + 5 ms before the first MEASURE
  read so the first averaged sample is ready.
- checkConfigurationRotating() reads one of {CONFIGURATION, CALIBRATION}
  per cycle and compares it against the value we wrote, so an externally
  reset device is detected within two cycles.
- '-t' arg validated against 1-3 at parse time; out-of-range values now
  exit with an error.
- New perf counters ina226_bad_register and ina226_reinit for field
  diagnosis; current driver state is surfaced in 'ina226 status'.

File layout: ina226_main.cpp folded into ina226.cpp. Constants/enums
namespaced under ina226. Params switched to DEFINE_PARAMETERS, and the
INA226_CONFIG raw-register override is removed in favor of a hardcoded
continuous-conversion config.

AuterionAutostarter::ina226_probe() updated to the new namespaced
ina226::Register and ina226::MANFID / ina226::DIEID constants.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

* fix(ina226): mask reserved bits when verifying CONFIGURATION register

The INA226 CONFIGURATION register has D15 (RST) self-clearing and
D14:D12 reserved, with D14 reading back as 1 regardless of what is
written. The verify step compared the raw read-back to the value
we wrote, so the check failed on every cycle and the driver
re-initialized itself every ~2 s. Mask the non-R/W bits before
comparing.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

---------

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-05-26 13:51:44 -06:00
Jacob Dahl
98ed6adafc refactor(ina238): rewrite driver for robustness and clarity (#27359)
Address customer-reported dropouts traced to several issues in the
prior driver:

- A single transient I2C blip flipped _initialized=false and re-ran
  probe()+Reset() inline on the next tick, losing most of a sample
  period on every isolated glitch.
- start() scheduled the first collect() ~100 ms after the device reset
  (INA238_SAMPLE_INTERVAL_US - 7 us), but the first averaged conversion
  takes 540 us x 3 channels x 64 samples ~= 103.7 ms -- so the first
  read sometimes hit post-reset zeros.
- The CONFIG register watchdog used set_bits/clear_bits that both
  collapsed to 0 in HIGH ADC range, making it a no-op for the default
  range. (ADCCONFIG and SHUNT_CAL were still checked.)
- setConnected(false) could fire up to three times per failed cycle
  (collect, register-check branch, RunImpl else), collapsing the
  intended ~2 s debounce.
- -t (battery index) was parsed with no range check; out-of-range
  values silently clamped to 1 inside Battery.

Rewrite:

- Non-blocking UNINITIALIZED / RESET / CONFIGURE / MEASURE state
  machine. Each step is its own RunImpl tick with an explicit
  ScheduleDelayed; init failures retry without losing the driver
  instance.
- Tolerate ~2 s of consecutive collect() failures
  (MAX_CONSECUTIVE_FAILURES = DISCONNECT_DEBOUNCE_US /
  SAMPLE_INTERVAL_US) before triggering a full reinit; isolated
  glitches just skip a cycle.
- SAMPLE_INTERVAL_US = 105 ms, just above the 103.68 ms ADC conversion
  period so we stop polling faster than the device produces samples.
  MEASURE compensates for in-tick I2C time so each tick is exactly
  SAMPLE_INTERVAL_US apart.
- CONFIGURE waits SAMPLE_INTERVAL_US + 5 ms before the first MEASURE
  read, comfortably above the first averaged conversion.
- checkConfigurationRotating() reads one config register per cycle and
  compares it against the value actually written, so an externally
  reset device is detected within three cycles regardless of ADC range.
- -t arg validated against 1-3 at parse time; out-of-range values now
  exit with an error.
- New perf counters ina238_bad_register and ina238_reinit. Driver
  state is also surfaced in 'ina238 status'.
- File layout: ina238_registers.hpp folded into ina238.h,
  ina238_main.cpp folded into ina238.cpp. Constants and enums namespaced
  under ina238. Params switched to DEFINE_PARAMETERS.
- RESET state publishes documented invalid sentinels (current = -1,
  temperature = NaN) instead of valid-looking zeros.



fix(ina238): pass literal i2c address to usage macro

PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS feeds its argument through the
module documentation parser's int(eval(...)) path, which only resolves
Python literals. The constexpr BASEADDR identifier crashed
make module_documentation with NameError. Match the convention in
sibling power_monitor drivers (ina220/ina226/ina228) and pass 0x45.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-05-26 13:51:32 -06:00
Jacob Dahl
bb013a69d3 docs(arkv6x): note bootloader UART7/TELEM1 mapping (#27429)
* docs(arkv6x): note bootloader UART7/TELEM1 mapping

The ARKV6X bootloader enables only UART7 (TELEM1), but the existing
serial port table reflects the runtime mapping where /dev/ttyS0 is
GPS1. Users flashing firmware over UART with px_uploader.py hit a
dead end when targeting GPS1 because no other UART responds in
bootloader mode.

* docs(arkv6x): fix uploader script name and add link

Script is named px4_uploader.py in the Tools directory; link to it
on GitHub so readers can find it.
2026-05-26 13:50:47 -06:00
PX4BuildBot
108785423d docs: auto-sync metadata [skip ci]
Co-Authored-By: PX4 BuildBot <bot@px4.io>
2026-05-26 17:37:56 +00:00