メインコンテンツまでスキップ

PaxPowerGlove

This page is also available in English. Please visit here.

Oculus Riftの仮想空間内の物体に干渉したい。

ということで、ファミコンの特殊コントローラであるところのパックス社製パワーグローブにモーションセンサを埋め込み、Arduino→PCと接続して、Unityの仮想空間内の手のモデルの動きを制御してみようと思います。

完成動画はこちら。

パワーグローブは本来、2つの超音波振動子から時間差で超音波を発生させてモーションキャプチャを実現しています。

発想は革新的・野心的で素晴らしいのですが、精度がいまいちなので、今回はその機構は使わず、新たにモーションセンサを搭載しています。

本来の機構で残っているのは曲げセンサのみです。

次の順序で進めます。

  1. パワーグローブの指の曲げ具合の取得
  2. モーションセンサによる手のモーションの取得とUnity空間のオブジェクトの回転制御
  3. と2の統合
  4. 近接無線通信モジュールXBeeによる無線通信
  5. 3と4の統合
  6. 振動モーターによるハプティック(触覚フィードバック)の実現
  7. 5と6の統合

必要なもの

ハードウェア

項目説明
Arduino比較的小型で安価で簡単に使えるマイコンボード。無線化してパワーグローブに内蔵する場合は、後述するArduino Fioが小型かつXBeeが直接接続でき、便利です。
パックスパワーグローブ通常はファミコンに接続して使う手袋型コントローラ。
抵抗(100kΩ)* 4何でも良いです。今回は千石電子通商で購入しました。
MPU-9150 9軸センサモジュールInvenSense社の3軸加速度+3軸ジャイロ+3軸コンパスのモーションセンサチップMPU-9150が載ったモジュール。

ソフトウェア

項目説明
Arduino IDEArduino用の開発環境。オフィシャルサイトからダウンロードしてください。
Unityマルチプラットフォーム対応のゲームエンジン。簡単に3D(or 2D)ゲームを作ることが出来る。オフィシャルサイトからダウンロードしてください。
I2C Device LibraryI2Cデバイス用C++ライブラリとMPU-6050(兼MPU-9150)のArduinoサンプルスケッチ。 https://github.com/jrowberg/i2cdevlib を開き、右側の「Download ZIP」をクリックしてダウンロードしてください。
Unity用C#スクリプト上記サンプルスケッチの出力をUnity側で受け取ってGameObjectを制御するC#スクリプト。本ページ下部からダウンロードしてください。

手順1.パワーグローブの指の曲げ具合の取得

まずは指の曲げ具合を取得してみます。

ハードウェアの準備

  1. 手の甲の部分のカバーと基板をプラスドライバーで外す。
  2. はんだ吸い取り線などを使って、配線を基板から外す。
  3. 手の甲側の4本の赤い線をすべてGNDに接続する。
  4. Arduinoの5V→抵抗→手の甲側のセンサ線と繋ぎ、抵抗とセンサの間にArduinoのアナログ入力を接続する。後述のスケッチでのセンサ線とアナログ入力の関係は次の通り。
センサ線アナログ入力端子
親指A0
人差し指A1
中指A2
薬指A3
小指センサなし-

曲げセンサは出力が抵抗値なので、同程度の抵抗器を使うことで抵抗値→電圧値に変換してArduinoに入力する、という回路が上記です。

ソフトウェアの準備

  1. 下記ArduinoスケッチをArduinoに書き込む。

動作確認

  1. シリアルモニタを開く。
  2. 指を曲げ伸ばしして数値が変化することを確認する。

Arduinoスケッチ

int fingers[4];

void setup() {
Serial.begin(9600);
}

void loop() {
int i;
fingers[0] = constrain(map(analogRead(A0), 678, 760, 0, 10), 0, 10) * 10;
fingers[1] = constrain(map(analogRead(A1), 835, 935, 0, 10), 0, 10) * 10;
fingers[2] = constrain(map(analogRead(A2), 770, 905, 0, 10), 0, 10) * 10;
fingers[3] = constrain(map(analogRead(A3), 750, 910, 0, 10), 0, 10) * 10;

for (i = 0; i < 4; i++) {
Serial.print("finger");
Serial.print(i);
Serial.print(":");
Serial.print(fingers[i]);
Serial.print("\t");
}
Serial.println();
delay(200);
}

