パッケージをどう作ってますか?
$ ros2 pkg create hoge
だけで済ませてませんか?
引数を設定しよう
ここでどんな引数が使えるか見てみましょう
$ ros2 pkg create --help
と打つと以下のように出てきますね
出力
usage: ros2 pkg create [-h] [--package-format {2,3}]
[--description DESCRIPTION] [--license LICENSE]
[--destination-directory DESTINATION_DIRECTORY]
[--build-type {cmake,ament_cmake,ament_python}]
[--dependencies DEPENDENCIES [DEPENDENCIES ...]]
[--maintainer-email MAINTAINER_EMAIL]
[--maintainer-name MAINTAINER_NAME]
[--node-name NODE_NAME] [--library-name LIBRARY_NAME]
package_name
Create a new ROS2 package
positional arguments:
package_name The package name
optional arguments:
-h, --help show this help message and exit
--package-format {2,3}, --package_format {2,3}
The package.xml format.
--description DESCRIPTION
The description given in the package.xml
--license LICENSE The license attached to this package
--destination-directory DESTINATION_DIRECTORY
Directory where to create the package directory
--build-type {cmake,ament_cmake,ament_python}
The build type to process the package with
--dependencies DEPENDENCIES [DEPENDENCIES ...]
list of dependencies
--maintainer-email MAINTAINER_EMAIL
email address of the maintainer of this package
--maintainer-name MAINTAINER_NAME
name of the maintainer of this package
--node-name NODE_NAME
name of the empty executable
--library-name LIBRARY_NAME
name of the empty library
よく使うものからピックアップしていきましょう
一応参考程度に引数なしで出力したものを書いておきます
おそらくデフォルトではament_cmakeが設定されているようです
引数なしver
├── CMakeLists.txt
├── include
│ └── hoge
├── package.xml
└── src
cmake_minimum_required(VERSION 3.5)
project(hoge)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
<?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>hoge</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="your-mail">your-name</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
--build-type
これは使っている人は多いのではないでしょうか
これは文字どおりビルドの方式を変えてくれるものです
使用例としては以下のような感じです
パッケージ名はhoge
とします
# cmake
$ ros2 pkg create hoge --build-type ament_cmake
# python
$ ros2 pkg create hoge --build-type ament-python
以下に出力されるファイルを書きます
長いので畳んでいます
ament_cmake
引数なしのところで書いたものと同じですが書きます
├── CMakeLists.txt
├── include
│ └── hoge
├── package.xml
└── src
cmake_minimum_required(VERSION 3.5)
project(hoge)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>hoge</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="your-email">your-name</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
ament_python
├── hoge
│ └── __init__.py
├── package.xml
├── resource
│ └── hoge
├── setup.cfg
├── setup.py
└── test
├── test_copyright.py
├── test_flake8.py
└── test_pep257.py
script-dir=$base/lib/hoge
[install]
install-scripts=$base/lib/hoge
from setuptools import setup
package_name = 'hoge'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='your-name',
maintainer_email='your-email',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
],
},
)
<?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>hoge</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="your-mail">your-name</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
--dependencies
ここからは
ament_cmake
ベースでお話します
これは実に便利なやつなんです
例えば--build-type
をament_cmake
にしたとして依存関係を記述したくなった時、
いつも依存関係をどのように記述していますか?
例えばrclcpp
を使いたくなり、cmake
に直接
find_package(rclcpp REQUIRED)
とか書いてませんか?
わざわざcmake
をこれを書くために編集するなんてめんどくさいと思いませんか?
ここで--dependencies
を使います
$ ros2 pkg create hoge --build-type ament_cmake --dependencies rclcpp
と書くだけでなんとCMakeLists.txt
とpackage.xml
に記述されるのです
実際に確認してみると
# find dependencies
find_package(rclcpp REQUIRED)
<depend>rclcpp</depend>
と記述されていますね
他にもよく使うものとしてstd_msgs
, sensor_msgs
, pythonとc++を両立したいときにはament_cmake_python
, rclpy
, 独自にメッセージ型を記述したいときはrosidl_default_generators
などでしょうか
全部依存関係に書いてしまいましょう
$ ros2 pkg create hoge --build-type ament_cmake --dependencies rclcpp rclpy ament_cmake_python std_msgs sensor_msgs rosidl_default_generators
クッソなげぇですわ〜
でもこうすると
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclpy REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(std_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
<depend>rclcpp</depend>
<depend>rclpy</depend>
<depend>ament_cmake_python</depend>
<depend>std_msgs</depend>
<depend>sensor_msgs</depend>
<depend>rosidl_default_generators</depend>
と勝手に記述してくれるので楽ですね
--node-name
これを書くだけでcmake
の記述がしなくて良くなります
どこまで書いてくれるのか確かめて見ましょう
次のコマンドを打ってプロジェクトを作成します
$ ros2 pkg create hoge --build-type ament_cmake --node-name my_node
ここでCMakeLists.txt
はどうでしょうか
add_executable(my_node src/my_node.cpp)
target_include_directories(my_node PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS my_node
DESTINATION lib/${PROJECT_NAME})
と記述されていますね
また、生成されたファイルを見てみると
.
├── CMakeLists.txt
├── include
│ └── hoge
├── package.xml
└── src
└── my_node.cpp
となっていて、src/my_node.cpp
を見てみると、
#include <cstdio>
int main(int argc, char ** argv)
{
(void) argc;
(void) argv;
printf("hello world hoge package\n");
return 0;
}
となっています
いやもうちょっとがんばってよ
あとはament_target_dependencies
を記述するくらいでしょうか
+ --dependencies
ではここでさっきやった--dependencies
を記述しましょう
そうするとどうなるのでしょうか
$ ros2 pkg create huga --build-type ament_cmake --node-name my_node --dependencies rclcpp
ここでCMakeLists.txt
を確認してみるとどうなっているかというと
ament_target_dependencies(
my_node
"rclcpp"
)
という行が追加されています
つまりament_target_dependencies
も書かなくてもいいということです
これで書く文量がかなり減ったのではないでしょうか
2つ書いてみた
ros2 pkg create hoge --build-type ament_cmake --node-name my_node1 --node-name my_node2
としたらどうなるか気になりませんか?
実行してCMakeLists.txt
を確認してみると
add_executable(my_node2 src/my_node2.cpp)
target_include_directories(my_node2 PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
としか実行ファイルの生成が指示されていません
つまりあとに書いたノードしか生成されないということみたいです
ちなみに
.
├── CMakeLists.txt
├── include
│ └── hoge
├── package.xml
└── src
└── my_node2.cpp
からも本当に後ろに書いたノードしか生成してくれないようです
--library-name
ライブラリ作って便利にコーディングしたいという方のためにros2はライブラリの生成も対応してくれています
次のコマンドを打ってプロジェクトを作成しましょう
$ ros2 pkg create hoge --build-type ament_cmake --library-name my_lib
生成されるファイルは以下のようになっています
.
├── CMakeLists.txt
├── include
│ └── hoge
│ ├── my_lib.hpp
│ └── visibility_control.h
├── package.xml
└── src
└── my_lib.cpp
ここでCMakeLists.txt
を確認すると
find_package(ament_cmake_ros REQUIRED)
# 省略
add_library(my_lib src/my_lib.cpp)
target_include_directories(my_lib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
# 省略
target_compile_definitions(my_lib PRIVATE "HOGE_BUILDING_LIBRARY")
install(
DIRECTORY include/
DESTINATION include
)
install(
TARGETS my_lib
EXPORT export_${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
# 省略
include
)
ament_export_libraries(
my_lib
)
ament_export_targets(
export_${PROJECT_NAME}
)
ではpackage.xml
はどうかというと
<buildtool_depend>ament_cmake_ros</buildtool_depend>
が追加されていますね
では生成されているinclude/hoge/my_lib.hpp
とsrc/my_lib.cpp
を確認していきましょう
#ifndef HOGE__MY_LIB_HPP_
#define HOGE__MY_LIB_HPP_
#include "hoge/visibility_control.h"
namespace hoge
{
class MyLib
{
public:
MyLib();
virtual ~MyLib();
};
} // namespace hoge
#include "hoge/my_lib.hpp"
namespace hoge
{
MyLib::MyLib()
{
}
MyLib::~MyLib()
{
}
} // namespace hoge
クラスの基本のキみたいな感じのものが生成されていますね
基本的にはこれに追加していって書いていく感じです
では一番(?)気になっているinclude/hoge/visibility_control.h
を見てみましょう
長いのでたたんでます
include/hoge/visibility_control.h
#ifndef HOGE__VISIBILITY_CONTROL_H_
#define HOGE__VISIBILITY_CONTROL_H_
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
// https://gcc.gnu.org/wiki/Visibility
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define HOGE_EXPORT __attribute__ ((dllexport))
#define HOGE_IMPORT __attribute__ ((dllimport))
#else
#define HOGE_EXPORT __declspec(dllexport)
#define HOGE_IMPORT __declspec(dllimport)
#endif
#ifdef HOGE_BUILDING_LIBRARY
#define HOGE_PUBLIC HOGE_EXPORT
#else
#define HOGE_PUBLIC HOGE_IMPORT
#endif
#define HOGE_PUBLIC_TYPE HOGE_PUBLIC
#define HOGE_LOCAL
#else
#define HOGE_EXPORT __attribute__ ((visibility("default")))
#define HOGE_IMPORT
#if __GNUC__ >= 4
#define HOGE_PUBLIC __attribute__ ((visibility("default")))
#define HOGE_LOCAL __attribute__ ((visibility("hidden")))
#else
#define HOGE_PUBLIC
#define HOGE_LOCAL
#endif
#define HOGE_PUBLIC_TYPE
#endif
#endif // HOGE__VISIBILITY_CONTROL_H_
ビルド環境で変わるやつですね
つまり、様々な環境に対応したROS2に対応するためののヘッダファイルだと思われます
もし、これでライブラリを作るときは触るファイルはinclude/<project_name>/<lib_name>.hpp
とsrc/<lib_name>
.cppだけでいいみたいですね
このライブラリに対しても--dependencies
が使えるようです
なので、ここでも簡単に依存関係を記述できるみたいです
終わりに
これで簡単に書けるようになったのではないでしょうか
例えば今、rclcpp
とstd_msgs
, sensor_msgs
を使ったノードを生成してくれと言われたらコマンド一行ですぐ作れますよね?
当然
$ ros2 pkg create hoge --node-name my_node --dependencies rclcpp std_msgs sensor_msgs
ですよね
これにてすべて終了です
では良きROS2ライフをお送りください!
不明点、間違っている点があればコメントなどで教えてください!