ROS 2 と互換な通信ライブラリ
- DDS と最低限の互換性がある
- std_msgs が使える
- Unity で使える
- Unity でクロスプラットフォームビルドできる (Windows, Mac, Android, ...)
Nix flake で ROS 2 Humble + Fast DDS の RMW (rmw_fastrtps_cpp) + .NET 8 SDK が揃います。
# Nix flake の devShell に入る (direnv 利用時は自動 reload)
nix developdevShell では RMW_IMPLEMENTATION=rmw_fastrtps_cpp を既定値にしています。
ros.cachix.org を利用するには trusted-users もしくは trusted-substituters に追加してください。未設定だと ROS パッケージを自前ビルドすることになります。
dotnet build
dotnet testこのリポジトリを clone した状態で、別の .NET アプリから rclsharp を参照して試せます。
dotnet new console -n MyRclsharpApp
dotnet add MyRclsharpApp/MyRclsharpApp.csproj reference src/rclsharp/rclsharp.csprojProgram.cs を次の内容に置き換えると、std_msgs/msg/String の talker / listener として動作します。
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Rclsharp.Common.Logging;
using Rclsharp.Dds;
using Rclsharp.Msgs.Std;
if (args.Length != 1 || (args[0] != "talker" && args[0] != "listener"))
{
Console.Error.WriteLine("Usage: dotnet run -- <talker|listener>");
return;
}
var mode = args[0];
var logger = new ConsoleLogger(mode, LogLevel.Info);
var options = new DomainParticipantOptions
{
DomainId = 0,
ParticipantId = mode == "talker" ? 1 : 2,
EntityName = $"rclsharp_{mode}",
Logger = logger,
// ROS_LOCALHOST_ONLY=1 の ROS 2 ノードとローカルで通信する設定。
LocalUnicastAddress = IPAddress.Loopback,
MulticastInterface = IPAddress.Loopback,
};
using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
cts.Cancel();
};
using var participant = new DomainParticipant(options);
participant.Start();
try
{
if (mode == "talker")
{
using var pub = participant.CreatePublisher<StringMessage>(
"chatter",
StringMessageSerializer.Instance,
StringMessage.DdsTypeName);
var count = 0;
while (!cts.IsCancellationRequested)
{
var message = new StringMessage($"Hello rclsharp: {++count}");
await pub.PublishAsync(message, cts.Token);
logger.Info($"Publishing: '{message.Data}'");
await Task.Delay(TimeSpan.FromSeconds(1), cts.Token);
}
}
else
{
using var sub = participant.CreateSubscription<StringMessage>(
"chatter",
StringMessageSerializer.Instance,
(message, source) => logger.Info($"I heard: '{message.Data}' from {source}"),
StringMessage.DdsTypeName);
await Task.Delay(Timeout.Infinite, cts.Token);
}
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
logger.Info("Stopping...");
}2 つのシェルで listener と talker を起動します。
dotnet run --project MyRclsharpApp -- listener
dotnet run --project MyRclsharpApp -- talkerlistener 側に I heard: 'Hello rclsharp: N' が出れば送受信できています。
ローカル PC 内で ROS 2 と疎通する場合は、ROS 2 側も同じ domain と localhost 設定にします。
export ROS_DOMAIN_ID=0
export ROS_LOCALHOST_ONLY=1ROS 2 の listener に rclsharp から送信する例:
ros2 run demo_nodes_cpp listener
dotnet run --project MyRclsharpApp -- talkerROS 2 の talker を rclsharp で購読する例:
ros2 run demo_nodes_cpp talker
dotnet run --project MyRclsharpApp -- listener別ホストと通信する場合は ROS_LOCALHOST_ONLY を無効にし、LocalUnicastAddress と
MulticastInterface に実際に使う NIC の IPv4 アドレスを指定してください。
CreatePublisher は既定で Reliable publisher を作ります。ROS 2 の sensor-data 相当の
Best Effort subscriber へ送る場合は、publisher 作成時に QoS を明示します。
using Rclsharp.Dds.QoS;
using var pub = participant.CreatePublisher<StringMessage>(
"chatter",
StringMessageSerializer.Instance,
ReliabilityQos.BestEffort,
StringMessage.DdsTypeName);Unity では API Compatibility Level を .NET Standard 2.1 に設定して利用します。
Unity 2022.3 の C# コンパイラは C# 11 の required members に対応していないため、
ライブラリ本体では required を使わず、Unity 同梱の .NET Standard 2.1 参照アセンブリで
コンパイルできる API に留めます。
Participant は DDSI-RTPS の lease timeout で remote から消えることを前提にします。
Publisher / Subscription の endpoint は Dispose 時に SEDP の built-in Topic へ
PID_STATUS_INFO 付き unregister DATA を送信し、remote の graph から早めに消えるようにします。
指定ドメインの SPDP マルチキャストに参加し、他の Participant (rclsharp 同士 / ROS 2 ノード) を検出します。
# Usage: dotnet run --project samples/SpdpDemo -- [domainId] [participantId] [entityName]
dotnet run --project samples/SpdpDemo -- 0 1 rclsharp_demo/chatter トピック (std_msgs/String) で文字列を送受信します。別シェルで起動してください。
# listener
dotnet run --project samples/TalkerListener -- listener
# talker
dotnet run --project samples/TalkerListener -- talkerlistener 側に I heard: 'Hello rclsharp: N' が出れば OK。
別シェルで ROS 2 talker を起動:
ROS_LOCALHOST_ONLY=1 ROS_DOMAIN_ID=0 ros2 run demo_nodes_cpp talkerSpdpDemo 側のログに ++ DISCOVERED ... unicast=UDPv4://127.0.0.1:7410 が出れば OK。