# ROSのワークスペース 自分が作るROSパッケージのためのフォルダ(ワークスペース)を作成します。 > 実習では配布さられたPCにはすでにをワークスペースがあります。 > (自分で作成したパッケージもインターネットからダウンロードしたものもこちらに入れます) > フォルダの名前や場所は何でも大丈夫ですが、ユーザのモームフォルダに直接 catkin_ws という名前のフォルダを使用するのが一般的です 次のコマンドで作成しましょう。 ```bash mkdir -p ~/catkin_ws/src # または複数のコマンドで: # mkdir ~/catkin_ws/ # cd ~/catkin_ws/ # mkdir src ``` 最初のコンパイルを実行してください。 ```bash cd ~/catkin_ws/ catkin_make ``` > コードをコンパイルするときに常にこのように ~/catkin_ws/ に入って`catkin_make`を実行します > > ただし、pythonを使う場合、コンパアイルをする必要がありますうので、`catkin_make`を使用することがありません! --- ### パッケージのダウンロード 試しにインターネットからパッケージをダウンロードして、コンパイルしてみましょう。 パッケージはROSワークスペース(~/catkin_ws/)の中のsrcに入れます。 パッケージディレクトリに切り替えます。 ```bash cd ~/catkin_ws/src/ ``` パッケージのgitリポジトリをクローンしましょう。 例えば: ```bash git clone https://github.com/leggedrobotics/ros_best_practices.git ``` > (これはあくまでもただの例です。ROSのテンプレートなどが入っているパッケージですが、実習ではそのテンプレートを使う必要はありません。) パッケージのコンパイル ```bash cd ~/catkin_ws/ catkin_make ``` 作ったROSワークスペースをROSで使えるためにする、ワークスペース内のdevelフォルダの中にあるsetup.*shスクリプトを使います。 ```bash source devel/setup.bash ``` なお、これは使用しているコンソールの一時的な設定にしかなっていません。ROSワークスペースを使いたい度に実行する必要があり、不便です。 どんなコンソールでもいつもROSワークスペースを使用できるようにするため、setup.bashスクリプトを.bashrcファイル(bashシェルの設定ファイル)から実行するように設定しましょう。 そのため、以下のコマンドを実行してください。 > 実習では配布さられたPCにはすでにを実行されました。 ```bash # 一回のみ実行!!! echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc ``` 先ほどコンパイルしたパッケージのノードを起動してみましょう。 ```bash rosrun ros_package_template ros_package_template ``` > エラーが出てすぐ終了します(ただのテンプレートなので気にしないでください) --- # ローンチファイル(*launchファイル*) launchファイルを使う目的: - 1つのコマンドで複数のノードの起動 - パラメータの設定 ## roslaunch launchファイルはroslaunchコマンドを実行します ```bash roslaunch <パッケージ名> <launchファイル名> ``` > 注意:roslaunchを使う前に roscore を実行する必要はありません! ROSマスターが起動してない場合、roslaunchがROSマスターを起動します。 > > 注意2:launchファイルは任意のフォルダーに置くことができます。 ただし、パッケージ内のlaunchという名前のフォルダに置くことが一般的ですので、その方法を強くお勧めします。 ## launchファイルの形式 XML形式を使っています。 例えば: ```xml <launch> <node pkg="turtlesim" type="turtlesim_node" name="turtlesim" /> <node pkg="turtlesim" type="turtle_teleop_key" name="teleop_key" /> <node pkg="package_name" type="executable_name" name="node_name" output="screen" /> </launch> ``` launchファイルの基本的なタグ - `launch`: launchファイルのルート要素 - `node`: 実行するノードを1つ指定します - `name`: ノード名(自由に定義できます) - `pkg`: ノードを含むパッケージ - `type`: ノードタイプ(= 上記のパッケージにある実行可能ファイル) - `output`: ログのメッセージを出力する場所の設定(`screen`または`log`) --- ### 引数 launchファイルでは引数(およびそれらのデフォルト値)を定義できます。 ```xml <arg name="引数の名前" default="デフォルト値" /> ``` launchファイルを実行するときに、引数は次のように設定できます。 ```bash roslaunch launch_file.launch arg_name:=引数の値 ``` launchファイル内で使用方法:`$(arg arg_name)` --- ### 外部ファイルを含める 大規模なプロジェクトの場合、複数のlaunchファイルに分割すると便利です。 その時、`<include>`タグを使用して別のlaunchファイルをインクルードできます。 ```xml <include file="launchファイル名"/> ``` 上記の`file`にはlaunchファイルまでのパスを入れないといけません。 そのためパッケージパスショートカットが使えます: `$(find パッケージ名)` 例えば ```xml <include file="$(find launchファイルが入っているパッケージの名前)/launch/launchファイル名"/> ``` インクルードしたlaunchファイルの引数の値は以下のように設定できます(`<include>`タグの中(!)に`<arg>`タグを使います) ```xml <include file="launchファイル名">  <arg name="引数1の名前" value="値1" />  <arg name="引数2の名前" value="値2" /> <include> ``` --- ### 引数とincludeを使ったlaunchファイルの例 ```xml <?xml version="1.9"?> <launch> <arg name="use_sim_time" default="true"/> <arg name="world" default="gazebo_ros_range"/> <arg name="debug" defau]t="false"/> <arg name="physics" defau1t="ode"/> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="wor1d_name" va]ue="$(find gazebo_plugins)/test/test_worlds/$(arg world).wor1d"/> <arg name="debug" value="$(arg debug)"/> <arg name="physics" value="$(arg physics)"/> </inc1ude> </launch> ``` --- launchファイルについてのWiki: https://wiki.ros.org/ja/roslaunch/XML --- # 自分のプログラムを作成する <!-- ## パッケージ ROSはパッケージで構成されています - ROSパッケージのディレクトリ `~/catkin_ws/src` - 環境に新しいワークスペースを追加する ```bash echo "source /home/<ユーザ名>/catkin_ws/devel/setup.bash" >> ~/.bashrc source ~/.bashrc ``` --- --> ### 新しいパッケージを作成する ワークスペースないのsrcフォルダ(~/catkin_ws/src)に入り、以下のコマンドを実行します ```bash catkin_create_pkg <パッケージ名> [依存するパッケージのリスト] ``` - 依存するパッケージは例えば - Pythonのコードを書く場合: rospy - C++のコードを書く場合: roscpp - Stringなどの一般のメッセージを使う場合:std_msgs - など (依存するパッケージは後で手動で追加することもできます) このコマンドは、パッケージとその中に2つのファイルのディレクトリを作成します。 - `package.xml` - パッケージの詳細(名前、バージョン等) - `CMakeLists.txt` - cmakeでのスクリプト では、パッケージを作ってみましょう ```bash # 「名字」のところを自分の名字に変えてください!! # 例えば robot1_work_yamada catkin_create_pkg robot1_work_名字 rospy std_msgs ``` --- ### パッケージ構造 典型的な構造: <img src="./v1_media/packet_structure0.png" alt="" > --- 新パッケージの作成についてより詳細な情報: https://wiki.ros.org/ja/Packages https://wiki.ros.org/ja/ROS/Tutorials/CreatingPackage --- ### package.xml パッケージ機能の定義: - パッケージ名 - バージョン - 著者 - 他のパッケージへの依存 など 例えば、以前githubからダウンロードしたパッケージのpackage.xml ```xml <?xml version="1.0"?> <package format="2"> <name>ros_package_template</name> <version>0.1.0</version> <description>A template for ROS packages.</description> <maintainer email="pfankhauser@e...">Peter Fankhauser</maintainer> <license>BSD</license> <url type="website">https://github.com/ethz-asl/ros_best_pr...</url> <author email="pfankhauser@ethz.ch">Peter Fankhauser</author> <buildtool_depend>catkin</buildtool_depend> <depend>roscpp</depend> <depend>sensor_msgs</depend> </package> ``` 詳細な情報(英語):https://wiki.ros.org/catkin/package.xml --- ### CMakeLists.txt C++コードをコンパイルするため、catkin_makeコマンドは内部cmakeコンパイルツールを使っています。 この実習では基本的にC++は使いませんので、CMakeLists.txtの説明は省略します。 詳細な情報:https://wiki.ros.org/ja/catkin/CMakeLists.txt --- ## Hello, ROS! それでは、始めてのROSプログラムを作ってみましょう。 Pythonを使います。 テキストエディターを開いて、以下の内容のファイルを作ってください。 ```python #!/usr/bin/env python3 import rospy from std_msgs.msg import String def hello(): // ROSの初期化 rospy.init_node('hello_ros') // ログメッセージを出力 rospy.loginfo("Hello, ROS!") # 上の関数を実行する hello() ``` hello.pyという名前をつけて、先ほど作ったパッケージ内のsrcフォルダに保存してください。 > 注意:catkin_ws/srcフォルダではなく、パッケージの中のsrcフォルダ(~catkin_ws/src/robot1_work_yamada/src)です。 > > 注意2:日本語の文字が入っているpythonファイルを実行すると、エンコーディングの問題のためSyntaxErrorが出ることがあります。 その場合、日本語が入っているコメントを削除してください。 --- ファイルをrosrunで起動させるため実行可能にする必要があります。 パッケージ内のsrcフォルダに入って、以下のを実行してください。 ```bash chmod +x hello.py ``` --- これで、プログラムを実行できます。 ```bash rosrun <パッケージ名> hello.py ``` --- ### C++版(任意) 実習では主にpythonを使いたいと思いますが、一応、C++のコードも見せます。読まなくても構いません。 ```cpp // 標準のROSクラスの定義 #include <ros/ros.h> int main (int argc, char** argv) { // ROSの初期化 ros::init(argc, argv, "hello_ros"); // このプログラムはROSノードです ros::NodeHandle nh; // ログメッセージを出力 ROS_INFO_STREAM("Hello, ROS!"); return 0; } ``` https://wiki.ros.org/roscpp --- ## ログメッセージについて ログメッセージを使えば、コンソールやログファイルにログを残せます。 - 基本的に、print関数の代わりにrospy.loginfo等の関数を使うのがお勧めです - ログのレベルとそれに該当する関数 - 情報:rospy.loginfo - 警告:rospy.logwarn - エラー:rospy.logerror など 変数の値を出力したときに以下のように使えます。 ```python rospy.loginfo("Result: %d", result); ``` ログメッセージをコンソールに出力したいときは、launchファイルで`output`オプションを`screen`に設定する必要があります。 ```xml <launch> <node name="listener" ... output="screen"/> </launch> ``` もっと知りたい場合は、以下のチュートリアルに目を通してください。 https://wiki.ros.org/ja/rospy_tutorials/Tutorials/Logging --- ## Hello, ROS! の定期的な実行 <!-- ```cpp #include <ros/ros.h> int main (int argc, char** argv) { ros::init(argc, argv, "hello_ros"); ros::NodeHandle nh; unsigned int broj = 0; // 実行する頻度(周波数) ros::Rate loopRate(10) // ros::ok() = ノードをまだ実行する必要があるかどうかの確認 while(ros::ok()) { ROS_INFO_STREAM("Hello, ROS!" << broj); broj++; // 着信メッセージの処理を可能にする ros::spinOnce(); loopRate.sleep(); } return 0; } ``` --> hello.pyはログメッセージを一度だけプリントして、終了しました。 これを連続的に行われるようにするには以下のようなコードが使えます。 ```python #!/usr/bin/env python3 import rospy from std_msgs.msg import String def hello2(): rospy.init_node('hello_ros') rate = rospy.Rate(10) # <= 10hz while not rospy.is_shutdown(): hello_str = "Hello, ROS! %s" % rospy.get_time() rospy.loginfo(hello_str) rate.sleep() # <= hello2() ``` > rospy.Rate で周波数を定義して、sleepはその周波数になるようにスリープします > (rospy.is_shutdown() は停止命令(= Ctrl-C)があったかどうかをチェックしています) hello2.pyという名前で保存して、試してください。 --- # プログラムでメッセージの配信と購読 ## メッセージを購読する 購読するトピックは`rospy.Subscriber`関数で定義します。 ```python rospy.Subscriber(トピック名, メッセージタイプ, コルバック関数) ``` *コールバック関数*を使用します - メッセージを受信するとすぐに呼び出されます - メッセージの内容は引数として関数に渡されます ```python #!/usr/bin/env python3 import rospy from std_msgs.msg import String def callback(message): # メッセージは message に入っています # タイプはstd_msgs/Stringなので、テキストはmessage.dataに入っています rospy.loginfo("I heard %s", message.data) def hello_listener(): rospy.init_node('hello_listener') # 購読するトピックの定義 rospy.Subscriber("chatter", String, callback) rospy.spin() if __name__ == '__main__': hello_listener() ``` > `rospy.spin` = ノードがシャットダウンするまで実行をブロックしていますが、その間にコールバックを処理します --- ## メッセージを配信する - 配信するトピックは`rospy.Publisher`関数で定義します。 ```python publisher = rospy.Publisher('chatter', String, queue_size=10) ``` - メッセージを作成し、コンテンツを入力した後、`publish`メソッドを使用して配信します。 ```cpp publisher.publish(message) ``` 以下は配信者を使うノードの例です。 ```python #!/usr/bin/env python3 import rospy from std_msgs.msg import String def hello_talker(): pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('hello_talker') r = rospy.Rate(10) # 10hz while not rospy.is_shutdown(): str = "hello world %s"%rospy.get_time() rospy.loginfo(str) pub.publish(str) r.sleep() if __name__ == '__main__': hello_talker() ``` --- こちらではメッセージの配信や購読について最も基本的なことしか説明していません。 より細かい説明が必要な場合は、以下のチュートリアルを読んでください。 https://wiki.ros.org/ja/ROS/Tutorials/WritingPublisherSubscriber%28python%29 --- 上の2つのファイル(配信者と購読者)を自分のパッケージの中に保存して、実行可能にしてください。 そして両方実行して、メッセージ通信がうまくいっているかどうかを確認してください。 --- → [課題](v1_task.html) ← [実習その1](v1_1.html) ↑ [ホームページ](index.html)