ROS コマンドラインツール シェル芸

ROS のコマンドラインツールでシェル芸をしました。
# ROS のコマンドラインツールをシェル芸で使う
みなさん ROS のコマンドラインツールは毎日使ってると思います。
rostopic, rosnode, rosparam, rosbag, rosservice... どれも便利です。
しかし、コマンドラインツールなんだからシェル芸で使っても良さそうなのに、
あんまりそういう使い方はされてない感じがしますね。
出力を grep するくらいでしょうか。
今回は ROS のコマンドラインツールを使ってシェル芸をやってみました。
# やりたいこと
```bash
$ rostopic echo|なんかコマンド|rostopic pub
```
という感じで、pub されているメッセージを標準出力に持ってきて、それを何か加工して、
rostopic pub に入力して pub/sub の世界に戻してやる、
みたいなことができたら面白そうなのでやってみます。
# できるの？
rostopic echo された文字列を加工するところまでは普通にできそうですが、
rostopic pub にデータをパイプで渡して pub することってできるんでしょうか？
試してみましょう。
ターミナルを3つ立てて

```bash:term1
$ rostopic pub hoge std_msgs/String "data: 'fuga'"
```

```bash:term2
$ rostopic echo hoge|rostopic pub piyo std_msgs/String
```

```bash:term3
$ rostopic echo piyo
```
すると、term3 で```data: "fuga"```が受信できます。
つまり、term2 では、rostopic echo で pub/sub の空間の hoge トピックからメッセージを受信して、
標準入出力の空間に持ってきて、それを rostopic pub で
pub/sub の空間に戻して piyo トピックに流し込むことができているわけです。
こうなるともうやりたいことはできそうな感じですね。
# sed で加工
term2 のコマンドを止めて、受信したメッセージをそのまま戻すのではなく、
ちょっと加工して戻してみましょう。

```bash:term2a
$ rostopic echo hoge|sed 's/g/n/g'|rostopic pub piyo std_msgs/String
```
sed で g を n に置換してみました。
これで term3 で ```data: "funa"``` が受信できるはずですね。
ところが term3 では何も受信されません。
term2 で rostopic pub に渡さずに

```bash:term2b
$ rostopic echo hoge|sed 's/g/n/g'
```
とすると、```data: "funa"``` が繰り返し出力されるのに、不思議ですね。
これは sed がパイプラインへの出力をバッファするからです。

```bash:term2c
rostopic echo hoge|sed -u 's/g/n/g'|rostopic pub piyo std_msgs/String
```
として、バッファせずに頻繁に出力するようにすると、
term3 で ```data: "funa"``` が受信できました。
# 亀を動かす
文字列をいじってるだけでは ROS らしくないので、亀でも動かしましょう。
何かセンサーの入力があって、それを処理して、亀が動くというのが ROS らしくてよさそうです。
ウェブカメラの Image メッセージを echo して、それをシェル芸で処理して、
Twist メッセージを作って、亀の目標速度として pub しましょう。

```bash:term4
$ rosrun usb_cam usb_cam_node
```
```bash:term5
$ rosrun turtlesim turtlesim_node
```
して、ウェブカメラの Image メッセージを pub、亀の目標速度の Twist メッセージを sub します。
そして、この間をつなぐシェル芸が

```bash:term6
$ rostopic echo /usb_cam/image_raw|tr -d '[,]'|awk 'BEGIN{c=0}$1=="width:"{width=$2}$1=="height:"{height=$2}$1=="step:"{step=$2}$1=="data:"{if(c%3==0){a=0;b=0;for(i=2;i<=NF;i=i+30){if((i-2)%step<step/2){a+=$i}else{b+=$i}}{printf "linear:\n  x: 0.1\n  y: 0.0\n  z: 0.0\nangular:\n  x: 0.0\n  y: 0.0\n  z: "(a>b?"0.1":"-0.1")"\n---\n";fflush()}}c++}'|rostopic pub /turtle1/cmd_vel geometry_msgs/Twist
```
のようになります。```rostopic echo```から````rostopic pub```まで
パイプラインで繋がったワンライナーになっています。
動かすと
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">$ rostopic echo|&lt;シェル芸&gt;|rostopic pub<br>で、ウェブカメラに写った焼酎のある方向に亀が曲がっていくやつができました。 <a href="https://t.co/58xtZEN3Xb">pic.twitter.com/58xtZEN3Xb</a></p>&mdash; 闇ときどき豚 (@yami_buta) <a href="https://twitter.com/yami_buta/status/1467841108793499650?ref_src=twsrc%5Etfw">December 6, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
こんな感じになります。
これで、やりたかったことができました。

# 経緯
なんでこういうことをやったかというと、以前から
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">rostopic echoの、シェル芸でいじりやすい形式で出力してくれるバージョンみたいなやつと、その出力(またはそれをシェル芸でいじったやつ)をパイプで受け取ってpubするやつがあったら面白いんじゃないかな。</p>&mdash; 闇ときどき豚 (@yami_buta) <a href="https://twitter.com/yami_buta/status/1467068524112003075?ref_src=twsrc%5Etfw">December 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
ということを考えていたんですが、これに対して[@ryuichiueda](https://twitter.com/ryuichiueda)先生から
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">rostopic echo | なんかコマンド | xargs rostopic pub <br><br>というのはできそう</p>&mdash; 上田 隆一 (@ryuichiueda) <a href="https://twitter.com/ryuichiueda/status/1467135089197064197?ref_src=twsrc%5Etfw">December 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
という反応があり「えっできるの？」と思ってやってみたらできました。