Intel EdisonのROSからTweetしてみる

　**2014/12/8 更新しました．**

　以前，[Edisonにロボット用のOSであるROSを導入しました](http://qiita.com/yoneken/items/eda0bedec847761088c1)．
　ROSを導入した理由は，これから数多くの機能をEdison上に構築していくわけですが，それらの機能間の結合を粗結合にしておくことで，機能の取り外しや，他人が作った機能を自分のシステムに組込むことを容易にするためです．また，ROSを使うと，C/C++やPython，Lispといった処理系が混在したシステムを簡単に構築できます．そのため，仕様の変更や追加が多く開発速度を重視したい処理はPythonを，速度が求められる処理はCをといった使い分けができるようになります．ROSの詳しい説明は，[このあたり](http://wiki.ros.org/ja)をご覧下さい．
　まー，”ロボット用のOS”なんて，大風呂敷広げてますが，これの主要な機能って，プロセス間の情報のやり取りが簡単にできることくらいです．全然大掛かりでも何でもない．あー．自作の機能について，それを実行するのに必要なライブラリを記述することができて，それをやっておくと，別のマシンに持って行ったときにライブラリのインストールをパッケージマネージャを駆使してコマンド一発でやってくれる機能があり，デプロイが簡単になるというのは利点かなぁ．

　ROSは，”ノード”という単位で一つ一つの機能を管理しています．今回は練習なので，ROSの簡単なノードを作ってみようと思います．

　この記事は，2014年のEdisonのアドベントカレンダーと，ROSのアドベントカレンダーの両方に登録しています☆

# catkinワークスペースの作成
## 場所について
　どこにでも作れるが，全部同じところに入れておいたほうが管理が楽．

　以下は作ったことがない人だけ．
$ mkdir ~/catkin_ws
$ cd ~/catkin_ws
$ mkdir src

## catkinワークスペースのイニシャライズ
　最初に，おまじないを唱える．

$ wstool init

これからワークスペース内に，参照するリポジトリ群をどんどん入れて行く際の初期化をする<del>とか何とか（今イチわかってない）</del>．

## 空のワークスペースをビルド

$ catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release

　正常に終了すると， **build_isolated** と **devel_isolated** というディレクトリができているはず．

## 新しいワークスペース用に現在の環境変数を設定

$ source ~/catkin_ws/install_isolated/setup.bash

　しばらくこのワークスペースを使い続けるなら，環境変数として *~/.bashrc* に上記コマンドを追加しておく．

# Tweetするパッケージの入手
　ROSを使うからには，コードなんか最小限しか書きたくないわけです．Twitter APIの仕様なんか，一切知りたくないわけです．そのため，他人様が作ったパッケージを導入します．
## 必要なPythonパッケージの事前の入手
　Debianだと，rosdepがうまく動いてくれない・・.･ﾟ･(ﾉд`)ﾟ･.
仕方ないので，手動でインストールした．
$ pip install oauth2 requests simplejson

## rostwitterの入手
　ROSは[パッケージのリスト](http://www.ros.org/browse/list.php)がまとまっているので便利ですね．
[JSKが作っている **rostwitter** というパッケージ](https://github.com/jsk-ros-pkg/jsk_common)が，それっぽい機能を提供してくれそうなので，お借りしましょうかね．
　<del>まだ，私がどのようにパッケージを配置するべきなのか分かっていないので，catkinワークスペースの外でリポジトリをcloneして，rostwitterの部分だけ，catkinワークスペース内のsrc下にコピーするようにしました．
　正しいやり方を，どなたかに教えて欲しいです．．(；´Д｀)</del>

<del>$ cd ~/work
$ git clone https://github.com/jsk-ros-pkg/jsk_common.git
$ cd ./catkin_ws
$ cp -R ../../jsk_common/rostwitter ./src</del>

　ワークスペース下のsrcにwstoolで持ってくるのが正解のようです．
$ cd ~/catkin_ws/src
$ wstool set --git jsk_common https://github.com/jsk-ros-pkg/jsk_common.git
$ wstool update jsk_common

　<del>この時点で，試しにビルドしてみましょう．</del>
　んで，この状態でビルドしようとすると，jsk_commonの中にrostwitterと一緒に入っている諸々高機能パッケージが，「ライブラリが足りなくてビルドできない！」と騒ぎだすので，rostwitterだけを選択してビルドしましょう．

$ catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --pkg rostwitter

> -- catkin 0.6.9
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 2 packages in topological order:
-- ~~  - rostwitter
-- ~~  - mytute1
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'rostwitter'
-- ==> add_subdirectory(rostwitter)
-- +++ processing catkin package: 'mytute1'
-- ==> add_subdirectory(mytute1)
-- Configuring done
-- Generating done

こんなかんじで出たので，うまくいったようです．

## アカウントとbotの情報を保存するファイルを作成する
　ロボット関連の情報は， */var/lib/robot* 以下に配置します．

　まずはディレクトリの作成
$ sudo mkdir /var/lib/robot


　このディレクトリ内に， **account.yaml** という名前でファイルを作成し，中にTwitter関連の情報を記述します．Twitterにアプリケーションからアクセスするためには，自作アプリを登録して，コンシューマーキーを発行し，さらにアクセスするアカウントのアクセストークンを取得する必要があります．[このへん参照](http://webgaku.hateblo.jp/entry/2014/04/11/200523)．

```yaml:account.yaml
{AKEY: 428639810-dwufhiEhi04FWIi3Lluh3fwiuhIWhi2fi8fwuFWf, ASECRET: fo9f3fwufwiGiuHF57Fui1ohifut7kfwuFKwufhwuF,
  CKEY: iruafhiiUEHWIiuHFWIUli, CSECRET: Eiuhf4fFW0fwwfehi2fWEiWooifwQEIUUfh2efFui}
```
上記の値は適当なので，自分で入手したものに書き換えること．

# メインのパッケージを自作する
## catkinパッケージの作成

$ cd src
$ catkin_create_pkg mytute1 std_msgs rospy rostwitter

　上は，「mytute1という名前の新しいパッケージを作ります．このパッケージは，std_msgsとrospyとrostwitter」というパッケージに依存しています．」という意味です．

　mytute1というディレクトリが作成され，中に **CMakeLists.txt** と **package.xml** というファイルと， **src** というディレクトリが作成されます．

　作成された **package.xml** 内の **description** ， **maintainer** ， **license** などのタグ内を適切に編集しましょう．

　ここに， *script* というディレクトリを作り，その中に以下のスクリプトを作成．

```python:talker.py
#!/usr/bin/env python

import rospy
from std_msgs.msg import String

def talker():
	pub = rospy.Publisher('/tweet', String, queue_size=10)
	rospy.init_node('talker', anonymous=True)
	r = rospy.Rate(0.01) # 0.01[Hz]

	while not rospy.is_shutdown():
		str = "Tweet from Edison through ROS Api : %s" % rospy.get_time()
		rospy.loginfo(str)
		pub.publish(str)
		r.sleep()

if __name__ == '__main__':
	try:
		talker()
	except rospy.ROSInterruptException:
		pass
```

[ROSのPythonチュートリアル](http://wiki.ros.org/rospy_tutorials/Tutorials/WritingPublisherSubscriber)をそのままで，Publishする先を **/tweet** に変えただけです．
　忘れずに，実行権限をつけておきましょう．

$ chmod +x ./talker.py


　また，このときにCMakeLists.txtも編集します．該当箇所は，

```bash:CMakeLists.txt
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
install(PROGRAMS
  script/talker.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
```

上記のように，install(PROGRAMS の項のコメントアウトを外して，作成したスクリプトをインストールするように指定します.

# ビルド&インストールする

$ catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --pkg mytute1


# 実行する
## 一つ一つノードを起動していく方法
　3枚ターミナルを開く必要があります．
　1枚目で，ROSシステムの全体を制御する **roscore** を実行します．
$ roscore

続けて，別のターミナルで， **rostweet/tweet.py** を実行します．
$ rosrun rostwitter tweet.py

さらに別のターミナルで， **mytute1/talker.py** を実行します．
$ rosrun mytute1 talker.py

すると，100秒ごとに，「Tweet from Edison through ROS Api : *タイムスタンプ* 」とTweetするようになるはずです．

## Launcherで一発起動する方法
　launchディレクトリを作成．
$ roscd mytute1
$ mkdir launch

中に，以下のファイルを記述する．

```html:mytute1.launch
<launch>
	<node pkg="rostwitter" name="tweet" type="tweet.py" />
	<node pkg="mytute1" name="mytute1" type="talker.py" output="screen" />
</launch>
```

CMakeLists.txtも修正する必要があります．install(FILES の項のコメントアウトを外して，作成した.launchファイルの登録．

```bash:CMakeLists.txt
## Mark other files for installation (e.g. launch and bag files, etc.)
install(FILES
  launch/mytute1.launch
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
```

その後，パッケージのビルド&インストール．

$ catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --pkg mytute1


そして，
$ roslaunch mytute1 mytute1.launch

これで，先ほどと同様にTweetが始まる．

**注．** どうやら，roslaunchに起動の順序を制御する方法はないらしく， **rostwitter/tweet.py** より先に **mytute1/talker.py** が起動した場合は，最初のTweetは空振りに終わる．
この，roslaunchをシーケンシャルな起動に対応させるかどうかについては，[過去に議論があった](https://groups.google.com/forum/#!topic/ros-sig-roslaunch/O3UXyrzbbM4)らしいが，そのときは「デッドロックを防ぐためにも，そのような機能はむしろないほうが望ましい」という意見が出ていたみたい．


　これで，ボタンを押したらTweetするみたいなのは，簡単に作れそう．
　「それ．わざわざEdison/ROSでやる必要あんの？」って指摘もあるんですが，Edisonの良いところは，これまで私たちがLinuxで普通にやってきたことを，当たり前のように使って組込みシステムで実現できるところにあると思っています．