Skip to content

AP_Radar: Nearby-craft OSD addition for formation flying#32333

Open
t413 wants to merge 3 commits into
ArduPilot:masterfrom
t413:radar
Open

AP_Radar: Nearby-craft OSD addition for formation flying#32333
t413 wants to merge 3 commits into
ArduPilot:masterfrom
t413:radar

Conversation

@t413

@t413 t413 commented Feb 28, 2026

Copy link
Copy Markdown

Summary

See the original PR #25684 here by @MUSTARDTIGERFPV!

This is to add support for FormationFlight to Ardupilot. It's an open-source inter-UAS positioning & telemetry for FPV pilots. It lets FPV pilots find each other in the air through beacons sent with positioning information over LoRa or ESPNOW.

Details

This commit:

  • Adds a new AP_Radar library implementing the MSP radar protocol (MSP2_SET_RADAR_POS, 0x100B), for aided formation FPV flights. Each aircraft broadcasts its 3D location to peers over MSP
  • The system is enabled by setting OSD1_RADAR_EN=1
  • AP_OSD_Screen additions: displays bearing arrow, horizontal distance, and vertical distance to the current peer, cycling through healthy peers every 2 seconds. Peer tracking state (_radar_peer_id, _radar_last_peer_change) is held as screen instance members.

Changes from original PR

  • fixed all merge conflicts
  • updated outdated API calls
  • now matching class/struct naming styles
  • added null checks that caused crashes
  • removed unused AP_Radar::_log_bit

Testing

  • Entirely written by human programmers. Code-reviewed by AI.
  • Tested in SITL: Simulation tested using the fomationflight simulated contacts
  • Tested on hardware
  • Logs attached
  • Logs available on request
  • Autotest included

Examples

287487159-24ba21cd-d345-4f41-bc82-bdc997bbb839

@t413

t413 commented Mar 1, 2026

Copy link
Copy Markdown
Author

Howdy folks!

Right now I've just reworked the original PR to work on master now that three years have passed. This approach as-is does touch 19 files and make a whole new library and task, just to marshal a radar_peers[6] array from the existing MSP library to the AP_OSD_Screen so it can run msp_handle_radar().

This approach is extensible, potentially paving the way for future alternate data sources or actions with this data. However it's quite the heavy addition.

If you'd prefer I can redo this to store the radar_peers[6] array in the AP_MSP library and have the OSD call a static singleton for data. This is not an unusual pattern for the OSD code.

@t413 t413 force-pushed the radar branch 2 times, most recently from fc35741 to 159ba6f Compare March 1, 2026 00:47

@Hwurzburg Hwurzburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat...but very specialized feature! As one of AP's FPV advocates I really like this!...that said, this feature should be disabled by default in all builds and use the custom firmware builder to enable... it's a good chunk of code and would be used by very few users...it needs a good wiki also linking Formation Flight...

@IamPete1

IamPete1 commented Mar 1, 2026

Copy link
Copy Markdown
Member

Any reason this would not work on copters or rovers? It might be better at the vehicle level rather than in plane.

@t413

t413 commented Mar 1, 2026

Copy link
Copy Markdown
Author

No reason at all! I was considering that myself, but kept it closely aligned to the original PR initially.

And I agree it's pretty niche. But it is a supported documented type in MSP, so I do think it would be reasonable try a MSP-stored OSD direct implementation (see my last comment) since it'd be a far far simpler and smaller implementation. I'll give that a first pass.

@Hwurzburg Hwurzburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be a build option only

@t413

t413 commented Mar 3, 2026

Copy link
Copy Markdown
Author

Alright, brand new re-written approach is ready for review!

My hope is that this more minimal lightweight structure can be included by default, without a default-off build option. That will greatly help adoption and the ease of including friends in formation flights. I believe, with the new minimal footprint, that it's appropriate.

So instead of adding a AP_Radar library, task, and large associated flash&memory– this follows as much AP president as possible and adds the protocol support to AP_MSP. Rather than 20 files/632 lines it's now 8 files/178 lines. It now adds exactly 123 bytes to memory, something we can lower if you'd like to reduce the RADAR_MAX_PEERS.

So please re-review and reconsider, given the new approach @Hwurzburg and @IamPete1!

@Hwurzburg Hwurzburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@t413 I dont know where you came up with it only being 123bytes....its well over a 1KB....this needs to be a separate build option for this feature

also commit structure is incorrect...one commit involving two different libraries...apparently our Malformed commits CI check needs some work...

@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Thank you for your review and efforts @Hwurzburg, I appreciate it.

A few things:

  • The "123 bytes to memory" is for RAM, and it's from me manually adding it up. You must mean flash?
  • You're seeing an increased 1K of flash?! That's huge, if that's true I agree it should be #if disabled. Where are you seeing 1KB?
  • "commit structure is incorrect" – ahh, I see that this can only have one library per commit from this page. Restructuring now.

@t413 t413 force-pushed the radar branch 4 times, most recently from 36a6067 to afb88b6 Compare March 4, 2026 07:34
@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Alright! Added the feature enabler, defaulted to off. Separated into two separate commits, one for each library. Got the extract_features.py system working and it passes all tests.. but looks like your colcon build action hung randomly and I don't have auth to re-trigger. Hopefully this all looks good!

