Attendees (unique) : 10
UTC0800
master ← tridge:pr-mavlink32bitsysid
opened 06:45AM - 15 Jul 26 UTC
### Summary
Implements 32 bit system IDs
See also:
- https://github.com/… ArduPilot/pymavlink/pull/1229
- https://github.com/ArduPilot/MAVProxy/pull/1704
- https://github.com/ArduPilot/mavlink/pull/515
- https://github.com/mavlink/rfcs/pull/20
### Classification & Testing (check all that apply and add your own)
- [ ] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [ ] Automated test(s) verify changes (e.g. unit test, autotest)
- [ ] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
### Description
This implements https://github.com/mavlink/rfcs/pull/20 but with 32 bit system IDs to allow for IPv4 addresses to be used for system IDs. This should make large drone light shows easier.
I also plan on making full 32 bit integers work with mavlink parameters to make this more practical for real IPv4 addresses. That will be a separate effort
< Discussion on Tridge’s MAVLink PR for double length system ID >
UTC0805
master ← hamishwillee:patch-8
opened 07:05AM - 25 Jun 26 UTC
Allow efficient scaling of a % value in UINT16 value. With this, 0 to 100 is rep… resented by 50000.
This is needed for https://github.com/mavlink/mavlink/pull/2526/changes#r3465455513 - but would do no harm anyway.
< Discussion on adding a uint16 and float16 range converters in pymavlink >
Lupus the Canine : float16 is pretty horrible for precision.
Andrew : Yes, but in our case we want a range that is close to 0 and 1, where the precision is adequate.
Tricks like centi-degrees work nicely, but it gets messy; we just got out of converting our controllers to SI.
Peter : I would use an integer 16 bit and create an arbitrary multiplier to cover the range of interest exactly (e.g. 0-360), to squeeze as much precision as possible.
A : This makes it unreadable and very bug-prone.
UTC0820
master ← Georacer:feature/custom_plane_controller
opened 03:02PM - 29 May 26 UTC
### Summary
This PR adds support for custom Plane controllers, as `AC_CustomC… ontrol` [does for Copter](https://ardupilot.org/dev/docs/copter-adding-custom-controller.html).
### Description
A new library `AP_CustomControl` has been created, which roughly operates the same as the existing Copter counterpart.
Things that are the same:
- The overall flag is `AP_CUSTOMCONTROL_ENABLED`. The library is not part of the features list. It is meant to be explicitly, locally compiled in. SITL will compile it by default.
- Multiple custom controllers can be compiled-in and selected via `CC_TYPE`.
- An AUX switch enables or disables the controller (109).
- A basic PID example is given, which can fly a plane successfully.
Things that are different:
- The Copter custom controller is designed to return a strict control API, in the form of `Vector3f` for roll/pitch/yaw pre-mixer inputs. However this is not very useful for Plane. See below for the new API.
- Copter uses `CC_AXIS` to quickly enable/disable custom roll/pitch/yaw controllers. Since AP_CustomController now recommends unconstrained access to output functions and servos alike, The parameter has been replaced by `CP_MASK`. This is meant to be used by the developer to fence whatever function within the custom controller he pleases.
#### Recommended API
The developer has complete freedom to shape the custom controller code to his liking.
However, the following methods of `AP_CustomControl` are the recommended way to interact with the outputs:
```c++
// Write a scaled value to all channels with a function.
void set_output_scaled(SRV_Channel::Function function, float value);
// Write a pwm value to all channels with a function. Not min/max constrained. servos.cpp may overwrite it.
void set_output_pwm(SRV_Channel::Function function, uint16_t value);
// Write pwm values on a channel. Not min/max constrained. servos.cpp may overwrite it.
void set_output_pwm_chan(uint8_t chan, uint16_t value);
// Override pwm values on a channel for one loop. servos.cpp will not overwrite it.
void set_output_pwm_chan_override(uint8_t chan, uint16_t value);
```
These will reach into `SRV_Channels` and write the passed values.
This also means that **any** servo channel can be written to, even unconfigured ones. This is very useful for experimental control allocation schemes.
The euler angle targets are exposed to
```c++
float get_roll_target_deg() { return _frontend.roll_target_deg; }
float get_nav_pitch_target_deg() { return _frontend.pitch_target_deg; }
float get_pitch_target_deg() { return _frontend.pitch_target_deg + _frontend.pitch_trim_deg; }
```
which are filled with
```c++
custom_control.roll_target_deg = nav_roll_cd * 0.01f;
custom_control.pitch_target_deg = nav_pitch_cd * 0.01f;
custom_control.pitch_trim_deg = g.pitch_trim;
```
#### Servo overrides
The custom controller task will run after the `stabilize` task and before the `set_servos` task.
This means that by default the safety checks mixing which happens in `servos.cpp` will still apply and may override the custom controller.
However, a method `set_output_pwm_chan_override(uint8_t chan, uint16_t value)` is given, in order to block `set_servos` from modifying this channel. This can be useful for implementing experimental/custom mixers.
#### Known drawbacks
- The parameter namespace is also `CC`. I think this might cause conflicts in the wiki?
- Due to the implementation details, output functions of GPIO (-1 enum value) cannot be addressed. Not sure how to fix that.
- AFAIK, the Plane codebase doesn't do rate controller and/or control surface bumpless transfer upon mode switches (e.g. FBWA->MANUAL). That means that there will be a step in servo output upon switching out of the custom controller and into a rate-controlling mode. The integrators are being actively reset, but this is a perfect solution. Perhaps the upcoming #32743 will fix this.
- Upon exiting the custom controller, all the main controllers are reset. Since these controllers are individually, constantly reset while the custom controller is running, there might be no reason to reset them all anew, including controllers which might not have been overriden.
#### Known unknowns
- I suspect the current RC inputs API doesn't allow accessing channels >8. I have to verify this.
- If the custom controller writes onto unused output channels, their PWM value will go from 0 whatever is requested. However, when the custom controller is suspended, the servo value will not return to 0. I do not yet know how to restore this state.
<img width="1368" height="919" alt="image" src="https://github.com/user-attachments/assets/ae199adb-25e8-4e05-9302-a11d03f59833" />
### Classification & Testing (check all that apply and add your own)
- [X] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [X] Automated test(s) verify changes (e.g. unit test, autotest)
- [X] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [X] Logs attached
- [X] Logs available on request
Testing has been carried out in autotests as well as RealFlight.
The new autotest attempts to explore as much of the new functionality as possible. You need to read the PID example controller that is used in order to fully understand the test.
In RF, the test have been done with the FT3DXL aircraft. It is very clear when the controller banks are switched, the Custom Controller isn't tuned for this aircraft and it produces angle overshoots. Other than that, no bugs or side-effects have been observed.
Parameters and logs: [Dropbox](https://www.dropbox.com/scl/fo/i9wncuajxgpdtiocgg9p1/ACuCPd5g3Vrdy4cHC1xioi4?rlkey=ay0d4q8ha7o4haa9r8xxsjclt&st=5onxxaek&dl=0)
### Size comparison
```
./Tools/scripts/size_compare_branches.py --board=Durandal --vehicle=copter,plane --no-merge-base --master=ap_master
SCB: Running (git symbolic-ref --short HEAD) in (.)
SCB-GIT: feature/custom_plane_controller_us
SCB: Building Task(Durandal, ap_master, /tmp/tmppvd76dfa/out-master-Durandal, ['copter', 'plane'], [] arm-none-eabi)
SCB: Running (git checkout ap_master) in (.)
SCB: Running (git submodule update --recursive) in (.)
SCB: Running (./waf configure --board Durandal --consistent-builds) in (.)
SCB: Running (./waf copter) in (.)
SCB: Running (./waf plane) in (.)
SCB: Running (rsync -ap build/ /tmp/tmppvd76dfa/out-master-Durandal) in (.)
SCB: Building Task(Durandal, feature/custom_plane_controller_us, /tmp/tmppvd76dfa/out-branch-Durandal, ['copter', 'plane'], [] arm-none-eabi)
SCB: Running (git checkout feature/custom_plane_controller_us) in (.)
SCB: Running (git submodule update --recursive) in (.)
SCB: Running (./waf configure --board Durandal --consistent-builds) in (.)
SCB: Running (./waf copter) in (.)
SCB: Running (./waf plane) in (.)
SCB: Running (rsync -ap build/ /tmp/tmppvd76dfa/out-branch-Durandal) in (.)
Board,copter,plane
Durandal,*,0
```
A : Some oustanding bugs still.
George : Oof, must have missed those. I’ll fix them.
UTC0824
master ← lthall:20260715_Replay_MSG_CREATE_Logged_Bytes
opened 06:16AM - 15 Jul 26 UTC
The logged length of a replay message is offsetof(_end), which excludes any
tai… l padding in the in-memory struct, so copying sizeof(msg) read up to 4 bytes
past the end of the log record buffer (a stack-buffer-overflow under
AddressSanitizer). On master this is demonstrable on RGPI (4 bytes) and RGPJ
(1 byte); RGPK (3 bytes) is also affected once the moving-baseline yaw work
lands. Copy the logged length and value-initialise the struct so the padding is
deterministic.
### Summary
Replay's MSG_CREATE copied sizeof(struct) out of a log record that only holds
offsetof(_end) bytes, reading past the end of the on-stack record buffer for any
R* message whose (unpacked) struct has tail padding. Copy exactly the logged
length and value-initialise the destination so its padding is deterministic.
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [x] Infrastructure change (e.g. unit tests, helper scripts)
- [ ] Automated test(s) verify changes (e.g. unit test, autotest)
- [x] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
#### How to demonstrate the problem and verify the fix
1. Root cause (compile-time, no build of ArduPilot needed). The logged payload is
offsetof(log_X, _end); the old memcpy copied sizeof(log_X). For any unpacked
struct with tail padding these differ, so the copy reads bytes that are not in
the record. Confirm with a throwaway program using the real field layouts:
$ cat > pad.cpp <<'EOF'
#include <cstdio>
#include <cstddef>
#include <cstdint>
struct Vector3f { float x, y, z; };
struct log_RGPI { Vector3f antenna_offset; float lag_sec;
uint8_t have_vertical_velocity:1,horizontal_accuracy_returncode:1,
vertical_accuracy_returncode:1,get_lag_returncode:1,
speed_accuracy_returncode:1,gps_yaw_deg_returncode:1;
uint8_t status, num_sats, instance, _end; };
struct log_RGPJ { uint32_t last_message_time_ms; Vector3f velocity;
float sacc, yaw_deg, yaw_accuracy_deg; uint32_t yaw_deg_time_ms;
int32_t lat, lng, alt; float hacc, vacc; uint16_t hdop;
uint8_t instance, _end; };
#define R(T) printf("%-9s sizeof=%2zu offsetof(_end)=%2zu overread=%zu\n",\
#T,sizeof(T),offsetof(T,_end),sizeof(T)-offsetof(T,_end));
int main(){ R(log_RGPI); R(log_RGPJ); }
EOF
$ g++ -O2 pad.cpp -o pad && ./pad
log_RGPI sizeof=24 offsetof(_end)=20 overread=4
log_RGPJ sizeof=56 offsetof(_end)=55 overread=1
The old macro copies the "sizeof" column; only the "offsetof(_end)" column
exists in the record. The difference is read out of bounds.
2. Runtime proof with AddressSanitizer.
a. Produce a log containing R* replay records (SITL, GPS present by default):
sim_vehicle.py -v ArduCopter
# in the console: param set LOG_REPLAY 1; param set LOG_DISARMED 1
# reboot, arm, fly ~30 s, disarm -> logs/00000001.BIN
b. Build Replay with ASan and run it on that log (reproduces on master):
CC=clang-19 CXX=clang++-19 ./waf configure --board sitl --debug --asan
./waf replay
./build/sitl/tool/Replay logs/00000001.BIN
ASan reports a stack-buffer-overflow whose read frame is the memcpy in
MSG_CREATE (LR_MsgHandler.cpp), backed by the msg[f.length] VLA in
AP_LoggerFileReader::update() (DataFlashFileReader.cpp) — for RGPI it reads
4 bytes past the buffer, for RGPJ 1 byte.
c. Apply this patch, rebuild (./waf replay) and rerun the same command on the
same log. The overflow report is gone and Replay output is unchanged.
### Description
Replay reads each dataflash record into an on-stack VLA sized to the record
length (uint8_t msg[f.length] in AP_LoggerFileReader::update(),
Tools/Replay/DataFlashFileReader.cpp). The payload after the 3-byte header is
therefore f.length - 3 == offsetof(log_X, _end) bytes.
MSG_CREATE in Tools/Replay/LR_MsgHandler.cpp reconstructed the message with
`memcpy(&msg, msgbytes+3, sizeof(msg))`. The AP_DAL replay structs
(libraries/AP_DAL/LogStructure.h) are not PACKED, so sizeof rounds the struct up
past the _end marker to satisfy alignment. sizeof therefore exceeds the logged
offsetof(_end) for every struct that has tail padding, and the memcpy reads that
many bytes past the end of the record buffer: 4 bytes for RGPI, 1 for RGPJ (and
3 for RGPK, once the moving-baseline yaw work adds it). This is undefined
behaviour and a stack-buffer-overflow flagged by AddressSanitizer.
The fix copies offsetof(log_X, _end) — exactly the bytes present in the record —
and value-initialises the destination (`log_X msg {}`) so the struct's tail
padding is deterministically zero rather than left as indeterminate stack bytes.
This is a general fix in the shared MSG_CREATE macro; it covers every R* handler,
not only the GPS records that surface it today. Only the host-side Replay tool is
affected; no flight firmware changes.
A : We’ll have to make sure we don’t break existing replays.
- We have a set of interesting logs that we can check against : EKFLogs - Google Drive
UTC0834
master ← zebulon-86:pr/lsm6dsv-driver-support
opened 05:51AM - 02 Jun 26 UTC
### Summary
Add support for `LSM6DSV32X` and `LSM6DSK320X` sub-variants in th… e shared LSM6DSV-family inertial sensor driver.
### Classification & Testing
- [x] Checked by a human programmer
- [x] Tested on hardware
- [x] Logs attached
### Description
Add `LSM6DSV32X` and `LSM6DSK320X` support to the shared LSM6DSV-family path. `LSM6DSK320X` is detected by `WHO_AM_I`, while `LSM6DSV32X` is split from `LSM6DSV16X` by reading `CTRL8[2]` after reset, as both parts report `WHO_AM_I=0x70`. Both variants are registered with dedicated INS device types, use the correct accel/gyro scale encodings, and are supported by `decode_devid.py`.
### Testing
**Ground identification**
- Pixhawk6C with `LSM6DSK320X + BMI088`: GCS banner reported
`IMU0: LSM6DSK320X fast sampling 2.0kHz`; `decode_devid.py` reported
`DEVTYPE_INS_LSM6DSK320X`.
- Pixhawk6C with `LSM6DSV16X + BMI088`: GCS banner reported
`IMU0: LSM6DSV16X fast sampling 2.0kHz`; `decode_devid.py` reported
`DEVTYPE_INS_LSM6DSV16X`.
- Pixhawk6X with three onboard `LSM6DSV32X` IMUs: GCS banner reported
`LSM6DSV32X fast sampling 2.0kHz` on `IMU0/1/2`; `decode_devid.py`
reported `DEVTYPE_INS_LSM6DSV32X`.
**Flight test**
- Platform: Pixhawk6C with `BMI088 + LSM6DSK320X`
- Indoor optical-flow flight, `220.7 s`, covering `STABILIZE`, `ALT_HOLD`,
and `LOITER`
The `LSM6DSK320X` maintained stable `2.0 kHz` fast sampling throughout the log.
`IMU.EG` / `IMU.EA`, `VIBE.Clip`, `XKF4.FS`, and `XKFS.AI` all stayed at `0`.
The `LSM6DSK320X` accel/gyro traces closely matched the onboard `BMI088`
reference over the selected flight window, with matching trend, phase, and
peak timing. `XKF1/#0` and `XKF1/#1` attitude solutions also tracked closely in
`Roll`, `Pitch`, and `Yaw`, with no sustained divergence.
Vibration remained normal throughout the flight. `VibeX/Y/Z` showed only brief
mid-flight increases, with no sustained high-vibration region or progressive
degradation; peak values stayed around the `10-12` range.
**Logs / evidence**
- [Pixhawk6C_BMI088-LSM6DSK320X_IndoorLoiter](https://drive.google.com/file/d/1iM1qrRqJg9o8bBxtl55GNdDxXOw_SNOS/view?usp=sharing)
- IMU: `LSM6DSK320X` maintained stable `2.0 kHz` fast sampling; accel/gyro traces closely match the onboard `BMI088` reference.
<img width="2259" height="1336" alt="Pasted image 20260602121021" src="https://github.com/user-attachments/assets/d643229f-1f76-4bed-8102-fb4f70669e50" />
<img width="2244" height="1277" alt="Pasted image 20260602100109" src="https://github.com/user-attachments/assets/0338e87a-740d-4683-a46b-a7b26bad31cc" />
<img width="2237" height="1236" alt="Pasted image 20260602100031" src="https://github.com/user-attachments/assets/7171a24b-2d63-4f8a-84c7-eec25ec3eba2" />
- XKF1: `XKF1/#0` and `XKF1/#1` attitude solutions track closely in `Roll`, `Pitch`, and `Yaw`, with no sustained divergence.
<img width="2248" height="626" alt="Pasted image 20260602100547" src="https://github.com/user-attachments/assets/ef8c95ea-62de-4752-908a-9ca2aafb4228" />
<img width="2227" height="612" alt="Pasted image 20260602100620" src="https://github.com/user-attachments/assets/379840bc-46bd-4eb5-bb86-2e293f3425c8" />
- VIBE: overall vibration remained normal, with only brief mid-flight increases and no sustained high-vibration region.
<img width="2235" height="616" alt="Pasted image 20260602100736" src="https://github.com/user-attachments/assets/077151d8-5f17-4c37-999d-5681c65e0498" />
### Notes
- Register configuration was validated indirectly through correct identification,
stable sample rate, zero IMU error counters, consistent flight data, and normal
EKF behavior.
- Flight evidence covers the `LSM6DSK320X` path on Pixhawk6C hardware.
- This contribution was developed with AI assistance; all changes were reviewed and validated by the human author.
P : BetaFlight do not allow boards with this sensor anymore, pointing to very high noise levels.
But Holybro have tested this and they say it works well.
Huibean : No, this PR is about a different part. The questionable part is an older one and we have merged it already.
Merged!
UTC0846
master ← lthall:20260715_AP_GPS_Unicore_Vertical_Baseline
opened 06:03AM - 15 Jul 26 UTC
UNIHEADINGA reports the 3D length of the antenna baseline and the elevation
ang… le of that baseline (pitch, +/-90 degrees), so the vertical component is
length*sin(pitch). Using tan overstated the vertical component (11% at 26
degrees) and exceeded the baseline length itself from 45 degrees, where the
overstated vertical component falls outside the tolerated vertical-separation
band and all yaw is rejected: steep antenna installations could never provide
yaw on this backend.
### Summary
Fix the Unicore UNIHEADINGA moving-baseline GPS yaw path to compute the
antenna baseline's vertical component as length*sin(pitch) instead of
length*tan(pitch).
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [ ] Automated test(s) verify changes (e.g. unit test, autotest)
- [x] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
### Description
The Unicore UNIHEADINGA message reports the moving-baseline antenna vector as a
3D baseline length plus an elevation angle (pitch). The down/vertical component
of that vector is therefore length*sin(pitch). The NMEA backend computed it as
length*tan(pitch), which overstates the vertical component by 1/cos(pitch):
about 11% at 26 degrees of pitch, and equal to or greater than the reported
baseline length itself from 45 degrees upward.
That vertical component is passed as `reported_D` into
`AP_GPS_Backend::calculate_moving_base_yaw()`, which rejects the fix when
`reported_D` falls outside a tolerance band built from the configured antenna
offset and the current vehicle attitude. An overstated vertical component pushes
`reported_D` above that band, so any appreciably pitched antenna baseline was
rejected and no GPS yaw was produced on this backend. Installations with a steep
antenna baseline could never obtain yaw.
The fix replaces tanf with sinf for this one term in the UNIHEADINGA handler in
libraries/AP_GPS/AP_GPS_NMEA.cpp. Only the Unicore NMEA backend is affected; the
u-blox, Septentrio and DroneCAN moving-baseline paths compute their own vertical
component and are unchanged.
MergeOnCIPass.
UTC0854
master ← davidbitton:local/cdc-ecm-spike
opened 08:52PM - 01 Jul 26 UTC
## Summary
Experimental **opt-in** USB **CDC-ACM + CDC-ECM** composite and an *… *AP_Networking** USB-ECM lwIP netif for static IPv4 over USB, exposed as a separate board target **`MatekH743-ECM`**.
- Stock **`MatekH743`** remains **dual CDC-ACM** (OTG2 in `SERIAL_ORDER`); ECM is **not** enabled by default.
- Lab board: `HAL_WITH_USB_CDC_ECM`, USB PID **`0x574E`**, product string `MatekH743-ECM`, shared **ACM-only** bootloader (`USE_BOOTLOADER_FROM_BOARD MatekH743`).
- Backend: `AP_NETWORKING_BACKEND_USB_ECM` (default off unless board defines it).
- Defaults (`defaults.parm`): `NET_ENABLE`, static-friendly DHCP off, **`NET_P1` UDP server / MAVLink2 / port 14550** so the FC does **not** need the GCS IP (GCS uses `udpout:FC_IP:14550` / QGC target host).
### HIL (author)
- Matek H743-Mini, macOS host NIC on ECM, static `192.168.144.14` (FC) / host peer on same `/24`.
- ICMP ping, MAVProxy `udpout:192.168.144.14:14550`, QGroundControl to same (UDP client → FC server).
- ACM MAVLink still works on the composite.
### Non-goals / notes for reviewers
- Not enabled in bootloader.
- F4 / insufficient EP budget out of scope (compile guards).
- macOS may show the USB iMACAddress as the interface MAC; host may need a **distinct** `lladdr` for reliable ARP (lab note).
- Frame reassembly accounts for hosts that pad to MPS without ZLP (ethertype / IP length heuristics).
- Local design notes under `local/cdc-ecm/` are **not** in this PR (gitignored author docs).
## Test plan
- [ ] `./waf configure --board MatekH743 && ./waf copter` (regression, no ECM)
- [ ] `./waf configure --board MatekH743-ECM && ./waf copter`
- [ ] Flash MatekH743-ECM; USB identity PID `0x574E`; single ACM + ECM NIC on host
- [ ] MAVProxy on ACM
- [ ] Host static IP on ECM iface; ping FC `NET_IPADDR` (default `192.168.144.14`)
- [ ] GCS via UDP client to `FC_IP:14550` with `NET_P1_TYPE=2` / protocol MAVLink2 (defaults)
- [ ] Confirm stock MatekH743 image still dual-ACM / no ECM symbols when ECM off
Draft for early review / direction; happy to split USB descriptors vs networking backend if preferred.
A : This is fascinating, but we need to know its flash cost.
I suspect it’s smaller.
Also what’s the bandwidth?
We need to make sure it works with Linux (RPi, NVidia, etc) as well.
It looks like it’s also allowing for dynamic instantiation of the USB interface, which is good.
UTC0902
master ← peterbarker:pr-claude/remove-yaw-reset-angle
opened 02:51AM - 15 Jul 26 UTC
### Summary
Removes the values supplied when handling resets from the AP_AHRS… library. These were unused.
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [x] Automated test(s) verify changes (e.g. unit test, autotest)
- [ ] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
```
Board AP_Periph antennatracker blimp bootloader copter heli iofirmware plane rover sub
CubeOrange-periph-heavy * *
Durandal -1144 -1136 * -1160 -1144 -1168 -1152 -1280
Hitec-Airspeed * *
KakuteH7-bdshot -1120 -1144 * -1120 -1136 -1344 -1208 -1024
MatekF405 -1432 -1344 * -1296 -1288 -1384 -1360 -1352
Pixhawk1-1M-bdshot -1320 -1328 -1352 -1336 -1176 -1336 -1368
SITL_x86_64_linux_gnu -4952 -9048 -4952 -4960 -4952 -4952 -4960
YJUAV_A6SE -1192 -1208 * -1200 -1184 -1336 -1144 -1384
f103-QiotekPeriph * *
f303-MatekGPS * *
f303-Universal * *
iomcu *
revo-mini -1376 -1368 * -1320 -1328 -296 -1296 -1384
skyviper-v2450 -1384
speedybeef4 -1480 -1368 * -1456 -1448 -1800 -1256 -1368
```
### Description
ArduPilot used to take the reset values and use it in its calculations. It not longer uses any of these, so just remove them from the results we track.
These were fragile anyway. Two resets in a row would lose the information about the previous reset. A caller could track the information it last acted on and the new value coming from the estimator easily enough, but a single, "this is the last reset value" is non-sensical.
Note that I don't need to chase this down into the EKF, the `AP_AHRS_NavEKFx` shims could translate. But this is a lot of wasted flash at the moment!
P : Lots of unused EKF methods. Cleaning them up saves a lot of flash.
A : I worry abot the EKF2 changes. We don’t test it thoroughly and we won’t know if something is broken.
We’d better test EKF2 vs SITL values.
UTC0916
master ← LupusTheCanine:RPMBuffer
opened 07:32PM - 13 Jul 26 UTC
### Summary
Make pin-based RPM sensors use ring buffer to hold samples, this … allows updating at 400Hz or every sample (at less than 400 pulses per second) while averaging over 14 samples or 1s whichever is shorter.
It is (intended to be) stacked on #33363
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [ ] Automated test(s) verify changes (e.g. unit test, autotest)
- [ ] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
### Description
Adds ring buffer to pin-based RPM sensors.
Lupus : The idea is to increase the rate at which the RPM data is saved. Ideally at 400Hz, up from 50Hz.
A : 400Hz sampling doesn’t make a lot of sense, unless your RPM is VERY high (e.g. 24000), and even then the inertia of the rotor will not allow very rapid changes.
Lu : This application is to use it for the heli RPM governor. Mine needs to be tightly tuned to get good RPM control response, but the 50Hz updates are too slow.
A : I’m very surprized that you need such high bandwidth in a governor.
Lu : In very small helicopters you need to update throttle very fast, to compensate for loading.
Leonard : At 50Hz update rate, you have about 10ms latency and you are prone to noise. But whether it’s worth it depends on your desired bandwidth. If you have a really high bandwidth system, then it might make sense.
A : Let’s see a list of the hardware used in this system.
Lu : What I’m really interested is run the RPM library at loop rate.
UTC0945
master ← peterbarker:pr/nvf-from-log-message-field
opened 01:30AM - 13 Jul 26 UTC
### Summary
Adds a method into AP_Logger's interface which tells the library … to start pushing out named-value mavlink messages for a nominated field.
Adds a mavlink message so a GCS can ask for it, and a Lua binding for persistent setups.
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [x] Automated test(s) verify changes (e.g. unit test, autotest)
- [x] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
<img width="2813" height="1532" alt="image" src="https://github.com/user-attachments/assets/e14f6638-52cb-448f-b2f4-579d1730181e" />
Given the size increase, we should probably leave this off on <=2048kB:
```
Board AP_Periph antennatracker blimp bootloader copter heli iofirmware plane rover sub
CubeOrange-periph-heavy 1632 *
Durandal 1312 1312 * 1280 1360 1320 1352 1368
Hitec-Airspeed * *
KakuteH7-bdshot 1312 1296 * 1360 1200 1112 1328 1400
MatekF405 32 48 * 40 32 48 56 40
Pixhawk1-1M-bdshot 32 40 40 40 48 48 40
SITL_x86_64_linux_gnu 4632 8736 536 4640 4640 544 4640
YJUAV_A6SE 1344 1368 * 1384 1456 1488 1376 1232
f103-QiotekPeriph * *
f303-MatekGPS * *
f303-Universal 16 *
iomcu *
revo-mini 32 40 * 40 40 48 48 40
skyviper-v2450 1520
speedybeef4 32 40 * 40 40 48 56 40
```
### Description
Adds sending of any dataflash field over mavlink.
There's the open question on that whole "GPS good to align" when the GPS has been absent for a long time, but... yeah, separate issue :-)
P : New MAVLink message requests a named value based on a pair of strings.
A : That’s useful. And not impossibly expensive in terms of flash.
Cute idea, I’ll test it in the weekend.
UTC0949
master ← Juergen-Fahlbusch:Juergen-Fahlbusch-patch-1
opened 11:40AM - 03 Jul 26 UTC
### Summary
AP_FlashStorage: set current_sector during init
Related discus… sion https://discuss.ardupilot.org/t/potential-incomplete-initialization-on-ap-flashstorage/144440
Perhaps resolves: https://github.com/ArduPilot/ardupilot/issues/33538
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [ ] Automated test(s) verify changes (e.g. unit test, autotest)
- [x] Tested manually, description below (e.g. SITL)
- [x] Tested on hardware
- [ ] Logs attached
- [ ] Logs available on request
### Description
While troubleshooting aninternal error 0x200000 I noticed that parameters could no longer be saved permanently. Notably, the parameters STAT_BOOTCNT and STAT_RUNTIME—which usually increment automatically—kept reverting to their previous values after a restart. Further analysis revealed that:
Sector 0 was marked with status [SECTOR_STATE_AVAILABLE] Sector 1 was marked with status [SECTOR_STATE_IN_USE] Consequently, the current parameters were being loaded from Sector 1. However, when writing new parameters, the system attempted to write to Sector 0. In my opinion, the cause of this is that the variable current_sector is not set to the active sector during initialization.
I was able to resolve the issue—at least for testing purposes—by inserting the initialization of the current_sector variable after the following code block:
// work out the first sector to read from using sector states
enum SectorState states[2] {header[0].get_state(), header[1].get_state()};
uint8_t first_sector;
if (states[0] == states[1]) {
if (states[0] != SECTOR_STATE_AVAILABLE) {
return erase_all();
}
first_sector = 0;
} else if (states[0] == SECTOR_STATE_FULL) {
first_sector = 0;
} else if (states[1] == SECTOR_STATE_FULL) {
first_sector = 1;
} else if (states[0] == SECTOR_STATE_IN_USE) {
first_sector = 0;
} else if (states[1] == SECTOR_STATE_IN_USE) {
first_sector = 1;
} else {
// doesn't matter which is first
first_sector = 0;
}
//added initialization current_sector
current_sector = first_sector;
P : This is very strange; how could it even work without it?
A : The first sector is usually zero, that’s why the default initialization saved us.
UTC0951
master ← lthall:20260704_GPS_Yaw_EKF_2
opened 11:35AM - 13 Jul 26 UTC
Summary
Moving-baseline GPS yaw assumes the vehicle is level; for antenna basel… ines with a vertical component the recovered yaw is biased when the vehicle rolls or pitches. This PR exports the antenna offset the yaw was calculated from and applies the exact attitude correction inside EKF3, per lane, at the fusion time horizon (gated behind EK3_FEATURE_MOVING_BASELINE, on 2 MB+ boards), with Replay support via a new RGPK DAL message.
### Classification & Testing (check all that apply and add your own)
- [x] Checked by a human programmer
- [ ] Non-functional change
- [ ] No-binary change
- [ ] Infrastructure change (e.g. unit tests, helper scripts)
- [x] Automated test(s) verify changes (e.g. unit test, autotest)
- [x] Tested manually, description below (e.g. SITL)
- [ ] Tested on hardware
- [ ] Logs attached
- [x] Logs available on request
Three new autotests, each verified to fail against the code without its fix (negative control) before being confirmed to pass with it:
- GPSForYawAttitudeCorrection: flies a circle with a large-Z antenna baseline; EKF yaw must track SIMSTATE truth while banked AND the yaw innovation test ratio must stay below 1 (a wrong measurement that is merely gate-rejected leaves the EKF coasting accurately on the gyro, so yaw-vs-truth alone can false-pass).
- GPSForYawVerticalBaseline: a baseline with no horizontal separation carries no yaw information; the driver must reject it rather than publish receiver noise as yaw.
- GPSForYawCompassFallback: with EK3_SRC1_YAW=3, a measurement the EKF rejects geometrically must count as "no usable yaw" so the magnetometer fallback engages after 10 s, even though the GPS is still publishing.
Existing GPSForYaw autotest still passes.
Description
The GPS driver recovers vehicle yaw from the reported baseline heading by subtracting the bearing of the body-frame antenna offset, which is only exact when the vehicle is level. An earlier attempt (#33380) corrected this in AP_GPS using AP::ahrs() attitude, but that creates an EKF->sensor->EKF loop (a bad lane contaminates every lane) and breaks Replay. Instead:
- AP_GPS records the body-frame offset used to calculate each moving-baseline yaw in GPS_State::mb_yaw_offset, exposed via AP_GPS::get_mb_yaw_offset(). The offset is zeroed whenever the published yaw does not come from a moving baseline (solution rejected, AGRICA lost, or a device-reported heading takes over: DroneCAN Heading, NMEA HDT/THS, KSXT) so a stale offset can never be paired with a heading it does not belong to. A shared yaw_source_instance() helper keeps the base->rover redirect identical between the yaw and the offset it accompanies.
- AP_GPS also rejects moving-baseline solutions whose receiver-reported baseline has insufficient horizontal separation (sqrt(dist^2 - D^2) < AP_GPS_MB_MIN_ANTENNA_SEPARATION_M): a baseline close to vertical carries no usable yaw regardless of antenna separation.
- AP_DAL carries the offset in a new low-rate RGPK message (written when changed), so Replay reproduces the fusion bit-exactly. Replaying older logs applies a zero offset, i.e. no correction.
- AP_NavEKF3 buffers the offset with each yaw measurement and correctGPSYawForAntennaOffset() applies the residual correction after storedYawAng.recall(), using this core's own roll/pitch at the fusion horizon (lane-independent, Replay-exact). yawAngErr is inflated by the tilt sensitivity |z|/|xy| of the levelled baseline. A measurement whose baseline is too close to vertical at the estimated attitude is treated exactly like no measurement: not fused, not used for the (innovation-ungated) yaw alignment, and it does not refresh last_gps_yaw_ms — so GPS_COMPASS_FALLBACK still engages and yaw-source health reporting stays truthful while the GPS keeps publishing unusable yaw. The correction is gated behind EK3_FEATURE_MOVING_BASELINE (enabled on 2 MB+ boards and Replay/DAL builds, and only where GPS_MOVING_BASELINE is compiled in); 1 MB boards keep the existing level-assumption behaviour and pay none of the flash.
Split into their own PRs (both found while working on this):
- AP_GPS (Unicore NMEA): UNIHEADINGA reports the 3D baseline length and its elevation angle, so the vertical component is length*sin(pitch); using tan overstated it (11% at 26 deg) and exceeded the baseline length itself beyond 45 deg, which made steep antenna installations unable to ever provide yaw on this backend. → <link PR>
- Replay: MSG_CREATE copied sizeof(msg) from a buffer that only holds the logged offsetof(_end) bytes, reading up to 4 bytes past the record (stack-buffer-overflow under AddressSanitizer for RGPI/RGPJ/RGPK). → <link PR>. This PR adds RGPK, which has tail padding like RGPI/RGPJ, so that Replay fix should land with or before this one for AddressSanitizer-clean replay of RGPK.
Known limitation (pre-existing, unchanged): yaw forwarded over the DroneCAN gnss_Heading message (AP_Periph Heading fallback, FC-as-CAN-GPS) cannot carry the antenna offset, so it remains uncorrected on the consumer; the receiving driver zeroes the offset to make that explicit.
L : I’m a little out of my depth regarding the validity of the data lag and EKF time horizon.
A : I’m happy with the structure and approach. Let’s test fly it!
Might be nice to add a log for the corrected yaw.