ROS2 7 (ros2cs 1)

C#でROS2を動かします。

ros2_dotnetから継続して開発を進めている人達が居てros2-for-unityとなってros2-for-unityの独立した一部としてros2csがあります。

ros2cs

これを利用してrclの層に対する実装をすることなくTopic通信とService通信を実現させます。

WindowsでROS2環境を作成することについては下記を参照ください。

ROS2 6 : Windows

Windows 11 HomeでVisual Studio Community 2022を使っています。
Windows 10でもProでも動作すると思いますがros2csのためにVisual Studioは2022が必要です。
(設定を変更すればVisual Studio 2019でも大丈夫です。)

環境はWindows 11 Homeです。ROS2 Humbleです。
CPU : 12th Gen Intel Core i5-1235U
Windows 11 Home on VMware 17
6コアを割り当ててます。

(ROS2 HumbleはOnly Windows 10 is supported.とのことですが、Windows 11でも動作する情報が多かったのでWindows 11でやってます。)

install 1 / .Net 6.0

下記でインストールはほぼ完了しています。

ROS2 6 : Windows

自分はxUnitは使わないので.Net 6.0だけインストールします。

ROS2CS – Windows 10
Download .NET 6.0

Windowsのx64です。

.Netは以前の.Net CoreのことでMacでもUbuntuでも動く方のやつです。
今の最新は8なのですが6でも十分に新しくVisual Studio 2022(以上)を要求してきます。

Windowsでのみ動作するのは.Net Frameworkで現在の最新は4.8.1です。

colcon buildは.Netなくても通ります。

install 2 / パスの長さの制限を外す

レジストリをいじります。

Maximum Path Length Limitation

これをやらないと少なくともmimick_vendorのbuildで失敗します。

build

C:\devに移動したとします。PowerShellでも、Git bashでも。


$ git clone https://github.com/RobotecAI/ros2cs.git

ros2-humble-20231122-windows-release-amd64.zipを使います。

ここから先はDeveloper PowerShell for VS 2022を使っていきます。管理者として実行します。
Developer PowerShell for VS 2022とPowerShellは別物扱いみたいで下記が再度必要です。

ps1を実行できるようにします。これのために管理者として実行が必要です。


PS > Set-ExecutionPolicy Unrestricted

Y


PS > cd ros2_humble
PS > local_setup.ps1

R


PS > cd ..
PS > cd ros2cs

get_repos.ps1はPowerShellで管理者として実行しないでも通ります。


PS > get_repos.ps1

build.ps1の実行のためにDeveloper PowerShell for VS 2022を使う必要があります。


PS > build.ps1

2時間7分かかりました。

build (古いReleaseを使った場合)

ros2-humble-20220523-windows-release-amd64.zipを使った場合。

build.ps1を実行する前にbuild.ps1を編集します。

build.ps1

<#
.SYNOPSIS
    Builds 'ros2cs'
.DESCRIPTION
    This script runs colcon build
.PARAMETER with_tests
    build with tests
.PARAMETER standalone
    standalone build
#>
Param (
    [Parameter(Mandatory=$false)][switch]$with_tests=$false,
    [Parameter(Mandatory=$false)][switch]$standalone=$false
)

$msg="Build started."
$tests_switch=0
if($with_tests) {
    $msg+=" (with tests)"
    $tests_switch=1
}
$standalone_switch=0
if($standalone) {
    $msg+=" (standalone)"
    $standalone_switch=1
}

Write-Host $msg -ForegroundColor Green
# colcon build --merge-install --event-handlers console_direct+ --cmake-args -DSTANDALONE_BUILD:int=$standalone_switch -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING:int=$tests_switch --no-warn-unused-cli
colcon build --merge-install --event-handlers console_direct+ --cmake-args -DSTANDALONE_BUILD:int=$standalone_switch -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING:int=$tests_switch --no-warn-unused-cli --continue-on-error --packages-skip-build-finished

–continue-on-error : packageのbuildに失敗しても他のpackageのbuildを行う
–packages-skip-build-finished : buildが完了しているpackagesのbuildをskipする

build.ps1の実行のためにDeveloper PowerShell for VS 2022を使う必要があります。


PS > build.ps1

ros2-humble-20220523-windows-release-amd64.zipを使った場合はbuildに失敗します。下記の対応が必要になります。

Commit

githubなので消えないと思いますが、抜粋を下記に示します。
xをコメントアウトしておいてoの修正をするのが良いと思います。

x : set(_regex “foreach\\(_expectedTarget (.+)\\)”)
o : set(_regex “foreach\\((_cmake)?_expected_?[Tt]arget (IN ITEMS )?(.+)\\)”)

x : string(REGEX REPLACE “${_regex}” “\\1” _targets “${_foreach_targets}”)
o : string(REGEX REPLACE “${_regex}” “\\3” _targets “${_foreach_targets}”)

上記の対応と同じ対応をエラーとなったファイルに対して行なって修正します。
一例. C:\dev\ros2cs\install\share\builtin_interfaces\cmake\ament_cmake_export_targets-extras.cmake

