"test size" runs pull request code, so its token is read-only and it
cannot comment. This runs on workflow_run, from the default branch and
without a checkout, validates the data it is handed and builds the table
itself, so nothing the pull request wrote is posted under the bot's name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolve the base branch once per run, so every board compares against the
same commit, and mark the legs that do not succeed. size-summary.json
goes to test_size_comment.yml; the markdown stays on the run's page.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The table says which commit it was built from and which it was compared
against, and --json-output writes the same as data for the workflow that
comments it on a pull request.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SDCardWPTest installed mission_spiral.lua with the non-context
install_example_script() and removed it with a bare
remove_installed_script() thirty lines later, with no try/finally
between them. Every wait_text() and set_parameter() in that stretch can
raise, and any of them leaves the script installed: the removal is
simply skipped.
That matters more here than for a leaked trick file, because
mission_spiral.lua ends in .lua - lua_scripts.cpp loads every .lua in
scripts/ - so the leftover is picked up and run by the next test to
start a vehicle with scripting enabled.
The test already pushes a context, and the harness pops any the test
leaves behind when it fails, so install_example_script_context() cleans
up on both paths. Every other install site in Tools/autotest already
uses the _context form.
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
workflows lint / lint (push) Canceled after 0s
The macOS jobs' working set is 480-560MB, so at ccache.env's 400M default
both evicted objects mid-build - 817 cleanups on sitl, 123 on CubeOrange -
and re-compiled them on the next run. Restoring a cache built from the same
source, they hit 42% (CubeOrange) and 19% (sitl); with the cache large
enough to hold the working set both hit 99.8%.
Add a max-size input to setup-ccache so this is per-job rather than global:
raising it for all jobs would waste the repository's shared 10GB cache
quota on the ~60 jobs that use well under 400M. The two macOS entries grow
by 208MB in total.
The macOS workflow built every vehicle twice, once normally and once
with --debug. The second pass doubled build time and, since debug and
non-debug objects don't share ccache entries, overflowed the 400M ccache
limit, so the cache thrashed even when warm.
A single vehicle is enough to check the debug build works on macOS.
Plane, Rover, Sub, Blimp, AntennaTracker and heli no longer get a
--debug (-O0) compile on macOS; each still gets one in its Linux SITL
test workflow.
waf does not persist `-j` in the configuration, it's only used for the
command it's specified on. So specifying `-j` to this script never did
anything to limit the number of build processes because the job limit
was only given to configure commands.
Now the script passes the appropriate number of jobs to build as well
as configure commands, so the limit is actually applied.
It's unclear if passing the number of jobs to the configure command
accomplishes a lot, but it doesn't hurt so it's kept.
previously adding or removing support for an OS meant changing lines unrelated to that OS.
Add a bit of cruft to the file so that adds/removes are just clean line additions or removal
RCOutput_PRU, RCOutput_AioPRU_PB2 and RCOutput_AeroIO wrote into their
channel arrays without checking the channel number; every other Linux
RCOutput backend already does. On PRU the overrun is particularly
unpleasant as pending[MAX_PWMS] aliases the corked flag, so a write to
channel 12 uncorks the backend and makes the subsequent push() a no-op.
SRV_Channels::output_ch_all() already sweeps 16 channels by default,
so these overruns are reachable today on pxf, erleboard and pocket2.
This reverts commit 2f87db990f.
PR #34359 was merged by mistake. On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default. The ESC started to enter
throttle calibration. Back the change out until the hold can be
chosen per output.
This reverts commit 157d471fe4.
PR #34359 was merged by mistake. On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default. The ESC started to enter
throttle calibration. Back the change out until the hold can be
chosen per output.
This reverts commit 239f5c1f97.
PR #34359 was merged by mistake. On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default. The ESC started to enter
throttle calibration. Back the change out until the hold can be
chosen per output.
This reverts commit 67fd60ce26.
PR #34359 was merged by mistake. On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default. The ESC started to enter
throttle calibration. Back the change out until the hold can be
chosen per output.
PWM1 is on PA15, the JTDI pin, whose reset and power-on pull-up gave the
M1 servo a short pulse on every boot. Declare it HOLD_HIGH so the
application keeps it a pulled-up input until RCOutput's first real
frame, matching the bootloader, which already keeps the pull-up.
The STM32 JTAG pins JTDI (PA15) and NJTRST (PB4) come out of every
reset, and out of power-on, with an internal pull-up enabled, and 84
hwdef directories in the tree route a PWM output through one of them:
61 through PA15, 38 through PB4, 15 through both. A servo on such an
output sees the line pulled high from then until firmware reconfigures
the pin. On the H743 that measured 692us to the bootloader's board init
on a warm reset, and 496us and 520us on two cold power-ons. Each is a
pulse inside the range servos accept, so the servo drives to an endpoint
and holds it through the rest of the boot. Nothing can shorten that
window, since no code runs during it.
Give hwdef a HOLD_HIGH keyword for PWM pins. The generator emits such a
pin as a pulled-up input with its timer alternate function preset, and a
HAL_PWM_HOLD_HIGH_MASK of the channels concerned. It rejects the keyword
on any pin RCOutput will never hand back to a timer: anything other than
a PWM(n) timer output in the main configuration, so also an RC input, the
alarm and an ALT(n) pin. One predicate decides both that and which pins
get a mask bit, so the two cannot disagree. The check is made when the
pin is parsed, which covers bootloader builds too. STM32F1 is rejected
outright, since its pin setup does not honour the keyword at all.
RCOutput keeps each channel an input until the first non-zero value is
pushed to it, in the PWM and DShot output paths, and only then switches
the pin to the timer. With the bootloader also keeping the pull-up, the
line is high continuously from the reset until the first real frame,
which for a channel outside BRD_SAFETY_MASK means until safety is
disarmed, so the servo sees a high far longer than any valid pulse
rather than a plausible short one followed by seconds of silence. On
the bench the test servo did not move at all across ten reboots.
The mode switch is an unlocked read-modify-write of the port registers,
and other threads change the modes of other pins on the same port, so
a single write can be lost. The channel is therefore not marked handed
over until a later output finds the pin already in alternate mode; until
then each output writes the mode again, so a lost write is repaired one
output later rather than leaving the pin an input until reboot.
Several other owners of a pad have to take it explicitly, because none
of them goes through the normal output path:
- the alarm driver configures a timer and never the pad, and disables
the group's channels first, so the hold on the alarm's own channel is
released before that. Only that channel: no real frame will ever
arrive for the rest of the group, so a HOLD_HIGH pin among them is
correctly left held;
- soft serial saves and restores the pad's mode, so BLHeli passthrough
hands the pin over when it selects it, or it would save "input" and
transmit nothing;
- neopixel and ProfiLED output is chosen at runtime by SERVOx_FUNCTION
on an ordinary PWM(n) pin and is sent without push_local(), so the
serial LED path releases its group's pads before driving them;
- DShot commands such as beeps are sent before arming, when nothing has
released the pad yet, so the command path releases every channel it
transmits on;
- bidirectional DShot, when enabled at runtime, takes the pads of a
whole group during init, so it clears the pending bit there. A pin
merely declared BIDIR keeps its hold; one whose group has bidirectional
DShot enabled gets no protection. The hwdef allows HOLD_HIGH and BIDIR
together deliberately.
Verified under Renode on YJUAV_A6SE_H743 with ArduPlane: the
application's board init leaves PA15 an input, it stays one through
24.8s of init, and the mode write that puts it on TIM2 lands at the same
microsecond as the first non-zero CCR1 write. With the first mode write
dropped on purpose, the next output found PA15 still an input and wrote
it; unmodified, the second output sees the mode has held and later
outputs no longer read the port. MatekF405-TE and the IOMCU
firmware still build, and a no-mask board's firmware is byte-identical.
Built with Tools/scripts/build_bootloaders.py from the hwdef change that
holds the PWM1/JTDI pin high through the bootloader, so a servo on M1 no
longer receives a 500 to 700us pulse on every reset and power-on.
PA15 drives PWM1 on this board and is also JTDI, which the STM32H743
brings out of every reset, and out of power-on, with its internal
pull-up enabled. The M1 servo line is therefore held high from then
until the bootloader's board init reconfigured the pin as a floating
input. On logic-analyser captures of the real board that is 692us on a
warm reset, and 496us and 520us on two cold power-ons, one over USB and
one at 12V. Each of those is a pulse inside the range most servos
accept, and it sent the servo to an extreme.
Configure PA15 as an input with pull-up in the bootloader instead, so
the line stays high continuously until the application switches the pin
to its timer, whose idle level is low. The servo then sees one high
lasting the whole bootloader, far outside any valid pulse width, rather
than a plausible command. Verified under Renode with the bootloader
held: PA15 reads input with pull-up while the bootloader owns the pins.
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
Rather than maintaining copies of the bus and device type tables,
decode_devid.py now parses the enums in AP_HAL/Device.h, AP_SerialManager.h
and the compass, IMU, baro and airspeed backend headers using
logger_metadata/enum_parse.py. A small rename map keeps established
display names (DRONECAN, AK0991x), and the retired LIS2MDL ID, which is
in no enum, is listed explicitly. Comments on enum entries are shown as
warnings when decoding.
--dump-json and --dump-json5 write the tables, with a format_version
and a content-hash data_version, for tools without a source tree;
--json reads such a file back. A copy of the script outside an
ArduPilot tree (as synced by MethodicConfigurator) reads devid.json from
its own directory. The files are published alongside LogMessages.* by
build_log_message_documentation.sh, and CI dumps them in the
logger_metadata step so that header changes which break parsing are
caught.
The tables had drifted from the headers: ACC_LSM9DS1,
INS_ZEROONE_FPGA_SCH16T and INS_ICM56686 were missing, MMC5883 is now
MMC5983, AK8963/BMM150 had trailing spaces, and several names now
follow the headers.
DEVTYPE_RM3100_2 (0x12) was introduced by dd4cf6ccdd and reverted by
a0cf4e158a; no release firmware used it. Tools/scripts/decode_devid.py
shows this comment as a warning when decoding such an ID.
Parameter conversion tables whose entries all share an old key found at
runtime (e.g. via find_top_level_key_by_pointer()) cannot be constant
if the key is stored in each entry, so a static table is initialised at
runtime and kept in RAM. Adding a ConversionInfoNoKey table type plus
convert_old_parameters() and convert_old_parameters_scaled() overloads
which take the key separately allows these tables to be placed in
.rodata.
--check-parameter-leaks, --no-check-parameter-leaks and
--unix-domain-socket with its --uds alias are accepted by autotest.py but
were not offered.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
waf runs from the root of the checkout, but the completion ran ./waf in
whatever directory it was typed in, so BUILD.md's suggested
alias waf="<ardupilot>/modules/waf/waf-light" proposed nothing at all
from a subdirectory. Ask git for the root, run waf there, and key the
cache on it rather than on the current directory.
Recognise the help by its "Main commands" heading rather than by being
non-empty: a clone whose waf submodule is still missing prints a notice
and exits 0, which passed the old check and cached the handful of
hardcoded words for that directory.
Read the cache variables with ${var-} so a shell with set -u does not
abort on the first tab press.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
--net-device, --sim-periph-lockstep and --use_sim_time are accepted by
the binaries but were not offered.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
autotest.py --help needs pymavlink installed; without it the checker
stopped on a traceback and never reached the checks after it, which is
how the SITL binary ones stayed unnoticed. A tool that cannot run is a
fact about the machine, not about the completion scripts, so warn and
skip it, as the missing SITL binary already did.
A long option may contain an underscore -- the SITL binaries have
--use_sim_time -- and stopping at it reported a missing --use that no
completion script could ever satisfy.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bash/_waf declares no options of its own any more -- it scrapes ./waf
--help when it completes -- so there is nothing left to fall out of sync.
What the checker still found there was its own case patterns: it read
--enable-*|--disable-*|--embed-* as three options waf does not accept and
reported them as stale.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The options are scraped from ./waf --help instead of being written out
here, the ~900 generated --enable-/--disable-/--embed- options are held
back until the word being completed asks for one, and the result is
cached for the shell session because ./waf --help costs ~0.2s and this
runs on every tab press.
The caches are per checkout and are not filled unless the help was read:
a tab press outside a checkout would otherwise cache the handful of
hardcoded words and disable completion for the rest of the session, and
a second checkout would inherit the first one's options and boards.
list_boards is cached the same way and its errors are discarded, so
--board no longer costs a waf run per tab press or complains outside a
checkout.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Enable -Werror by default for the QURT C and C++ compiler flags now that the outstanding absolute-value warnings have been addressed. Keep the existing --disable-Werror option available for development builds.
terrain_srtm_alt_ms is zero until the first writeTerrainData, and
imuSampleTime_ms counts from boot, so for the first five seconds of uptime
the age test passes against a terrain altitude that is still zero.
terrain_srtm_alt_valid then reports a terrain height the core has never
received: FuseOptFlow scales flow from it, getHeightControlLimit drops the
optical flow altitude cap, and getFilterStatus counts it towards relative
position validity.
On the ground at boot that costs little, since the value it invents is the
height above an origin the vehicle is sitting on. It matters after an
in-flight watchdog reset, where millis() restarts at zero and the vehicle
comes back armed and flying.
gndHgtValidTime_ms is guarded against exactly this one expression away, so
this is the same idiom rather than a new one. The 5 s is named while it is
being touched, because it is about to have a second user.
No autotest: the window is the first five seconds of uptime and closes
before healthy() opens, so SITL cannot enter it from a cold boot, and the
in-flight reset that reaches it is not something the harness can stage.
EK3_OptflowTerrainScaleHeight flies above the rangefinder range with
EK3_OPTIONS bit 2, so the flow scale height comes from the terrain
database, and off the Kalaupapa cliffs where the ground falls about 160 m
below the EKF origin. Where the terrain sits at the origin altitude both
sign conventions agree, so a flat field would discriminate nothing.
GPS navigates, which keeps flow out of the velocity solution and makes the
trajectory independent of the scale height, so the two builds fly the same
path. The scale height reaches the innovation only through vehicle
velocity, so the window read is the traverse rather than a hover at the end
of it: over a stationary hold the signal is absent whichever expression is
in use. Measured across the traverse, the XKF5 consistency ratio is 0 with
the height right and 255 - the logged ceiling - with it inverted.
It flies at 60 m rather than 40 m because the terrain 50 m north of home
rises to 185.8 m AMSL against a 165.25 m home. At 40 m the margin over that
ridge is 19.5 m, and any lower would put the rangefinder back in range and
bypass the branch under test.
The test does not prove the database rather than the terrain offset state
supplied the height. With the option cleared the frozen terrain state gives
a scale height about 3.7x low, which measures a ratio of 3 - inside the
gate, and indistinguishable from a pass. A negative leg on this signal
would not discriminate, so none is claimed.
terrain_srtm_alt is the terrain height above the EKF origin, positive up:
AP_AHRS::writeTerrainAMSL() converts the AMSL height AP_Terrain supplies
with alt_amsl_m - origin.alt, and the core stores it verbatim. pd is the
vehicle's position.z, positive down. Height above ground is therefore (-pd)
minus the terrain height, not the terrain height minus pd. The neighbouring
terrainState expression is right because terrainState is itself a D
coordinate, built as position.z + rngOnGnd, so the two branches of one
variable were being differenced in opposite conventions.
Where the AHRS and core origins coincide the old error is 2 x
terrain_srtm_alt, so it is smallest where the origin sits at field
elevation and grows with relief - and it moves the wrong way, reading high
over ground that is above the origin. AP_AHRS subtracts the one public
origin and hands the same figure to every core, which then differences it
against its own position.z, so where a core's own origin altitude has moved
- ekfGpsRefHgt drift, or lanes aligning against different receivers under
EK3_AFFINITY - the corrected form still carries that difference. The trace
here is complete only for the default EK3_OGN_HGT_MASK.
A terrain height that disagrees with the datum still collapses the scale
height to the on-ground range through the MAX, exactly as it does today.
The old expression could go negative too - over ground that sits further
below the origin than the vehicle sits above it - so this is pre-existing,
and the sign fix moves which geometry triggers it rather than closing it.
Falling back to terrainState there is the obvious repair and it does not
work: the enclosing condition has already declared that state stale.
Measured in SITL off the Kalaupapa cliffs, holding 60 m above an origin the
ground falls to 160 m below, so the true height above ground reaches 220 m.
GPS navigates, so flow is not fused into velocity and both builds fly the
same trajectory; only the scale height differs. Across the traverse the
logged flow innovation consistency ratio saturates its 255 ceiling - at
least 2.55, so flow at that geometry is rejected outright - against a peak
of 0 with this change. The raw innovation is deliberately not quoted: XKF5
logs it as an int16 scaled by 1000, and the old expression drives it past
the wrap point, so the logged figure there is an aliased value rather than
the real one.