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.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
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>
PR #27324 swapped find_package(PythonInterp) for find_package(Python3),
whose macOS defaults (FRAMEWORK=FIRST, STRATEGY=VERSION) override
Python3_ROOT_DIR and PATH to resolve the highest-versioned framework
Python. CI then matched Homebrew's 3.14 while pip installed kconfiglib
into the actions/setup-python 3.10 venv, breaking `make px4_sitl`
configure with "No module named menuconfig".
Pin Python3_EXECUTABLE to .venv/bin/python when present (macos.sh
creates the venv but neither it nor CI exports VIRTUAL_ENV), and set
FIND_STRATEGY=LOCATION + FIND_FRAMEWORK=LAST so dev machines and Linux
containers without a venv still pick the interpreter that has the
project's pip dependencies.
* fix(ci): wipe NuttX submodule state between boards in build_all_runner
NuttX .o and lib*.a live in the shared submodule trees under
platforms/nuttx/NuttX/{nuttx,apps}, not in per-board build/<board>/.
NuttX's recursive make doesn't treat PX4's per-board defconfig changes
as a reason to recompile, so consecutive board builds in one workspace
were linking stale objects from an earlier board (e.g. stm32_spi.o from
fmu-v2 linked into fmu-v4pro, which doesn't enable SPI4).
Run git clean -dXf on both NuttX submodules between iterations to drop
gitignored build state. This mirrors what make clean already does for
submodules and preserves the incremental-build wins for single-board
use.
* fix(cmake): isolate kernel mm/libc objects with BINDIR=kbin
mm and libs/libc compile the same sources for both the kernel and user
passes in protected builds. Without separate output dirs the kernel
objects clobber bin/*.o and the user-mode libmm.a/libc.a end up pulling
in kernel-only symbols (nxsem_wait, g_current_regs, nx_read, nx_write,
g_mmheap, ...) at link time. Matches NuttX's own tools/LibTargets.mk.
On boards with a slow startup sequence (e.g. FMU-V6XRT), the health
checks run before load_mon and ekf2 have published their first message,
producing spurious "Preflight Fail" entries in dmesg.
Gate the cpuload and estimator_status checks on
uORB::Subscription::advertised(). While the topic has never been
advertised the publisher has not started yet, so skip the check
silently. Once advertised, missing or stale data is reported as before
so real failures are still caught.
Signed-off-by: SofianElmotiem <sofianelmotiem@gmail.com>
Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(cmake): use Python3 module; cache PYTHON_EXECUTABLE properly
The legacy `find_package(PythonInterp 3)` is deprecated (warned with
noisy CMP0148 by cmake 3.27+, currently visible on Ubuntu 24.04 CI
runs).
It also stores its result as PYTHON_EXECUTABLE without a proper CACHE
type, which interacts badly with the Makefile's `cmake-cache-check`.
`cmake -L` skips UNINITIALIZED entries, so the
`-DPYTHON_EXECUTABLE=...` passed by the top-level Makefile is never
matched in the cache and every invocation forces a full reconfigure.
Switch to `find_package(Python3 COMPONENTS Interpreter REQUIRED)`,
then bridge to the legacy `PYTHON_EXECUTABLE` name that the rest of
the codebase still references.
Promote it to a CACHE FILEPATH entry so cmake -L lists it, preserving
any user-supplied value verbatim (find_package(Python3) canonicalises
e.g. bin/python3 to bin/python3.13, defeating a string-based cache
match).
Signed-off-by: Daniel Fanache <dan@rts.ro>
* fix(cmake): promote CONFIG to CACHE STRING for incremental builds
When CONFIG is passed via `-DCONFIG=...` on the cmake command line, it
is stored as an UNINITIALIZED cache entry. `cmake -L` skips
UNINITIALIZED entries by design, so the Makefile's
`cmake-cache-check` (which uses `cmake -L` to diff desired vs cached
options) never finds CONFIG in the output, concludes the cache is
stale, and triggers a full reconfigure on every `make <target>`
invocation.
If a config identifier is given, we force promote it to CACHE
STRING. This preserves the user supplied value as it was, while making
it visible to `cmake -L`, so the cache-check succeeds when nothing has
changed.
Signed-off-by: Daniel Fanache <dan@rts.ro>
* fix(cmake): track default.px4board as a configure dependency
Non-default labels merge `default.px4board` + `{label}.px4board` via
`merge_config.py`, but only the label file was listed as a configure
dependency. Changes to `default.px4board` were silently ignored until
a clean build, which is surprising and easy to debug for hours.
Register `default.px4board` as a CMAKE_CONFIGURE_DEPENDS in the
non-default-label branch so edits trigger reconfigure as expected.
Signed-off-by: Daniel Fanache <dan@rts.ro>
* fix(cmake): correct NuttX apps/library build dependency tracking
Three dependency graph defects in the libapps.a and per NuttX library
custom_commands caused either spurious full rebuilds or stale outputs
on incremental builds.
(1) `builtin_list.h` and `builtin_proto.h` are regenerated by the apps
build from `px4.bdat`/`px4.pdat` on every invocation. They were
included in `nuttx_apps_files`, so on each build we saw them as
changed inputs and re-triggered the apps target perpetually. Exclude
them with a `list(FILTER)`.
(2) libapps.a's custom_command lacked `px4.bdat`/`px4.pdat` as
dependencies, so module additions or renames (which regenerate those
registries) did not propagate to a rebuild of the builtin command
table. Add them to DEPENDS.
(3) NuttX's recursive make does not always notice that
`builtin_list.h` has been regenerated and that `builtin_list.c`
therefore needs recompiling. Touch `builtin_list.c` so NuttX's make
picks up the indirect change.
Additionally, drop the destructive cleanup COMMANDs that ran at the
start of libapps.a and each per-library custom_command (`remove
-f *.a`, `find ... -delete *.o`). These were workarounds for the now
fixed dependency tracking; without them removed, they would also force
unnecessary full rebuilds every time.
Signed-off-by: Daniel Fanache <dan@rts.ro>
---------
Signed-off-by: Daniel Fanache <dan@rts.ro>
Co-authored-by: Ramon Roche <mrpollo@gmail.com>
* fix(ekf2): use variance for yaw observations
* docs(ekf2): fix EKF2_EVA_NOISE unit comment
The parameter is a 1-sigma angle noise in rad (matching the unit
declared in params_external_vision.yaml and the squaring done in
EKF2.cpp), not an angular rate.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Pulls in PX4/PX4-GPSDrivers#211 (astyle fixes: trailing whitespace in
sbf.cpp, missing brace-init space in ubx.h) so PX4-Autopilot's
make check_format passes on astyle 3.x.
* feat(crsf_rc): add CRSF receiver bind command
Add ability to initiate CRSF receiver binding from QGroundControl or
the NSH console. When MAV_CMD_START_RX_PAIR is received with
RC_TYPE_CRSF, the driver sends the CRSF bind command frame over UART.
Binding is rejected when armed or on singlewire configurations.
Also adds RC_TYPE and RC_SUB_TYPE constants to VehicleCommand.msg and
replaces magic numbers in DsmRc and RCInput drivers.
Based on PX4/PX4-Autopilot#23294.
* style(crsf_rc): use C++ style comment
* style(crsf_rc): zero-init vcmd, remove noisy comments, drop unused enum value
* fix(rc): check write return value in BindCRSF, guard Spektrum bind against invalid sub-type
* fix(rc): warn and deny invalid Spektrum bind sub-type
Previously, an unrecognized param2 sub-type would silently leave
dsm_bind_pulses at 0 and return the generic UNSUPPORTED ACK. Add an
explicit else-branch that logs a PX4_WARN and returns DENIED so users
get clear feedback in QGC.
Set CONFIG_STM32H7_DTCMEXCLUDE=y on the four STM32H7 ARK boards
(fmu-v6x, fmu-v6s, fpv, pi6x) so DTCM is no longer part of the kernel
heap. Stacks and dynamic buffers can otherwise land in DTCM, which AHB
DMA masters (SDMMC IDMA, MDMA, BDMA, DMA1/2) cannot access, causing file
operations to fail with EIO/ETIMEDOUT.
Refs PX4/PX4-Autopilot#27242.
An empty mission is the normal "no mission loaded" state, not a rejected
mission. check_mission_valid() runs in the background whenever its trigger
conditions change, so logging this as a critical mavlink/event spammed
QGC even when the pilot was not in mission mode and had no mission on
board. The commander already surfaces auto_mission_missing through the
arming checks when mission mode is actually requested.
The committed ark_fmu-v6s_bootloader.bin was built before BOARD_TYPE was
set to 61 in src/hw_config.h, so it advertises board id 57 (the v6x id)
to px_uploader. Uploading any v6s firmware then fails with:
Board mismatch: No suitable firmware for board 57 (available: [61])
Rebuild the bootloader from the current source so the binary reports
board id 61 and matches firmware.prototype.
* chore(boards): copy ark/fmu-v6x to ark/fmu-v6s
Verbatim copy of ark/fmu-v6x board support to ark/fmu-v6s to
establish a baseline. Functional changes will follow in the next commit.
* feat(boards): add ark/fmu-v6s board support
Low-cost variant of ARK V6X with:
- STM32H743IIK6 MCU (no hardware crypto)
- Single IIM-42653 IMU on SPI1 (SPI2/SPI3 removed)
- IIS2MDC magnetometer on I2C4
- BMP390 barometer on I2C4
- Single sensor power rail
Board ID 61, USB PID 0x003C.
* feat(px4_uploader): add ARK FMU v6s USB ID to the uploader
* refactor: rename SENS_IMU_TEMP to HEATER1_TEMP in rc.board_defaults
* refactor: remove unused ADC channel definitions in board_config.h
* refactor: update ADC channel definitions and remove unused sensor power control
* arkv6s sensor roations
* Add support for Murata SCH16T IMU in default.px4board configuration
* Update bootloader binary for FMU v6s
* Update boards/ark/fmu-v6s/src/hw_config.h
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Update boards/ark/fmu-v6s/src/hw_config.h
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(ark/fmu-v6s): enable CONFIG_CRYPTO for encrypted_logs build
CONFIG_CRYPTO_RANDOM_POOL was set without its parent CONFIG_CRYPTO,
so it was silently dropped and px4_get_secure_random was compiled out,
breaking the ark_fmu-v6s_encrypted_logs link.
---------
Co-authored-by: alexklimaj <alex@arkelectron.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
I2CBusIterator::external() was returning px4_i2c_bus_external(_bus),
where _bus is the constructor filter argument (the user's -b value,
which defaults to -1 when no bus is specified). When a driver was
started with -I and no -b (e.g. iis2mdc -I start, bmp388 -I start),
_bus stayed -1, px4_i2c_bus_external(-1) fell through to its "not
found" fallback that returns true, and the boot log printed
"on I2C bus 4 (external)" for sensors sitting on an internal bus.
Pass bus().bus instead so the result reflects the bus the iterator
is currently positioned on. This mirrors SPIBusIterator::external()
and restores the pre-8080ca966a8 semantics.
Device::external() (the override used by sensors status and
calibration) already used the device id's bus number, so only the
boot-time print was wrong.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Coverage overlaps with mavsdk_tests on iris (mission + offboard
posctl); MAVROS plugin behavior belongs to the MAVROS project.
Drops the workflow, .test launchers, rostest_px4_run.sh, and the
integrationtests/ python helpers.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* docs(releases): draft v1.17.0 release notes
Drafts the v1.17.0 release notes based on commits in the
release/1.16..release/1.17 diff, with every PR citation verified as an
ancestor of release/1.17 and not shared with release/1.16.
Major Changes leads with the experimental MC Neural Network Control
mode and the on-device TFLM integration, the new Altitude Cruise mode
for multicopters, FW Takeoff improvements, FW and Rover ROS 2 Control
Interface setpoints, and the in-tree Zenoh middleware maturing toward
rmw_zenoh compatibility.
Hardware Support is reorganized into four sub-groups: New Flight
Controllers, New Build Targets for Existing Hardware, New CAN
Peripherals & Vehicle Platforms, and Existing Boards: Improvements.
The Simulation section is split into Gazebo and SIH sub-groups. The
ROS 2 / DDS section is split into uXRCE-DDS and Zenoh.
Posted on main as a draft to give docs maintainers visibility and
collect review feedback. Backport strategy to release/1.17 (alpha/beta
banner variant vs the stable banner variant on main) is a follow-up
discussion.
Also fixes a long-anchor scroll-restoration bug in
px4_ros2_control_interface.md by giving the FwLateralLongitudinal
heading an explicit short anchor (#fw-lateral-longitudinal-setpoint),
and updates the corresponding link in releases/main.md.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* docs(releases): address review on v1.17.0 notes
- Cross-link Altitude Cruise in the intro paragraph.
- Reframe MC Neural Network Control as an experimental test path
rather than first-class on-device inference; move it to the bottom
of Major Changes.
- Drop the redundant "opt-in" wording from the Zenoh Major Changes
bullet.
- Rewrite Upgrade Guide as a true upgrade procedure (actionable
numbered steps with what to do and why) following the v1.14 release
notes pattern instead of a flat parameter-delta list.
- Add the missing PR reference for the extended MISSION_CURRENT entry
(#25034, populating the MAVLink mavlink/mavlink#1869 fields).
- Dedupe Safety / Commander against Common: failsafe takeover,
Offboard-to-Position-without-RC, and motor-failure timeout checks
are now listed only once in Common.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
---------
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Restart the Micro-XRCE-DDS Agent before each integration test so DDS
graph state from a previous PX4 instance does not leak into the next
test.
The MicroXRCEAgent is started once per session, but PX4 reboots between
tests. The Agent retains writer entries from the previous PX4, so when
the new PX4 reconnects, count_publishers() in px4-ros2-interface-lib's
waitForFMU returns >0 immediately against a stale entry. Phase 1
(discovery) returns instantly, then Phase 2 (heartbeat) times out
waiting for a message on a subscription matched to a dead writer.
This is why ModesTest.denyArming (first test) passes while every later
ModesTest fails with "timeout while waiting for FMU heartbeat".
Adds an optional pre_test_hook on test_runner.Tester so ROS-specific
lifecycle stays out of the shared test_runner. The workflow stops
starting the Agent externally; ros_test_runner.py owns the lifecycle.
Refs #27328
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* feat(gpsRedundancyCheck): add GPS redundancy failsafe with divergence check
- Monitors GPS count and triggers configurable failsafe (COM_GPS_LOSS_ACT) when count drops below SYS_HAS_NUM_GPS
- Tracks online (present+fresh) and fixed (3D fix) receivers separately; emits "receiver offline" vs "receiver lost fix"
- Detects position divergence between two receivers against combined RMS eph uncertainty plus lever-arm separation
- Pre-arm warns immediately; in-flight requires 2s sustained divergence to suppress multipath false alarms
- Adds GpsRedundancyCheckTest functional test suite
New parameters: SYS_HAS_NUM_GPS, COM_GPS_LOSS_ACT
* feat(sensor_gps_sim): publish second GPS instance using SENS_GPS1 lever arm params
When SENS_GPS1_OFFX or SENS_GPS1_OFFY is non-zero, publish a second sensor_gps instance offset by those values from the vehicle position.
fix(sensor_gps_sim): give second instance distinct device_id
Both simulated GPS instances previously shared the same device_id (address 0x00). This prevented testing the device-ID matching path in SITL since both slots would match the same receiver.
* refactor(gpsRedundancyCheck): address code review feedback
* refactor(gpsRedundancyCheck): address code review feedback
* docs: add GNSS check failsafe documentation
Update safety.md and releases/main.md to document the new GNSS check
failsafe (SYS_HAS_NUM_GNSS, COM_GPS_LOSS_ACT) introduced in PX4.
* docs(update): Subedit to taste
* refactor(gps): move GNSS redundancy detection into sensors module
Add GnssRedundancyStatus topic and GnssRedundancyMonitor in
vehicle_gps_position. Commander's gpsRedundancyCheck becomes a thin
consumer of the new topic. Detection lives with blending/fallback in
one module.
Also rename COM_GPS_LOSS_ACT -> COM_GNSS_LSS_ACT.
* docs(safety): clarify GNSS failsafe wording and rename COM_GNSS_LSS_ACT
* refactor(failsafe): consistent default case as fallback for existing option
* Rename COM_GNSS_LSS_ACT -> COM_GNSSLOSS_ACT
for readability
* fix(gnssRedundancyCheck): move logic back into the commander checks and various improvement suggestions
- Rename to GNSS instead of gps
- Use hysteresis
- Small logic refactorings
- Adapt unit tests to different interface
- User reporting on which GPS is offline or doesn't have a fix
* docs(gnssRedundancyCheck): simplify explanations
* refactor(gnssRedundancyCheck): update year numbers in copyright
---------
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
Co-authored-by: Matthias Grob <maetugr@gmail.com>
* fix(navigator): guard terrain altitude check for position mission items
updateAltToAvoidTerrainCollisionAndRepublishTriplet() calls
get_absolute_altitude_for_item() on the current mission item without first
checking whether the item contains a position.
For non-position mission items, the altitude field has no setpoint meaning.
Using it in the terrain descent condition can make the check operate on an
invalid mission-item altitude.
Add the same item_contains_position() guard used by other mission altitude
handling paths before reading the mission item altitude.
* navigator: remove redundant mission item checks
Remove checks already covered by item_contains_position() and update the
terrain avoidance comment to match the current condition.
* SITL: mavlink bind to a specific interface using an environment variable PX4_NET_INTERFACE
Fixes issue #26384
* document the usage of PX4_NET_INTERFACE
* Improved Docs:
- Added new Environment Configuration subsection at the end of SITL Simulation
- Removed the old Bind MAVLink to Specific Network Interface subsection (content consolidated into the new section)
---------
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>