抵抗値は個体毎に違うと思うので、適宜調整してください。

手順2.モーションセンサによる手のモーションの取得とUnity空間のオブジェクトの回転制御

パワーグローブはグローブ側から超音波を発射し、テレビの周りに設置した超音波センサで検知することによって、位置を検出しています。

今回はこの機構をInvenSense社のモーションセンサチップMPU-9150で置き換えて、手全体のモーションを取得し、Unity空間のオブジェクトの回転を制御してみます。

詳細は、モーションセンサをご覧ください。

手順3.1と2の統合

さあついに、上記1と2を統合します。

ハードウェアの準備

  1. 1と2の回路を組み合わせる。Arduino Unoであれば、ピンが重複しないので、単に組み合わせるだけです。

ソフトウェアの準備(1):Arduinoスケッチ

  1. モーションセンサで作成したArduinoスケッチを次のように修正する。
  2. 286-297行目を次のように変更する。 (unidiff風に書いています。要するに先頭が-の行を削除して、先頭が+の行を追加するだけです。)
        #ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
- Serial.println(q.z);
+ Serial.print(q.z);
+ Serial.print("\t");
+ Serial.print(constrain(map(analogRead(A0), 678, 760, 0, 10), 0, 10) * 6);
+ Serial.print("\t");
+ Serial.print(constrain(map(analogRead(A1), 835, 935, 0, 10), 0, 10) * 6);
+ Serial.print("\t");
+ Serial.print(constrain(map(analogRead(A2), 770, 905, 0, 10), 0, 10) * 6);
+ Serial.print("\t");
+ Serial.println(constrain(map(analogRead(A3), 750, 910, 0, 10), 0, 10) * 6);
#endif

ソフトウェアの準備(2):Unityプロジェクト

  1. 下記ファイルをダウンロードし、解凍して、PaxPowerGlove.unityを開く。

PaxPowerGloveUnity.zip

動作確認

  1. Unityの再生ボタンを押す。
  2. パワーグローブを傾けてみて、手のモデルが動けば成功! 動かない場合は、Arduino本体のリセットボタンを押してみてください。

お疲れ様でした。 :)

手順4.XBeeによる無線通信

上記までは有線で通信をしていましたが、近接無線通信モジュールXBeeを使って無線通信をしてみます。

詳細は XBee をご覧ください。

手順5.3と4の統合

さあついに、上記3と4を統合します。

  1. 先ほどのArduinoスケッチを次のように修正する。 (unidiff風に書いています。要するに先頭が-の行を削除して、先頭が+の行を追加するだけです。)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
- TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
+ TWBR = 12; // for Arduino Fio
    // initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
- Serial.begin(115200);
+ Serial.begin(57600); // for Arduino Fio

手順6.振動モーターによるハプティック(触覚フィードバック)の実現

ハードウェアの準備

右図のような回路を5本分用意する。

ソフトウェアの準備

執筆中。

char c = Serial.read();
if (c != -1) {
c -= '0';
for (int i = 0; i < 5; i++) {
if ((c & 0b00010000) != 0) {
digitalWrite(3, HIGH);
}
if ((c & 0b00001000) != 0) {
digitalWrite(4, HIGH);
}
if ((c & 0b00000100) != 0) {
digitalWrite(5, HIGH);
}
delay(7);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
if ((c & 0b00000010) != 0) {
digitalWrite(6, HIGH);
}
if ((c & 0b00000001) != 0) {
digitalWrite(7, HIGH);
}
delay(7);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
}
}

手順7.5と6の統合

執筆中。

備考

SerialPort.ReadLine()をUpdate()内で使うと遅延が大きく、使い物になりません。

今回はMSDNの記述にしたがって、別スレッドでReadLine()しています。

パワーグローブを入手できない場合

市販の手袋にスイッチサイエンスの曲げセンサSEN-08606を接着するとよいかもしれません。

プロトタイプからの変遷

参考