Leap Motionで認識した指の数に応じて、PaPeRo i に様々な動きをさせてみる

手を触れずにPCを操作できるデバイスとして話題となった Leap Motion を使って PaPeRo i に人の手を数えさせたりする方法の一例を、前回記事「Leap Motion で PaPeRo i に指の数を数えさせる」で紹介しましたが、今回は伸びている指の数によって、PaPeRo i にいろいろな動きをさせる方法の一例を紹介したいと思います。

Leap Motionは、WindowsPCに接続して使用します。

2021年1月現在Leap MotionSDKバージョン4.1.0 がリリースされているので、こちらを使った手順を紹介します。

手順(PaPeRo i 側)

(1) PaPeRo i 制御用WebSocket通信アドオンシナリオをまだインストールしていない場合は、「PaPeRo iをRaspberry Pi上のpythonから操作する」の「PaPeRo iにアドオンシナリオをインストール」に従ってインストール作業を行います。

手順(WindowsPC 側)

ここでは Windows10 Home がインストールされたノートPC上で行った作業手順を紹介します。

(1) https://developer.leapmotion.com/get-started から、Leap MotionのSDKをダウンロードします(要ユーザー登録)。

(2) ダウンロードしたzipファイル(LeapDeveloperKit_4.1.0+52211_win.zip)を、任意のフォルダに解凍します。

(3) 解凍してできた LeapDeveloperKit_4.1.0+52211_win というフォルダの中の、Leap_Motion_Installer_v4-2020-release-updates_public_win_x64_4.1.0+52211_ah1889.exe を実行し、画面の指示に従ってインストール作業を行います。

(4) Pythonをまだインストールしていない場合は、https://www.python.org/ からダウンロードしてインストールします。

(5) ws4py をまだインストールしていない場合は、コマンドプロンプトから下記のコマンドを入力する事によりインストールします。

pip install ws4py

(6) 「PaPeRo i でPythonを使えるようにする」にあるリンクから「PaPeRo i 制御用Pythonライブラリ」をダウンロードし、zipファイルの中身(pypapero.py)を任意のフォルダに置きます。

(7) numpyをインストールします。

pip install numpy

pipでのインストールが失敗する場合は、https://sourceforge.net/projects/numpy/files/NumPy/ からインストーラーをダウンロードしてインストールします。

(8) Leap MotionをPCに接続し、タスクバーの右端付近の ^ の部分をクリックして隠れているインジケーターを表示し、その中のLeap Motionのアイコンが緑色になっている事を確認します。

(9) Leap Motion SDK 4.1.0では、WebSocketによるデータ取得機能が既定では無効になっているので、有効にするために、(8)で確認した Leap Motion のアイコンを右クリックし、「設定…」をクリックします。
Leap Motion コントロールパネルが現れますので、「全般」タブの「システム」グループの「Webアプリケーションを許可」にチェックを入れて、「OK」ボタンをクリックします。

(10) 下記の内容をコピー・ペーストして、ppr_lmc_fcoumot.py を作成し、pypapero.py と同じフォルダに置きます。


