Skip to content

Commit 8059a26

Browse files
committed
feat: model autonomous drone airplane telemetry with UNCLASSIFIED classification across all 7 languages
1 parent 5c05b77 commit 8059a26

21 files changed

Lines changed: 1019 additions & 310 deletions

File tree

‎README.md‎

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ Traditionally, bridging these two environments requires:
6262
```mermaid
6363
flowchart LR
6464
subgraph "Autonomous Edge (Lattice OS)"
65-
L1["ALTIUS-600M Drone"] -->|Protobuf / JSON| LSDK["Anduril Lattice SDK<br/>(anduril.entitymanager.v1)"]
66-
L2["Dive-LD AUV"] -->|Protobuf / JSON| LSDK
67-
L3["Sentry Tower"] -->|Protobuf / JSON| LSDK
65+
L1["Fury UAV (FURY-UAV-01)"] -->|Protobuf / JSON| LSDK["Anduril Lattice SDK<br/>(anduril.entitymanager.v1)"]
66+
L2["Altius-600M Loitering Munition"] -->|Protobuf / JSON| LSDK
67+
L3["Dive-LD AUV"] -->|Protobuf / JSON| LSDK
6868
end
6969
7070
subgraph "PolyXML Polyglot Telemetry Bridge"
@@ -105,7 +105,7 @@ PolyXML provides **native dual-serialization parity** out of the box:
105105
```mermaid
106106
flowchart TD
107107
subgraph Ingestion["1. Edge Ingestion"]
108-
Lattice["Anduril Lattice Track<br/>(Protobuf / JSON)"]
108+
Lattice["Anduril Lattice Autonomous Drone Track<br/>(Protobuf / JSON)"]
109109
end
110110
111111
subgraph ModelLayer["2. Strongly-Typed Domain Model"]
@@ -217,12 +217,12 @@ Run the automated generation script across all 7 targets:
217217

218218
## 🗺 Semantic Field Mapping
219219

220-
The bridge translates telemetry from `anduril.entitymanager.v1.Entity` into compliant USAF UCI `uci:EntityMT` messages:
220+
The bridge translates telemetry from `anduril.entitymanager.v1.Entity` (autonomous drone airplane telemetry) into compliant USAF UCI `uci:EntityMT` messages:
221221

222222
| Anduril Lattice Telemetry Field | USAF UCI v2.5 XML Element | UCI XSD Type | Description |
223223
| :--- | :--- | :--- | :--- |
224224
| `id` | `EntityID/UUID` | `xs:string` | Unique global asset / track identifier |
225-
| `callsign` | `EntityID/Callsign` | `xs:string` | Human-readable tactical callsign |
225+
| `callsign` (`FURY-UAV-01`) | `EntityID/Callsign` | `xs:string` | Human-readable tactical drone callsign |
226226
| `timestamp` | `CreationTimestamp` | `xs:dateTime` | ISO 8601 UTC creation timestamp |
227227
| `timestamp` | `MessageHeader/Timestamp` | `xs:dateTime` | Header transmission timestamp |
228228
| `status` (`CONFIRMED`) | `EntityStatus` | `EntityStatusEnum` | Track status (`POTENTIAL`, `CONFIRMED`, `LOST`, `DROPPED`) |
@@ -232,8 +232,14 @@ The bridge translates telemetry from `anduril.entitymanager.v1.Entity` into comp
232232
| `kinematics.heading_degrees` | `Kinematics/Heading` | `xs:double` | True heading (0.0 to 360.0 degrees) |
233233
| `kinematics.ground_speed_mps` | `Kinematics/GroundSpeed` | `xs:double` | Horizontal velocity over ground (m/s) |
234234
| `kinematics.vertical_speed_mps` | `Kinematics/VerticalSpeed` | `xs:double` | Rate of climb / descent (m/s) |
235+
| `kinematics.airspeed_mps` | `Kinematics/Airspeed` | `xs:double` | Drone true airspeed (m/s) |
236+
| `kinematics.pitch_degrees` | `Kinematics/Pitch` | `xs:double` | Drone pitch attitude (-90.0 to 90.0 degrees) |
237+
| `kinematics.roll_degrees` | `Kinematics/Roll` | `xs:double` | Drone roll attitude (-180.0 to 180.0 degrees) |
235238
| `source_system` | `SourceSystem` | `xs:string` | Originating subsystem / mesh node ID |
236-
| `classification` (`SECRET`) | `SecurityInformation/Classification` | `ClassificationEnum` | Security marking (`UNCLASSIFIED`, `CONFIDENTIAL`, `SECRET`, `TOP_SECRET`) |
239+
| `flight_plan.flight_mode` | `FlightMode` | `xs:string` | Autopilot navigation mode |
240+
| `flight_plan.active_waypoint_id` | `ActiveWaypoint` | `xs:string` | Current navigation waypoint identifier |
241+
| `flight_plan.fuel_remaining_percent` | `FuelPercentage` | `xs:double` | Remaining fuel / endurance percentage (0-100%) |
242+
| `classification` (`UNCLASSIFIED`) | `SecurityInformation/Classification` | `ClassificationEnum` | Security marking (`UNCLASSIFIED`, `CONFIDENTIAL`, `SECRET`, `TOP_SECRET`) |
237243

