ロボットプログラミングⅡ-2021:ROS2演習2-はじめてのROS2プログラミング(Python)

この記事は金沢工業大学 ロボティクス学科で2021年後学期開講中のロボットプログラミングⅡ用です.

演習2では次の内容を学び,Pythonを使ったROS2プログラミングを体験します.

内 容

  • ワークスペース
  • パッケージ

参考サイト

 

ワークスペース

  • 概要
    • これからROS2でいろいろなプログラムを作っていきます。ROS2ではプログラムをパッケージ(package)とよばれる単位で作っていきます。まずは、パッケージを保存する作業用のディレクトリ(フォルダ)を作りましょう。ROS2ではこれをワークスペース(workspace)とよびます。1つのワークスペースに好きなだけパッケージを作ることができます。端末でパッケージを使うためには、設定ファイルを反映する必要があります。
    • まず、既にインストールされているROS2の設定ファイルを反映します。これは、これから新規に作成するワークスペースのパッケージをビルドするために必要です。この環境のことをアンダーレイ(underlay)とよびます。一方、これから新規に作成するワークスペースの環境をオーバーレイ(overlay)とよびます。オーバーレイはアンダーレイをもとにした環境です。
  • 設定ファイルの実行
    • 次のsourceコマンドでアンダーレイの設定ファイル/opt/ros/foxy/setpu.bashを実行します。sourceはファイルに書かれたコマンドを現在のシェルで実行するコマンドです。
      • $ source /opt/ros/foxy/setup.bash
  •  ワークスペース用ディレクトリの作成
    • 次のコマンドでワークスペースに使用するディレクトリを作成します。ディレクトリ名は何でもよいですが,ここではよく使われるcolcon_wsを使います。先頭の$は入力を受け付けるコマンドプロンプトなので打つ必要はありません。
      • $ mkdir -p ~/colcon_ws/src

パッケージ

  • 概要
    • パッケージはあなたが作成した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があるかを見つけるのに使う。
  • 作成
    • ディレクトリを移動する。
      • $ 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_python  --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>
    •  ROS2のプログラムを作成する。典型的なROS2プログラムは次の処理をしている。
      1. 初期化
        • rclpy.init(): ROS2通信のための初期化。ROS2ノード作成する前に呼び出さなければならない。
      2. ROS2ノードの作成
        • rclpy.create_node()関数を呼び出すか、Nodeクラスからインスタンスを作成するかどちらかの方法で作成する。通常はクラスを使ってプログラムを作成するので後者の方法を選ぶ。
      3. ノードの処理(コールバック関数を使う場合が多い)
        • 次の関数でノードを処理を実行する。
          • rclpy.spin():処理を実行して、ノードが終了するまでブロックする。
          • rclpy.spin_once():処理を1回実行するか、タイムアウトの期限までウェイトする。
      4. 終了処理
        • rclpy.destroy_node():ノードを破壊する。
        • rclpy.shutdown():初期化コンテキストを終了する。
      5. なお、簡単に説明した初期化や終了処理のAPIは以下のリンクで詳細がわかる。
  • ビルド
    • ROS2ではビルドツールにcolconを使う。
      • ビルドするためにworkspace_nameディレクトリに移動する。
        • $ cd ~/workspace_name
      • 次のcolconコマンドでビルドする。このコマンドではワークスペースにある全てのパッケージをビルドする。
        • $ colcon build
    • 便利なオプション
      • packages-select:1つのパッケージmy_packageだけビルドしたいときはこのオプションをcolcon buildの後に付けてビルドする。
        • $ colcon build --packages-select my_package
      • symlink-install:可能な場合、ファイルをコピーする代わりにシンボリックリンク(Windowsのショートカット)でインストールする。Pythonの場合は、これによりソースコードを改変しても再ビルドが不要になるお勧めのオプション。
        • $ colcon build --symlink-install
    • ワークスペースで初めてビルドすると~/workspace_nameディレクトリにbuild、install、logディレクトリが作成される。
  • 設定ファイルの実行
    • アンダーレイ設定ファイルの実行
      • $ source /opt/ros/foxy/setup.bash
    • オーバーレイ設定ファイルの反映。作成したワークスペースの設定ファイルを実行する。これにより、あなたのワークスペースがパスに追加されるので、パッケージの実行可能ファイルを使うことができるようになる。
      • $ source ~/workspace_name/install/setup.bash
  • ノードの実行
    • 次のros2 runコマンドで、パッケージ名<package_name>、ノード名<node_name>を実行する。
      • $ ros2 run <package_name> <node_name>

ハンズオン

