Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9a6efc5
board_types: reserve IDs 100-110 for Syro, add SYRO_V6X
vbgitrepos Jun 24, 2026
0d29be4
.github: linux: removed duplicated build introduced in https://github…
khancyr Jun 25, 2026
118c7ed
.github: cygwin: update ccache sloppiness
khancyr Jun 25, 2026
04979f4
Tools: cygwin_build: don't -j8 on GH
khancyr Jun 25, 2026
1beebe0
SITL: Multicopter overrides parent's update_battery()
hunt0r Jun 23, 2026
bd5cd32
AP_HAL_SITL: Add cmdline option for dds use sim clock
stephendade Jun 15, 2026
beef30f
SITL: Add cmdline option for dds use sim clock
stephendade Jun 15, 2026
5b2ae42
AP_DDS: Add cmdline option for dds use sim clock
stephendade Jun 15, 2026
450f3e9
Tools: Add cmdline option for dds use sim clock
stephendade Jun 17, 2026
175b2be
autotest: generalise inverted flight test across heli frames
peterbarker Jun 24, 2026
c6a991d
Autotest: only test Heli Single instead of all frames
bnsgeyer Jun 25, 2026
b65d7d6
hwdef: rename fmuv3 hwdef.dat files to hwdef.inc
peterbarker Jun 23, 2026
485ef49
hwdef: add fmuv3 and fmuv3-bdshot hwdef.dat including the .inc
peterbarker Jun 23, 2026
764d436
hwdef: make fmuv3-bdshot inherit from fmuv3 instead of duplicating it
peterbarker Jun 23, 2026
4642452
hwdef: make the IMU heater board-specific rather than via fmuv3
peterbarker Jun 23, 2026
a1b3634
hwdef: skyviper-v2450 does not have an IMU heater
peterbarker Jun 22, 2026
05b13df
hwdef: the Pixhawk1 family, fmuv2 and mRoX21 have no IMU heater
peterbarker Jun 23, 2026
c487d82
bootloaders: TBS LUCID H7 OEM
andyp1per Apr 17, 2026
b886cc9
AP_Bootloader: TBS LUCID H7 OEM board id
andyp1per Apr 17, 2026
15def76
hwdef: TBS LUCID H7 OEM
andyp1per Apr 17, 2026
cbbd4e0
autotest: add a test for GPS_INPUT consumption
peterbarker Jun 26, 2026
5b2ecf0
AP_HAL_SITL: All vehicles now use SITL::Aircraft voltage & current
hunt0r Jun 22, 2026
81f23db
AP_Scripting: add send_named_int function
uxduck Jun 11, 2026
4de7190
GCS_MAVLink: add send_named_int function
uxduck Jun 11, 2026
9f5c458
Tools: add LoggedNamedValueInt test
khancyr Jun 11, 2026
918718f
Tools: remove context_push/pop from LoggedNamedValueXXXX tests as une…
khancyr Jun 17, 2026
1f36df1
AP_HAL_ChibiOS: add CORVON743V2 board
holydust Jun 6, 2026
5b812a8
bootloaders: add CORVON743V2
holydust Jun 6, 2026
f099333
autotest: split Parameters test into three separate tests
peterbarker Jun 20, 2026
88513ed
autotest: fix ParametersMIS_TOTAL race against EKF home-set
peterbarker Jun 20, 2026
8bc0083
CI: test_size: post size table to PR
khancyr Jun 29, 2026
b23cb29
CI: test_size: use REST API for PR comment to avoid GraphQL restriction
khancyr Jun 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/cygwin_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ jobs:
CYGPATH_GITHUB_WORKSPACE=$(cygpath -u "$GITHUB_WORKSPACE") &&
mkdir -p "${CYGPATH_GITHUB_WORKSPACE}/ccache" &&
mkdir -p /usr/local/etc &&
echo "export CCACHE_SLOPPINESS=file_stat_matches" >> ~/ccache.conf &&
echo "export CCACHE_SLOPPINESS=file_stat_matches,include_file_ctime,include_file_mtime,time_macros" >> ~/ccache.conf &&
echo "export CCACHE_DIR=${CYGPATH_GITHUB_WORKSPACE}/ccache" >> ~/ccache.conf &&
echo "export CCACHE_BASEDIR=${CYGPATH_GITHUB_WORKSPACE}" >> ~/ccache.conf &&
echo "export CCACHE_COMPRESS=1" >> ~/ccache.conf &&
Expand All @@ -178,6 +178,8 @@ jobs:
source ~/ccache.conf &&
ccache -s
- uses: ./.github/actions/setup-ccache
with:
key-suffix: cygwin-sitl
- name: Prepare Python environment
env:
PATH: /usr/bin:$(cygpath ${SYSTEMROOT})/system32
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/test_linux_sbc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ jobs:
toolchain: base # GCC
- config: navigator64
toolchain: aarch64
- config: linux
toolchain: base # GCC
- config: t3-gem-o1
toolchain: aarch64
exclude:
Expand Down
21 changes: 20 additions & 1 deletion .github/workflows/test_size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ jobs:
if: always()
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
with:
Expand All @@ -394,4 +395,22 @@ jobs:
run: |
mkdir -p size-diffs/
python3 Tools/scripts/build_tests/global_size_summary.py \
--input-dir size-diffs/ >> $GITHUB_STEP_SUMMARY
--input-dir size-diffs/ | tee /tmp/size-summary.md >> $GITHUB_STEP_SUMMARY