238244
---
239245

@@ -366,7 +372,7 @@ using namespace polyxml::generated;
366372

367373
EntityMt entity;
368374
entity.object_state = ObjectStateEnum::Active;
369-
entity.security_information.classification = ClassificationEnum::Secret;
375+
entity.security_information.classification = ClassificationEnum::Unclassified;
370376
entity.message_data.kinematics.latitude = 34.9125;
371377
entity.message_data.kinematics.longitude = -117.8833;
372378
static_assert(XmlModel<EntityMt>); // Enforced via C++20 concept
@@ -393,7 +399,10 @@ public record KinematicsType(
393399
double altitude,
394400
Optional<Double> heading,
395401
Optional<Double> groundSpeed,
396-
Optional<Double> verticalSpeed
402+
Optional<Double> verticalSpeed,
403+
Optional<Double> airspeed,
404+
Optional<Double> pitch,
405+
Optional<Double> roll
397406
) {}
398407
```
399408

@@ -519,7 +528,7 @@ polyxml-defense-examples/
519528
│ ├── UCI_SecurityMarkings_v2_5_0.xsd # Full DoD security markings XSD
520529
│ └── UCI_Versioning_v2_5_0.xsd # UCI versioning attributes XSD
521530
├── data/
522-
│ ├── lattice_entity.json # Autonomous ALTIUS-600M loitering munition track payload
531+
│ ├── lattice_entity.json # Autonomous flying drone airplane telemetry payload (FURY-UAV-01)
523532
│ └── uci_entity.xml # Validated USAF UCI v2.5 Entity XML message
524533
├── generated/ # PolyXML compiler outputs (rebuilt via 'polyxml build')
525534
│ ├── rust/uci_entity_core.rs

‎data/lattice_entity.json‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"id": "e4a71d80-86d1-4cb3-91f9-8d07e600572b",
3-
"callsign": "ALTIUS-600M-EDGE-01",
3+
"callsign": "FURY-UAV-01",
44
"timestamp": "2026-09-20T11:00:00Z",
55
"source_system": "LATTICE_MESH_NODE_DELTA",
6-
"classification": "SECRET",
6+
"classification": "UNCLASSIFIED",
77
"status": "CONFIRMED",
88
"location": {
99
"latitude": 34.9125,
@@ -13,6 +13,26 @@
1313
"kinematics": {
1414
"heading_degrees": 285.5,
1515
"ground_speed_mps": 165.2,
16-
"vertical_speed_mps": -1.5
16+
"vertical_speed_mps": -1.5,
17+
"airspeed_mps": 172.4,
18+
"pitch_degrees": 2.1,
19+
"roll_degrees": -1.4
20+
},
21+
"flight_plan": {
22+
"flight_mode": "AUTONOMOUS_WAYPOINT_NAVIGATION",
23+
"mission_id": "MISSION-MOJAVE-SURVEILLANCE-42",
24+
"active_waypoint_id": "WP-DELTA-04",
25+
"target_altitude_meters": 4500.0,
26+
"target_airspeed_mps": 175.0,
27+
"fuel_remaining_percent": 84.6,
28+
"battery_backup_percent": 99.2,
29+
"estimated_endurance_minutes": 245.0
30+
},
31+
"sensor_payload": {
32+
"sensor_type": "EO_IR_MULTISPECTRAL_GIMBAL",
33+
"gimbal_azimuth_deg": 42.5,
34+
"gimbal_elevation_deg": -28.0,
35+
"laser_designator_armed": false,
36+
"tracking_mode": "GEO_POINT_LOITER"
1737
}
1838
}

‎data/uci_entity.xml‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<uci:Entity xmlns:uci="https://www.vdl.afrl.af.mil/programs/oam">
33
<uci:SecurityInformation>
4-
<uci:Classification>SECRET</uci:Classification>
4+
<uci:Classification>UNCLASSIFIED</uci:Classification>
55
<uci:OwnerProducer>USA</uci:OwnerProducer>
66
</uci:SecurityInformation>
77
<uci:MessageHeader>
8-
<uci:MessageID>MSG-98214-DELTA</uci:MessageID>
8+
<uci:MessageID>MSG-E4A71D80</uci:MessageID>
99
<uci:Timestamp>2026-09-20T11:00:00Z</uci:Timestamp>
1010
<uci:OriginatorID>LATTICE_MESH_NODE_DELTA</uci:OriginatorID>
1111
</uci:MessageHeader>
1212
<uci:ObjectState>ACTIVE</uci:ObjectState>
1313
<uci:MessageData>
1414
<uci:EntityID>
1515
<uci:UUID>e4a71d80-86d1-4cb3-91f9-8d07e600572b</uci:UUID>
16-
<uci:Callsign>ALTIUS-600M-EDGE-01</uci:Callsign>
16+
<uci:Callsign>FURY-UAV-01</uci:Callsign>
1717
</uci:EntityID>
1818
<uci:CreationTimestamp>2026-09-20T11:00:00Z</uci:CreationTimestamp>
1919
<uci:EntityStatus>CONFIRMED</uci:EntityStatus>
@@ -24,7 +24,13 @@
2424
<uci:Heading>285.5</uci:Heading>
2525
<uci:GroundSpeed>165.2</uci:GroundSpeed>
2626
<uci:VerticalSpeed>-1.5</uci:VerticalSpeed>
27+
<uci:Airspeed>172.4</uci:Airspeed>
28+
<uci:Pitch>2.1</uci:Pitch>
29+
<uci:Roll>-1.4</uci:Roll>
2730
</uci:Kinematics>
2831
<uci:SourceSystem>LATTICE_MESH_NODE_DELTA</uci:SourceSystem>
32+
<uci:FlightMode>AUTONOMOUS_WAYPOINT_NAVIGATION</uci:FlightMode>
33+
<uci:ActiveWaypoint>WP-DELTA-04</uci:ActiveWaypoint>
34+
<uci:FuelPercentage>84.6</uci:FuelPercentage>
2935
</uci:MessageData>
3036
</uci:Entity>

‎examples/cpp/main.cpp‎

Lines changed: 111 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,32 @@
1010
namespace fs = std::filesystem;
1111
using namespace polyxml::generated;
1212

13+
// Statically verify C++20 XmlModel concept
14+
static_assert(XmlModel<EntityMt>, "EntityMt must satisfy C++20 XmlModel concept");
15+
static_assert(XmlModel<EntityMdt>, "EntityMdt must satisfy C++20 XmlModel concept");
16+
static_assert(XmlModel<KinematicsType>, "KinematicsType must satisfy C++20 XmlModel concept");
17+
1318
struct LatticeEntity {
1419
std::string id;
15-
std::string callsign;
20+
std::optional<std::string> callsign;
1621
std::string timestamp;
17-
std::string source_system;
18-
std::string classification;
22+
std::optional<std::string> source_system;
23+
std::optional<std::string> classification;
1924
std::string status;
2025
double latitude = 0.0;
2126
double longitude = 0.0;
2227
double altitude_meters = 0.0;
23-
double heading_degrees = 0.0;
24-
double ground_speed_mps = 0.0;
25-
double vertical_speed_mps = 0.0;
28+
std::optional<double> heading_degrees;
29+
std::optional<double> ground_speed_mps;
30+
std::optional<double> vertical_speed_mps;
31+
std::optional<double> airspeed_mps;
32+
std::optional<double> pitch_degrees;
33+
std::optional<double> roll_degrees;
34+
std::optional<std::string> flight_mode;
35+
std::optional<std::string> active_waypoint_id;
36+
std::optional<double> fuel_remaining_percent;
2637
};
2738

28-
// Simple zero-dependency JSON field extractor for benchmark demo
2939
std::string extract_string_field(const std::string& json, const std::string& key) {
3040
std::regex re("\"" + key + "\"\\s*:\\s*\"([^\"]+)\"");
3141
std::smatch match;
@@ -63,12 +73,12 @@ EntityMt translate_lattice_to_uci(const LatticeEntity& lattice) {
6373
entity.object_state = ObjectStateEnum::Active;
6474

6575
// SecurityInformation & Header
66-
entity.security_information.classification = ClassificationEnum::Secret;
76+
entity.security_information.classification = ClassificationEnum::Unclassified;
6777
entity.security_information.owner_producer = "USA";
6878

6979
entity.message_header.message_id = "MSG-" + lattice.id.substr(0, 8);
7080
entity.message_header.timestamp = lattice.timestamp;
71-
entity.message_header.originator_id = lattice.source_system;
81+
entity.message_header.originator_id = lattice.source_system.value_or("LATTICE_MESH_NODE_DELTA");
7282

7383
// MessageData
7484
entity.message_data.entity_id.uuid = lattice.id;
@@ -87,8 +97,14 @@ EntityMt translate_lattice_to_uci(const LatticeEntity& lattice) {
8797
entity.message_data.kinematics.heading = lattice.heading_degrees;
8898
entity.message_data.kinematics.ground_speed = lattice.ground_speed_mps;
8999
entity.message_data.kinematics.vertical_speed = lattice.vertical_speed_mps;
100+
entity.message_data.kinematics.airspeed = lattice.airspeed_mps;
101+
entity.message_data.kinematics.pitch = lattice.pitch_degrees;
102+
entity.message_data.kinematics.roll = lattice.roll_degrees;
90103

91104
entity.message_data.source_system = lattice.source_system;
105+
entity.message_data.flight_mode = lattice.flight_mode;
106+
entity.message_data.active_waypoint = lattice.active_waypoint_id;
107+
entity.message_data.fuel_percentage = lattice.fuel_remaining_percent;
92108

93109
return entity;
94110
}
@@ -137,11 +153,29 @@ std::string serialize_uci_xml(const EntityMt& entity) {
137153
if (entity.message_data.kinematics.vertical_speed) {
138154
oss << "<VerticalSpeed>" << *entity.message_data.kinematics.vertical_speed << "</VerticalSpeed>";
139155
}
156+
if (entity.message_data.kinematics.airspeed) {
157+
oss << "<Airspeed>" << *entity.message_data.kinematics.airspeed << "</Airspeed>";
158+
}
159+
if (entity.message_data.kinematics.pitch) {
160+
oss << "<Pitch>" << *entity.message_data.kinematics.pitch << "</Pitch>";
161+
}
162+
if (entity.message_data.kinematics.roll) {
163+
oss << "<Roll>" << *entity.message_data.kinematics.roll << "</Roll>";
164+
}
140165
oss << "</Kinematics>";
141166

142167
if (entity.message_data.source_system) {
143168
oss << "<SourceSystem>" << *entity.message_data.source_system << "</SourceSystem>";
144169
}
170+
if (entity.message_data.flight_mode) {
171+
oss << "<FlightMode>" << *entity.message_data.flight_mode << "</FlightMode>";
172+
}
173+
if (entity.message_data.active_waypoint) {
174+
oss << "<ActiveWaypoint>" << *entity.message_data.active_waypoint << "</ActiveWaypoint>";
175+
}
176+
if (entity.message_data.fuel_percentage) {
177+
oss << "<FuelPercentage>" << *entity.message_data.fuel_percentage << "</FuelPercentage>";
178+
}
145179
oss << "</MessageData>";
146180
oss << "</EntityMT>";
147181
return oss.str();
@@ -156,70 +190,106 @@ std::string serialize_uci_json(const EntityMt& entity) {
156190
oss << "\"ObjectState\":\"" << to_string(*entity.object_state) << "\",";
157191
}
158192
oss << "\"MessageData\":{";
159-
oss << "\"EntityID\":{\"UUID\":\"" << entity.message_data.entity_id.uuid << "\"},";
193+
oss << "\"EntityID\":{\"UUID\":\"" << entity.message_data.entity_id.uuid << "\"";
194+
if (entity.message_data.entity_id.callsign) {
195+
oss << ",\"Callsign\":\"" << *entity.message_data.entity_id.callsign << "\"";
196+
}
197+
oss << "},";
160198
oss << "\"EntityStatus\":\"" << to_string(entity.message_data.entity_status) << "\",";
161-
oss << "\"Kinematics\":{\"Latitude\":" << entity.message_data.kinematics.latitude << ",\"Longitude\":" << entity.message_data.kinematics.longitude << "}";
199+
oss << "\"Kinematics\":{";
200+
oss << "\"Latitude\":" << entity.message_data.kinematics.latitude << ",";
201+
oss << "\"Longitude\":" << entity.message_data.kinematics.longitude;
202+
if (entity.message_data.kinematics.airspeed) {
203+
oss << ",\"Airspeed\":" << *entity.message_data.kinematics.airspeed;
204+
}
205+
oss << "}";
206+
if (entity.message_data.flight_mode) {
207+
oss << ",\"FlightMode\":\"" << *entity.message_data.flight_mode << "\"";
208+
}
162209
oss << "}}";
163210
return oss.str();
164211
}
165212

166213
int main() {
167214
std::cout << "================================================================================" << std::endl;
168215
std::cout << "🛸 PolyXML: Anduril Lattice SDK ↔ USAF UCI C2 Bridge (Modern C++20)" << std::endl;
216+
std::cout << " Autonomous Flying Drone Airplane Telemetry (UNCLASSIFIED)" << std::endl;
169217
std::cout << "================================================================================" << std::endl;
170218

171-
std::string data_path = find_data_file();
172-
if (data_path.empty()) {
219+
std::string data_file = find_data_file();
220+
if (data_file.empty()) {
173221
std::cerr << "Error: Could not locate data/lattice_entity.json" << std::endl;
174222
return 1;
175223
}
176224

177-
std::ifstream file(data_path);
178-
if (!file.is_open()) {
179-
std::cerr << "Error opening file: " << data_path << std::endl;
180-
return 1;
181-
}
182-
183-
std::stringstream buffer;
184-
buffer << file.rdbuf();
185-
std::string json_content = buffer.str();
225+
std::ifstream file(data_file);
226+
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
186227

187228
LatticeEntity lattice;
188-
lattice.id = extract_string_field(json_content, "id");
189-
lattice.callsign = extract_string_field(json_content, "callsign");
190-
lattice.timestamp = extract_string_field(json_content, "timestamp");
191-
lattice.source_system = extract_string_field(json_content, "source_system");
192-
lattice.status = extract_string_field(json_content, "status");
193-
lattice.latitude = extract_double_field(json_content, "latitude");
194-
lattice.longitude = extract_double_field(json_content, "longitude");
195-
lattice.altitude_meters = extract_double_field(json_content, "altitude_meters");
196-
lattice.heading_degrees = extract_double_field(json_content, "heading_degrees");
197-
lattice.ground_speed_mps = extract_double_field(json_content, "ground_speed_mps");
198-
lattice.vertical_speed_mps = extract_double_field(json_content, "vertical_speed_mps");
199-
200-
std::cout << "Ingesting Lattice Track: " << lattice.callsign << " (ID: " << lattice.id << ")" << std::endl;
229+
lattice.id = extract_string_field(content, "id");
230+
lattice.callsign = extract_string_field(content, "callsign");
231+
lattice.timestamp = extract_string_field(content, "timestamp");
232+
lattice.source_system = extract_string_field(content, "source_system");
233+
lattice.classification = extract_string_field(content, "classification");
234+
lattice.status = extract_string_field(content, "status");
235+
236+
lattice.latitude = extract_double_field(content, "latitude");
237+
lattice.longitude = extract_double_field(content, "longitude");
238+
lattice.altitude_meters = extract_double_field(content, "altitude_meters");
239+
240+
double hdg = extract_double_field(content, "heading_degrees");
241+
if (hdg != 0.0) lattice.heading_degrees = hdg;
242+
243+
double gs = extract_double_field(content, "ground_speed_mps");
244+
if (gs != 0.0) lattice.ground_speed_mps = gs;
245+
246+
double vs = extract_double_field(content, "vertical_speed_mps");
247+
if (vs != 0.0) lattice.vertical_speed_mps = vs;
248+
249+
double as = extract_double_field(content, "airspeed_mps");
250+
if (as != 0.0) lattice.airspeed_mps = as;
251+
252+
double pitch = extract_double_field(content, "pitch_degrees");
253+
if (pitch != 0.0) lattice.pitch_degrees = pitch;
201254

255+
double roll = extract_double_field(content, "roll_degrees");
256+
if (roll != 0.0) lattice.roll_degrees = roll;
257+
258+
lattice.flight_mode = extract_string_field(content, "flight_mode");
259+
lattice.active_waypoint_id = extract_string_field(content, "active_waypoint_id");
260+
double fuel = extract_double_field(content, "fuel_remaining_percent");
261+
if (fuel != 0.0) lattice.fuel_remaining_percent = fuel;
262+
263+
std::cout << "Ingesting Autonomous Drone Telemetry: "
264+
<< (lattice.callsign ? *lattice.callsign : "N/A")
265+
<< " (ID: " << lattice.id << ")" << std::endl;
266+
267+
// 1. Ingest & Serialize to XML
202268
auto start_xml = std::chrono::high_resolution_clock::now();
203269
EntityMt uci_entity = translate_lattice_to_uci(lattice);
204270
std::string xml_output = serialize_uci_xml(uci_entity);
205271
auto end_xml = std::chrono::high_resolution_clock::now();
206-
auto xml_us = std::chrono::duration_cast<std::chrono::nanoseconds>(end_xml - start_xml).count() / 1000.0;
272+
double xml_us = std::chrono::duration<double, std::micro>(end_xml - start_xml).count();
207273

208274
std::cout << "\n[1] Generated USAF UCI XML Message (latency: " << xml_us << " μs):" << std::endl;
209275
std::cout << xml_output << std::endl;
210276

277+
assert(xml_output.find("EntityMT") != std::string::npos);
278+
assert(xml_output.find("UNCLASSIFIED") != std::string::npos);
279+
assert(xml_output.find("FURY-UAV-01") != std::string::npos);
280+
281+
// 2. Inherent JSON Serialization
211282
auto start_json = std::chrono::high_resolution_clock::now();
212283
std::string json_output = serialize_uci_json(uci_entity);
213284
auto end_json = std::chrono::high_resolution_clock::now();
214-
auto json_us = std::chrono::duration_cast<std::chrono::nanoseconds>(end_json - start_json).count() / 1000.0;
285+
double json_us = std::chrono::duration<double, std::micro>(end_json - start_json).count();
215286

216287
std::cout << "\n[2] Generated Native JSON on Same Model (latency: " << json_us << " μs):" << std::endl;
217288
std::cout << json_output << std::endl;
218289

219-
assert(xml_output.find("EntityMT") != std::string::npos);
220-
assert(xml_output.find(lattice.id) != std::string::npos);
221-
assert(xml_output.find("CONFIRMED") != std::string::npos);
222-
assert(uci_entity.validate());
290+
// Verify C++20 default equality comparison
291+
EntityMt copy_entity = uci_entity;
292+
assert(copy_entity == uci_entity);
223293

224294
std::cout << "\n✅ C++20 Lattice ↔ UCI Bridge executed successfully!" << std::endl;
225295
return 0;

0 commit comments

Comments
 (0)