A ROS 2-compatible (DDS/RTPS) communication library implemented in pure C#/.NET.
No native libraries and no bridge process required — talk directly to ROS 2 nodes via pub/sub. Because the DDS/RTPS layer itself is implemented in C#, it runs cross-platform: Windows / macOS / Linux as well as IL2CPP and AOT targets such as Android and iOS.
English | 日本語
Several ways already exist to talk to ROS 2 from Unity / .NET. ROSettaDDS differs from them as follows.
| ros-sharp | ros2-for-unity (ros2cs) | ROSettaDDS | |
|---|---|---|---|
| Transport | rosbridge (WebSocket / JSON) | Native rcl/rmw bindings |
Pure C# RTPS/DDS |
| Bridge process | Required (rosbridge_server) |
Not required | Not required |
| Native dependency | None | Yes (must be built per platform) | None |
| Platforms | Anywhere Unity/.NET runs | Where the native libs are prebuilt (mainly Linux/Windows) | Anywhere .NET runs (Win/Mac/Linux/Android/iOS…) |
| Direct pub/sub with ROS 2 | Via bridge | Direct | Direct |
| Overhead | High (JSON serialization + WebSocket) | Low | Low |
| AOT / IL2CPP | — | Depends on native libs | Supported (msg generated at compile time) |
- ros-sharp is a bridge-based approach: you run
rosbridge_serveron the ROS 2 side and exchange JSON over WebSocket. It is easy to set up, but it requires a separate bridge process and incurs JSON serialization and WebSocket overhead. ROSettaDDS does pub/sub natively over the same RTPS that ROS 2 speaks, with no bridge in between. - ros2-for-unity (ros2cs) shares a similar philosophy: it binds from C# to the native ROS 2
rcl/rmwlibraries and does DDS pub/sub directly. The overhead is low, but it requires building and shipping native libraries for each platform, which limits where it can run. ROSettaDDS implements DDS/RTPS entirely in C#, so it has no native dependency and runs anywhere .NET runs — including macOS and mobile.
- Interoperates with ROS 2 (Fast DDS) at the RTPS level
- Bundles
std_msgs/builtin_interfaces/geometry_msgs; generates CDR-compatible C# types from.msg - Selectable Reliable / Best Effort QoS
- Zero native dependency; IL2CPP / AOT-compatible compile-time msg generation
Rcl.Context/Rcl.Node2-layer API aligned with the ROS 2rcl_context_t/rcl_node_tmodel- Verified on Unity 6000.3 (.NET Standard 2.1); supports cross-platform builds
Note
See docs/compatibility.md for the supported scope and verification policy, and docs/interop.md for interoperability checks against ROS 2.
With this repository cloned, you can reference ROSettaDDS from a separate .NET console app.
dotnet new console -n MyROSettaDDSApp
dotnet add MyROSettaDDSApp/MyROSettaDDSApp.csproj reference src/rosettadds/rosettadds.csprojWrite Program.cs like this to publish / subscribe std_msgs/msg/String. The public API is
split into two layers, mirroring the ROS 2 rcl_context_t / rcl_node_t split:
Rcl.Contextowns the domain-wide DDS resources (UDP transport × 4, discovery, SPDP/SEDP).Rcl.Nodeis the user-facing object that createsPublisher<T>/Subscription<T>/ServiceClient<TReq,TRes>.
using ROSettaDDS.Rcl;
using ROSettaDDS.Msgs.Std;
using var context = new Context(new ContextOptions
{
DomainId = 0,
EntityName = "rosettadds_demo",
// By default all local NICs are enumerated and advertised, so LAN nodes can reach you.
// Set LocalhostOnly = true to restrict to loopback (equivalent to ROS_LOCALHOST_ONLY=1).
});
context.Start();
using var node = new Node(context, "rosettadds_demo");
// subscribe
node.CreateSubscription<StringMessage>(
"chatter", StringMessageSerializer.Instance,
(msg, source) => Console.WriteLine($"I heard: '{msg.Data}' from {source}"),
StringMessage.DdsTypeName);
// publish
var pub = node.CreatePublisher<StringMessage>(
"chatter", StringMessageSerializer.Instance, StringMessage.DdsTypeName);
await pub.PublishAsync(new StringMessage("Hello rosettadds"));Note
The legacy ROSettaDDS.Dds.DomainParticipant type is still present for backward compatibility
and now delegates to Rcl.Context + Rcl.Node internally. New code should use the
ROSettaDDS.Rcl namespace directly. See docs/compatibility.md
for the migration note.
A complete sample that splits the talker / listener into separate processes is in
samples/TalkerListener. Start them in two shells.
dotnet run --project samples/TalkerListener -- listener
dotnet run --project samples/TalkerListener -- talkerIf the listener prints I heard: 'Hello rosettadds: N', messages are flowing.
CDR-compatible C# types (struct + ICdrSerializer<T>) are generated from .msg at compile
time (IL2CPP / AOT compatible); there is no runtime generation. There are two ways to do it.
Register .msg files as AdditionalFiles and the C# types are generated transparently at build
time.
<ItemGroup>
<ProjectReference Include="path/to/ROSettaDDS.SourceGenerator.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="msgs\**\*.msg" ROSettaDDSMsgPackage="sample_msgs" />
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="ROSettaDDSMsgPackage" />
</ItemGroup>For example, msgs/sample_msgs/msg/Demo.msg:
std_msgs/Header header
string name
float64[] values
int32 count
generates a Demo type and a DemoSerializer in the ROSettaDDS.Msgs.Sample namespace, ready
to use:
using ROSettaDDS.Msgs.Sample;
var demo = new Demo(header, "custom message", new[] { 1.5, 2.5, 3.5 }, 7);See samples/CustomMsgGen for a runnable example.
Scans <input>/<package>/msg/<Name>.msg and emits .cs. Use it to generate into a Unity Assets
folder, or when you want to commit and manage the generated code.
# Regenerate standard msgs (input: msgs/, output: src/rosettadds/Msgs/)
dotnet run --project tools/rosettadds-genmsg -- --input msgs --output src/rosettadds/MsgsNote
See docs/msg-codegen.md for the supported grammar, naming policy, and usage in each environment.
Node.CreatePublisher creates a Reliable publisher by default. To send to a Best Effort
subscriber (equivalent to ROS 2 sensor-data), specify the QoS explicitly when creating the
publisher.
using ROSettaDDS.Dds.QoS;
using var pub = node.CreatePublisher<StringMessage>(
"chatter",
StringMessageSerializer.Instance,
ReliabilityQos.BestEffort,
DurabilityQos.Volatile,
StringMessage.DdsTypeName);A Nix flake provides ROS 2 Humble + the Fast DDS RMW (rmw_fastrtps_cpp) + the .NET 8 SDK.
# Enter the flake devShell (auto-reloads with direnv)
nix developThe devShell sets RMW_IMPLEMENTATION=rmw_fastrtps_cpp by default. To use ros.cachix.org, add
it to trusted-users or trusted-substituters; otherwise ROS packages are built from source.
dotnet build
dotnet test| Document | Contents |
|---|---|
| docs/compatibility.md | Supported scope and verification policy |
| docs/interop.md | Interoperability checks against ROS 2 |
| docs/msg-codegen.md | Grammar and naming policy of msg code generation (rosidl equivalent) |
Samples live under samples/ (TalkerListener / CustomMsgGen / SpdpDemo).