Raspberry Pi 4 を使ったROS入門　第3回　Hello world

# はじめに
この記事は研究室の学生の教育用に作成してゆきます．
現在はROS2がメジャーとなってきておりますが，まずは自習が出来るよう文献が豊富なROS1でROSの扱いに慣れてみます．
ROSは既に多くの文献があり，それだけでも自習可能ですが解説されているバージョンや環境が違い，初心者には躓きやすい内容だと思ったため，改めてまとめてみます．

前回はこちら
[Raspberry Pi 4 を使ったROS入門　第2回　ROSの概要とチュートリアル　turtlesm](https://qiita.com/H-Ando-robo/items/e55ca60c74bd3009fb4d)
次回はこちら
[Raspberry Pi 4 を使ったROS入門　第4回　Gazeboを使ったシミュレーション](https://qiita.com/H-Ando-robo/items/436755c05fc652478079)

# 動作環境
Raspberry Piを使用します．(用意できるならUbuntu入りのPCが◎)
ROSはUbuntu上で動くソフトなのですが，設定の違いによってトラブルが起きやすいので，クリーンインストールしてから始めることをお勧めします．
ROSのバージョンはUbuntuのバージョンとリンクしてます．

本記事で使用する機器とバージョン
| 使用機器 | Ubuntuバージョン | ROSバージョン |
|:------------:|:------------:|:------------:|
|Raspberry Pi 4 Model B / 8GB|20.04|Noetic Ninjemys|

※RAMが2GB，4GBだとビルドが途中で落ちることが多々ありました．
出来れば8GBが良いかもしれません．

# 1. ワークスペースの作成
それではROSを使ってプログラミングを始めてみましょう． 
本記事ではVSCodeというソフトを使用し，プログラミングを行っていきます．下記を参考に導入しておいてください.
[Raspberry Pi 4 を使ったROS入門　第1.5回　環境構築②　VNCとVSCodeの導入](https://qiita.com/H-Ando-robo/items/bf0b0410a5f9da07514c)

ROSを使ったプログラムを作成する為にはワークスペースと呼ばれる作業用ディレクトリが必要です．以下のコマンドで作業ディレクトリを作りましょう． 

```
mkdir -p ~/catkin_ws/src 
cd ~/catkin_ws/ 
catkin_make 
```
青い文字で下記の通り表示されれば成功です．〇〇〇はユーザー名が入ります．
```
#### 
#### Running command: "make -j4 -l4" in "/home/〇〇〇/catkin_ws/build" 
#### 
```

下記コマンドで初期設定を行います．
```
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc 
source ~/.bashrc
echo $ROS_PACKAGE_PATH 
```
以下の通り表示されれば問題ありません.
```
/home/〇〇〇/catkin_ws/src:/opt/ros/noetic/share 
```
準備が整いましたので作業用のワークスペースにディレクトリを移動した後,VSCodeを起動します．
```
cd ~/catkin_ws/src 
code . 
```

# 2. 新しいパッケージの作成
起動したVSCodeで表示⇒コマンドパレットからROS：と打ち込み，Create Catkin Packageを選択します． 
パッケージ名を付けるように言われますので，今回は以下の通りで入力しておきます． 
![Screenshot from 2022-12-28 16-50-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438020/b641fac9-c5d3-0af4-3e4f-e4fa5f75c661.png)
```
beginner_tutorial
```
続いて依存関係について聞かれるので，以下の通り入力します． 
```
roscpp rospy std_msgs 
```

## 2.1 配信者のノードを書く

左側のエクスプローラーのbeginner_tutorialフォルダの上で右クリックし，新しいフォルダーを作成，ここではフォルダ名をscriptsとしておきます．そのフォルダの中で新しいファイルを作成しtalker.pyというファイルを作成しておきます．(src/beginner_tutorial/scriptsとなっていればOK)
```src/beginner_tutorial/scripts/talker.py
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    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__':
    try:
        talker()
    except rospy.ROSInterruptException: pass
```

## 2.2 購読者のノードを書く
配信者同様にbeginner_tutorial/scripts/listener.pyとして下記のスクリプトを作成します．
```rc/beginner_tutorials/scripts/listener.py
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    
def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()
        
if __name__ == '__main__':
    listener()
```

## 2.3 パッケージのビルドとプログラムの実行
作成したパッケージのビルドを行います．
ニューの”ターミナル”→”ビルドタスクの実行”からあるいは，Ctrl + Shift + Bを実行し，”catkin_make:build”を選択すると，ビルドが実行されます． 

次にVSCodeからroscoreを起動してみます． 
表示⇒コマンドパレット　から　ROS:Startを選択します．同じくコマンドパレットからROS:Stopを選択すると停止できます． 
VSCodeの左下の表示 ROS1.noeticの左に✓マークが表示されていれば実行されています． 

メニューバーのターミナルから新しいターミナルをクリックすると画面下にターミナルが表示されます． 
表示されたターミナルで下記コマンドを実行し，Pythonのファイルを実行可能な状態にします． 
```
roscd beginner_tutorial/scripts/ 
chmod +x talker.py  
chmod +x listener.py 
```
では次のコマンドを実行し，書いたプログラムを実行してみましょう．VSCodeでは複数のターミナルを分割して表示できます．ターミナルエリアの右上にある
![Screenshot from 2022-12-28 18-09-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438020/cdb70307-129c-a658-9952-d835a414a242.png)
↑こちらのアイコンをクリックします． 
1つめのターミナル
```
rosrun beginner_tutorial listener.py 
```
2つめのターミナル
```
rosrun beginner_tutorial talker.py
```

listenerを実行したターミナルに以下の通り出れば成功です.
```
[INFO] [1654582899.090518]: I heard hello world 1654582899.0898001 
[INFO] [1654582899.191099]: I heard hello world 1654582899.1900246 
[INFO] [1654582899.290757]: I heard hello world 1654582899.2899556
```
talker.pyを実行したターミナルでCtrl+Cを押してみてください．配信者のノードが止まるため,購読者のプログラムも止まるはずです．

今回は2つのノードが通信をしている訳ですが，単にlistener.pyが文字を表示している訳ではない事を確認してみましょう．新しいターミナルで下記コマンドを実行します． 
```
rqt_console 
```
Listener.pyとtaker.pyが実行中であればこのwindowにも同じようにI heard …が表示されたと思います．この機能ではネットワーク上に分散配置されたすべてのROSノードのloginfoが一斉に確認できます．下にあるExclude MessageのInfoをクリックして青く反転した状態にしてみます． 

するとメッセージが消えたと思います．rospyにはlogという機能があり，その重要度によってレベルが決められます． 

重要なものからFatal，Error，Warm，Info，Debugでrospy.loginfoはそのうちのInfoというレベルになります．このようにrqt_consoleには必要なLogを選択する機能がたくさんありますので，必要になったら別途調べてみてください． 
ROSは複数のノードが複雑に通信しあってロボットを制御してゆきます．このようにデバッグを容易に行うことができるツールが豊富に用意されているのもポイントです．

![Screenshot from 2022-12-28 18-20-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438020/03af4909-e99d-b3a6-11be-0e03f820aea2.png)

# 3. roslaunchで楽に複数のプログラムを起動する
ROSでは性質上たくさんのプログラムを同時に起動する必要が有り，ターミナルを一杯立ち上げることになりがちです．roslaunchはroscoreを含む複数のプログラムを一斉に立ち上げるツールです．システムが複雑になってきたらぜひ活用してください．

立ち上がっているターミナルを一度全部終了させ，VSCodeにてbeginner_tutorial内にlaunchフォルダを作成してください．そのフォルダの中にchat.launchというファイルを作成して下記の通り記述してください．
```beginner_tutorial/launch/chat.launch
<launch> 
  <node pkg="beginner_tutorial" name="talker" type="talker.py"/> 
  <node pkg="beginner_tutorial" name="listener" type="listener.py"/> 
</launch> 
```

roslaunchでは拡張子が.launchのファイルをlaunchフォルダに格納する決まりになっています． 

解説していきます． 
launchの設定ファイルは　launch　と　/launchで挟みます． 
node pkg="ros_start" name="talker" type="talker.py"/
とありますが，nodeでROSのノードであることを指定しています．pkgはパッケージ名です．Typeが実行するファイル名です．nameはそのままノードの名前となるのですがROSの管理上，実行ファイル名ではなく，このnameで管理されます．プログラムの中身でrospy.init_node()で名前を指定しましたが，roslaunchではこのnameで指定した物が使用されます．とりあえずは同じにしておけば単体で起動する場合もややこしくないと思います． 

設定したroslaunchを起動するには下記コマンドを実行します． 
roslaunch＋(パッケージ名)＋(ファイル名)あるいはroslaunch＋(ファイルパス) 
```
roslaunch beginner_tutorial chat.launch
```
実行結果は下記の通りになります． 
```
... logging to /home/h-ando/.ros/log/e6d212a2-868f-11ed-b4b5-a9a6a4a9271c/roslaunch-hando-ubuntu-52379.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://hando-ubuntu:44493/

SUMMARY
========

PARAMETERS
 * /rosdistro: noetic
 * /rosversion: 1.15.15

NODES
  /
    listener (beginner_tutorial/listener.py)
    talker (beginner_tutorial/talker.py)

ROS_MASTER_URI=http://localhost:11311

process[talker-1]: started with pid [52408]
process[listener-2]: started with pid [52409]
```
先ほどの様なlistenerの実行結果が表示されていません．roslaunchではデフォルトでは各ノードの出力は表示されません．しかし，rostopicを使うとちゃんと動いていることが確認できます． 
下記コマンドを実行します． 
```
rostopic list
```
すると下記のように表示され，chatterトピックが確認できます． 
```
/chatter 
/rosout 
/rosout_agg 
```
下記コマンドでchatterのデータを確認できます． 
```
rostopic echo /chatter
```
下記のように表示され，先ほどと同じようなデータが送られてきていることが分かります．
```
data: "hello world 1654585653.8753424" 
--- 
data: "hello world 1654585653.9753573" 
--- 
```
rqt_graphでも確認できます． 
```
rqt_graph 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438020/819de681-106c-56bb-9eab-417f66f1e3e7.png)

元々の表示を見たい場合はlaunchファイルに以下の通り書き換えると表示されるようになります．

```beginner_tutorial/launch/chat.launch
<launch> 
  <node pkg="beginner_tutorial" name="talker" type="talker.py"/> 
  <node pkg="beginner_tutorial" name="listener" type="listener.py" output="screen"/>
</launch> 
```

ros_launchには機能が豊富ですので，もし他に機能が気になれば下記のサイトを参考にしてみてください． 
http://wiki.ros.org/ja/roslaunch/XML 
これでVSCodeを使ったROSプログラミング開発が出来るようになりました． 

# おわりに
今回はVSCodeを使ってROSのプログラムを自作してみました．
登場したプログラムは公式のチュートリアルを流用したものです．
それぞれの行で何をしているかは公式サイトに載っていますので参考にしてみてください．

http://wiki.ros.org/ja/ROS/Tutorials/WritingPublisherSubscriber%28python%29

お疲れ様でした．