この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。演習3では次のコンテンツを学びます。
コンテンツ
- ワークスペース
- パッケージ
参考サイト
ワークスペース
- 概要
- これからROS2でいろいろなプログラムを作っていきます。ROS2ではプログラムをパッケージ(package)とよばれる単位で作っていきます。まずは、パッケージを保存する作業用のディレクトリ(フォルダ)を作りましょう。ROS2ではこれをワークスペース(workspace)とよびます。1つのワークスペースに好きなだけパッケージを作ることができます。端末でパッケージを使うためには、設定ファイルを反映する必要があります。
- まず、既にインストールされているROS2の設定ファイルを反映します。これは、これから新規に作成するワークスペースのパッケージをビルドするために必要です。この環境のことをアンダーレイ(underlay)とよびます。一方、これから新規に作成するワークスペースの環境をオーバーレイ(overlay)とよびます。オーバーレイはアンダーレイをもとにした環境です。
- 設定ファイルの実行
- 次のsourceコマンドでアンダーレイの設定ファイル/opt/ros/foxy/setpu.bashを実行します。sourceはファイルに書かれたコマンドを現在のシェルで実行するコマンドです。
$ source /opt/ros/foxy/setup.bash
- 次のsourceコマンドでアンダーレイの設定ファイル/opt/ros/foxy/setpu.bashを実行します。sourceはファイルに書かれたコマンドを現在のシェルで実行するコマンドです。
- ワークスペース用ディレクトリの作成
- 次のコマンドで名前がworkspace_nameのワークスペースに使用するディレクトリを作成します。ディレクトリ名は何でもよい。先頭の$は入力を受け付けるコマンドプロンプトなので打つ必要はありません。
$ mkdir -p ~/workspace_name/src
- 次のコマンドで名前がworkspace_nameのワークスペースに使用するディレクトリを作成します。ディレクトリ名は何でもよい。先頭の$は入力を受け付けるコマンドプロンプトなので打つ必要はありません。
パッケージ
- 概要
- パッケージはあなたが作成したROS2コードの入れ物と考えることもできます。パッケージを使うことにより、あなたのROS2コードを簡単に公開したり、ビルドできるようになります。
- 種類
- ROS2ではビルドシステムとしてamentを使い、ビルドするツールとしてcolconを使います。パッケージの種類はCMakeとPythonがあります。CMakeはソフトウェアをビルド、テストするツールでCやC++のビルドに使われます。
- 構成
- CMake:次のファイルが必須
- CMakeLists.txt:パッケージのコードをビルドする方法が書かれたファイル
- package.xml:パッケージに関するメタ情報が書かれたファイル
- Python
- setup.py:パッケージのインストールする方法が書かれたファイル
- setup.cfg:パッケージに実行可能ファイルがある場合に必要なファイル。ros2 runコマンドが実行可能ファイルを見つけるのに使う。
- package.xml:パッケージに関するメタ情報が書かれたファイル
- /<package_name>:パッケージと同じ名前のディレクトリ。ROS2のツールがパッケージに
__init__.py
があるかを見つけるのに使う。
- CMake:次のファイルが必須
- 作成
- ディレクトリを移動する。
$ cd ~/colcon_ws/src
- 次のros2 pkg createコマンドで名前がpackage_nameのパッケージを作成する。なお、package_nameの前後についている<と>はその引数が省略できなことを示している。
- Python
$ ros2 pkg create --build-type ament_python <package_name>
- なお、”
--node-name
“のオプションをつけるとノードも作成できる(オススメ)。$ ros2 pkg create --build-type ament_cmake --node-name <node_name> <package_name>
- CMake
$ ros2 pkg create --build-type ament_cmake <package_name>
- なお、”
--node-name
“のオプションをつけるとノードも作成できる(オススメ)。$ ros2 pkg create --build-type ament_cmake --node-name <node_name> <package_name>
- Python
- ROS2のプログラムを作成する。典型的なROS2プログラムは次の処理をしている。
- 初期化
- rclpy.init(): ROS2通信のための初期化。ROS2ノード作成する前に呼び出さなければならない。
- ROS2ノードの作成
- rclpy.create_node()関数を呼び出すか、Nodeクラスからインスタンスを作成するかどちらかの方法で作成する。通常はクラスを使ってプログラムを作成するので後者の方法を選ぶ。
- ノードの処理(コールバック関数を使う場合が多い)
- 次の関数でノードを処理を実行する。
- rclpy.spin():処理を実行して、ノードが終了するまでブロックする。
- rclpy.spin_once():処理を1回実行するか、タイムアウトの期限までウェイトする。
- 次の関数でノードを処理を実行する。
- 終了処理
- rclpy.destroy_node():ノードを破壊する。
- rclpy.shutdown():初期化コンテキストを終了する。
- なお、簡単に説明した初期化や終了処理のAPIは以下のリンクで詳細がわかる。
- 初期化
- ディレクトリを移動する。
- ビルド
- ROS2ではビルドツールにcolconを使う。
- ビルドするためにworkspace_nameディレクトリに移動する。
$ cd ~/workspace_name
- 次のcolconコマンドでビルドする。このコマンドではワークスペースにある全てのパッケージをビルドする。
$ colcon build
- ビルドするためにworkspace_nameディレクトリに移動する。
- 便利なオプション
- packages-select:1つのパッケージmy_packageだけビルドしたいときはこのオプションをcolcon buildの後に付けてビルドする。
-
$ colcon build --packages-select my_package
-
- symlink-install:可能な場合、ファイルをコピーする代わりにシンボリックリンク(Windowsのショートカット)でインストールする。Pythonの場合は、これによりソースコードを改変しても再ビルドが不要になるお勧めのオプション。
-
$ colcon build --symlink-install
-
- packages-select:1つのパッケージmy_packageだけビルドしたいときはこのオプションをcolcon buildの後に付けてビルドする。
- ワークスペースで初めてビルドすると~/workspace_nameディレクトリにbuild、install、logディレクトリが作成される。
- ROS2ではビルドツールにcolconを使う。
- 設定ファイルの実行
- アンダーレイ設定ファイルの実行
$ source /opt/ros/foxy/setup.bash
- オーバーレイ設定ファイルの反映。作成したワークスペースの設定ファイルを実行する。これにより、あなたのワークスペースがパスに追加されるので、パッケージの実行可能ファイルを使うことができるようになる。
$ source ~/workspace_name/install/setup.bash
- アンダーレイ設定ファイルの実行
- ノードの実行
- 次のros2 runコマンドで、パッケージ名<package_name>、ノード名<node_name>を実行する。
$ ros2 run <package_name> <node_name>
- 次のros2 runコマンドで、パッケージ名<package_name>、ノード名<node_name>を実行する。
ハンズオン
A. 一連の作業体験
では、ワークスペース作成からパッケージ作成と実行までの一連の流れを体験しょう!この例ではワークスペース名をcolcon_ws、Pythonパッケージとしている。なお、自動生成されるソースコードは端末に”Hi from hello”と表示されるだけでROS2ノードを作成しているわけではない。
- ワークスペースの作成と移動
$ mkdir -p ~/colcon_ws/src
$ cd ~/colcon_ws/src
- アンダーレイ設定ファイルの実行
$ source /opt/ros/foxy/setup.bash
- パッケージとノード作成。
--node_name
オプションをつけると”Hi from hello.”と端末に出力するソースコードが自動生成される。ここではノード名をhello_node、パッケージ名をhelloにする。 - ビルド
$ cd ~/colcon_ws
$ colcon build
- オーバーレイ設定ファイルの実行
$ source install/setup.bash
- ノードの実行
- 自動生成されるソースコードはROS2ノードを作成していないのでノードの実行ではないが、ROS2ノードを実行するコマンドは、
$ ros2 run hello hello_node
- 問題がなければ次のように端末に表示される。
- Hi from hello.
- 自動生成されたソースコードの確認
- 少し幸せになる設定
- 毎回、アンダーレイとオーバーレイの設定ファイルを実行するのは面倒なので次のコマンドを実行して.bashrcに追記する。
$ echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc
- 毎回、アンダーレイとオーバーレイの設定ファイルを実行するのは面倒なので次のコマンドを実行して.bashrcに追記する。
B. 初めてのROS2プログラム作成
次に、上で自動作成されたhello_node.pyを改変して初めてのROS2ノードのプログラムを作って行こう!
- ソースコードの作成
$ cd ~/colcon_ws/src/hello/hello
$ gedit hello_node.py
-
import rclpy # ROS2のPythonモジュールをインポートする from rclpy.node import Node # rclpy.nodeモジュールからNodeクラスをインポート def todo(): # 実行したい処理の関数 while True: # 無限ループ print("hello world") # 端末に出力 def main(): # main関数 rclpy.init() # 初期化 node = Node('hello_node') # ノードの生成。Nodeクラスのコンストラクタの引数はノード名。 todo() # 実行したい処理 rclpy.spin(node) # 終了まで待機 rclpy.shutdown() # 終了処理 if __name__ == '__main__': main()
ソースコードを説明する。1行目のrclpyはROS2のPythonモジュールなので、Pythonを使う場合は必ずインポートしなけれならない。2行目はノードを作成する雛形となるNodeクラスをrclpy.nodeモジュールからインポートしている。次に飛んで15、16行目は、 この自作ソースコードをモジュールとしてimportできるようにする書き方。詳細はネットで検索しよう。
少し戻って、8〜13行目のmain関数を説明する。このPythonプログラムではmain関数から実行され、このコードではmain関数がエントリーポイント(開始点)となる。上で説明したようにROS2のプログラムでは、まず、9行目のrclpy.init()で初期化して、10行目でノードを生成している。ノードを生成する書き方はいくつかあるが、ここでは、ノード名を’hello_node’として、Nodeクラスからインスタンスnodeを生成している。Nodeクラスのコンストラクタは、最低一つの引数ノード名を取る。ノードを生成したらノードに実行させたい処理に関する関数を書く。この例では、”hello world”と端末に出力し続けている。12行目のrclpy.spin(node)で上で生成したnodeをプログラムが終了するまで待機(ブロック)している。最後に13行目のrclpy.shutdown()で終了処理をしている。
- Package.xmlファイルの編集
- 自動作成されたPackage.xmlを次に示す。ここで、変更する必要があるのは次の5項目。現時点では特に変更する必要はないが、自作パッケージを公開するときは変更しましょう。
- 4行目:name (パッケージ名)
- 5行目:version(パッケージのバージョン)
- 6行目:description (パッケージの説明)
- 7行目:maintainer email (保守者、メールアドレス)
- 8行目:license (パッケージのライセンス)
- 自動作成されたPackage.xmlを次に示す。ここで、変更する必要があるのは次の5項目。現時点では特に変更する必要はないが、自作パッケージを公開するときは変更しましょう。
- Setup.pyファイルの編集
- 自動作成されたSetup.pyを次に示す。ここで、変更する必要があるのは次の6項目。この内容は、Package.xmlと同じにしなければならない。パッケージを公開しない場合でも変更する必要がある項目は6番目のentry_pointsである。この例ではパッケージを作成するときに
--node-name
をつけてノードも作成したのでプログラムの開始点となるentry_points(エントリーポイント)も23行目のように自動的に生成されている。意味はhello_nodeのエントリーポイントはhelloパッケージのhello_nodeノードのmain関数となる。エントリーポイントが自動生成されると楽なのでパッケージを作成するときは--node-name
のオプションをつけよう!- 3行目:package_name (パッケージ名)
- 7行目:version(パッケージのバージョン)
- 16行目:maintainer (保守者)
- 17行目:maintainer_email (保守者のメールアドレス)
- 18行目:description (パッケージの説明)
- 23行目:entry points (プログラムの開始点)
- ‘ノード名 = パッケージ名.ノード名:main’
- 自動作成されたSetup.pyを次に示す。ここで、変更する必要があるのは次の6項目。この内容は、Package.xmlと同じにしなければならない。パッケージを公開しない場合でも変更する必要がある項目は6番目のentry_pointsである。この例ではパッケージを作成するときに
- ビルド
$ cd ~/colcon_ws
$ colcon build
- オーバーレイ設定ファイルの実行
$ source ~/colcon_ws/install/setup.bash
- ノードの実行
- 次のコマンドを実行して、下図のようにhello worldが表示されれば成功!Ctrl-c (Ctrlキーとcキーを同時に押す)でノードを終了させる。
$ ros2 run hello hello_node
- 次のコマンドを実行して、下図のようにhello worldが表示されれば成功!Ctrl-c (Ctrlキーとcキーを同時に押す)でノードを終了させる。
ホームワーク
- hello_node.pyを少し改良して、”連番:hello world”と端末に約1秒毎に表示されるようにしよう。連番は1からカウントアップされる。
- ヒント:約1秒毎に表示するためにtimeモジュールをインポートし、time.sleep(1)関数で1秒スリープを入れる。
- helloパッケージのhello_node.pyプログラムをクラス化した次のコードを使い、hello2パッケージを作成して実行しよう。この書き方がよく使われるのでしっかり理解しよう。
3. キーボードから打たれた文字列をそのまま表示するechoノードを作ろう。ソースコードはクラス化すること。
終わり
コメント