ROS2 on Fedora39

はじめに

OS と名乗っておきながらライブラリやツールの集まりで,全然 OS じゃないじゃんと思って食わず嫌いしていた.

The Robot Operating System (ROS) is a set of software libraries and tools for building robot applications. From drivers and state-of-the-art algorithms to powerful developer tools, ROS has the open source tools you need for your next robotics project.

https://docs.ros.org/en/iron/index.html

とはいえ,食わず嫌いも良くないなと考え直し ROS2 を触ってみることにする.

ROS2

ROS2 の説明を書こうと思ったが,分かりやすそうなものがあったのでリンクを貼っておく.

Install

環境は Fedora 39.インストールは基本的には公式の手順をトレースするだけ.

$ cat /etc/fedora-release 
Fedora release 39 (Thirty Nine)
RHEL (source) — ROS 2 Documentation: Iron documentation

ビルドツールをインストールする.

$ sudo dnf install -y \
  cmake \
  gcc-c++ \
  git \
  make \
  patch \
  python3-colcon-common-extensions \
  python3-flake8-builtins \
  python3-flake8-comprehensions \
  python3-flake8-docstrings \
  python3-flake8-import-order \
  python3-flake8-quotes \
  python3-mypy \
  python3-pip \
  python3-pydocstyle \
  python3-pytest \
  python3-pytest-repeat \
  python3-pytest-rerunfailures \
  python3-rosdep \
  python3-setuptools \
  python3-vcstool \
  wget

dnf に対応していないパッケージをインストールする.

$ python3 -m pip install -U --user \
  flake8-blind-except==0.1.1 \
  flake8-class-newline \
  flake8-deprecated

vcs コマンドを使っていろいろなリポジトリから必要なソースを拾ってくる.

$ mkdir -p ~/ros2_iron/src
$ cd ~/ros2_iron
$ vcs import --input https://raw.githubusercontent.com/ros2/ros2/iron/ros2.repos src

dnf で諸々アップデートしてから,rosdep で関連パッケージをインストールする.

$ sudo dnf update
$ sudo rosdep init
$ rosdep update
$ rosdep install --from-paths src --ignore-src -y --skip-keys "assimp fastcdr ignition-cmake2 ignition-math6 python3-pygraphviz rti-connext-dds-6.0.1 urdfdom_headers"

ビルドする.いくつか環境変数を設定しておかないとビルドに失敗するので注意.

$ cd ~/ros2_iron/
$ export RPM_ARCH=$(uname -m)
$ export RPM_PACKAGE_RELEASE=1.0
$ export RPM_PACKAGE_VERSION=1.0
$ export RPM_PACKAGE_NAME=qt_gui_cpp
$ colcon build --symlink-install

動作確認

ターミナル1で環境変数を設定して,メッセージ送信処理を実行する.

$ . ~/ros2_iron/install/local_setup.bash
$ ros2 run demo_nodes_cpp talker
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 1'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 2'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 3'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 4'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 5'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 6'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 7'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 8'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 9'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 10'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 11'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 12'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 13'
[INFO] [0000000000.000000000] [talker]: Publishing: 'Hello World: 14'

ターミナル2も環境変数を設定して,メッセージ受信処理を実行する.

$ . ~/ros2_iron/install/local_setup.bash
$ ros2 run demo_nodes_py listener
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 9]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 10]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 11]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 12]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 13]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 14]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 15]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 16]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 17]
[INFO] [0000000000.000000000] [listener]: I heard: [Hello World: 18]

ソース見てみるとこんな感じ.chatter というトピックを使って talker と listener がメッセージの送受信を行っている.

// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// 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.

#include <chrono>
#include <cstdio>
#include <memory>
#include <utility>

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/register_node_macro.hpp"

#include "std_msgs/msg/string.hpp"

#include "demo_nodes_cpp/visibility_control.h"

using namespace std::chrono_literals;

namespace demo_nodes_cpp
{
// Create a Talker class that subclasses the generic rclcpp::Node base class.
// The main function below will instantiate the class as a ROS node.
class Talker : public rclcpp::Node
{
public:
  DEMO_NODES_CPP_PUBLIC
  explicit Talker(const rclcpp::NodeOptions & options)
  : Node("talker", options)
  {
    // Create a function for when messages are to be sent.
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    auto publish_message =
      [this]() -> void
      {
        msg_ = std::make_unique<std_msgs::msg::String>();
        msg_->data = "Hello World: " + std::to_string(count_++);
        RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", msg_->data.c_str());
        // Put the message into a queue to be processed by the middleware.
        // This call is non-blocking.
        pub_->publish(std::move(msg_));
      };
    // Create a publisher with a custom Quality of Service profile.
    // Uniform initialization is suggested so it can be trivially changed to
    // rclcpp::KeepAll{} if the user wishes.
    // (rclcpp::KeepLast(7) -> rclcpp::KeepAll() fails to compile)
    rclcpp::QoS qos(rclcpp::KeepLast{7});
    pub_ = this->create_publisher<std_msgs::msg::String>("chatter", qos);

    // Use a timer to schedule periodic message publishing.
    timer_ = this->create_wall_timer(1s, publish_message);
  }

private:
  size_t count_ = 1;
  std::unique_ptr<std_msgs::msg::String> msg_;
  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr pub_;
  rclcpp::TimerBase::SharedPtr timer_;
};

}  // namespace demo_nodes_cpp

RCLCPP_COMPONENTS_REGISTER_NODE(demo_nodes_cpp::Talker)
// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// 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.

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/register_node_macro.hpp"

#include "std_msgs/msg/string.hpp"

#include "demo_nodes_cpp/visibility_control.h"

namespace demo_nodes_cpp
{
// Create a Listener class that subclasses the generic rclcpp::Node base class.
// The main function below will instantiate the class as a ROS node.
class Listener : public rclcpp::Node
{
public:
  DEMO_NODES_CPP_PUBLIC
  explicit Listener(const rclcpp::NodeOptions & options)
  : Node("listener", options)
  {
    // Create a callback function for when messages are received.
    // Variations of this function also exist using, for example UniquePtr for zero-copy transport.
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    auto callback =
      [this](std_msgs::msg::String::ConstSharedPtr msg) -> void
      {
        RCLCPP_INFO(this->get_logger(), "I heard: [%s]", msg->data.c_str());
      };
    // Create a subscription to the topic which can be matched with one or more compatible ROS
    // publishers.
    // Note that not all publishers on the same topic with the same type will be compatible:
    // they must have compatible Quality of Service policies.
    sub_ = create_subscription<std_msgs::msg::String>("chatter", 10, callback);
  }

private:
  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
};

}  // namespace demo_nodes_cpp

RCLCPP_COMPONENTS_REGISTER_NODE(demo_nodes_cpp::Listener)

おわりに

とりあえず導入と簡単な動作確認はできたが,まだなんら ROS2 の恩恵を享受した実感がない.

慣れてくれば,自前でマルチプロセスやマルチスレッドを実装するより,ROS2 のメッセージキューを使ってプロセス間通信したほうが簡単に疎結合なプログラムが実装できる気がしないでもないが,もう少しチュートリアル進めて見る.

コメント

タイトルとURLをコピーしました