- name: Post size table to PR
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
run: |
MARKER="<!-- size-table -->"
{ echo "$MARKER"; cat /tmp/size-summary.md; } > /tmp/full-comment.md
PR=${{ github.event.pull_request.number }}
EXISTING=$(gh api "repos/${{ github.repository }}/issues/${PR}/comments" \
--jq "[.[] | select(.body | startswith(\"${MARKER}\"))][0].id // empty")
if [ -n "$EXISTING" ]; then
gh api "repos/${{ github.repository }}/issues/comments/${EXISTING}" \
-X PATCH --field body=@/tmp/full-comment.md
else
gh api "repos/${{ github.repository }}/issues/${PR}/comments" \
-X POST --field body=@/tmp/full-comment.md
fi
6 changes: 5 additions & 1 deletion Tools/AP_Bootloader/board_types.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ Reserved "GUMSTIX [BL] FMU v6" 54
Reserved "ARK CAN FLOW" 80
Reserved "NXP ucans32k146" 34

# IDs 110-119 reserved for Syro
TARGET_HW_SYRO_V6X 110

# values from external vendors
EXT_HW_RADIOLINK_MINI_PIX 3

Expand Down Expand Up @@ -504,7 +507,8 @@ AP_HW_TBS_LUCID_PRO 5251
AP_HW_TBS_L431_PERIPH 5252
AP_HW_TBS_LUCID_H7_WING 5253
AP_HW_TBS_LUCID_H7_WING_AIO 5254
AP_HW_TBS_LUCID_H7V3 5256
AP_HW_TBS_LUCID_H7_OEM 5255
AP_HW_TBS_LUCID_H7V3 5256

# IDs 5270-5279 reserved for SpeedyBee
AP_HW_SpeedyBeeF405WINGV2 5270
Expand Down
78 changes: 78 additions & 0 deletions Tools/autotest/arducopter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13438,6 +13438,83 @@ def GPSForYaw(self):
raise NotAchievedException("Expected to get GPS-from-yaw (want %f got %f)" % (want, m.yaw))
self.wait_ready_to_arm()

def GPS_INPUT(self):
'''Test GPS data injected via the GPS_INPUT MAVLink message (GPS_TYPE=MAV)'''
# feed the first GPS instance over MAVLink rather than a simulated
# serial backend. Disable the simulated serial GPS so the only GPS
# data ArduPilot sees is what we inject below:
self.set_parameters({
"GPS1_TYPE": 14, # MAV
"SIM_GPS1_ENABLE": 0, # no simulated serial GPS
})
self.reboot_sitl()

# we will echo the simulator's true state back as GPS_INPUT, so make
# sure SIM_STATE (which carries truth lat/lng/alt/velocity) is streamed:
self.context_set_message_rate_hz(mavutil.mavlink.MAVLINK_MSG_ID_SIM_STATE, 10)

class GPSInputFeeder(vehicle_test_suite.TestSuite.MessageHook):
'''emit a GPS_INPUT message for each SIM_STATE, pretending to be a
companion computer supplying the GPS solution'''
def __init__(self, suite):
super().__init__(suite)
self.count = 0

def progress_prefix(self):
return "GPSIN: "

def process(self, mav, m):
if m.get_type() != 'SIM_STATE':
return
self.count += 1
now_s = self.suite.get_sim_time_cached()
# an arbitrary but valid GPS week and ms-of-week; ArduPilot
# only requires week>0 and fix>=3 to apply jitter correction:
time_week = 2345
time_week_ms = int(now_s * 1000) % (7 * 86400 * 1000)
mav.mav.gps_input_send(
int(now_s * 1e6), # time_usec
0, # gps_id (first instance)
0, # ignore_flags: 0 == every field is valid
time_week_ms,
time_week,
3, # fix_type: 3D fix
m.lat_int, # 1e7 degrees
m.lon_int, # 1e7 degrees
m.alt, # metres
1.0, # hdop
1.5, # vdop
m.vn, m.ve, m.vd, # NED velocity, m/s
0.2, # speed_accuracy, m/s
0.5, # horiz_accuracy, m
0.8, # vert_accuracy, m
15, # satellites_visible
0, # yaw (0 == not provided)
)

