Naoki-Hiraoka / rtmros_beginner_tutorial

4 stars 1 forks source link

自作RTCを作りながら詰まったところ #1

Closed ketaro-m closed 10 months ago

ketaro-m commented 10 months ago

自作のRTC(manta_rtc)を作りながら詰まったところ(誤植を含めて)報告させていただいきます. PRにすべきであればPRにします.

ketaro-m commented 10 months ago
  1. "sample_service_rtc"において誤植と思われるものを発見しました.

    README.md #L129README.md #L271のいずれにおいても

class ServerService_impl
  : public virtual POA_MySample::MyOriginalService,
    public virtual PortableServer::RefCountServantBase

となっているものは,

class ServerService_impl
  : public virtual POA_sample_service_rtc::MyOriginalService,
    public virtual PortableServer::RefCountServantBase
{

であると思います.(ServerService_impl.hのファイル自体はそうなっています)

ketaro-m commented 10 months ago
  1. "sample_service_bridge"についての注意書き

MyServer.cpp#L12にある以下の記述において,"service0"という名前は固定なのですね. ソースコードのどこにも"service0"という記述をいれずにビルドしてもsrc_gen/MyBridgeServiceROSBridge.cppstd::string port_name = "service0";という固定記述が作られるようで,おそらくOpenHRPの(バージョンによると思いますが)仕様なのだと理解しています.

RTC::ReturnCode_t MyServer::onInitialize(){
  m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0);
  addPort(m_MyServerServicePort);
  return RTC::RTC_OK;
}

そして,このポートを"MyBridgeService"という名前でProviderポートとして登録するのがこの行で,server.launch内でこのようにconnectするときの名前に相当するという理解で正しいでしょうか.

<rtconnect from="MyServer0.rtc:service0"     to="MyBridgeServiceROSBridge.rtc:MyBridgeService" />

初見で見たときに,すぐ上でserviceポートを初期化している箇所#L6で指定する名前と同一であるため,このポートのことを差しているのかと混同してしまいました…

MyServer::MyServer(RTC::Manager* manager):
  RTC::DataFlowComponentBase(manager),
  m_MyServerServicePort("service0")
{
  m_service0.setComponent(this);
}

困惑を避ける意味と理解を促すために,以下のようにポート名の変更とコメントを追加するのはいかがでしょうか.

#include "MyServer.h"
#include <iostream>

MyServer::MyServer(RTC::Manager* manager):
  RTC::DataFlowComponentBase(manager),
  m_MyServerServicePort("MyServerService")
{
  m_service0.setComponent(this);
}

RTC::ReturnCode_t MyServer::onInitialize(){
  m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0);  // "service0"は固定
  addPort(m_MyServerServicePort);
  return RTC::RTC_OK;
}
<rtconnect from="MyServer0.rtc:MyServerService"     to="MyBridgeServiceROSBridge.rtc:MyBridgeService" />
Naoki-Hiraoka commented 10 months ago

ありがとうございます。フィードバックをいただけてとても助かります。

"sample_service_rtc"において誤植と思われるものを発見しました.

ありがとうございます。修正しました。

"sample_service_bridge"についての注意書き

いいえ、違います。

サンプルパッケージは、3つのことをしています。

  1. idlの定義 (idl/MyBridgeService.idl)
  2. ROSBridgeの自動生成 https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/sample_service_bridge/CMakeLists.txt#L19
  3. サーバーRTCの作成 (rtc/MyServer)

1に対して2と3は依存しています. が、2と3は独立であって、互いに影響を全く与えません。MyServerのソースコードを変えても、生成されるROSBridgeには影響は全くありません。この点が伝わっていない気がします。

server.launch内で

<rtconnect from="MyServer0.rtc:service0"     to="MyBridgeServiceROSBridge.rtc:MyBridgeService" />

として、3のサーバーの"service0"というproviderポートと、2のROSBridgeの"MyBridgeService"というconsumerポートを接続しています。

3のサーバーのproviderポートの名前を"service0"と名付けているのは、https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/sample_service_bridge/rtc/MyServer/MyServer.cpp#L6 です。https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/sample_service_bridge/rtc/MyServer/MyServer.cpp#L12 に書いてある"service0"は、ただの飾りです。https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L211 とhttps://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L220 に説明があります。

2のROSBridgeのconsumerポートの名前"MyBridgeService"ですが、これは、rtmbuildがidlからROSBridgeを自動生成するときに、idlに書かれたinterface名がポート名になるようにする仕様になっています。https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Creating_Service_ROS_Bridge_Automatically.md?plain=1#L42-L43 に説明があります。自動生成スクリプトのhttps://github.com/start-jsk/rtmros_common/blob/57331a5179d0d10947ff6f58eae744aa8c0be22a/rtmbuild/scripts/idl2srv.py#L495 で指定しています。

ソースコードのどこにも"service0"という記述をいれずにビルドしてもsrc_gen/MyBridgeServiceROSBridge.cppにstd::string port_name = "service0";という固定記述が作られるようで,おそらくOpenHRPの(バージョンによると思いますが)仕様なのだと理解しています.

ここはMyServerのソースコードなので、MyBridgeServiceROSBridge側の名前には一切関係がありません。

