# トピックの書き方

## ROSチュートリアルの流れ

1. [ROSパッケージの作り方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_create_pkg)
2. [トピックの書き方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_write_topic) ←今ここ
3. [独自のメッセージファイルの作り方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_create_msg)
4. [まとめて起動するやり方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_use_launch)　
5. [サービスの書き方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_write_service)
6. [独自のサービスファイルの作り方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_create_srv)

## はじめに

ROSでは、使用するプログラム言語として主に**Python**と**C++**&#x304C;用いられますが、このチュートリアルでは**Python**を使用したいと思います。

ROSの通信方式は主に**トピック、サービス、アクション**の3つあります。この章では最も使用されることが多いトピックから説明していきます。

まず、トピックで使用されるパブリッシャ(publisher)とサブスクライバ(subscriber)ついて説明します。

この2つは、ノード間をトピックを介してデータをやり取りするときに使用され、 簡易的に説明するとこうなります。

* パブリッシャ : データを配信
* サブスクライバ : データを受け取る

![](https://164413620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LQj-2xtXRtxfWAIKc7B%2F-LRL5Z5CVVJ5moHXt6qe%2F-LRL5_0XZXTjfkT4lITK%2Fpub_sub.png?generation=1542264084304315\&alt=media)

やり取りするデータはメッセージの指定された型に入れ配信されます。

詳しくは[ROSでよく使用する用語](https://raspimouse-sim-tutorial.gitbook.io/project/appendix/ros_word#topic)を御覧ください。

メッセージは、標準パッケージの**std\_msgs**の他に、自分で定義することもできます。

それではパブリッシャとサブスクライバを書いていきましょう。

まず[ROSパッケージの作り方](https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial/how_to_create_pkg)で作成した`ros_tutorial`に移動します。ディレクトリ移動には`roscd`という便利なコマンドがあります。このコマンドはどこからでも指定のパッケージに移動できます。

詳しくは[よく使用するROSコマンドのroscd](https://raspimouse-sim-tutorial.gitbook.io/project/appendix/ros_comand#roscd)を御覧ください。

```
roscd ros_tutorial
```

Pythonのプログラムはscriptsディレクトリの中で作成します。 scriptsディレクトリが無い場合は作成しましょう。

```
mkdir scripts
```

## パブリッシャ

今回は、現在時刻を送るプログラムを書いていきます。

プログラム名は`time_pub.py`とします。

```
vim scripts/time_pub.py
```

{% code title="time\_pub.py" %}

```python
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float64

rospy.init_node('time_pub')
pub = rospy.Publisher('UnixTime', Float64 , queue_size=1)

rate = rospy.Rate(10)
while not rospy.is_shutdown():
    now = rospy.get_time()
    pub.publish(now)
    rate.sleep()
```

{% endcode %}

書いたプログラムには以下のコマンドを実行してください。

```
chmod +x scripts/time_pub.py
```

これはプログラムに実行権限を与えています。

**Python**の場合は、プログラムに対し`chmod +x <プログラム名>`を行い、一度実行権限を与えれば、変更のたびに`catkin_make`は必要ありません。

### コード解説

```
#!/usr/bin/env python
```

Pythonでプログラムを書くときのお約束で、シバンといいます。

```
import rospy
```

`rospy`というモジュールをインポートしています。`rospy`はPythonでROSを扱うときに使用します。

```
from std_msgs.msg import Float64
```

`std_msgs`の`Float64`という型のメッセージをインポートしています。`Float64`は浮動小数点変数の64ビットという意味です。

```
rospy.init_node('time_pub')
```

`time_pub`というノードを定義しています。

```
pub = rospy.Publisher('UnixTime', Float64 , queue_size=1)
```

`UnixTime`というトピック名、`Float64`というメッセージの型、`queue_size`が1のパブリッシャを定義しています。`queue_size`はバッファの数で、10 \[Hz]周期でパブリッシュするときは1でも大丈夫です。10 \[Hz]以上の周期でパブリッシュするときや複数のメッセージをパブリッシュするときは大きい値にするといいでしょう。

```
rate = rospy.Rate(10)
while not rospy.is_shutdown():
    now = rospy.get_time()
    pub.publish(now)
    rate.sleep()
```

`now = rospy.get_time()`は`now`という変数に現在のUnixTimeを代入しています。

`pub.publish(now)`は`now`をパブリッシュしています。

シャットダウンされるまで10 \[Hz] 周期で上記の2つを行っています。

## サブスクライバ

次にサブスクライバを書きます。

サブスクライバは`time_sub.py`とします。

```
vim scripts/time_sub.py
```

{% code title="time\_sub.py" %}

```python
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float64

def callback(message):
    print(message.data)

if __name__ == "__main__":
    rospy.init_node('time_sub')
    sub = rospy.Subscriber('UnixTime', Float64 , callback)
    rospy.spin()
```

{% endcode %}

パブリッシャと同様に以下のコマンドを実行してください。

```
chmod +x scripts/time_sub.py
```

### コード解説

```
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float64
```

ここまでパブリッシャと同じです。

```
def callback(message):
    print(message.data)
```

callback関数を定義しています。

`message.data`というのは、Float64の中のdataを参照するという意味です。

```
if __name__ == "__main__":
```

Pythonではプログラムがインポートされた場合、関数を自動で実行してしまいますが、 このif文内に書いた関数は自動で実行されなくなります。

```
    rospy.init_node('time_sub')
```

`time_sub`というノードを定義しています。

```
    sub = rospy.Subscriber('UnixTime', Float64 , callback)
```

サブスクライバの宣言をしています。

パブリッシャが`UnixTime`という名前のトピック、`Float64`という型で配信しているため、こちらも合わせる必要があります。

最後の`callback`は、受け取った`Float64`型のデータを渡す関数を書く部分であり、今回はcallback関数に渡しています。

```
    rospy.spin()
```

プログラムを終了させないようにしています。

## 相関図

![](https://164413620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LQj-2xtXRtxfWAIKc7B%2F-LRL5Z5CVVJ5moHXt6qe%2F-LRL5_0hjQODWAcOvHnm%2Ftime_pub_sub.png?generation=1542264084540261\&alt=media)

## 実行方法

それぞれ別のターミナルでそれぞれを起動します。

```
roscore
```

```
rosrun ros_tutorial time_pub.py
```

```
rosrun ros_tutorial time_sub.py
```

## 実行結果

`time_sub.py`を起動したとき、以下のように出力されたら正常に動作しています。

```
$ rosrun ros_tutorial time_sub.py 
1540459203.78
1540459203.88
1540459203.98
1540459204.08
1540459204.18
1540459204.28
1540459204.38
1540459204.48
1540459204.58
1540459204.68
1540459204.78
1540459204.88
1540459204.98
1540459205.08
1540459205.18
    　︙
```

出力されているこの数値はUNIX時間というもので、 1970年1月1日午前0時0分0秒からの経過秒数になります。
