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


ROS のコマンドラインツールでシェル芸をしました。

ROS のコマンドラインツールをシェル芸で使う

みなさん ROS のコマンドラインツールは毎日使ってると思います。
rostopic, rosnode, rosparam, rosbag, rosservice... どれも便利です。
しかし、コマンドラインツールなんだからシェル芸で使っても良さそうなのに、
あんまりそういう使い方はされてない感じがしますね。
出力を grep するくらいでしょうか。
今回は ROS のコマンドラインツールを使ってシェル芸をやってみました。

やりたいこと

$ rostopic echo|なんかコマンド|rostopic pub

という感じで、pub されているメッセージを標準出力に持ってきて、それを何か加工して、
rostopic pub に入力して pub/sub の世界に戻してやる、
みたいなことができたら面白そうなのでやってみます。

できるの?

rostopic echo された文字列を加工するところまでは普通にできそうですが、
rostopic pub にデータをパイプで渡して pub することってできるんでしょうか?
試してみましょう。
ターミナルを3つ立てて

term1
$ rostopic pub hoge std_msgs/String "data: 'fuga'"
term2
$ rostopic echo hoge|rostopic pub piyo std_msgs/String
term3
$ rostopic echo piyo

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

sed で加工

term2 のコマンドを止めて、受信したメッセージをそのまま戻すのではなく、
ちょっと加工して戻してみましょう。

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 に渡さずに

term2b
$ rostopic echo hoge|sed 's/g/n/g'

とすると、data: "funa" が繰り返し出力されるのに、不思議ですね。
これは sed がパイプラインへの出力をバッファするからです。

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 しましょう。

term4
$ rosrun usb_cam usb_cam_node
term5
$ rosrun turtlesim turtlesim_node

して、ウェブカメラの Image メッセージを pub、亀の目標速度の Twist メッセージを sub します。
そして、この間をつなぐシェル芸が

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まで
パイプラインで繋がったワンライナーになっています。
動かすと


こんな感じになります。
これで、やりたかったことができました。

経緯

なんでこういうことをやったかというと、以前から


ということを考えていたんですが、これに対して@ryuichiueda先生から

という反応があり「えっできるの?」と思ってやってみたらできました。