* docs(contributing): discourage force-pushing during review
A force-push after review has begun erases the commits a reviewer has read, so they cannot see what changed since. The guidance told contributors to squash and reword instead, which contradicts the commit and pr agent skills. PRs are typically squash-merged, so branch history does not need cleaning up before merge.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* ci(workflows): remove commit message check
PRs are squash-merged under the PR title, which is still checked. Flagging the individual commits pushed contributors to rewrite history mid-review.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Queue unwritten stdin instead of dropping it when a request is larger
than the pipe can take at once, and drain the queue without blocking
the CAN work queue. Only stdin needs to stay nonblocking (it's written
from that work queue); stdout reads stay blocking, gated on FIONREAD,
like the mavlink shell already does.
Report a shell session that has exited as an explicit error instead of
silently swallowing EPIPE and returning empty output. Surface that
error in the Python client as well.
Flush the queued stdin on idle polls too, not just when new input
arrives, since an idle poll is all the client sends while the user
isn't typing. Only redirect fd 0/1 for the child once both stdio
backups succeeded, so a dup() failure can't leave the node's own
stdin/stdout pointing into the shell pipes. Distinguish EAGAIN (retry
later) from EPIPE (never will succeed) when flushing queued stdin, so
a dead shell doesn't hold the queue forever refusing new input.
Only compile the shell sources when CONFIG_UAVCANNODE_COMMAND_SHELL is
enabled, matching how every other optional uavcannode feature is
gated, instead of pulling nshlib into every board's image. Detect a
dead shell task with nxsched_get_tcb(), the same lookup top/cpuload.cpp
use, instead of a POSIX-only helper with no NuttX implementation. Fix
GetNodeInfo name decoding in the client to tolerate non-UTF-8 bytes
instead of crashing the scan.
Signed-off-by: danielbuleandra <daniel.buleandra@auterion.com>
The workflow triggers on pull requests that touch a board defconfig or
the USB ID tooling, and checks only the defconfigs the PR adds or
modifies. The file list comes from diffing the checked-out PR merge
commit against its base parent, so no API call or token is needed. A PR that changes the tooling itself is checked against every
board, so a checker change is proven on the real tree and not only by
its unit tests. A test keeps the tooling list and the workflow paths
filter in sync.
A manual run checks every board. There is no push or scheduled run: the
registry repo checks its own changes against PX4 main, and board
changes reach main only through PRs.
The mypy and flake8 step for the checker and runner lives in
python_checks.yml with the other Python tooling checks.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Boards that ship the Dronecode USB vendor ID 0x3643 must use a product
ID allocated in the Dronecode/usb-ids registry, and nothing in the tree
enforces that. A board reusing another board's PID, or picking an
unallocated one, becomes ambiguous to host tools that identify boards
by VID/PID.
The contract is the registry mapping: a defconfig under
boards/<vendor>/<board>/ using VID 0x3643 must use a registered PID
whose px4_board is exactly <vendor>/<board>. The USB vendor string is
deliberately not checked, since the registry does not govern it. Boards
on other vendor IDs are ignored.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Every px4_add_git_submodule call ran check_submodules.sh twice, at
configure and build time, and with CI=true force-updated each submodule
every time, a 2017 workaround for an interactive prompt that is gone.
VS Code and CLion force-updated too, resetting submodule changes under
development.
The check now runs once per configure. A missing submodule is fetched;
one at another commit is kept as it is, with a warning locally and an
error in CI.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Some boards heartbeat from more than one component on the same sysid. An
FMUv6X-RT on v1.17 sends HEARTBEAT from compid 1 (PX4) and from compid 236
with autopilot=MAV_AUTOPILOT_INVALID. connect() accepted the first
heartbeat from anyone and left target_component at pymavlink's default of
0, so param and mission requests went out as broadcast, the other
component could answer, and param_stress mixed its PARAM_VALUE stream
(index, count, values) into the autopilot's download.
connect() now waits for a heartbeat whose autopilot is not
MAV_AUTOPILOT_INVALID and pins target_system/target_component to its
source. pymavlink only latches target_system once and never sets the
component, so the pin holds for the life of the connection. The
wait_heartbeat() helper shares that filter and, once pinned, only counts
the pinned component; wait_reconnect() goes through connect() and gets
the same behavior after a reboot.
PARAM_VALUE replies in px4bench.params, param_stress and link_forwarding
are filtered to the pinned component, and flight_mission uses the pinned
component for MAVFTP and the armed/disarmed heartbeat checks instead of a
hardcoded 1.
Diagnosed by @farhangnaderi in #27852.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The 1.17 run in #27840 read 'SDLOG_UTC_OFFSET not found in downloaded
set' as the parameter not existing on that release. It does exist there;
the download itself was the anomaly (19 params total, where a booted
board reports hundreds, since the autopilot lists used params only).
Name the downloaded count and that semantics in the failure so the next
tiny param set is diagnosed as a degraded session, not a missing param.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
log_transfer crashed with a raw ImportError on setups whose pymavlink
predates the mavftp module (#27840). mavftp first shipped in pymavlink
2.4.42, so raise the floor in pyproject.toml, Tools/setup/requirements.txt
and the README, and guard the import in px4bench.ftp so an old install
reports a clear upgrade hint instead of a traceback. Both mavftp
consumers now import it through the guard.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Running the suite from main against a release/1.17 FMUv6X-RT board
(#27840) failed boot_health and flight_mission at 'shell open' while
reboot_loop passed the same check 10/10 in the same run. The failing
opens were the sessions immediately following a closed one, so the
single wake write was being consumed before the firmware nsh pipes were
reading and no amount of waiting could recover it. Re-send the wake
write every second until the deadline, strip stale BENCHOPEN wake lines
from subsequent command output, and replace the 5s hardcoded at every
call site with one px4bench.SHELL_OPEN_TIMEOUT (10s) so the budget is
tunable in one place.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Each build job compiled its group one target at a time, and the serial
parts of every build (configure, the NuttX make, linking) left the 4-vCPU
runners about half idle. Two concurrent builds keep them around 80% busy
and cut total build-step time about 24% and runner cost about 17%.
Larger runners and more slots were measured and cost more than they save.
build_all_runner.py replaces build_all_runner.sh. NuttX compiles inside
its source tree, so each extra slot is a git worktree under .build_slots/.
All submodules are fetched once before building, each slot clones them
locally from the checkout, and builds run with GIT_SUBMODULES_ARE_EVIL=1
so CMake's per-configure submodule check does not sync and update them
concurrently on the shared .git/config. Targets that write the same
build/ directory (<board>_deb with <board>_default, the metadata targets
with px4_sitl_default) always share a slot, and the runner refuses a plan
that would split them. Every target is built even after a failure. Build
output streams with a [seconds|slot target] prefix, each target prints its
memory usage or, on failure, the excerpt from the first error, and a Build
Logs step prints each target's full log as one collapsed group. Slot build
directories are moved into build/, so packaging is unchanged.
The matrix now carries targets as a list plus a slot count from
build_all_config.yml; the comma-joined string existed only because
workflow expressions could not pass an array to a shell command, which
join() now does. The scan job runs new tests for the generated matrix and
the slot assignment.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Homebrew rebuilds and drops the gz bottles whenever homebrew-core bumps
protobuf or abseil, which breaks the macOS Gazebo install until the pins
catch up. conda-forge keeps every package it has published, so
Tools/setup/macos/pixi.toml and its lock install the same gz, protobuf,
abseil, OpenCV and GStreamer binaries until the lock is updated on
purpose. OpenCV is the headless build, and GStreamer brings the good,
bad and ugly plugin sets the gz camera plugin's pipeline uses.
macos.sh installs the environment with pixi and loads it from the venv
activation through a small script, since pixi shell-hook would export
the installing shell's PATH. The build and the gz launch do not depend
on that activation: CMake searches the environment like it pins the
.venv Python, and px4-rc.gzsim sources gz_env.sh before it looks for
gz, which loads the environment when it is not already active and puts
its lib dir ahead of Homebrew's in the dyld fallback path.
conda-forge's gz-transport13 does not pull in cppzmq, so the manifest
lists it.
The osrf/simulation pin, the protobuf pin and the weekly bot that
refreshed them are removed. The homebrew-core commit moves into
homebrew-pins.txt unchanged.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
PX4 SIH with the Hawkeye visualizer replaces jMAVSim, in SITL and as the
display-only viewer for SIH running on hardware. Drop the jMAVSim
submodule, its make targets, px4-rc.jmavsim, the 10017_jmavsim_iris
airframe and the VS Code debug helpers, stop installing Java and ant in
the macOS and Arch setup scripts, and point the remaining mentions at SIH
and Hawkeye.
BREAKING CHANGE: make px4_sitl jmavsim and SYS_AUTOSTART 10017 no longer
exist. Use make px4_sitl_sih sihsim_quadx with Hawkeye instead.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Build all targets / Scan for Board Targets (push) Canceled after 0s
Build all targets / Seed [${{ matrix.chip_family }}] (push) Canceled after 0s
Build all targets / Build [${{ matrix.runner }}][${{ matrix.group }}] (push) Canceled after 0s
Build all targets / Upload Artifacts (push) Canceled after 0s
Checks / Gate Checks [check_format] (push) Canceled after 0s
Checks / Gate Checks [check_newlines] (push) Canceled after 0s
Checks / Gate Checks [module_documentation] (push) Canceled after 0s
Checks / Gate Checks [shellcheck_all] (push) Canceled after 0s
Checks / Gate Checks [validate_module_configs] (push) Canceled after 0s
Checks / Unit Tests (push) Canceled after 0s
MacOS build / build (push) Canceled after 0s
Ubuntu environment build / Build and Test (ubuntu:22.04) (push) Canceled after 0s
Ubuntu environment build / Build and Test (ubuntu:24.04) (push) Canceled after 0s
Container build / Set Tags and Variables (push) Canceled after 0s
Container build / Build Container (amd64) (push) Canceled after 0s
Container build / Build Container (arm64) (push) Canceled after 0s
Container build / Deploy To Registry (push) Canceled after 0s
Failsafe Simulator Build / build (failsafe_web) (push) Canceled after 0s
ITCM check / Checking nxp_mr-tropic (push) Canceled after 0s
ITCM check / Checking nxp_tropic-community (push) Canceled after 0s
ITCM check / Checking px4_fmu-v5x (push) Canceled after 0s
ITCM check / Checking px4_fmu-v6xrt (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (humble, amd64, ros2-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (humble, amd64, ros2-gazebo-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (jazzy, amd64, ros2-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (jazzy, amd64, ros2-gazebo-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (humble, arm64, ros2-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (humble, arm64, ros2-gazebo-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (jazzy, arm64, ros2-dev) (push) Canceled after 0s
ROS Development Container / Build ROS Development Image (jazzy, arm64, ros2-gazebo-dev) (push) Canceled after 0s
ROS Development Container / Publish Multi-Architecture ROS Development Image (humble, ros2-dev) (push) Canceled after 0s
ROS Development Container / Publish Multi-Architecture ROS Development Image (humble, ros2-gazebo-dev) (push) Canceled after 0s
ROS Development Container / Publish Multi-Architecture ROS Development Image (jazzy, ros2-dev) (push) Canceled after 0s
ROS Development Container / Publish Multi-Architecture ROS Development Image (jazzy, ros2-gazebo-dev) (push) Canceled after 0s
ROS Integration Tests / build (push) Canceled after 0s
ROS Translation Node Tests / Build and test [humble] (push) Canceled after 0s
ROS Translation Node Tests / Build and test [jazzy] (push) Canceled after 0s
SITL Tests / Testing PX4 quadx (push) Canceled after 0s
SITL Tests / Testing PX4 standard_vtol (push) Canceled after 0s
SITL Tests / Testing PX4 hex (push) Canceled after 0s
SITL Tests / Testing PX4 xvert (push) Canceled after 0s
FLASH usage analysis / Analyzing px4_fmu-v2 (push) Canceled after 0s
FLASH usage analysis / Analyzing px4_fmu-v5x (push) Canceled after 0s
FLASH usage analysis / Analyzing px4_fmu-v6x (push) Canceled after 0s
Python CI Checks / build (push) Canceled after 0s
FLASH usage analysis / Publish Results (push) Canceled after 0s
Static Analysis / Clang-Tidy (push) Canceled after 0s
* feat(ci): report flash and RAM use against capacity, analyze fmu-v2
The size comment showed only the delta, which does not say how close a target is to its limit. Capacity comes from the board's own linker script, because the flash-analysis build links against an oversized flash region so that a change which overflows still gets a report.
fmu-v2 adds an F4 next to the F7 and H7 targets, and with 1 MB of flash it is the FMU that overflows first.
Assisted-by: Claude:claude-opus-5-5
* fix(ci): shorten the size comment's usage columns
Five columns with capacities spelled out made the table too wide to read at a glance.
Assisted-by: Claude:claude-opus-5-5
The commit hash compiled into px4_firmware_version_binary() changes its code size, so a PR with no code change reported -8 B on v6x and got a comment. Changes that only touch agent instructions also no longer build the targets.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): report flash and static RAM usage separately
Bloaty's VM total includes zero-initialized RAM and understates the combined cost of data and code copied from flash into RAM. Report the flash load image and static RAM allocations independently so the PR headline reflects each resource's actual change.
Assisted-by: Codex
* docs(ci): trim memory analysis comment
Assisted-by: Codex
* fix(ci): diff PR flash usage against the merge commit's base
The base branch tip is fetched when the job runs, so a PR merged while its job was queued was compared against itself and reported a near-zero change, and commits landed in the meantime showed up as reverted.
* fix(ci): measure flash image from section headers
ld maps the ELF header into the first LOAD segment when its max page size exceeds the flash origin's alignment (binutils 2.34 defaults to 64 KiB), so segment-based accounting rejected valid firmware as outside the flash region.
* feat(ci): flag notable flash and RAM changes
Growth over 100 B and 1000 B gets yellow and red markers, savings over 100 B green, so reviewers can spot size regressions without reading the numbers.
* refactor(ci): derive flash and RAM totals without per-target constants
The matrix duplicated each board's flash-analysis linker region, which would drift silently. Section headers alone distinguish code executing in place (VMA == LMA) from data copied to or reserved in RAM, and the image span matches objcopy -O binary.
* fix(ci): limit the bloaty breakdown to VM sizes
Debug, symbol and string table rows only change the file size and made up most of the comment.
* fix(ci): post flash analysis only when size changes
A push that puts flash and static RAM back to zero was still rewriting the sticky comment, so a PR with no size change carried a zero report. Remove that comment instead. Fork tokens cannot delete it, so those PRs hand a delete artifact to the poster.
Assisted-by: Grok:grok-4.7
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): retain zero-delta flash analysis comments
Existing reports can be updated when size deltas return to zero, avoiding a separate privileged deletion path.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Assisted-by: Codex:gpt-6
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
The schema path still says component_information/, so --skip-if-no-schema makes the check a no-op. QGC only accepts parameter metadata version 1, while the schema floor rose for optional fields. Override that floor and keep emitting version 1.
Assisted-by: Grok:4.7
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
The job ran brew update and then installed whatever Homebrew was publishing, except Gazebo, which stayed on one commit. Those were built against different protobufs, so a release upstream failed the build with no commit here. Check the package repos out at commits recorded in the tree and do not update them. Run on macos-15 only, so the OS label cannot move either.
Assisted-by: Grok:grok-4.7
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
The build runs brew update and then pours Gazebo from one pinned tap commit while the rest of the install, including protobuf, comes from current Homebrew. A release in either repo fails the check with no commit here, and the GitHub-hosted image moves on its own, so the job cannot be a closed set. Drop the build and the weekly pin refresh. The setup script, the pins, and the refresh script stay for local use.
Assisted-by: Grok:grok-4.7
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Every gz .pb.h refuses to compile against anything but the exact protobuf
its gencode came from, so the bottles gz-tap-pin.txt holds osrf/simulation
at only build against the protobuf homebrew-core shipped the day OSRF built
them. homebrew-core moves protobuf on its own schedule and OSRF rebuilds
days later, so `make px4_sitl` has been failing on macOS on every branch
since homebrew-core shipped protobuf 36.2.
Pin protobuf as well, to the homebrew-core revision that installs the
version the pinned gz bottles carry, and derive that pin from the bottles
themselves so the two can never disagree. A protobuf release then becomes a
no-op here instead of days of red CI while OSRF catches up.
The pinned install has to run after the other simulation packages and with
the dependents check off: opencv@4 depends on protobuf too, brew resolves a
dependency against the versions recorded in the dependent's bottle, and it
reinstalls dependents whose linkage it has just broken. Pinning the formula
with `brew pin` is not an option either, brew then refuses to install
anything that depends on it.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
* fix(macos.sh): trust brew taps before tapping them
Recent Homebrew validates every formula of a tap while tapping it. On
Homebrew 6.0+ loading a formula from an untrusted tap is refused, so
`brew tap osx-cross/arm` and `brew tap PX4/px4` now fail with
"Cannot tap ...: invalid syntax in tap!" because `brew trust` only ran
afterwards. Without the PX4/px4 tap, `brew install` aborts on `fastdds`
before pouring any package, ccache included, and the macOS CI job dies
with `ccache: command not found`. main has been red since 2026-09-14.
Run `brew trust` before `brew tap`; it accepts taps that are not
installed yet.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(macos.sh): trust osrf/simulation tap before tapping it
Same ordering problem as the toolchain taps: with Homebrew 6.0+ tapping
an untrusted tap fails, so there is no tap clone to apply the
gz-tap-pin.txt pin to. The later install of
osrf/simulation/gz-harmonic then taps it implicitly at HEAD, silently
skipping the pin and risking Gazebo building from source.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
* fix(macos.sh): set -e to abort on first failure
The script kept going after a failed `brew tap` or `brew install`, so
the macOS CI job only failed much later with `ccache: command not
found`, far away from the actual cause.
Add `set -e`. Commands that are allowed to fail (`brew uninstall flock`
on a machine without it, `brew doctor` warnings, fetching the gz tap pin
whose failure is already handled by the following checkout) get an
explicit `|| true`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Signed-off-by: Julian Oes <julian@oes.ch>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Julian Oes <julian@oes.ch>
Docs - Orchestrator / T2: Link Check (push) Canceled after 0s
Docs - Orchestrator / T3: Build Site (push) Canceled after 0s
Docs - Orchestrator / T4: Deploy (push) Canceled after 0s
FLASH usage analysis / Publish Results (push) Canceled after 0s
Static Analysis / Clang-Tidy (push) Canceled after 0s
* feat(ros2): add Humble development images and distro releases
Build Humble on Jammy without replacing its ROS DDS libraries: Agent 2.4.3
links private, pinned Fast DDS/CDR dependencies. Publish Humble and Jazzy
tags independently while leaving packaged runtime images Jazzy-only.
Assisted-by: Copilot:gpt-6-astra
* refactor(ros2): share pinned Agent DDS libraries across distros
Build the Agent against the same private Fast DDS and Fast CDR pins on Humble and Jazzy, without replacing either ROS underlay. Remove distro-specific build branches and name the dependency manifest for its shared role.
Assisted-by: Copilot:gpt-6-astra
The NWBlue Pro H757 is a 30x30 mm FPV flight controller built around the
CubePilot CubeNode H757 module: STM32H757, on-module ICM45686 IMU and
on-carrier DPS368 baro on SPI3, IIS2MDC magnetometer on I2C3, microSD on
SDMMC2, 9 DShot/PWM outputs, CAN1 and six UARTs.
Pin assignments follow the ArduPilot NWBLUE_PROH757 hwdef, including board
ID 5730. The sensor rotations do not: the hwdef specifies ROTATION_ROLL_180
for the IMU, but on this hardware both the IMU and the magnetometer are
unrotated, confirmed on the bench and by compass calibration.
PLL1P runs at 480MHz so the timer clock is 240MHz, which DShot600 divides
into exactly 20 ticks per bit. At 400MHz that division truncates and every
bit comes out 4.2% short, which some ESCs reject. Bidirectional DShot works
on every output except FMU_CH6: that one is TIM4_CH4, and the H7 DMAMUX has
no request line for it.
Timers: TIM1/2/3/4 drive the outputs, TIM8_CH3 the buzzer so a passive
piezo produces a real tone, TIM12 the HRT and TIM6 the uavcan clock. TIM5
is deliberately left unallocated - the HRT does not work there (every
periodic work item runs once and is never rescheduled, while
interrupt-driven peripherals keep going so the board still looks alive),
and it is also the H7 default for the uavcan clock, where it kept DroneCAN
from coming up.
There is no analog OSD chip, so an HD VTX has to render the OSD itself over
MSP DisplayPort on the VTX connector (USART6 / TEL2). MSP_OSD_CONFIG is
left unset so that port can equally serve as a plain TEL2.
px4_uploader learns the board's USB ID (CubePilot VID 0x2DAE, PID 0x2001).
bringup.md records what has been verified on hardware and what has not.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Julian Oes <julian@oes.ch>
Make the standalone ROS toolchain available from the same registries as the ROS runtime images. Preserve opt-in publication, existing GHCR tags and both architecture SBOM indexes.
Assisted-by: Copilot
Provide a supported Jazzy environment for SIH/Gazebo development and source builds, with pinned tooling and reproducible multi-architecture image publishing. Separate package and container assets from ROS source preparation, and keep checkout workspaces fresh through a Python CLI.
Assisted-by: Copilot:gpt-6-astra
* feat(mavlink): serve packed parameters as @PARAM/param.pck
QGC already downloads ArduPilot parameters as a packed FTP file, which
is much more reliable on lossy SiK links than the PARAM_VALUE firehose.
Serve the same format from PX4 so a hash miss can use that path.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(mavlink): serialize the full message when resending a cached FTP reply
_last_reply caches only the header, PayloadHeader and four data bytes,
but the resend path handed that 19-byte array to the serializer as a
complete mavlink_file_transfer_protocol_t, which reads 254 bytes and
transmits whatever follows the cache. The decoded request is dead once
the resend decision is made, so expand the cache into it instead of
adding another message to the receiver thread's stack. Clear the unused
payload before caching so a resent NAK matches the original.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* test(mavsdk_tests): download parameters via MAVLink FTP
Fetch @PARAM/param.pck through MAVSDK's burst download on SIH and check
every entry against the PARAM_VALUE stream, so the packed format and the
FTP server's session, size and EOF handling stay covered by the SITL
tests that QGC and MAVSDK both rely on.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(mavlink): cache FTP Open ACKs whose size LSB is 5
_reply skipped the compact cache whenever data[0] was kErrNoSessionsAvailable. On a NAK that is the error code; on an Open ACK it is the file size LSB. A lost Open ACK for param.pck of that length was retried as a second Open and failed.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(tools): download packed parameters over MAVFTP
Host-side check of @PARAM/param.pck against the PARAM_VALUE stream.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(mavlink): pad so a defaulted value does not straddle an FTP block
pack() kept the last 4 bytes of an entry in one chunk. With withdefaults those bytes are the default, so the value can still split. QGC always requests defaults; a hole-fill then retries one chunk with a live param_get().
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(mavlink): snapshot param.pck at open so a param_set cannot corrupt it
Pack the used set once into a heap buffer. Reads memcpy that snapshot, so a value change during the download cannot shift later entries or splice two generations across a retried FTP block.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(mavlink): freeze param.pck membership instead of snapshotting the file
Keep which parameters appear and whether each includes a default in bitsets (~1 KB). Pack values live. Layout cannot shift mid-download; a retried block cannot splice a number.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* style(mavlink): format MavlinkFtpParamTest.cpp
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* refactor(mavlink): keep FTP work buffers as members
@PARAM/param.pck is a connect-time path, not the rare path the lazy new[] was for. send() could free the buffers after 2 s of no request while a burst was still running. Fold them into the instance (495 B) and always idle-close the session at 30 s.
A new Open takes over the single session so a lost Terminate on a slow link does not NAK until that close.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(tools): make mavftp_param.py reliable on a radio link
pymavlink applied FTP timings after ResetSessions, wrote param.pck?withdefaults=1 into cwd, and bumped the session id on Open retry (PX4 only ACKs session 0). Set radio timings at construction, pin session 0, retry a missed Open, and treat a complete decode as success.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(mavlink): accept packed parameter FTP uploads
CreateFile/Write/Terminate of @PARAM/param.pck applies the ArduPilot
packed stream so a GCS can bulk-load without a PARAM_SET round trip per
value. Unknown and read-only names are skipped; Terminate NAKs a
truncated file or the with-defaults magic.
* test(mavsdk_tests): upload MPC_XY_P via packed param FTP
Pin the SIH upload case to a known float instead of whatever
get_all_params() returns first.
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
On NuttX these are two things: / is the filesystem root, and /fs/microsd is the
SD card mounted under it. MAVLink FTP serves the root and confines writes to the
SD card, so the read-only ROMFS at /etc is visible but cannot be written.
On POSIX they were the same directory. PX4_ROOTFSDIR and PX4_STORAGEDIR both
resolved to CONFIG_BOARD_ROOT_PATH, which on SITL is ".", so the working
directory was simultaneously the FTP root and the only writable area. The
consequences were that the ROMFS symlink sat inside the FTP root, and that
_validatePathIsWritable() had nothing meaningful to check against and so was
compiled out on POSIX entirely, leaving no write restriction at all.
Give POSIX the same split. CONFIG_BOARD_ROOT_PATH keeps its meaning as the
storage directory, and a new CONFIG_BOARD_FS_ROOT_PATH names the root FTP
serves, defaulting to the storage path so every existing board is unchanged.
SITL sets the root to "." and storage to "./fs", which mirrors NuttX: logs,
parameters, dataman and eeprom move under ./fs, and etc/ stays in the root as
read-only data.
With storage distinct from the root, the write restriction now applies on every
platform rather than NuttX only, and no longer compares against a hardcoded
prefix length that was wrong for any board not using /fs/microsd.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Julian Oes <julian@oes.ch>
The bash version spent most of its lines on plumbing: parsing a report
back out of a per-commit `brew ruby` child, awk and herestrings for set
logic, bash 3.2 workarounds, and a trap to restore the tap. The job
itself is small and lives inside Homebrew anyway, so run the whole thing
under Homebrew's Ruby and call its tap, formula and bottle APIs directly.
One process instead of one Homebrew startup per candidate commit, the
tap checkout restored by ensure, tarballs checked with Net::HTTP, and no
second language embedded in a string. Formulary.clear_cache and
Tap#clear_cache between checkouts keep each candidate's formulae fresh.
GITHUB_OUTPUT still arrives because brew forwards GITHUB_* whenever CI
is set. Same walk, same exemption for formulae unbottled at the pin,
same outputs; verified to pick the same commit as the bash version.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
homebrew-core moved to protobuf 36.0 and abseil 20260817.0, and the
macos-15 runner image (20260828) now ships that snapshot. The gz bottles
at the pinned commit c90f81ac were built against protobuf 35.1, so the
gz_bridge build fails on every run since today with
gz/msgs/details/discovery.pb.h:17:2: fatal error: "Protobuf C++
gencode is built with an incompatible version of"
on main as well as on this PR. 43aee9cc is tap HEAD, where OSRF has
rebuilt every gz-harmonic dependency for protobuf 36.0 and abseil
20260817.0 (the gz-msgs10 10.4.0_2 bottle's INSTALL_RECEIPT records
both). Tools/ci/refresh_gz_tap_pin.sh picked this commit.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The weekly refresh workflow carried its logic inline, compared only the
tap SHA against the pin, and duplicated the --sim-tools package list.
`brew install --dry-run` never prints "from source", so its bottle check
could not fire.
Tools/ci/refresh_gz_tap_pin.sh now owns the job and the workflow calls
it. It reads the osrf/simulation formulae from macos.sh, walks the tap
from HEAD back to the pin, asks Homebrew at each commit whether every
formula in the runtime closure has a bottle for the host, HEAD-requests
each tarball, and rewrites the pin to the first commit that passes.
Formulae with no bottle at the current pin (the gz-harmonic
meta-formula, which OSRF never bottles) are not required.
peter-evans/create-pull-request opens or updates the bot PR from the
script's outputs, so an unmerged bump is refreshed instead of duplicated.
The job runs on macos-15, the oldest macOS in compile_macos.yml, because
Homebrew pours an older macOS bottle onto a newer one, not the reverse.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
macos.sh only pinned osrf/simulation when --ci was passed, so dev
machines still hit OSRF's bottle-gap window and built Gazebo from
source. Apply it whenever --sim-tools runs.
The pin is a point-in-time SHA with nothing to advance it, so add a
weekly workflow that checks whether osrf/simulation HEAD is fully
bottled and opens a PR bumping gz-tap-pin.txt when it is.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: FARHANG <farhang.nba@gmail.com>
* fix(uploader): shorten the wait for a bootloader after reboot
Reboot-to-bootloader is immediate, so this wait only has to cover USB
re-enumeration, not the reboot. Five seconds of it meant a port that was
never going to answer held up every other port on the list, and it could
outlast the window it was trying to catch: a board sits in its bootloader
for BOOTLOADER_DELAY, 3s on some boards and 5s on most, before it jumps to
the application.
With an FMU-v6C and a Black Magic probe attached, a pass over the probe's
two CDC nodes drops from 14.75s to 5.45s, and a running application is in
its bootloader 3.52s after the uploader starts.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
* fix(uploader): report ports by their /dev/serial/by-id name
A ttyACM number is handed out in plug order and says nothing about which
device it belongs to, which is awkward as soon as there is more than one
CDC device on the bus -- "Attempting reboot on /dev/ttyACM0" gives no hint
that it is a debug probe rather than the board.
Resolve each detected port back to its by-id symlink when one exists, so
every message names the device. This also collapses a duplicate: a board
is matched both by a by-id pattern and by the /dev/ttyACM* catch-all, so
it was being probed twice per pass. With an FMU-v6C and a Black Magic
probe attached, detection goes from four entries with two naming the same
board to three, each identifying itself.
Linux only; elsewhere, and for ports with no symlink, paths are unchanged.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julian Oes <julian@oes.ch>
---------
Signed-off-by: Julian Oes <julian@oes.ch>
* fix(ci): attach FMU bootloader .bin to GitHub releases
Releases only shipped `_bootloader.px4`, the USB uploader envelope. SWD recovery needs the raw `.bin` at 0x08000000.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): do not attach unused bootloader .px4
USB flashing would write it into the application slot. SWD uses the raw .bin.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): omit bootloader SBOMs from GitHub releases
GitHub Releases glob artifacts/**/*.sbom.spdx.json. Bootloader metadata dirs are not a recovery artifact.
*_bootloader_* variants (e.g. bootloader_secureboot) stay omitted: those images are baked with in-tree test keys.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(bootloader): point SWD recovery at the release .bin
Match the cannode pre-built blurb. The .px4 envelope is not the SWD image.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* docs(bootloader): scope release .bin to SWD programmers
gdb load needs ELF program headers. The release image is a raw .bin for ST-Link / CubeProgrammer / OpenOCD, and only in-tree *_bootloader targets are attached.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): publish flashable CAN node firmware
Release packaging only collected .px4 files, which the DroneCAN bootloader cannot flash.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): attach canbootloader .bin as the SWD image
The cannode bootloader is a raw .bin for st-flash, not a .px4 envelope.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): drop cannode.zip from release assets
The target-named .uavcan.bin and _canbootloader.bin files are the flashable images; the zip only duplicated them.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(sensors): decouple sensor internal/external classification from the bus
A sensor's internal/external classification was derived from its bus
(px4_i2c_bus_external / px4_spi_bus_external), but a bus is a wire: one bus
routinely serves both chips soldered on the FC and a pinned-out connector, and
any onboard sensor on such a shared bus was classified external. That hands an
onboard mag an operator-settable rotation instead of the board rotation, feeds
an onboard baro's self-heated die temperature into air density as if it were
ambient, and inverts the 75/50 default priority. FMU-v6C and AirBrainH743
worked around it with hand-rolled device_id whitelists behind
BOARD_OVERRIDE_I2C_DEVICE_EXTERNAL; FMU-v6XRT's second onboard baro was simply
misclassified.
Classify the device instead of the bus: drivers publish is_external in
sensor_accel/gyro/mag/baro, derived from the device id by default and
overridden by the new -O start flag ("onboard") for onboard sensors that share
a bus with an external connector. -I/-X stay pure bus probe filters.
The question "is this sensor external" had four answers. It now has one, with
a single override point:
-O -> I2CSPIDriverConfig::external -> Device::set_external() and the
PX4* wrappers -> is_external in the sensor topic
px4_i2c_device_external() was px4_i2c_bus_external() with a device id decode in
front, and calibration::DeviceExternal() forwarded to device_is_external();
both are gone. Device::external() stops being a bus query: it is non-virtual,
defaults to device_is_external(), and takes the declared value through
set_external(), so the five I2C/SPI overrides that used to answer it from the
bus are deleted and cannot diverge again. device::I2C and device::SPI set it
from the config, so every driver built on the bus framework follows -O without
doing anything. px4_i2c_bus_external() and px4_spi_bus_external() survive as
what they honestly are - bus predicates - reachable only through the fallback.
-O is opt-in per driver (BusCLIArguments::support_onboard), the same way -k is:
a flag that every driver advertised but only a handful honoured would be a
silent no-op on the rest. This also drops the special case for the mcp23009 and
mcp23017 GPIO expanders, which use -O for their output state and simply do not
opt in.
sensor_gyro_fifo carries is_external too. VehicleAngularVelocity prefers the
FIFO topic for any IMU that publishes one, so without it the rate controller
would take its rotation from the bus while VehicleIMU took it from the topic -
the same chip, two classifications.
The BOARD_OVERRIDE_I2C_DEVICE_EXTERNAL hook is removed along with both board
implementations, replaced by -O on the affected rc.board_sensors lines.
FMU-v5x, MR-CANHUBK3, KakuteF7, NXT-Dual and MicoAir H743-Lite each start an
onboard barometer on an external bus and get the flag as well.
Assisted-by: Claude:claude-fable-5, Claude:claude-opus-5[1m]
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat(sensors): treat shared buses as first-class topology
A boolean internal/external flag cannot describe a bus that carries both
hard-mounted chips and a connector. -O was an opt-in override for that
case, so most drivers silently ignored it and classification still
followed the bus.
Declare Internal / External / Shared on the bus, probe External and
Shared, and classify each sensor from -I/-s vs -X/-S.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(ci): drop stale ITCM symbols and clang-tidy errors
ITCM lists still named calibration::DeviceExternal and
px4_spi_bus_external after both were removed. The host test stubs
forwarded varargs in a way the analyzer rejected, and stripped I2C
headers kept extra trailing newlines.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* fix(sensors): inline device_is_external into the header
Reaching it through drivers__device pulled the kernel-only library into
the userspace image of a protected build; giving it a library of its own
put an archive referencing px4_i2c_buses/px4_spi_buses after the board
library that defines them. Inlining sidesteps both.
* fix(sensors): compile tcbp001ta and probe canhubk3 GPS mag
tcbp001ta is not an I2CSPIDriver, so config.external does not exist; it
only ever starts on internal SPI. -X on canhubk3 I2C2 never ran because
that bus is Internal.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
ensure_env() sent the child's stdout to DEVNULL to keep this process's stdout
parseable, but the generator reports missing imports with print(), so that was
exactly the output being discarded. What survived was a CalledProcessError
whose message repeats the argv, and the argv carries every .msg path: 9901
bytes on one line, naming no cause and no remedy.
Capture both streams and, on failure, exit with the child's own output. The
message names the command that failed and its exit code rather than asserting
what kind of failure it was, so it stays accurate whatever the child is or why
it failed. Missing empy now reports 167 bytes:
loadconfig: px_generate_zenoh_topic_files.py failed (exit 1)
Failed to import em: No module named 'em'
You may need to install it using:
pip3 install --user empy
stdout stays clean on success, so callers that parse it are unaffected.
Smoke tested on Ubuntu 24.04, matching the runner base: happy path returns
valid JSON for --group and --group --seeders; missing empy and missing
pyros-genmsg each report the cause and remedy; an unrunnable generator reports
the interpreter's own "can't open file"; a child exiting non-zero with no
output reports "(no output)" rather than an empty message; and a preset
ZENOH_KCONFIG_TOPICS still skips the generator entirely.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
A .px4board line whose value does not fit its symbol's type is not an error to
kconfiglib. It warns, drops the assignment, and leaves the symbol at its
default, so the loaded config quietly differs from the file and no consumer
downstream can tell. corvon 743v2 built with the wrong UAVCAN interface count
this way, and the only trace was a warning in a job that exited 0.
load_target_config() now compares kconf.warnings before and after the load and
exits on any "assignment ignored", naming the file and quoting the warning.
Checked against the whole tree: 293 targets load with none rejected, so this
does not fail existing boards. Reintroducing the quoted value makes it exit 1
with the file path and the reason.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* feat(gps): add u-blox u-center mode on UART2
GPS_UBX_BAUD2 alone never reached the receiver: outside the RTCM and GCS
modes the driver leaves UART2 untouched, so attaching a USB-serial adapter
to it produced no traffic. GPS_UBX_MODE 7 configures UART2 as a UBX
diagnostic port while the autopilot keeps its session on UART1.
* chore(gps): bump PX4-GPSDrivers submodule
Pulls in the u-center UART2 mode from PX4-GPSDrivers#228.
* docs(docs): prettier and cross link
* docs(docs): subedit
* chore(gps): bump PX4-GPSDrivers submodule
Picks up the info-level log for the u-center UART2 configuration, on top
of the CFG-UART1/2-ENABLED key ID fix now merged upstream.
* feat(gps): log what each UART carries after configuration
The line reported the link speed but not what the receiver was actually
configured to do with the port. Bumps PX4-GPSDrivers for the UART1 role
lookup and the matching per-port lines on UART2.
* feat(tools): add ubx_monitor.py, a live view of a u-blox serial link
Autobauds, then reports what the receiver is actually sending: link
utilisation, MON-VER identity, NAV-PVT fix state and per-message rates.
Written to check the u-center diagnostic port, useful for any GPS UART.
* chore(gps): point PX4-GPSDrivers at main
The u-center UART2 mode merged upstream (#228); track main instead of the
development branch.
---------
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
When homebrew-core bumps a shared dependency, OSRF's bot bumps each gz
formula's revision and deletes its bottle block within minutes of the upstream
merge. The matching rebuild is a separate, unautomated step: across 2026 the
gap ran 0.5 to 11 days, median 2.5, leaving gz unbottled roughly 18% of the
time. In that window macos.sh compiles gz-sim8, gz-msgs10 and five others from
source and the setup step goes from ~8min to 20-30min.
The removal only edits the formula. The bottle tarballs are never deleted from
OSRF's S3 bucket, so pinning to the last fully bottled revision keeps installs
binary while upstream catches up.
Gated behind a new --ci flag rather than applied unconditionally. Automation
wants a reproducible, fast install; development machines want the current
formulae and can absorb a source build, and should not have their tap left on
a detached HEAD as a side effect of running the setup script.
Only the gz tap is pinned. opencv@4, protobuf, gstreamer and the rest still
track homebrew-core, so CI keeps catching upstream formula breakage on every
PR, which is the reason --sim-tools runs there in the first place.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The Dockerfile only ever copied requirements.txt, so optional-requirements.txt
was never installed into the image even though it sits in the build context.
Every CI job needing pyelftools therefore fetched it from PyPI at job time and
failed whenever files.pythonhosted.org returned 502s.
symforce publishes no Linux aarch64 wheel and no sdist, so installing the file
unguarded would break the linux/arm64 image build. Gate it with an environment
marker so aarch64 installs pyelftools only.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* ci(build-all): seed ccache only for chip families with cold caches
Measured across recent runs, the seeder stage contributes nothing in
steady state: all 264 build-job cache restores in the 8 most recent
successful runs came from group-level caches, zero from seeder caches,
yet the stage gates the build matrix for ~3.4 min of every run's
critical path and burns ~22 8cpu-runner-minutes warming caches nobody
reads. Its fail-fast value is similarly thin: 2 of the last 40 failed
runs failed at seed stage; the other 34 passed seeding and failed in
the matrix anyway.
Probe each family's ccache namespace in the RunsOn cache bucket from
the group_targets job and emit only cold families into the seed
matrix. Warm runs skip the stage entirely (the matrix starts right
after the scan); a cold family still seeds first and gates the matrix,
which is the one case the warmup pays for. The probe fails open: if
the bucket env, the listing, or the assumed object layout is wrong,
every family reads as cold and the workflow behaves exactly as before.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* ci(build-all): fail open when seeder probe output is unparseable
The has_cold computation ran unguarded under bash -e: malformed probe
output would fail the whole workflow instead of falling back to the
full seeder matrix. Guard it so every failure path degrades to seeding
everything, on RunsOn and on downstream forks without it alike.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* ci(build-all): move seeder probe logic into the helper script
The probe step carried fail-open shell logic inline in the workflow.
Move output writing, has_cold computation, and all fail-open handling
into filter_cold_seeders.py; the workflow step is now a single script
invocation. The script always exits zero and degrades every failure
(missing bucket env, aws error, unparseable input) to the full seeder
matrix.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* ci(build-all): probe the magic cache's real object layout
The first probe guessed cache/{key} for the magic-cache object layout
and read every family COLD, degrading to unconditional seeding. The
real layout is cache/v1/{org}/{repo}/{ref}/{version-hash}/{cache-key};
the version hash is the actions/cache digest and not knowable a
priori, so list the default-branch scope once (main-scope caches are
visible to every ref) and match cache-key basenames. Verified locally
against the live bucket: all 10 families read warm and the seed stage
skips.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* ci(build-all): single-source ccache key roots in the matrix generator
The ccache key convention was encoded three times: hand-assembled in
the workflow's restore/save steps, again in the seeder's
cache-key-prefix argument, and a third time in the probe script. Drift
between them is silent thanks to the probe's fail-open design: a
renamed key scheme would read every family COLD forever and quietly
revert to unconditional seeding.
Mint the namespace root once in generate_board_targets_json.py as
cache_prefix on every group and seeder matrix entry, with seeders
occupying the reserved 'seeder' group inside their family namespace.
The workflow composes {cache_prefix}-{group}-{ref}-{sha} from matrix
fields only, and the probe greps the root it is handed, knowing
nothing of the format. Composed keys are byte-identical to the old
scheme (asserted for all 33 groups and 10 seeders), so no cache is
invalidated.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
---------
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Build all targets / Scan for Board Targets (push) Canceled after 0s
Build all targets / Seed [${{ matrix.chip_family }}] (push) Canceled after 0s
Build all targets / Build [${{ matrix.runner }}][${{ matrix.group }}] (push) Canceled after 0s
Build all targets / Upload Artifacts (push) Canceled after 0s
Checks / Gate Checks [check_format] (push) Canceled after 0s
Checks / Gate Checks [check_newlines] (push) Canceled after 0s
Checks / Gate Checks [module_documentation] (push) Canceled after 0s
Checks / Gate Checks [shellcheck_all] (push) Canceled after 0s
Checks / Gate Checks [validate_module_configs] (push) Canceled after 0s
Checks / Unit Tests (push) Canceled after 0s
MacOS build / build (push) Canceled after 0s
Ubuntu environment build / Build and Test (ubuntu:22.04) (push) Canceled after 0s
Ubuntu environment build / Build and Test (ubuntu:24.04) (push) Canceled after 0s
Container build / Set Tags and Variables (push) Canceled after 0s
Container build / Build Container (amd64) (push) Canceled after 0s
Container build / Build Container (arm64) (push) Canceled after 0s
Container build / Deploy To Registry (push) Canceled after 0s
Failsafe Simulator Build / build (failsafe_web) (push) Canceled after 0s
ITCM check / Checking nxp_mr-tropic (push) Canceled after 0s
ITCM check / Checking nxp_tropic-community (push) Canceled after 0s
ITCM check / Checking px4_fmu-v5x (push) Canceled after 0s
ITCM check / Checking px4_fmu-v6xrt (push) Canceled after 0s
ROS Integration Tests / build (push) Canceled after 0s
ROS Translation Node Tests / Build and test [humble] (push) Canceled after 0s
ROS Translation Node Tests / Build and test [jazzy] (push) Canceled after 0s
SITL Tests / Testing PX4 quadx (push) Canceled after 0s
SITL Tests / Testing PX4 standard_vtol (push) Canceled after 0s
SITL Tests / Testing PX4 xvert (push) Canceled after 0s
FLASH usage analysis / Analyzing px4_fmu-v5x (push) Canceled after 0s
FLASH usage analysis / Analyzing px4_fmu-v6x (push) Canceled after 0s
Python CI Checks / build (push) Canceled after 0s
FLASH usage analysis / Publish Results (push) Canceled after 0s
Static Analysis / Clang-Tidy (push) Canceled after 0s
The pynacl install step from #27237 was a stopgap until the build
container shipped pynacl preinstalled. That happened in #27237 itself:
it added pynacl to Tools/setup/requirements.txt, which dev_container.yml
bakes into the image, so v1.18.0-beta1 and later already ship it. Only
the v1.17.0-rc2 pin here kept the step alive: 30+ unpinned PyPI pulls
per workflow run that already cost us a matrix job to PyPI 502s.
Verified by building px4_fmu-v6x_secureboot locally in
px4io/px4-dev:v1.18.0-beta2: the signing step runs against the baked-in
pynacl with no pip install. The voxl2 container keeps its own pin and
needs no fallback since only CONFIG_BOARD_SECUREBOOT targets (NuttX
platform only) invoke the signing script.
Expect one cold ccache run after merge: the new container's compilers
invalidate all caches at once via compiler_check = content.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The voxl2 build group carried chip_family 'native' while its seeder
carried 'voxl2', so the group restored/saved under
ccache-native-x64-voxl2-0-* while the seeder saved under
ccache-voxl2-x64-seeder-*. The restore-keys chain can never cross that
namespace gap: the seeder's warm cache is discarded every run, and cold
builds fall back to the SITL seeder cache (host gcc objects, zero
possible hits against aarch64-linux-gnu-gcc or hexagon-clang). Present
since #27050.
Give the voxl2 group chip_family 'voxl2' so it shares the seeder's key
namespace, drop the now-redundant voxl2 special-casing in seeder
generation, and size the voxl2 cache at 800M since it holds objects for
two toolchains (aarch64-gnu + hexagon-clang) and already sits near the
400M limit.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
macos.sh --sim-tools installs the unversioned Homebrew opencv formula, which
is now 5.0.0, and PX4-OpticalFlow does not build against it:
klt_feature_tracker/src/trackFeatures.cpp:43:10:
fatal error: 'opencv2/core/types_c.h' file not found
PX4-OpticalFlow/src/flow_opencv.cpp:110:7:
fatal error: no member named 'undistortPoints' in namespace 'cv'
types_c.h was removed in OpenCV 5, and undistortPoints moved when calib3d was
split into 3d/calib. The failure lands about a thousand targets into
make px4_sitl and points at submodule sources rather than at the dependency.
ubuntu.sh takes libopencv-dev from apt, which is still 4.x, so CI never sees
this.
Install opencv@4 instead. It is keg-only, so find_package still resolves to
5.0.0 without a prefix hint. Add one alongside the qt@5 hint from 9c2e634325,
which is keg-only for the same reason.
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jackson Korba <jackson.korba@gmail.com>