import sys import time import json from enum import Enum import numpy as np from ws4py.client.threadedclient import WebSocketClient import pypapero class State(Enum): st0 = 10 st1 = 11 st2 = 12 st3 = 13 end = 999 class LeapMotionController(WebSocketClient): def opened(self): self.connected = True print("Connected to LeapMotion") def closed(self, code, reason): print("Disconnected from LeapMotion") def received_message(self, msgrcv): message = str(msgrcv) self.lastMsg = message def get_hands_data(msg_dic_rcv): hands_data = [] if "hands" in msg_dic_rcv: hands = msg_dic_rcv["hands"] for i in range(len(hands)): hand_data = {} hand_data["id"] = hands[i]["id"] hand_data["direction"] = hands[i]["direction"] hand_data["palmNormal"] = hands[i]["palmNormal"] hand_data["type"] = hands[i]["type"] hand_data["fingerBases"] = [None, None, None, None, None] if "pointables" in msg_dic_rcv: pointables = msg_dic_rcv["pointables"] for i in range(len(pointables)): if pointables[i]["handId"] == hand_data["id"]: finger_type = pointables[i]["type"] hand_data["fingerBases"][int(finger_type)] = pointables[i]["bases"] hands_data.append(hand_data) return hands_data def get_fcount(): msg_dic_rcv = json.loads(ws_lmc.lastMsg) hands_data = get_hands_data(msg_dic_rcv) hcount = len(hands_data) fcount = 0 for i_hand in range(hcount): for i_finger in range(5): vec_bone = (-1) * np.array(hands_data[i_hand]["fingerBases"][i_finger][2][2]) vec_hand = np.array(hands_data[i_hand]["direction"]) if i_finger == 0 : vec_hand = np.cross(hands_data[i_hand]["direction"], hands_data[i_finger]["palmNormal"]) if hands_data[i_hand]["type"] == "left": vec_hand = (-vec_hand) val_dot = np.dot(vec_bone, vec_hand) if val_dot > 0.0: fcount += 1 return fcount def get_hcount(): msg_dic_rcv = json.loads(ws_lmc.lastMsg) hands_data = get_hands_data(msg_dic_rcv) hcount = len(hands_data) return hcount def main(papero): prev_time = time.monotonic() past_time = 0 state = State.st0 while state != State.end: messages = papero.papero_robot_message_recv(0.1) now_time = time.monotonic() delta_time = now_time - prev_time prev_time = now_time msg_dic_rcv = json.loads(ws_lmc.lastMsg) hands_data = get_hands_data(msg_dic_rcv) if messages is not None: msg_dic_rcv = messages[0] else: msg_dic_rcv = None if papero.errOccurred != 0: print("------Error occured(main()). Detail : " + papero.errDetail) break if state == State.st0: papero.send_start_speech("伸びている指の数に応じて動作します。" + "座布団のボタンで終了します。") past_time = 0.0 state = State.st1 elif state == State.st1: past_time += delta_time if past_time > 0.5: papero.send_get_speech_status() state = State.st2 elif state == State.st2: if msg_dic_rcv is not None: if msg_dic_rcv["Name"] == "getSpeechStatusRes": if str(msg_dic_rcv["Return"]) == "0": state = State.st3 else: past_time = 0 state = State.st1 elif state == State.st3: fcount = get_fcount() hcount = get_hcount() print("fcount=", fcount) if fcount==0 and hcount==1: papero.send_turn_led_on("ear",["W3W3", "2"]) elif fcount==1 : papero.send_turn_led_on("cheek", ["R3R3", "2"]) elif fcount==2 : papero.send_turn_led_on("mouth", ["R3R3R3R3R3R3R3R3R3", "2"]) elif fcount==3 : papero.send_turn_led_on("mouth", ["G3G3G3G3G3G3G3G3G3", "2"]) elif fcount==4 : papero.send_move_head(["A-15T500L", "R0T1000L", "A0T500L"], ["A0T500L", "R0T1500L"]) elif fcount==5 : papero.send_start_speech("こんにちわ。パペロと申します。") past_time = 0 state = State.st1 if msg_dic_rcv is not None: if msg_dic_rcv["Name"] == "detectButton": state = State.end if __name__ == "__main__": ws_lmc = LeapMotionController("ws://127.0.0.1:6437/v6.json", protocols=None) ws_lmc.lastMsg = "{}" ws_lmc.connected = False ws_lmc.connect() while not ws_lmc.connected: time.sleep(0.1) ws_lmc.send('{"optimizeHMD": false}') ws_lmc.send('{"enableGestures": false}') ws_lmc.send('{"background": false}') simulator_id, robot_name, ws_server_addr = pypapero.get_params_from_commandline(sys.argv) papero = pypapero.Papero(simulator_id, robot_name, ws_server_addr) main(papero) papero.papero_cleanup() ws_lmc.close()

(11) コマンドプロンプトの cd コマンドで、カレントディレクトリを ppr_lmc_fcoumot.py 及び pypapero.py の置いてあるディレクトリにします。

(12) 下記のコマンドで、ppr_lmc_fcoumot.py を実行します。

python ppr_lmc_fcoumot.py -wssvr ws://PaPeRoiのIPアドレス:8088/papero

※PaPeRo i シュミレータで行う場合は、シュミレーターのページを表示させておき、下記のコマンドで実行します。

python ppr_lmc_fcoumot.py -sim シュミレータID

実行すると、PaPeRo i が「伸びている指の数に応じて動作します。座布団のボタンで終了します」と発話します。
その後、Leap Motionの上に手をかざすと、伸びている指の数に応じた動作をします。

本記事のプログラムは、以下のような動作をします。
指0本 → 耳が光る
指1本 → 頬が赤く光る
指2本 → 口が赤く光る
指3本 → 口が緑に光る
指4本 → お辞儀をする
指5本 → 「こんにちは。パペロと申します。」と発話する


0