LoginSignup
27
9

More than 3 years have passed since last update.

ROS1 -> ROS2のポーティングときにハマった点のまとめ その2

Last updated at Posted at 2019-12-01

はじめに

こんにちは、先日こんな記事を投稿したものです。
さらに作業を続けていて罠はコレだけじゃなかったっていうのが発覚したので第二報を出したいと思います。

罠その8 tf2_rosのインターフェースが変わっている

まず英語、日本語にかかわらずドキュメントがほぼありません。
強いて言うならコレ
githubのリポジトリを確認してみてもdashingのブランチがない・・・・
でもnavigation2とかが来ていて座標変換ができてないわけないでしょうと思いつつaptのパッケージを確認してみたらどこから来たかはわからないがたしかにいる・・・・
とりあえずROS1と同じ感覚でtf2_ros::Bufferのインスタンスを作ろうとしたら

error: no matching function for call to ‘tf2_ros::Buffer::Buffer()’

APIが変わっているようなので、/opt/ros/dashing/以下にあるヘッダを探してコンストラクタを探す。

Screenshot from 2019-10-16 10-34-45.png

第一引数にClockオブジェクトが必要になっている!
なので、このようにコンストラクタ関数に初期化を書けば使うことができます

    PointsTransformComponent::PointsTransformComponent(const rclcpp::NodeOptions & options)
    : Node("points_transform", options),
        ros_clock_(RCL_ROS_TIME), 
        buffer_(std::make_shared<rclcpp::Clock>(ros_clock_)),
        listener_(buffer_)

さらにLookupTransformのAPIも変わっている。

    TF2_ROS_PUBLIC
    virtual geometry_msgs::msg::TransformStamped 
    lookupTransform(const std::string& target_frame, const std::string& source_frame,
                    const tf2::TimePoint& time, const tf2::Duration timeout) const override;

ros::Timeがrclcppではなくtf2::TimePointという独自型になっています。
ちなみにこの型はheaderのスタンプをいれたら変換してくれるというような甘えた仕様はありません:innocent:
tf2::Durationも同様です。
諦めて以下のようなコードを書いてtransformを取得しましょう。

geometry_msgs::msg::TransformStamped transform_stamped = 
  buffer_.lookupTransform("lidar", "map", time_point, tf2::durationFromSec(1.0));

罠その9 node handler的なものの仕様が変わっている

ROS1ではnode handleというオブジェクトを経由してpublisher/subscriberを作成していました、このオブジェクトは何個生成しても生成時にノード作成処理を伴わないため、複数node handleを使ったノードを作ることができました。
しかし、ROS2でそれをやるとノード作成処理が走ってしまうようで同じ名前のノードが2つ発生します。
どんな副作用がでるかは未検証ですが、避けたほうが良いでしょう。

罠その10 subscriberのcallbackでコンパイルエラーがでる

publisherはチュートリアルの通りに作ることができたのだが、subscriberを作ろうとしたところ何故かエラーになる。
Screenshot from 2019-10-16 10-19-36.png

libpoints_transform_component.so: `rosidl_message_type_support_t const* 
  rosidl_typesupport_cpp::get_message_type_support_handle<sensor_msgs::msg::PointCloud2_<std::allocator<void> > >()' に対する定義されていない参照です

std_msgs::msg::Stringに変更してみたところ、このエラーは出なくなった。
ライブラリリンクの問題のようだ
確認するとCMakeLists.txtに

CMakeLists.txt
find_package(sensor_msgs REQUIRED)

を入れ忘れていた、どうもメッセージ型のパッケージをfind_packageし忘れていてもヘッダのインクルードはできてしまう仕様らしい:thinking:

罠その11 rclpy向けメッセージ型でコケる

同じパッケージの中でメッセージ生成+ノード作成をやろうとしたらハマった・・・
原因不明、同様の症状が報告されているものの解決策は書いていない。
rclpy向けのメッセージ生成でコケているようだ
https://answers.ros.org/question/330444/errors-during-messages-compilation-in-ros2/

メッセージ用のパッケージを分離してビルドするとうまく行く。謎
と思ってたら近藤さんから真相を教えてもらった、どうもrclpyでCMakeLists.txtなしでビルドできるようになった副作用らしい。
今後はメッセージは分離しよう

罠その12 std::threadでスレッドを作ると死ぬ

rclcpp componentの中でstd::threadを使ってスレッドを切った場合joinしないとスレッドが別れた瞬間にクラッシュ、joinするとjoinsした瞬間にクラッシュした。
一定周期で回す処理はtimerを使うことでなんとかなることが判明
ただ、OpenMPみたく高速化のためスレッドを切る場合とかは大丈夫なんだろうか・・・(未検証です・・・すみません。)

まとめ

今回も前回に続いてかなり罠が見つかる結果となった(まあ、お世辞にもパッケージが揃っているとは言えない状況なのでしかたないと思うが・・・)
しかし、罠といってもちょっとお約束を守れば解決できそうなものがほとんどで、慣れればROS2のほうがROS1より圧倒的に人権であると感じる。
Let's start ROS2!!

27
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
9