『Leap Motion』
Leap Motionとは
Leap Motionとは、
- Circle
(指をくるくる回す動き) - Swipe
(手を横に振る動き) - Key Taps
(キーボードのキーを叩くような指の動き) - Screen Taps
(ディスプレイをつつく、 タブレット端末をタップする様な動き)
サイズは、
手や指、
3Dモーションセンサの代表格としてMicrosoftのKinectが存在しますが、
- Kinect
- 全身の動作が対象
- 分解能はLeap Motionに比べ相対的に低い
- 公式ドライバ・
SDKはWindowsのみ対応 - TVやディスプレイの上に載せて使用する
- Leap Motion
- 手と指の動作が対象
- 分解能はKinectと比べ相対的に高い
(公称0. 01mm単位) - 公式ドライバ・
SDKがWindows/ Mac OS X/ Linuxに対応している - ディスプレイや、
ノートPCの前に置いて使用する
Leap Motionを使用すれば、
![図1 Leap Motionの本体 図1 Leap Motionの本体](/assets/images/admin/serial/01/ubuntu-recipe/0302/thumb/TH800_001.jpg)
入手方法
Leap Motionは公式サイトの
Amazon.
Leap Motion本体以外にもHPからHP ENVY17-j100 Leap Motion SEが2013年12月9日(月)現在、
Ubuntuへの対応とインストール
前述のとおりLeap Motionにはデバイスドライバとサービスを含んだLeap Packageが公式で準備されており、
まず、
アカウントの登録とサインインを済ましたら、
インストーラをダウンロードしたら、
$ tar -xvf Leap_Packages_1.0.9+8409_Linux.tar $ cd Leap_Packages_1.0.9+8409_Linux
Leap_
- デバイスドライバ
- デーモンとその起動スクリプト
- コントロールパネル
(GUIプログラム) - コントロールパネルから起動する検証・
設定プログラム
Ubuntu 13.
$ sudo dpkg -i Leap-1.0.9+8409-x64.deb
インストールに成功したら、
$ sudo service leapd status
「leapd start/
次にGUIのコントロールパネルであるLeapControlPanelを起動します。この時点でLeap Motion本体をコンピューターに接続していないようであれば接続をしておきましょう。
$ LeapControlPanel &
初回起動時にはソフトウェア使用許諾契約書の受諾画面が表示されますので、
![図2 ソフトウェア使用許諾契約書 図2 ソフトウェア使用許諾契約書](/assets/images/admin/serial/01/ubuntu-recipe/0302/thumb/TH800_002.jpg)
Leap Control Panelが起動すると、
![図3 Leap Control Panelのインジケーター。Leap Motion本体との接続に成功していると緑色のランプが点灯する 図3 Leap Control Panelのインジケーター。Leap Motion本体との接続に成功していると緑色のランプが点灯する](/assets/images/admin/serial/01/ubuntu-recipe/0302/thumb/TH400_003.jpg)
インジケーターのアイコンをクリックすると、
最後にLeap Control PanelをUnityのDashから呼び出せるように設定をしておきましょう。~/.local/
[Desktop Entry]
Comment=Leap Control Panel
Terminal=false
Name=Leap Control Panel
Exec=/usr/bin/LeapControlPanel
Type=Application
Icon=
![図4 診断ビジュアライザー。手指の動きや、モードによってはジェスチャーの認識、ペイント(指やペンの軌跡を表示する)が確認できる 図4 診断ビジュアライザー。手指の動きや、モードによってはジェスチャーの認識、ペイント(指やペンの軌跡を表示する)が確認できる](/assets/images/admin/serial/01/ubuntu-recipe/0302/thumb/TH800_004.jpg)
Leap Motionでアプリケーションを動かす
Leap Motionが使用できるようになったので、
Leap MotionのアプリストアであるAir Spaceには沢山のアプリケーションが登録されています。しかし、
幸いにして対応しているアプリケーションがまったくないわけではなく、
また、
加えて、
Leap Motionでプログラムを作成する
サンプルコードを動かす
折角SDKが準備されているのですから、
Leap MotionのDeveloper KitはC++と、
$ sudo apt-get install build-essential libgl1-mesa-dev libglu1-mesa-dev libX11-dev libXi-dev libfreetype6-dev libxinerama-dev libxcursor-dev libasound2-dev
今回はDeveloper KitのダウンロードページからLinux版のDeveloper Kitを選択してtar.
ダウンロードしたtgzを以下のコマンドを入力するか、
$ tar -zxvf LeapDeveloperKit_release_linux_1.0.9+8391.tgz
tgzファイルを展開すると、
次にサンプルコードのビルドを行います。ビルドの手順はいたって簡単で、
$ cd LeapDeveloperKit/LeapSDK/samples $ make $ ./Sample
サンプルコードは、
Frame id: 4439, timestamp: 204738476, hands: 1, fingers: 2, tools: 0, gestures: 2 Hand has 2 fingers, average finger tip position(2.26608, 119.957, 23.326) Hand sphere radius: 51.9412 mm, palm position: (-39.6446, 104.173, 73.8909) Hand pitch: 17.9848 degrees, roll: 10.6252 degrees, yaw: 30.5056 degrees Circle id: 1, state: 2, progress: 6.91424, radius: 28.3288, angle 7.81488, counterclockwise Circle id: 5, state: 2, progress: 1.08783, radius: 10.1404, angle 5.0886, counterclockwise
サンプルコードはonFrameという関数の中で情報を印字するために指の本数や手の有無、
簡単な例として、
#include <stdlib.h>
#include <iostream>
#include "Leap.h"
using namespace Leap;
#define ROCK 0
#define PAPER 1
class MyListener : public Listener {
public:
virtual void onInit(const Controller&);
virtual void onConnect(const Controller&);
virtual void onDisconnect(const Controller&);
virtual void onExit(const Controller&);
virtual void onFrame(const Controller&);
virtual void onFocusGained(const Controller&);
virtual void onFocusLost(const Controller&);
private:
int before_handstate;
};
void MyListener::onInit(const Controller& controller) {
before_handstate = ROCK;
std::cout << "Initialized" << std::endl;
}
void MyListener::onConnect(const Controller& controller) {
controller.enableGesture(Gesture::TYPE_CIRCLE);
}
void MyListener::onDisconnect(const Controller& controller) {
std::cout << "Disconnected" << std::endl;
}
void MyListener::onExit(const Controller& controller) {
std::cout << "Exited" << std::endl;
}
void MyListener::onFrame(const Controller& controller) {
const Frame frame = controller.frame();
if (!frame.hands().isEmpty()) {
// Get the first hand
const Hand hand = frame.hands()[0];
// Check if the hand has any fingers
const FingerList fingers = hand.fingers();
int handstate;
if (!fingers.isEmpty()) {
if(fingers.count() == 5){
handstate = PAPER;
if(before_handstate != PAPER){
std::cout << "パー(指5本)検知" << std::endl;
system("eject");
}
}
}else{
handstate = ROCK;
if(before_handstate != ROCK){
std::cout << "グー(指0本)検知" << std::endl;
system("eject -t");
}
}
before_handstate = handstate;
}
}
void MyListener::onFocusGained(const Controller& controller) {
}
void MyListener::onFocusLost(const Controller& controller) {
}
int main() {
MyListener listener;
Controller controller;
controller.addListener(listener);
std::cout << "Press Enter to quit..." << std::endl;
std::cin.get();
controller.removeListener(listener);
return 0;
}
ビルドは下記コマンドで行います。/opt/
$ g++ -Wall -I/opt/LeapSDK/include LeapEject.cpp -o LeapEject -L/opt/LeapSDK/lib -lLeap
WebSocketを使ってみる
leapdは標準でWebSocketサーバを持っています。 Leap Motionがつながっているコンピューターの6437番ポートへWebSocketクライアントとして接続するだけで、
本来はWebブラウザがLeap Motionへアクセスして、
BBB上で動作しているコード
$ sudo apt-get install python-pip $ sudo pip install websocket-client
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from websocket import create_connection
import Adafruit_BBIO.PWM as PWM
import json
import sys
import os
import signal
# Leap MotionのWebSocketサーバのポートは6437番
LEAP_ADDRESS = "ws://192.168.1.10:6437"
CANNOT_DETECT = -1
CLOCK_WISE = 0
COUNTER_CLOCK_WISE = 1
# サーボモータのsignalはP9_14ピンに接続する
SERVO_PIN = "P9_14"
# 最小デューティ比(0度)
DUTY_MIN = 88.7
# 最大デューティ比(180度)
DUTY_MAX = 97.4
DUTY_SPAN = DUTY_MAX - DUTY_MIN
g_input_angle = 0
def isClockWise(a, b) :
if a[0] * b[0] + a[1] * b[1] + a[2] * b[2] > 0 :
return True
else :
return False
def doCircle(LeapData, gesture) :
global g_input_angle
circle_direction = detectRotationDirection(LeapData, gesture)
if circle_direction == CLOCK_WISE :
print('clockwise')
g_input_angle = g_input_angle + 0.5 if g_input_angle < 180.0 else 180.0
angleToduty(g_input_angle)
elif circle_direction == COUNTER_CLOCK_WISE :
print('counter clockwise')
g_input_angle = g_input_angle - 0.5 if g_input_angle > 0.0 else 0.0
angleToduty(g_input_angle)
def detectRotationDirection(LeapData, gesture) :
if len(gesture['pointableIds']) >= 1 :
ii = iter(LeapData['pointables'])
for pointable in ii :
if pointable['id'] == gesture['pointableIds'][0] :
direction = pointable['direction']
normal = gesture['normal']
if isClockWise(direction, normal) :
return CLOCK_WISE
else :
return COUNTER_CLOCK_WISE
break
return CANNOT_DETECT
def detectGesture(LeapData) :
if 'gestures' in LeapData and LeapData['gestures'] :
gesture, gesture_type = getGesture(LeapData)
if gesture_type == 'circle' :
print ('circle')
doCircle(LeapData, gesture)
elif gesture_type == 'keyTap' :
print ('keyTap')
elif gesture_type == 'screenTap' :
print ('screenTap')
elif gesture_type == 'swipe' :
print ('swipe')
def getGesture(LeapData) :
if 'gestures' in LeapData and LeapData['gestures'] :
gesture = LeapData['gestures'][0]
gesture_type = gesture['type']
return gesture, gesture_type
def angleToduty(angle) :
angle_f = float(angle)
if angle_f > 180.0 : angle_f = 180.0
if angle_f < 0.0 : angle_f = 0.0
duty = 100 - ((angle_f / 180) * DUTY_SPAN + DUTY_MIN)
PWM.set_duty_cycle(SERVO_PIN, duty)
if __name__ == "__main__" :
# initialize
ws = create_connection(LEAP_ADDRESS)
PWM.start(SERVO_PIN, (100 - DUTY_MIN), 50.0)
pid = os.fork()
if pid == 0 :
while 1:
recv = ws.recv()
if recv :
decode_json_data = json.loads(recv)
detectGesture(decode_json_data)
sys.exit()
else :
while 1 :
c = sys.stdin.read(1)
if c :
os.kill(pid, signal.SIGTERM)
# finalize
ws.close()
PWM.stop(SERVO_PIN)
PWM.cleanup()
sys.exit()
まとめ
Leap Motionはその性質上、