Again, thank you for your help–

@Hwurzburg Hwurzburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colcon is always problematic,,,,restarted

you did not disable the feature for F7/H7 devices....we need a discussion on whether we spend 1Kbyte on this feature...especially when it brings some F7s down from 15K free to 14K free....personally, I am against this,even though I am an FPV flyer exclusively on all vehicle types...

Also, I agree with @peterbarker that this data should be in the location storage so as to enable following, auto gimbal poiting, etc. but I dont consider it a blocker to this...the flash impact above is, however, to me

Comment thread libraries/AP_MSP/AP_MSP.h Outdated
#define RADAR_PEER_FRESH_TIME_MS 3000

struct MSP_RadarPeer {
MSP::msp_radar_pos_message_t info;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could save a fair bit by only storing what its actually used. Only lat long and alt?

@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Great to hear back @Hwurzburg and @IamPete1. A few things

  • 1kb additional. How are you coming to this number? I never got a reply about it before and I'd like to classify it better.
  • Disable for F7/H7 devices: The default is set to 0 in the Feature() definition in build_options.py. Is this not correct? I'm following existing president & documentation as best as I can.
  • location storage: agreed, sounds like a good next-step PR effort after this.
  • @IamPete1's review about MSP_RadarPeer storing less data: Sure, I'll do that too. The additional RAM footprint was only ~120bytes total for this PR but I can see if it can be lowered more. I do fear storing this data independent of the MSP packet context will invite more scope-creep calls to move where it lives. But I'll make the change for you, of course.

@LupusTheCanine

Copy link
Copy Markdown

Great to hear back @Hwurzburg and @IamPete1. A few things

  • 1kb additional. How are you coming to this number? I never got a reply about it before and I'd like to classify it better.
  • Disable for F7/H7 devices: The default is set to 0 in the Feature() definition in build_options.py. Is this not correct? I'm following existing president & documentation as best as I can.
  • location storage: agreed, sounds like a good next-step PR effort after this.
  • @IamPete1's review about MSP_RadarPeer storing less data: Sure, I'll do that too. The additional RAM footprint was only ~120bytes total for this PR but I can see if it can be lowered more. I do fear storing this data independent of the MSP packet context will invite more scope-creep calls to move where it lives. But I'll make the change for you, of course.

I think this fundamentally shouldn't be limited to MSP datalink, soon somebody will want this with MAVLink, FLARM and ADSB 😀,

@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Sounds great @LupusTheCanine, let's work on that in a new PR afterwards!

This PR adds

  1. MSP_RADAR protocol support
  2. OSD "radar peer" element
  3. Necessary minimal storage in a reasonable place to enable the system

1 and 2 are valuable additions however the data is stored in the future. Let's keep appropriate scope and move forward. I can't wait for people to want MAVLink, FLARM and ADSB additions and expand the system. In the future we could add an AP_Radar library like the original PR #25684 from 2023 did or a locations DB like in #24429.

@Hwurzburg

Hwurzburg commented Mar 4, 2026

Copy link
Copy Markdown
Contributor
* 1kb additional. How are you coming to this number? I never got a reply about it before and I'd like to classify it better.

see the CI size tests under "All checks have passed"...for example the kakuteF7...
Screenshot from 2026-03-04 15-12-17

* Disable for F7/H7 devices: The default is set to 0 in the `Feature()` definition in build_options.py. Is this not correct? I'm following existing president & documentation as best as I can.

in the MSP.h you enable this for ANY MSP inclusion...the F7/H7 has MSP enabled...so it gets enabled...I dont think this feature needs to be enabled anytime MSP is included...

@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Thank you @Hwurzburg!

I'll look into how that test runs so I can figure out how to get this info locally. Waiting 2h for actions to run isn't feasible.

And so the default parameter in build_options.py just .. doesn't apply to H/F7 boards?

@t413

t413 commented Mar 4, 2026

Copy link
Copy Markdown
Author

Pushed a newly updated version, now with

  • #define AP_MSP_RADAR_ENABLED 0 in AP_MSP_config.h as @Hwurzburg requested
  • more minimal storage usage as @IamPete1 requested
  • rebased against master as the docs request

Ready to go! Now to wait 2h for the actions to run.

Update: finished! 5h this time 🫠

But it looks good! I've back-ported it to the latest stable branch and got it flashed and running great on two different wings of mine.

@kelvin8-glitch

Copy link
Copy Markdown

Im so happy your working on this. I didn't even know that had this feature. I definitely want to try this out on my wings and drones too. Can't wait to see the progression here. Thanks

@Singinius

Copy link
Copy Markdown

Happy to see someone working on a solution for this! Excited to try it out!

@vrquaeler

Copy link
Copy Markdown

Hi Tim,
Keep going !!!
Will pull your repo and give it a try.

@t413

t413 commented Apr 13, 2026

Copy link
Copy Markdown
Author

Hey folks! Did lots of testing and analysis with this and came up with a few changes. Was holding out hope that they could be an additional PR later but it's been 6 weeks. So a few changes!

