ROSでLeapMotionのデータを得る

LeapMotionを買って以来、塩漬け状態だったので使ってみることにした。
といっても、既に先達がROSパッケージを作成しているのでそれをインストールする程度。
公式にはros-groovy-leap-motionというパッケージが出ているので、それを導入する。
元ネタはこちら。http://wiki.ros.org/leap_motion

LeapSDKのインストール

ROSパッケージの導入に先立ってLeapSDKのインストールが必要となる。
Leap Motion Developer PortalのサイトからLinux用のSDKを入手して展開すると LeapDeveloperKit_2.0.1+15831_linux のようなフォルダができる。インストールの詳細はREADMEファイルを見ればわかるようになっている。
フォルダには、Leap-2.0.1+15831-x64.debやLeap-2.0.1+15831-x86.debといったdebian用のパッケージが含まれているので、64bit版ならx64の方を、32bit版ならx86の方をそれぞれインストールする。(ちなみに下記は32bit版の場合)

sudo dpkg --install Leap-1.2.0-x86.deb

その後、LeapSDKフォルダを適当な場所(例えばホームディレクトリ)に移動する。また、Pythonがライブラリを見つけられるように環境変数PYTHONPATHを設定する。ホームディレクトリ以下にLeapSDKを置いた場合には以下のようにする。

export PYTHONPATH=$PYTHONPATH:$HOME/LeapSDK/lib/x86:$HOME/LeapSDK/lib

インストール直後はLeap Motionのデーモン(leapd)が起動していない場合もあるので起動しておく。

leapd &

LeapControlPanelを起動すると通知エリアにLeapMotionのアイコンが表示されるので適当に設定しておく。「トラブルシューティング」タブの低リソースモードにしておくと負荷が小さいらしい。

ROSパッケージのインストール

単に以下のようにすれば良い。

sudo apt-get install ros-groovy-leap-motion

leap_motionノードの実行

rosrunを用いて実行する。

rosrun leap_motion sender.py

起動すると残念ながらエラーの嵐となる。

Traceback (most recent call last):
  File "/opt/ros/groovy/lib/leap_motion/leap_interface.py", line 66, in on_frame
    if not frame.hands.empty:
  File "/home/itoh/LeapSDK/lib/Leap.py", line 831, in 
    __getattr__ = lambda self, name: _swig_getattr(self, HandList, name)
  File "/home/itoh/LeapSDK/lib/Leap.py", line 57, in _swig_getattr
    raise AttributeError(name)
AttributeError: empty

詳細はわからないがLeapSDKのAPIの変更によるもののようだ。対応するには、/opt/ros/groovy/lib/leap_motion/leap_interface.pyを修正して、65行目を変更する必要がある。具体的には、

if not frame.hands.empty:

これを、

if not frame.hands.is_empty:

のようにする。
これでrosrunで実行できるようになり、LeapMotionの上に手をかざすと/leapmotion/dataというトピックで座標値を得られるようになる。

rostopic echo /leapmotion/data

得られるデータはこんな感じ。

header:
  seq: 5042
  stamp:
    secs: 0
    nsecs: 0
  frame_id: ''
direction:
  x: 0.932909011841
  y: 0.0798121988773
  z: -0.351156324148
normal:
  x: 0.12350487709
  y: -0.986899614334
  z: 0.103806167841
palmpos:
  x: 51.1228790283
  y: 163.470443726
  z: 170.911972046
ypr:
  x: 130.047144825
  y: 12.8048776592
  z: 94.8898589823
---

rosbridgeへの対応

普通の使い方であれば上記で良いのだが、rosbridge経由で使いたい場合には問題が生じる(かもしれない)。

rosbridge rosbridge_server rosbridge_websocket.launch

上記でrosbridgeを起動し、外部から接続しようとすると、以下のようなエラーが表示される。

subscribe: Unable to load the manifest for package leapmotion.

どうやら、ROSが/leapmotion/dataというトピックからパッケージを見つけられないようである。これは、トピック名を/leapmotion/dataから/leap_motion/dataのようにパッケージ名を含むように変えることで対応できる。これには、/opt/ros/groovy/lib/leap_motion/sender.pyの11行目を修正する。

pub_ros   = rospy.Publisher('leapmotion/data',leapros)

これを、

pub_ros   = rospy.Publisher('leap_motion/data',leapros)

のようにする。
当然ながら、上記の修正以後は /leap_motion/data というトピック名でsubscribeする。
(実は、ブログ記事を書くためにパッケージ名を/leapmotion/dataに戻したら、そのままでもうまく行くことがわかった。理由は不明だがROSの方でトピックとパッケージの対応を保持しているのかもしれない)
LeapMotionで得られたデータをどうするかはこれから考える予定。