A C++17 backend that ingests multiple noisy, asynchronous battlefield sensor streams (GPS, vision, RF, radar, lidar), fuses them into a single real-time estimated state per entity using a Kalman filter, and publishes the fused state via CLI and WebSocket server.
- Real-time, multi-source ingestion with asynchronous, delayed, and missing updates.
- Multi-entity tracking with separate per-entity filter state.
- Sensor fusion using a high-performance Kalman filter with a constant-velocity motion model.
- Concurrency: dedicated ingestion, fusion, and output loops designed for low latency and high throughput.
- A synthetic sensor generator for reproducible demos without hardware.
+----------------------------------------------------------------+
| Sensor Layer |
| +----------+ +----------+ +----------+ +----------+ |
| | GPS | | RADAR | | VISION | | LIDAR | |
| +----+-----+ +----+-----+ +----+-----+ +----+-----+ |
+-------+-------------+-------------+-------------+---------------+
| | | |
+-------------+-------------+-------------+
|
+---------v---------+
| Fusion Engine |
| - Kalman Filter |
| - Entity Tracker |
| - Cleanup / TTL |
+---------+---------+
|
+-------------+-------------+
| |
+-----v------+ +---------v--------+
| CLI | | WebSocket Server |
| Visualizer | | (port 8080) |
+------------+ +------------------+
- Sensor generator(s): 1 thread per synthetic sensor (GPS/Radar/Vision/etc.)
- Fusion engine:
- Fusion thread: consumes measurements from a thread-safe queue and updates per-entity trackers
- Output thread: periodically publishes fused states at a configurable rate
- Main thread: orchestration + signal handling (Ctrl+C)
Each fused update includes:
entityIdentityTypeposition(x, y, z)velocity(vx, vy, vz)confidence(0..1)timestamp+lastUpdateTimemeasurementCountcontributingSensors(recent sensor types that updated the track)
The WebSocket server broadcasts JSON messages at ~10 Hz to all connected clients.
battle-node/
├── CMakeLists.txt
├── README.md
├── index.html (WebSocket test client)
├── include/
│ ├── common/
│ ├── sensors/
│ ├── fusion/
│ ├── output/
│ └── system/
├── src/
│ ├── common/
│ ├── sensors/
│ ├── fusion/
│ ├── output/
│ └── system/
└── demo/
└── demo_script.cpp
- CMake 3.15+
- A C++17 compiler (GCC / Clang / MSVC)
- Eigen3 (for matrix math)
- Boost (for WebSocket server via Boost.Beast)
Eigen3
Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y libeigen3-devmacOS (Homebrew)
brew install eigenWindows (vcpkg)
vcpkg install eigen3Boost
Ubuntu/Debian
sudo apt-get install -y libboost-all-devmacOS (Homebrew)
brew install boostWindows (vcpkg)
vcpkg install boostmkdir -p build
cd build
cmake ..
cmake --build . -jExecutables produced:
sensor_fusion(full system run)demo(short portfolio demo)
cd build
./demoWhat you should see:
- A terminal dashboard updating live every ~0.5–1s (depending on configured output rate).
- Stable fused tracks even when individual sensors drop or jitter.
cd build
./sensor_fusionDefault behavior (from src/main.cpp):
- Starts multiple synthetic sensors with different update rates/noise profiles.
- Tracks multiple entities simultaneously.
- Streams fused results to CLI and WebSocket server on port 8080.
- Runs until Ctrl+C.
To test the WebSocket connection, open index.html in your browser and click "Connect".
You can adjust these in src/main.cpp:
-
Fusion output rate:
fusionEngine->setOutputRateHz(5.0);
-
Stale track eviction:
fusionEngine->setStaleEntityTimeout(std::chrono::seconds(15));
-
Per-sensor behavior (noise/update/dropout/delay):
SyntheticSensorGenerator(SensorType::GPS, 1.0, 5.0); setDropoutProbability(0.10); setDelayMs(10, 50);
-
Entity trajectories:
- Initial position + constant velocity for each entity.
The server broadcasts JSON updates at ~10 Hz on ws://localhost:8080.
Example JSON for a single entity update:
{
"entityId": 101,
"type": "VEHICLE",
"position": {"x": 150.23, "y": 80.45, "z": 0.00},
"velocity": {"vx": 15.00, "vy": 10.00, "vz": 0.00},
"confidence": 0.92,
"measurements": 145
}Implementation:
- Production-ready WebSocket server using Boost.Beast
- Async I/O with session management
- Thread-safe message queuing with backpressure handling
- Supports multiple concurrent clients
- Graceful connection/disconnection handling
Testing:
Open index.html in your browser or connect with any WebSocket client:
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (e) => console.log(JSON.parse(e.data));- Add an enum value in include/common/Types.h.
- Implement a new class that implements
SensorInterface(or extendSyntheticSensorGenerator). - Define:
- update rate
- measurement covariance (noise model)
- optional velocity availability
- confidence behavior
- Implement
OutputInterface. - Register it in
SensorFusionSystemviaaddOutputInterface(...). - Publish fused states in your preferred protocol:
- file logger
- UDP multicast
- gRPC streaming
- additional WebSocket endpoints
- Constant-turn / acceleration model (EKF/UKF).
- Outlier rejection (Mahalanobis gating).
- Per-sensor latency compensation + measurement-time ordering.
- Track management (init/confirm/delete logic).
- Metrics endpoint (rates, queue depths, per-entity update intervals).
- Motion model is constant velocity (good baseline; easy to extend).
- Entity classification is simplified; entity type is currently defaulted in the tracker creation path.
MIT License