# 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 <パッケージ名>
```
> 注意:roslaunchを使う前に roscore を実行する必要はありません! ROSマスターが起動してない場合、roslaunchがROSマスターを起動します。
>
> 注意2:launchファイルは任意のフォルダーに置くことができます。 ただし、パッケージ内のlaunchという名前のフォルダに置くことが一般的ですので、その方法を強くお勧めします。
## launchファイルの形式
XML形式を使っています。
例えば:
```xml
```
launchファイルの基本的なタグ
- `launch`: launchファイルのルート要素
- `node`: 実行するノードを1つ指定します
- `name`: ノード名(自由に定義できます)
- `pkg`: ノードを含むパッケージ
- `type`: ノードタイプ(= 上記のパッケージにある実行可能ファイル)
- `output`: ログのメッセージを出力する場所の設定(`screen`または`log`)
---
### 引数
launchファイルでは引数(およびそれらのデフォルト値)を定義できます。
```xml
```
launchファイルを実行するときに、引数は次のように設定できます。
```bash
roslaunch launch_file.launch arg_name:=引数の値
```
launchファイル内で使用方法:`$(arg arg_name)`
---
### 外部ファイルを含める
大規模なプロジェクトの場合、複数のlaunchファイルに分割すると便利です。
その時、``タグを使用して別のlaunchファイルをインクルードできます。
```xml
```
上記の`file`にはlaunchファイルまでのパスを入れないといけません。
そのためパッケージパスショートカットが使えます: `$(find パッケージ名)`
例えば
```xml
```
インクルードしたlaunchファイルの引数の値は以下のように設定できます(``タグの中(!)に``タグを使います)
```xml
```
---
### 引数とincludeを使ったlaunchファイルの例
```xml
```
---
launchファイルについてのWiki:
https://wiki.ros.org/ja/roslaunch/XML
---
# 自分のプログラムを作成する
### 新しいパッケージを作成する
ワークスペースないの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
```
---
### パッケージ構造
典型的な構造:
---
新パッケージの作成についてより詳細な情報:
https://wiki.ros.org/ja/Packages
https://wiki.ros.org/ja/ROS/Tutorials/CreatingPackage
---
### package.xml
パッケージ機能の定義:
- パッケージ名
- バージョン
- 著者
- 他のパッケージへの依存
など
例えば、以前githubからダウンロードしたパッケージのpackage.xml
```xml
ros_package_template
0.1.0
A template for ROS packages.
Peter Fankhauser
BSD
https://github.com/ethz-asl/ros_best_pr...
Peter Fankhauser
catkin
roscpp
sensor_msgs
```
詳細な情報(英語):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
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
```
もっと知りたい場合は、以下のチュートリアルに目を通してください。
https://wiki.ros.org/ja/rospy_tutorials/Tutorials/Logging
---
## Hello, ROS! の定期的な実行
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)