This repository extends embeddedRTPS with Selective Field Transmission (SFT), a middleware mechanism that decouples transmission content from statically defined message types in publish-subscribe systems. Industrial and robotics developers often face a dilemma: They can follow established best practices and use standard message types, such as in the Robot Operating System 2 (ROS2) and COVESA projects, to benefit from reusable and interoperable interfaces, or they can introduce proprietary, project-specific message types tailored to receiver requirements to reduce bandwidth. SFT resolves this trade-off by dynamically adapting the transmitted message components to each receiver’s actual needs while preserving unmodified standard interfaces.Receivers declare or automatically derive the required message components, which are communicated to the publisher. The publisher then serializes and transmits only the required component subset per receiver with minimal developer intervention. Our evaluation shows that SFT achieves significant bandwidth reductions without measurable per-message latency overhead, with savings proportional to the number and size of unused fields.
Upstream: The unmodified embeddedRTPS reference implementation lives at https://github.com/embedded-software-laboratory/embeddedRTPS. This fork adds the SFT and FRDP layers on top of that codebase.
A standard DDS/RTPS writer always serializes the full sample, even when the subscriber only reads a subset of the fields. SFT changes that contract:
- Readers report which fields they actually access — either by static configuration or by automatic compile-time tracking of getter calls.
- Writers learn the union of required fields per remote reader through a dedicated discovery protocol (FRDP — Field Requirements Discovery Protocol).
- Only the requested fields are serialized on the wire, together with a small bitmask describing which fields are present. Unrequested fields are skipped entirely.
- History caching is field-aware: retransmissions and durability replay can target a specific
(SequenceNumber, FieldMask)pair, so late-joining readers with different field requirements do not force the writer to keep the maximal payload around indefinitely.
For aligned access patterns this reduces wire bytes proportionally to the unused field fraction and removes the corresponding (de)serialization cost on both ends.
All SFT code lives next to the upstream embeddedRTPS sources and is namespaced consistently. The pieces that make up the feature are:
| Area | Files | Role |
|---|---|---|
| Message base class | include/rtps/messages/SFTMessage.hpp | Abstract base class every SFT-enabled type derives from. Defines serialize_partial / deserialize_partial / generate_field_mask / reset_access_counts and carries the per-sample object_field_mask. |
| Selective writer | include/rtps/entities/SelectiveWriter.h, SelectiveWriter.tpp | Writer specialization that consumes SFTMessage * samples, looks up the per-reader required mask via FRDP, and emits partial CDR encodings. |
| Selective reader | include/rtps/entities/SelectiveReader.h, SelectiveReader.tpp | Reader specialization templated on a concrete SFTMessage subtype. Announces field requirements via FRDP and dispatches deserialized samples through an sftCallback_fp. |
| Field-aware history cache | include/rtps/storages/SFTHistoryCache.h, src/storages/SFTHistoryCache.cpp | Stores changes keyed by (SequenceNumber, FieldMask), so reliable retransmissions can reuse or recompute the right partial encoding per reader. |
| FRDP agent | include/rtps/discovery/FRDPAgent.h, src/discovery/FRDPAgent.cpp | Field Requirements Discovery Protocol. Each participant runs one. Readers call announceFieldRequirements(guid, mask); writers query getFieldRequirements(remoteReaderGuid) and react via registerRequirementsUpdateCallback. |
| FRDP wire data | include/rtps/discovery/FieldRequirementsData.h, src/discovery/FieldRequirementsData.cpp | Serializable (readerGuid, fieldMask, updateSequence) triple that travels over the FRDP builtin endpoint. |
| BitVector utility | include/rtps/sft/core/BitVector.hpp | 32-bit bitset wrapper used throughout the SFT path (constexpr-friendly, popcount/findFirst/range helpers, 0b…_bv literal). |
| Configuration | include/rtps/sft/sft_config.h | Preprocessor knobs: SFT_FIELDMASK_MODE, SFT_MAX_PRECOMPUTED_MASKS, SFT_MASK_REDUNDANCY_COUNT, SFT_ENABLE_BLOCK_BLUEPRINT, SFT_VERBOSE. |
A two-node SFT request/response example lives in example/ReqResp/:
- SftSender.cpp — creates a
SelectiveWriteronSftExchange_A2Band aSelectiveReader<Message3f128>onSftExchange_B2A. The reader callback only touchesfield1andfield3, driving FRDP to converge the remote writer's mask to0x5. - SftResponder.cpp — the symmetric peer.
The wire mask printed by the receiver (wireMask=0x…) shows that the writer eventually drops the unused field from the serialized payload after FRDP has propagated the reader's requirements.
| Directory | Description |
|---|---|
| include/rtps/sft/ | SFT core: config, types, BitVector, compile-time access tracking |
| include/rtps/entities/ | SelectiveWriter / SelectiveReader next to the upstream Writer / Reader |
| include/rtps/messages/ | SFTMessage base class |
| include/rtps/storages/ | SFTHistoryCache next to the upstream history caches |
| include/rtps/discovery/ | FRDPAgent, FieldRequirementsData next to SPDP/SEDP |
| example/ReqResp/ | SFT and non-SFT request/response example nodes |
| tracer/ | SOATracer node executables (C++ sources) |
| tracer/idl-files/ | IDL sources and generated SFT message headers |
| tools/ | Code generation (Micro-XRCE-DDS-Gen) for SFT message types |
| thirdparty/ | Bundled dependencies (e.g. Micro-CDR) |
git submodule update --init --recursive
mkdir build && cd build
cmake ..
make -j4MIT. See LICENSE. The base embeddedRTPS implementation that this work is derived from is published under the same terms at https://github.com/embedded-software-laboratory/embeddedRTPS.