feeder = GPSInputFeeder(self)
self.install_message_hook_context(feeder)

# confirm ArduPilot consumed the injected GPS:
self.wait_gps_fix_type_gte(3, timeout=60, verbose=True)
self.wait_gps_satellite_count("GPS_RAW_INT", 15, timeout=30)

# the EKF should accept the MAVLink GPS and allow arming:
self.wait_ready_to_arm()

# the estimated position should track the truth we are feeding in:
self.install_message_hook_context(
vehicle_test_suite.TestSuite.ValidateGlobalPositionIntAgainstSimState(self, max_allowed_divergence=25))

# and we should be able to fly under position control:
self.takeoff(10, mode='GUIDED')
self.fly_guided_move_local(20, 0, 10)
self.do_RTL()

if feeder.count == 0:
raise NotAchievedException("Never sent any GPS_INPUT messages")
self.progress("Sent %u GPS_INPUT messages" % feeder.count)

def SMART_RTL_EnterLeave(self):
'''check SmartRTL behaviour when entering/leaving'''
# we had a bug where we would consume points when re-entering smartrtl
Expand Down Expand Up @@ -17822,6 +17899,7 @@ def tests2b(self): # this block currently around 9.5mins here
self.DO_WINCH,
self.SensorErrorFlags,
self.GPSForYaw,
self.GPS_INPUT,
self.DefaultIntervalsFromFiles,
self.GPSTypes,
self.MultipleGPS,
Expand Down
24 changes: 20 additions & 4 deletions Tools/autotest/arduplane.py
Original file line number Diff line number Diff line change
Expand Up @@ -7319,7 +7319,6 @@ def MAV_CMD_EXTERNAL_WIND_ESTIMATE(self):

def LoggedNamedValueFloat(self):
'''ensure that sent named value floats are logged'''
self.context_push()
self.install_example_script_context('simple_loop.lua')
self.set_parameters({
'SCR_ENABLE': 1,
Expand All @@ -7331,16 +7330,33 @@ def LoggedNamedValueFloat(self):
"name": "Lua Float",
})
dfreader = self.dfreader_for_current_onboard_log()
self.context_pop()

m = dfreader.recv_match(type='NVF')
if m is None:
raise NotAchievedException("Did not find NVF message")
self.progress(f"Received NVF with value {m.Value}")

def LoggedNamedValueInt(self):
'''ensure that sent named value ints are logged'''
self.install_example_script_context('simple_loop.lua')
self.set_parameters({
'SCR_ENABLE': 1,
})
self.reboot_sitl()
self.wait_ready_to_arm()
self.wait_statustext('hello, world')
m = self.assert_received_message_field_values('NAMED_VALUE_INT', {
"name": "Lua Int",
})
dfreader = self.dfreader_for_current_onboard_log()

m = dfreader.recv_match(type='NVI')
if m is None:
raise NotAchievedException("Did not find NVI message")
self.progress(f"Received NVI with value {m.Value}")

def LoggedNamedValueString(self):
'''ensure that sent named value strings are logged'''
self.context_push()
self.install_example_script_context('simple_named_string.lua')
self.set_parameters({
'SCR_ENABLE': 1,
Expand All @@ -7352,7 +7368,6 @@ def LoggedNamedValueString(self):
"value": "Lua String Value",
})
dfreader = self.dfreader_for_current_onboard_log()
self.context_pop()

m = dfreader.recv_match(type='NVS')
if m is None:
Expand Down Expand Up @@ -8459,6 +8474,7 @@ def tests1b(self):
self.mavlink_AIRSPEED,
self.Volz,
self.LoggedNamedValueFloat,
self.LoggedNamedValueInt,
self.LoggedNamedValueString,
self.AdvancedFailsafeBadBaro,
self.DO_CHANGE_ALTITUDE,
Expand Down
78 changes: 61 additions & 17 deletions Tools/autotest/helicopter.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,24 +278,28 @@ def HeliQuadFlip(self):
# shaping cannot recover cleanly
self.ModeFlip(do_pitch_flip=False)