下記を繰り返すと、面倒ですがbuildは完了します。PCが遅いと半日作業、一日作業となってしまいます。XXX_msgsとYYY_interfacesと他でエラーでます。

build.ps1やってエラーだす → 修正する → colcon build –merge-install –packages-select actionlib_msgs

面倒ですが、やってればとりあえず終わって次に進める、ということが重要な場面もあります。
generatorのところを修正するのが良いのでしょうが、量が多くて読む気がおきません。

動作確認 1

ここから先はDeveloper PowerShell for VS 2022を使っていきます。管理者として実行しなくてもいい気がします。


PS > cd install
PS > local_setup.ps1

PS > ros2 run ros2cs_examples ros2cs_talker.exe

別のDeveloper PowerShell for VS 2022。local_setup.ps1は実行済とします。


PS > ros2 run ros2cs_examples ros2cs_listener.exe


成功 !!

Hello WorldとI heardが見えます。

動作確認 2


PS > ros2 run ros2cs_examples ros2cs_service.exe

別のDeveloper PowerShell for VS 2022。local_setup.ps1は実行済とします。


PS > ros2 run ros2cs_examples ros2cs_client.exe


失敗 !!

Service ServerにRequestが届いていることは確認できますが、Service ClientにResponseが返ってきてません。

動作確認 3

ros2csのgithubを見ても、ros2-for-unityのgithubを見ても、Service通信に成功しているようです。

追加の確認をします。


PS > ros2 run ros2cs_examples ros2cs_service.exe

別のDeveloper PowerShell for VS 2022。local_setup.ps1は実行済とします。


PS > ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1, b: 2}"


成功 !!

3が返ってきます。

Clientに問題がありそうです。

修正する

こいつが犯人です。

C:\dev\ros2cs\src\ros2cs\ros2cs_examples\ROS2Client.cs

下記は修正後です。

ROS2Client.cs

// Copyright 2019-2021 Robotec.ai
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


using System;
using System.Threading;
using ROS2;
using std_msgs;
using sensor_msgs;
using example_interfaces;
using System.Threading.Tasks;

namespace Examples
{
  /// <summary> A simple service client class to illustrate Ros2cs in action </summary>
  public class ROS2Client
  {
 
    public static void Main(string[] args)
    {
      Console.WriteLine("Client start");
      Ros2cs.Init();
      INode node = Ros2cs.CreateNode("talker");
      Client<example_interfaces.srv.AddTwoInts_Request, example_interfaces.srv.AddTwoInts_Response> my_client = node.CreateClient<example_interfaces.srv.AddTwoInts_Request, example_interfaces.srv.AddTwoInts_Response>("add_two_ints");
    
      example_interfaces.srv.AddTwoInts_Request msg = new example_interfaces.srv.AddTwoInts_Request();
      msg.A = 7;
      msg.B = 2;

      while ( !my_client.IsServiceAvailable() )
      {
        Thread.Sleep(TimeSpan.FromSeconds(0.25));
        Console.WriteLine("wait service");
      }

      // example_interfaces.srv.AddTwoInts_Response rsp = my_client.Call(msg);
      // Console.WriteLine("Sum = " + rsp.Sum);

      Task<example_interfaces.srv.AddTwoInts_Response> rsp = my_client.CallAsync(msg);
      Console.WriteLine("CallAsync done");
      rsp.ContinueWith((task) => { Console.WriteLine("Got async answer " + task.Result.Sum); });

      Console.WriteLine("Client shutdown");
      Ros2cs.Spin(node);
      Ros2cs.Shutdown();
    }
  }
}

下記を読みます。

C:\dev\ros2cs\src\ros2cs\ros2cs_core\Client.cs

TakeMessage()でresponseを扱っているとわかります。

git bashをインストールしておいてgrepで調べると下記でTakeMessageを呼び出しているとわかります。

C:\dev\ros2cs\src\ros2cs\ros2cs_core\Ros2cs.cs

Ros2cs.csを読むとSpinOnce()でTakeMessageを呼んでいます。
ということで、ROS2Client.csにはSpin()が無いからresponseが受け取れてないとわかります。

ROS2のService通信は非同期なので同期に見える書き方をするのは本来違うはずなのでros2-for-unityを参考にしながらCallAsyncにしたら完了です。
きちんとしたServiceを設計、実装するときにきちんとした記述にします。

動作確認 4


PS > ros2 run ros2cs_examples ros2cs_service.exe

別のDeveloper PowerShell for VS 2022。local_setup.ps1は実行済とします。


PS > colcon build --merge-install --packages-select ros2cs_examples
PS > ros2 run ros2cs_examples ros2cs_client.exe


成功 !!

広告

IT開発関連書とビジネス書が豊富な翔泳社の通販『SEshop』
さくらのレンタルサーバ
ムームードメイン
Oisix(おいしっくす)
らでぃっしゅぼーや
珈琲きゃろっと
エプソムソルト


ROS2 1 (Install ROS2)
ROS2 2 (Workspace, Package)
ROS2 3 (Topics (C++))
ROS2 4 (Creating custom srv file)
ROS2 5 (Services (C++))


«       »