はじめに
本記事は、ROS2アドベントカレンダー1日目の記事です!
今回はPythonパッケージ管理ソフトウェアのRyeをROS2で使った例を示そうと思います。
ROS2×Pythonパッケージ管理ソフトウェアについての意見は様々あります。本記事も一例としてとらえてください。
環境
以下の環境で動作を確認しています。
項目 | バージョン |
---|---|
Ubuntu | 22.04 |
ROS2 | Humble |
手順
簡単に手順を説明すると以下です。
- Ryeをインストールする
- ROS2のパッケージを作成する (PythonのROSノードですが、ビルド方法はament_cmakeを選択)
- パッケージのディレクトリ内でRyeの設定を行う
- ソースコードを作成する
- ビルドする
- Ryeの環境に入り、ros2 run コマンドでPythonファイルを実行する
記事内では上記について説明しますが、ソースコードは以下にあるので実行したい方はREADME通りにコマンドを実行していくとRye上でROSノードの動作確認までできます。
Ryeをインストールする
curl -sSf https://rye-up.com/get | bash
echo 'source "$HOME/.rye/env"' >> ~/.bashrc
参考:
https://rye-up.com/guide/installation/#installing-rye
ROS2のパッケージを作成する
今回はパッケージ名を rye_sample_pkg
とします。
ros2 pkg create rye_sample_pkg --license MIT
自動的に生成されるファイルは以下のようになります。
PythonのROSノードを作成しますがament_cmakeを使用するためCMakeLists.txt等があって問題ありません。
rye_sample_pkg/
├ CMakeLists.txt
├ LICENSE
├ include/
├ rye_sample_pkg
├ package.xml
├ src/
パッケージのディレクトリ内でRyeの設定を行う
cd ~/ros2_ws/rye_sample_pkg
rye init
以下のように、READMEやpyproject.xmlが自動生成されます。
rye_sample_pkg/
├ CMakeLists.txt
├ LICENSE
├ README.md
├ include/
├ rye_sample_pkg
├ package.xml
├ pyproject.tom
├ src/
rye pin
コマンドで、そのディレクトリ内で作成されるPythonのbinファイルのバージョンを指定できます。rclpy等ROS2のソフトウェアは/opt/ros/
配下のものを使用するのでPythonのメジャーバージョンはUbuntu本体のものと合わせましょう。
その後、rye sync
コマンドで環境が作成されます。
rye pin 3.10
rye sync
ディレクトリ構成は以下のようになり、requirements*ファイルが自動生成されます。
rye_sample_pkg/
├ CMakeLists.txt
├ LICENSE
├ README.md
├ include/
├ rye_sample_pkg
├ package.xml
├ pyproject.tom
├ src/
├ requirements-dev.lock
├ requirements.lock
ソースコードを作成する
名称は問わないですが今回は scripts
ディレクトリを作成してその中にソースコードを作成しましょう。
mkdir scripts
cd scripts
vi talker.py
ROS2の以下のページを参考に作成します。
https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
#/usr/bin/env python3
import rclpy
from rclpy.node import Node
import sys
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.get_logger().info(f"python path: {sys.executable}")
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
また、talker.pyに実行権限をつけましょう。CMakeの設定でPythonファイルをインストールするためです。
sudo chmod +x talker.py
ros2 のノードのために必要な __init__.py
を作成しましょう。
mkdir rye_sample_pkg
cd rye_sample_pkg
touch __init__.py
CMakeLists.txtにPythonのインストールの設定を追記しましょう。
cmake_minimum_required(VERSION 3.8)
project(rye_sample_pkg)
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_python REQUIRED)
find_package(rclpy REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
ament_python_install_package(${PROJECT_NAME})
install(PROGRAMS scripts/talker.py DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
ビルドする
いつも通り colcon buildでビルドしましょう。
CMakeListsで設定した通り、install/rye_sample_pkg/lib/rye_sample_pkg/配下にtalker.pyがコピーされたら成功です。
colcon build --packages-select rye_sample_pkg --symlink-install
ROSノードを実行する
Ryeの環境内に入った後にros2 runでROSノードを起動するとryeの環境でROSノードが立ち上がります。
cd ~/ros2_ws/src/rye_sample_pkg
rye shell
ros2 run rye_sample_pkg talker.py
[INFO] [1700807070.570010760] [minimal_publisher]: python path: /home/koichi/ros2_ws/src/rye_sample_pkg/.venv/bin/python3
[INFO] [1700807071.071507709] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [1700807071.573184340] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [1700807072.072772997] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [1700807072.572920468] [minimal_publisher]: Publishing: "Hello World: 3"
Ryeの使い方
今更ですが、Ryeの使い方を簡単に紹介します。
プロジェクトへパッケージの追加
rye add XXX
# 例
rye add numpy
rye add tensorflow
パッケージの削除
rye remove XXX
# 例
rye remove numpy
上記のコマンドは、pyproject.tomlファイルを操作するだけで実際のインストール/アンインストールは行われません。それらを実行するには下記を実行します。
パッケージのインストール/アンインストール
rye sync
ryeの環境に入る
上記で、requirements*や、 .venvなどが生成されます。
以下のコマンドでryeの実行環境に入ることができます。
rye shell
# または
. .venv/bin/activate
ROS2での使い方
Poetryなどはワークスペースごと or モノレポで管理されているプロジェクトを一括で管理する際に有用だったと思っています。
それに比べてRyeはパッケージごとにPythonの仮想環境まるごと使い分けることが可能ではあるので、そこは差別化できるのかと思いました。
おわりに
ROS2に限らず、Pythonのパッケージ管理方法に正解はなさそうなのでこれからも慎重に向き合っていきましょう!
アドベントカレンダー、盛り上がっていきましょう!