A. 一連の作業体験
では、ワークスペース作成からパッケージ作成と実行までの一連の流れを体験しょう!この例ではワークスペース名をcolcon_ws、Pythonパッケージとしている。なお、自動生成されるソースコードは端末に”Hi from hello”と表示されるだけでROS2ノードを作成しているわけではない。

  1. ワークスペースの作成と移動
    • $ mkdir -p  ~/colcon_ws/src
    • $ cd ~/colcon_ws/src
  2. アンダーレイ設定ファイルの実行
    • $ source /opt/ros/foxy/setup.bash
  3. パッケージとノード作成。--node_nameオプションをつけると”Hi from hello.”と端末に出力するソースコードが自動生成される。ここではノード名をhello_node、パッケージ名をhelloにする。
    • $ ros2 pkg create --build-type ament_python --node-name hello_node hello
    • パッケージがうまく作られたか確認しよう。次のlsコマンドを実行して、下図のようにhello、resource、testディレクトリとpackage.xml、setup.cfg、setup.pyファイルができていれば成功。lsコマンドに-Fオプションをつけているので、ディレクトリの場合は最後に/がついて表示される。
      • $ ls -F ~/colcon_ws/src/hello
  4. ビルド
    • $ cd  ~/colcon_ws
    • $  colcon build
  5. オーバーレイ設定ファイルの実行
    • $ source install/setup.bash
  6. ノードの実行
    • 自動生成されるソースコードはROS2ノードを作成していないのでノードの実行ではないが、ROS2ノードを実行するコマンドは、
    • $ ros2 run hello  hello_node
    • 問題がなければ次のように端末に表示される。
      • Hi from hello.
  7. 自動生成されたソースコードの確認
    • では、”Hi from hell.”と表示する自動生成されたソースコードを見てみよう。次のコマンドを打ち込むと端末に下図のように表示される。ここで、catはファイルの中身を端末に表示するコマンド。端末にprint文で”Hi  from   hello.”と表示する簡単なソースコードだとわかる。
      • $ cat ~/colcon_ws/src/hello/hello/hello_node.py
  8. 少し幸せになる設定
    • 毎回、アンダーレイとオーバーレイの設定ファイルを実行するのは面倒なので次のコマンドを実行して.bashrcに追記する。
      • $ echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc
      • $ echo "source ${HOME}/colcon_ws/install/local_setup.bash" >> ~/.bashrc

 

B. 初めてのROS2プログラム作成

次に、上で自動作成されたhello_node.pyを改変して初めてのROS2ノードのプログラムを作って行こう!

  • ソースコードの作成
    • $ cd ~/colcon_ws/src/hello/hello
    • $ gedit hello_node.py
      • 上の作業で自動的に作成されたhello_node.pyは次図のようになっている。1行目のmain関数は端末に’Hi from hello.’を表示する。ここで5行目はこのコードをモジュールとしてimportできるようにするおまじない。詳しくはネットで調べてみよう!
    • では、この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 (パッケージのライセンス)

  • Setup.pyファイルの編集
    • 自動作成されたSetup.pyを次に示す。ここで、変更する必要があるのは次の6項目。この内容は、Package.xmlと同じにしなければならない。パッケージを公開しない場合でも変更する必要がある項目は6番目のentry_pointsである。この例ではパッケージを作成するときに--node-nameをつけてノードも作成したのでプログラムの開始点となるentry_points(エントリーポイント)も23行目のように自動的に生成されている。意味はhello_nodeのエントリーポイントはhelloパッケージのhello_nodeノードのmain関数となる。エントリーポイントが自動生成されると楽なのでパッケージを作成するときは--node-nameのオプションをつけよう!
      1. 3行目:package_name (パッケージ名)
      2. 7行目:version(パッケージのバージョン)
      3. 16行目:maintainer (保守者)
      4. 17行目:maintainer_email (保守者のメールアドレス)
      5. 18行目:description (パッケージの説明)
      6. 23行目:entry points (プログラムの開始点)
        • ‘ノード名 = パッケージ名.ノード名:main’

  • ビルド
    • $ cd  ~/colcon_ws
    • $  colcon build
  • オーバーレイ設定ファイルの実行
    • $ source ~/colcon_ws/install/setup.bash
  • ノードの実行
    • 次のコマンドを実行して、下図のようにhello worldが表示されれば成功!Ctrl-c (Ctrlキーとcキーを同時に押す)でノードを終了させる。
      • $ ros2 run hello  hello_node

ホームワーク

  1.  hello_node.pyを少し改良して、”連番:hello world”と端末に約1秒毎に表示されるようにしよう。連番は1からカウントアップされる。
    • ヒント:約1秒毎に表示するためにtimeモジュールをインポートし、time.sleep(1)関数で1秒スリープを入れる。
  2. helloパッケージのhello_node.pyプログラムをクラス化した次のコードを使い、hello2パッケージを作成して実行しよう。この書き方がよく使われるのでしっかり理解しよう。

3. キーボードから打たれた文字列をそのまま表示するechoノードを作ろう。ソースコードはクラス化すること。

終わり

コメント

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