  • Less flash usage!
    • Now 636 bytes additional when enabled (vs ~1k before)
    • And that's despite the new features below:
  • Handles stale duplicate radar packets from FormationFlight
    • FormationFlight sends stale repeat duplicate packets for quite a while without any sequence or timestamp, sadly. This now handles repeat stale data nicely.
  • Logs radar data to SD card for debugging, analysis, and review
  • Reports new and lost contacts as gcs->send_text so they show as info log alerts
  • OSD now shows stale contact age
  • Rebased against main again

Hopefully we can get some movement on this? Are there reservations? As requested it's now a default-off feature.

Edit: CI got some errors from the new log items. Documented them and pushed again and it fixed most targets but for some reason 5 of the SITL tests are still failing and I'm having trouble figuring out why. Any insight would be appreciated.

Edit2: Figured it out with fresh eyes. Should pass tests now.

@t413 t413 force-pushed the radar branch 3 times, most recently from 14d85ab to 41880c0 Compare April 13, 2026 19:25

@Hwurzburg Hwurzburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tools stuff needs to be separate commits since its a different library

t413 added 3 commits April 13, 2026 13:54
- Adds the MSP radar protocol type/struct (MSP2_SET_RADAR_POS, 0x100B)
- stored in the static singleton AP_MSP with getters
  * now stored as Location + time only
  * includes is_healthy method
  * now ignores incoming duplicate data for better stale reporting
- Enables reporting of nearby craft for formation flying
- Used for aided formation FPV flights, broadcasting 3D position
- fully disabled by default, AP will keep ignoring these packets
- logs to AP::logger under "MSPR" type
  * now documents log fields with correct format
- sends gcs messages for new and lost contacts

Based on the 2023 PR ArduPilot#25684 by @MUSTARDTIGERFPV
- adds to build_options.py
- adds to extract_features.py
- adding to both allows it to be enabled/detected and pass tests
- enabled with OSD1_RADAR_EN=1
- displays bearing arrow, horizontal distance, and vertical distance
  to the current peer, cycling through healthy peers every 2 seconds. 
- reports stale data age
- Peer tracking state (_radar_peer_id, _radar_last_peer_change) is 
  held as screen instance members.
- not included in the build by default, gated by AP_MSP_RADAR_ENABLED
- extracted draw_location method from draw_home
  * saves quite a bit of program space
}
#endif
GCS* gcs = GCS::get_singleton();
if (!was_present and now_present) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!was_present and now_present) {
if (!was_present && now_present) {

GCS* gcs = GCS::get_singleton();
if (!was_present and now_present) {
gcs->send_text(MAV_SEVERITY_INFO, "MSP Radar %c detected", msg.radar_no + 'A');
} else if (was_present and !now_present) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if (was_present and !now_present) {
} else if (was_present && !now_present) {

@tridge tridge left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me, but needs to be compiled on at least SITL so it doesn't bit-rot

#endif

#ifndef AP_MSP_RADAR_ENABLED
#define AP_MSP_RADAR_ENABLED 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be enabled on at least SITL so it gets compile tested, possibly should enable on all boards with more than 2M flash so it also gets built on boards like CubeRed and thus compile tested on STM32

UNUSED_RESULT(peer->location.get_height_above(loc, vertical_distance));
// Simple lightweight version: arrow + integer meters
const char sym = (vertical_distance >= 0) ? SYMBOL(SYM_UP) : SYMBOL(SYM_DOWN);
backend->write(x, y, false, "%c%dm", sym, (int)fabsf(vertical_distance));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both location and vertical dist writing to same x,y location on screen? doesn't seem right

@vrquaeler

vrquaeler commented May 8, 2026

Copy link
Copy Markdown

I think this fundamentally shouldn't be limited to MSP datalink, soon somebody will want this with MAVLink, FLARM and ADSB 😀,

That would be a killer feature. MAVLink in particular, it's ArduPilot's "native" language.
We could use this in conjunction with the great "Plane_follow" script from @timtuxworth.

Just dreaming ...
Let's get through this PR first...

@thespova

Copy link
Copy Markdown
Contributor

Yeah, glad to see this being worked on getting merged. Looks like nots of new stuff getting added to it too.

@thespova

Copy link
Copy Markdown
Contributor

Does this include @robustini 's changes here #25684 (comment) ?

@robustini

robustini commented May 14, 2026

Copy link
Copy Markdown
Contributor

Thank you for this implementation!
Once it’s merged, I’ll implement and test the exchange of position and altitude data between two RC controllers using ELRS and a backpack via ESPNOW.
This way, without needing additional onboard hardware, we’ll be able to share global position data on the ground (not in flight), with minimal lag, but it will work.
I've already created something more complex here using the two backpacks, and I think this implementation could work.

EDIT: I’ve already implemented everything, but based on my previous implementation.
In my case, two TX units with ELRS are used, and the necessary data is exchanged via the two paired backpacks in ESPNOW.
On the Ardupilot side, a small modification to my previous AP Radar implementation was also necessary.
I’m conducting bench tests and will then test it in flight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.