1. 概要
理解するためには、作ってみるです。
以下、「Ubuntu 24.04」の環境で。
なかなか、いいサンプルがありません。
「examples/rclcpp at jazzy · ros2/examples · GitHub」のものを使おうと思いますが。
上記は、「rolling」のようなので、いつ中身が変わるかは、わかりません。
参考にしているのは、2024年11月28日時点のものです。
2. ワークスペース作成
仮に、ワークスペース名を、「colcon_ws」として、まずワークスペースのエリアを確保します。
mkdir -pv ~/colcon_ws/src
3. パッケージ作成
「mypackage」という名前のパッケージを作成します。
cd ~/colcon_ws/src
ros2 pkg create mypackage
下記のような出力がありまして・・・。
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['hogehoge <hogehoge@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./mypackage
creating ./mypackage/package.xml
creating source and include folder
creating folder ./mypackage/src
creating folder ./mypackage/include/mypackage
creating ./mypackage/CMakeLists.txt
[WARNING]: Unknown license 'TODO: License declaration'. This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identifiers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0
結果として、下記のディレクトリ・ファイルが作成されます。
`-- mypackage
|-- CMakeLists.txt
|-- include
| `-- mypackage
|-- package.xml
`-- src
参考サイトで紹介されている、ソースコードを作成します。
コードの内容は、末尾に記述しています。
ソースコード作成の結果、下記のような構成になるはずです。
|-- CMakeLists.txt
|-- include
| `-- mypackage
| |-- publisher_node.hpp
| |-- subscriber_node.hpp
| `-- visibility.h
|-- package.xml
`-- src
|-- composed.cpp
|-- publisher_node.cpp
|-- standalone_publisher.cpp
|-- standalone_subscriber.cpp
`-- subscriber_node.cpp
4. ビルド
ビルドします。
cd ~/colcon_ws
colcon build --packages-select mypackage
うまくいけば、下記のような表示なるはず。
(時間は、もっとかかると思います)
Starting >>> mypackage
Finished <<< mypackage [3.78s]
Summary: 1 package finished [4.78s]
5. 実行
作成したものを実行します。
2つの端末で実行します。
「Subscriber」側。
ros2 run mypackage composition_subscriber
「Publisher」側。
ros2 run mypackage composition_publisher
「Subscriber」側の表示。
[INFO] [1732868452.471512538] [subscriber_node]: Subscriber: 'Hello, world! 0'
[INFO] [1732868452.969242249] [subscriber_node]: Subscriber: 'Hello, world! 1'
[INFO] [1732868453.465351847] [subscriber_node]: Subscriber: 'Hello, world! 2'
[INFO] [1732868453.966899584] [subscriber_node]: Subscriber: 'Hello, world! 3'
[INFO] [1732868454.468686238] [subscriber_node]: Subscriber: 'Hello, world! 4'
[INFO] [1732868454.967533737] [subscriber_node]: Subscriber: 'Hello, world! 5'
「Publisher」側の表示。
[INFO] [1732868452.467683305] [publisher_node]: Publisher: 'Hello, world! 0'
[INFO] [1732868452.966664863] [publisher_node]: Publisher: 'Hello, world! 1'
[INFO] [1732868453.463301435] [publisher_node]: Publisher: 'Hello, world! 2'
[INFO] [1732868453.963718499] [publisher_node]: Publisher: 'Hello, world! 3'
[INFO] [1732868454.466485590] [publisher_node]: Publisher: 'Hello, world! 4'
[INFO] [1732868454.963764438] [publisher_node]: Publisher: 'Hello, world! 5'
止めるときは、Ctrl+C で止めます。
6. ソースコード
コピー元のソースから必要な部分のみを取り出し、加工しています。
ヘッダ。
「~/colcon_ws/src/mypackage/include/mypackage」配下に作成します。
「publisher_node.hpp」
#ifndef MINIMAL_COMPOSITION__PUBLISHER_NODE_HPP_
#define MINIMAL_COMPOSITION__PUBLISHER_NODE_HPP_
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
#include "mypackage/visibility.h"
class PublisherNode : public rclcpp::Node
{
public:
MINIMAL_COMPOSITION_PUBLIC PublisherNode(rclcpp::NodeOptions options);
private:
void on_timer();
size_t count_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};
#endif
「subscriber_node.hpp」
#ifndef MINIMAL_COMPOSITION__SUBSCRIBER_NODE_HPP_
#define MINIMAL_COMPOSITION__SUBSCRIBER_NODE_HPP_
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
#include "mypackage/visibility.h"
class SubscriberNode : public rclcpp::Node
{
public:
MINIMAL_COMPOSITION_PUBLIC SubscriberNode(rclcpp::NodeOptions options);
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
#endif
「visibility.h」
#ifndef MINIMAL_COMPOSITION__VISIBILITY_H_
#define MINIMAL_COMPOSITION__VISIBILITY_H_
#ifdef __cplusplus
extern "C"
{
#endif
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define MINIMAL_COMPOSITION_EXPORT __attribute__ ((dllexport))
#define MINIMAL_COMPOSITION_IMPORT __attribute__ ((dllimport))
#else
#define MINIMAL_COMPOSITION_EXPORT __declspec(dllexport)
#define MINIMAL_COMPOSITION_IMPORT __declspec(dllimport)
#endif
#ifdef MINIMAL_COMPOSITION_DLL
#define MINIMAL_COMPOSITION_PUBLIC MINIMAL_COMPOSITION_EXPORT
#else
#define MINIMAL_COMPOSITION_PUBLIC MINIMAL_COMPOSITION_IMPORT
#endif
#define MINIMAL_COMPOSITION_PUBLIC_TYPE MINIMAL_COMPOSITION_PUBLIC
#define MINIMAL_COMPOSITION_LOCAL
#else
#define MINIMAL_COMPOSITION_EXPORT __attribute__ ((visibility("default")))
#define MINIMAL_COMPOSITION_IMPORT
#if __GNUC__ >= 4
#define MINIMAL_COMPOSITION_PUBLIC __attribute__ ((visibility("default")))
#define MINIMAL_COMPOSITION_LOCAL __attribute__ ((visibility("hidden")))
#else
#define MINIMAL_COMPOSITION_PUBLIC
#define MINIMAL_COMPOSITION_LOCAL
#endif
#define MINIMAL_COMPOSITION_PUBLIC_TYPE
#endif
#ifdef __cplusplus
}
#endif
#endif
ソース。
「~/colcon_ws/src/mypackage/src」配下に作成します。
「composed.cpp」
#include <memory>
#include "mypackage/publisher_node.hpp"
#include "mypackage/subscriber_node.hpp"
#include "rclcpp/rclcpp.hpp"
int main(int argc, char* argv[])
{
rclcpp::init(argc, argv);
rclcpp::executors::SingleThreadedExecutor exec;
rclcpp::NodeOptions options;
auto publisher_node = std::make_shared<PublisherNode>(options);
auto subscriber_node = std::make_shared<SubscriberNode>(options);
exec.add_node(publisher_node);
exec.add_node(subscriber_node);
exec.spin();
rclcpp::shutdown();
return 0;
}
「publisher_node.hpp」
#include <chrono>
#include "mypackage/publisher_node.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
PublisherNode::PublisherNode(rclcpp::NodeOptions options)
: Node("publisher_node", options), count_(0)
{
publisher_ = create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = create_wall_timer(500ms, std::bind(&PublisherNode::on_timer, this));
}
void PublisherNode::on_timer()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publisher: '%s'", message.data.c_str());
publisher_->publish(message);
}
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(PublisherNode)
「standalone_publisher.cpp」
#include <memory>
#include "mypackage/publisher_node.hpp"
#include "rclcpp/rclcpp.hpp"
int main(int argc, char* argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<PublisherNode>(rclcpp::NodeOptions()));
rclcpp::shutdown();
return 0;
}
「standalone_subscriber.cpp」
#include <memory>
#include "mypackage/subscriber_node.hpp"
#include "rclcpp/rclcpp.hpp"
int main(int argc, char* argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SubscriberNode>(rclcpp::NodeOptions()));
rclcpp::shutdown();
return 0;
}
「subscriber_node.cpp」
#include "mypackage/subscriber_node.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
SubscriberNode::SubscriberNode(rclcpp::NodeOptions options)
: Node("subscriber_node", options)
{
subscription_ = create_subscription<std_msgs::msg::String>(
"topic",
10,
[this](std_msgs::msg::String::UniquePtr msg) {
RCLCPP_INFO(this->get_logger(), "Subscriber: '%s'", msg->data.c_str());
});
}
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(SubscriberNode)
「CMakeLists.txt」「package.xml」
「~/colcon_ws/src/mypackage」配下に作成します(元があるので、編集)。
「CMakeLists.txt」
cmake_minimum_required(VERSION 3.8)
project(mypackage)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)
include_directories(include)
add_library(composition_nodes SHARED
src/publisher_node.cpp
src/subscriber_node.cpp)
target_compile_definitions(composition_nodes
PRIVATE "MINIMAL_COMPOSITION_DLL")
ament_target_dependencies(composition_nodes rclcpp rclcpp_components std_msgs)
# This package installs libraries without exporting them.
# Export the library path to ensure that the installed libraries are available.
if(NOT WIN32)
ament_environment_hooks(
"${ament_cmake_package_templates_ENVIRONMENT_HOOK_LIBRARY_PATH}")
endif()
add_executable(composition_publisher src/standalone_publisher.cpp)
target_link_libraries(composition_publisher composition_nodes)
ament_target_dependencies(composition_publisher rclcpp)
add_executable(composition_subscriber src/standalone_subscriber.cpp)
target_link_libraries(composition_subscriber composition_nodes)
ament_target_dependencies(composition_subscriber rclcpp)
add_executable(composition_composed src/composed.cpp)
target_link_libraries(composition_composed composition_nodes)
ament_target_dependencies(composition_composed rclcpp class_loader)
install(TARGETS
composition_nodes
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(TARGETS
composition_publisher
composition_subscriber
composition_composed
DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
「package.xml」
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>mypackage</name>
<version>0.0.1</version>
<description>MyPackage</description>
<maintainer email="hogehoge@sing.ne.jp">hogehoge</maintainer>
<license>BSD License</license>
<author email="jacob@openrobotics.org">Jacob Perron</author>
<author>Mikael Arguedas</author>
<author>Morgan Quigley</author>
<author email="sloretz@openrobotics.org">Shane Loretz</author>
<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>rclcpp</build_depend>
<build_depend>rclcpp_components</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>rclcpp</exec_depend>
<exec_depend>rclcpp_components</exec_depend>
<exec_depend>std_msgs</exec_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
7. 備考
本ページは、下記のサイトを参考にさせていただきました。
「ROS 2におけるワークスペース・パッケージの作成とビルド #ROS2」
「ROS2チュートリアル - パッケージ作成 #ROS2」
「examples/rclcpp at jazzy · ros2/examples · GitHub」