ROSBridge内で自動生成されるstd::string port_name = "service0";という固定記述ですが、registerConsumer関数でしか使っていないので、ポート名とは一切関係のないただの飾りです。(https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L538 に説明があります。)

そして,このポートを"MyBridgeService"という名前でProviderポートとして登録するのがこの行で,

RTC::ReturnCode_t MyServer::onInitialize(){
  m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0);
  addPort(m_MyServerServicePort);
  return RTC::RTC_OK;
}

いいえ。この第一引数service0は飾りで、registerProviderの第二引数にはidlに定義されているインターフェースの型名です。https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L220 に説明があります。

"service0"という名前でProviderポートとして登録するのは、

MyServer::MyServer(RTC::Manager* manager):
  RTC::DataFlowComponentBase(manager),
  m_MyServerServicePort("service0")
{
  m_service0.setComponent(this);
}

です。https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L211 に説明があります。

ここで登録された"service0"という名前が、server.launch内でfrom="MyServer0.rtc:service0"とconnectするときの名前に相当します.

初見の方もわかるようにするためには、どこの記述を直したらよいと思いますか?

ketaro-m commented 10 months ago

ご丁寧な解説ありがとうございます!! 僕のコメントの書き方がわかりにくかったような気がするのですが,僕が理解しきれていなかったのは

  1. ROSBridgeのconsumerポートの名前"MyBridgeService"を何に変えてもlaunchでconnnectするようにしたらよいと思っていたが,idlの書かれたinterface名に拘束されている.

2のROSBridgeのconsumerポートの名前"MyBridgeService"ですが、これは、rtmbuildがidlからROSBridgeを自動生成するときに、idlに書かれたinterface名がポート名になるようにする仕様になっています。

  1. "service0"という名前はOpenHRPの仕様ではなく,rtmros_common/rtmbuild/scripts/idl2srv.pyの仕様である.

m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0); に書いてある"service0"は、ただの飾りです。

という点でした.

1.に関しては,僕の読み込みが足りなかったと思います.実際こちらに解説がありましたね…

https://github.com/Naoki-Hiraoka/rtmros_beginner_tutorial/blob/9fc00a712920c788aff3f80a66bc99b1ef64d0dc/openrtm_beginner_tutorial/Writing_Simple_Service_Server_Client_RTC.md?plain=1#L220

2.に関してですが,飾りといっても以下の部分でハードコーディングされているので,これは"service0"以外にするとだめということですよね.(実際別のものにするとビルドは通りますがlaunchできなくなりました)

https://github.com/start-jsk/rtmros_common/blob/57331a5179d0d10947ff6f58eae744aa8c0be22a/rtmbuild/scripts/idl2srv.py#L495

また, サーバーのproviderポートの名前を"service0"と名付けている

m_MyServerServicePort("service0") 

と,2.に該当する飾り変数"service0"

m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0); 

が別のものを差しているというのは初見では混同してしまったので,名前は別にするとその誤解は避けられるかと思います.

以上を踏まえて,下記のような変更はいかがでしょうか.

  1. Writing_Simple_Service_Server_Client_RTC.md #L220上で
`registerProvider`の第一引数`service0`は単なる名前であり、何を与えても実用上あまり重要ではない.

`registerProvider`の第一引数`service0`は単なる名前であるが,自動生成スクリプトの [rtmros_common/rtmbuild/scripts/idl2srv.py](https://github.com/start-jsk/rtmros_common/blob/57331a5179d0d10947ff6f58eae744aa8c0be22a/rtmbuild/scripts/idl2srv.py#L495) で指定されているため,`service0`にしなければいけない.

のように変える.

  1. ソースコード上で以下のようにサーバーのproviderポートの名前と飾り変数を分ける.
#include "MyServer.h"
#include <iostream>

MyServer::MyServer(RTC::Manager* manager):
  RTC::DataFlowComponentBase(manager),
  m_MyServerServicePort("MyServerService")
{
  m_service0.setComponent(this);
}

RTC::ReturnCode_t MyServer::onInitialize(){
  m_MyServerServicePort.registerProvider("service0", "MyBridgeService", m_service0); 
  addPort(m_MyServerServicePort);
  return RTC::RTC_OK;
}
<rtconnect from="MyServer0.rtc:MyServerService"     to="MyBridgeServiceROSBridge.rtc:MyBridgeService" />
Naoki-Hiraoka commented 10 months ago

2.に関してですが,飾りといっても以下の部分でハードコーディングされているので,これは"service0"以外にするとだめということですよね.(実際別のものにするとビルドは通りますがlaunchできなくなりました)

あれ、launchできなくなるとは知りませんでした。InPort/OutPortは名前を何にしても大丈夫だったので、参考 ServicePortの場合をあまり確認していませんでした。

確認の上、修正します。ありがとうございます。

Naoki-Hiraoka commented 10 months ago

サービスの場合はregisterProvider等の第一引数のインスタンス名はただの飾りではなく、サーバー側とクライアント側で同じでないといけませんでした。

https://github.com/gbiggs/rtctree/blob/bd725a47ac87c259c8bce06156ccc9ab71111c26/rtctree/ports.py#L388-L391

各所のREADMEを修正し、サンプルのサーバーのproviderポートの名前と飾り変数を分けました。