def HeliQuadInvertedFlight(self):
'''fly inverted on collective-pitch quad frame'''
self.customise_SITL_commandline(
[],
defaults_filepath=self.model_defaults_filepath('heli-quad'),
model="heli-quad:@ROMFS/models/heliquad.json",
wipe=True,
)
def fly_inverted_flight(self, collective_servos=None, yaw_tolerance=20):
'''engage inverted flight from a hover in ALT_HOLD and verify that the
vehicle stays inverted and holds altitude, then recover. Assumes the
frame has already been set up and the vehicle is disarmed. If
collective_servos is given those servo channels must reach negative
blade pitch (PWM below mid) while inverted. yaw_tolerance is the
allowed heading drift in degrees, or None to not check heading (a
single tail rotor re-trims when inverted and drifts slowly).'''
rc_option_inverted = 43
self.set_parameter("RC10_OPTION", rc_option_inverted)
self.set_rc(10, 1000)
# clear any interlock/throttle override left over from a previous
# frame's attempt, so the vehicle can pass its arming checks
self.zero_throttle()
self.set_rc(8, 1000)
self.takeoff(30, mode='ALT_HOLD')

self.progress("Engaging inverted flight")
self.set_rc(10, 2000)
tstart = self.get_sim_time()
while True:
if self.get_sim_time_cached() - tstart > 10:
if self.get_sim_time_cached() - tstart > 15:
raise NotAchievedException("Did not roll inverted")
m = self.assert_receive_message('ATTITUDE')
if abs(math.degrees(m.roll)) > 150:
Expand All @@ -312,22 +316,61 @@ def HeliQuadInvertedFlight(self):
roll_deg = math.degrees(m.roll)
if abs(roll_deg) < 150:
raise NotAchievedException(f"Did not stay inverted (roll {roll_deg:.1f})")
yaw_err = (math.degrees(m.yaw) - hold_yaw_deg + 180) % 360 - 180
if abs(yaw_err) > 20:
raise NotAchievedException(f"Did not hold heading while inverted (err {yaw_err:.1f}deg)")
if yaw_tolerance is not None:
yaw_err = (math.degrees(m.yaw) - hold_yaw_deg + 180) % 360 - 180
if abs(yaw_err) > yaw_tolerance:
raise NotAchievedException(f"Did not hold heading while inverted (err {yaw_err:.1f}deg)")
alt = self.get_altitude(relative=True)
if abs(alt - hold_alt) > 5:
raise NotAchievedException(f"Lost altitude while inverted ({alt:.1f}m vs {hold_alt:.1f}m)")
servo = self.assert_receive_message('SERVO_OUTPUT_RAW')
for n in 1, 2, 3, 4:
max_collective = max(max_collective, getattr(servo, f"servo{n}_raw"))
if max_collective >= 1500:
if collective_servos is not None:
servo = self.assert_receive_message('SERVO_OUTPUT_RAW')
for n in collective_servos:
max_collective = max(max_collective, getattr(servo, f"servo{n}_raw"))
if collective_servos is not None and max_collective >= 1500:
raise NotAchievedException("Rotor not at negative collective while inverted (max %u)" % max_collective)
self.progress("Inverted flight held altitude and heading, max collective PWM %u" % max_collective)
self.progress("Inverted flight held altitude and heading")

self.progress("Disengaging inverted flight")
self.set_rc(10, 1000)
self.wait_attitude(desroll=0, despitch=0, tolerance=10, timeout=15)

def HeliQuadInvertedFlight(self):
'''fly inverted on collective-pitch quad frame'''
self.customise_SITL_commandline(
[],
defaults_filepath=self.model_defaults_filepath('heli-quad'),
model="heli-quad:@ROMFS/models/heliquad.json",
wipe=True,
)
# the four collective servos must swing to negative blade pitch
self.fly_inverted_flight(collective_servos=(1, 2, 3, 4))
self.do_RTL()

def HeliSingleInvertedFlight(self):
'''attempt inverted flight on heli single frame and check the set that
succeeds matches expectations'''
# parameters that let the traditional heli frames push the collective
# negative far enough to hold inverted flight; set for this test only.
# IM_STB_COL_* only affect STABILIZE collective; the maneuver flies in
# ALT_HOLD so they are belt-and-braces.
inverted_params = {
"H_COL_MIN": 1260,
"H_COL_ANG_MIN": -12,
"ATC_RATE_R_MAX": 120,
"ATC_RATE_P_MAX": 120,
"IM_STB_COL_1": 40,
"IM_STB_COL_2": 70,
"IM_STB_COL_3": 80,
}
self.customise_SITL_commandline(
[],
defaults_filepath=self.model_defaults_filepath('heli'),
model="heli",
wipe=True,
)
self.set_parameters(inverted_params)
self.fly_inverted_flight(yaw_tolerance=30)
self.do_RTL()

def hover(self):
Expand Down Expand Up @@ -1328,6 +1371,7 @@ def tests(self):
self.HeliQuad,
self.HeliQuadFlip,
self.HeliQuadInvertedFlight,
self.HeliSingleInvertedFlight,
self.MountFailsafeAction,
self.StickArmingRequiresZeroThrottle,
])
Expand Down
Loading
Loading