WiiのコントローラがBlueToothを介してPCと接続できることは結構有名な話ですが、これはBalance Boardも同様です。
PCで体重管理をしたいと考えた場合、USB接続対応の体重計を探してみると現在のところ2万円以上の高機能なモデルしか見あたりません。
Wii Balance Boardならば最近発売されたWiiFit Plusがソフト込みで9000円くらいで買えます。(ボードのみの販売はありません)
しかもうちには先日の万華鏡を作る際に購入したWebCamもあるので、同時に写真を撮りためることもできそうです。
というわけで早速WiiFit Plusを購入し、Processingで体重計を作ってみました。
ProcessingでWii Balance Boardの値を取得
WiiRemoteの接続用ライブラリは各言語別にいくつも存在します。
WindowsでProcessingから使う場合は、現在のところ以下の二つの選択肢があるようでした。
前者はProcessingだけで完結しますが、残念ながら国内で一般的な東芝製Bluetoothスタックのアダプタに対応していません。
後者はWiiFlashのローカルサーバを立ち上げておく必要はあるものの、東芝製Bluetoothスタックでも動作します。私が購入したBlueToothアダプタは東芝製スタックのものだったので、今回は後者の方法を採用しました。
なお、WiiFlashはバランスボードに対応していますが、Wiimote.pdeはバランスボードに未対応のため少しだけ修正が必要です。
Wiimote.pdeの修正
Wiimote.pdeは元々書籍「WiiRemoteプログラミング」のサンプル用に作られたものです。標準ではWiiリモコンにしか対応していません。
しかし、この書籍の中でバランスボードの仕様が解説されているので、簡単に対応させることができました。
@@ -31,6 +31,14 @@
y = readFloat();
z = readFloat();
extensionType = readByte();
+ if (extensionType == 3) {
+ /** バランスボードからデータを取得します */
+ bottomLeftKg = readFloat();
+ bottomRightKg = readFloat();
+ topLeftKg = readFloat();
+ topRightKg = readFloat();
+ totalKg = readFloat();
+ }
}
/** 拡張タイプ */
@@ -51,6 +59,8 @@
float batteryLevel;
/** 加速度 */
float x, y, z;
+ /** バランスボード */
+ float bottomLeftKg, bottomRightKg, topLeftKg, topRightKg, totalKg;
Client client;
int[] buffer;
Wii Balance Board Weighing Machine
完成した体重計は以下の通り。(値と写真はイメージです)
- 起動後、バランスボードに載って3秒ほど動かずにいると計測値が固定されます。
- WiiリモコンのAボタンで撮影に移行します。
- Bボタンで撮影後、Aボタンで終了します。
本体のコードは次のようになっています。なお、実行するにはWiiFlashの他、WebCamの接続とフォントの用意が必要です。
import processing.video.*;
int framerate_val = 60;
PFont ui_font;
String todays_date = "";
int now_step = 1;
Wiimote wiimote;
boolean bb_initialized = false;
float bb_offset_value = 0;
float measured_weight = 0;
boolean weight_lock = false;
int weight_lock_timer = 0;
float temp_weight_memory = 0;
Capture cap;
int camera_width = 320;
int camera_height = 240;
boolean cap_saved = false;
color bg_color = (#F3F0BB);
color fg_color = (#58626E);
color fg_dark = (#8FA690);
color fg_hilight = (#37334C);
void setup() {
size(camera_width, camera_height);
stroke(fg_color);
smooth();
frameRate(framerate_val);
ui_font = loadFont("Arial-BlackItalic-48.vlw");
textFont(ui_font, 24);
wiimote = new Wiimote(this);
cap = new Capture(this, camera_width, camera_height);
todays_date = String.valueOf(year()) + "-" + String.valueOf(month()) + "-" + String.valueOf(day());
}
void draw() {
wiimote.update();
switch(now_step){
case 1 :
background(bg_color);
pushMatrix();
pushStyle();
translate(width / 2, 0);
textAlign(CENTER);
fill(fg_color);
text("WBB Weighing Machine", 0, 24);
if (bb_initialized == false && wiimote.totalKg != 0) {
bb_offset_value = wiimote.totalKg;
bb_initialized = true;
}
if (bb_initialized) {
textFont(ui_font, 48);
float temp_weight = float(round((wiimote.totalKg - bb_offset_value) * 10)) / 10;
if (temp_weight < 1) {
temp_weight = 0;
}
if (weight_lock) {
fill(fg_hilight);
text(measured_weight + " Kg", 0, 150);
fill(fg_color);
text("----------------", 0, 180);
} else {
fill(fg_dark);
text(temp_weight + " Kg", 0, 150);
text("----------------", 0, 180);
fill(fg_color);
if (temp_weight > 10 && ((temp_weight - temp_weight_memory) < 3)) {
if (weight_lock_timer < framerate_val){
weight_lock_timer += 1;
} else if (weight_lock_timer < framerate_val * 2){
text("----", 0, 180);
weight_lock_timer += 1;
} else if (weight_lock_timer < framerate_val * 3){
text("--------", 0, 180);
weight_lock_timer += 1;
} else {
text("----------------", 0, 180);
measured_weight = temp_weight;
weight_lock = true;
}
} else {
weight_lock_timer = 0;
fill(fg_dark);
text("----------------", 0, 180);
}
}
temp_weight_memory = temp_weight;
}
popStyle();
popMatrix();
if (wiimote.a.pushed && weight_lock) {
save_weight();
now_step += 1;
}
break;
case 2 :
if(cap.available()) {
cap.read();
image(cap, 0, 0);
}
if (wiimote.b.pushed) {
save_cap();
}
if (wiimote.a.pushed && cap_saved) {
exit();
}
break;
}
}
void save_weight() {
String load_lines[] = loadStrings("list.txt");
String save_lines[] = splice(load_lines, todays_date + " : " + measured_weight, 0);
saveStrings("list.txt", save_lines);
println("save:list.txt");
}
void save_cap() {
save("capture_" + todays_date + ".png");
delay(500);
cap_saved = true;
println("save:capture_" + todays_date + ".png");
}
実際試してみて分かったこと
WiiRemoteをPCとBlueTooth接続するたびにSyncさせるのが面倒です。
Syncは最初の一回で良いものと思っていましたが、実際は毎回必要でした。特にバランスボードは裏の電池カバーを外さなければならないのが辛いです。
参考書籍
WiiRemoteを使ったプログラミングについて詳しく解説されているほか、作例の紹介なども多くて楽しめます。今回の記事が書けたのは完全にこの本のおかげです。
完全にPC接続目的で購入しましたが、本来のゲームもなかなか面白いです。Amazonは品薄のようなので楽天で探す方が安いかも知れません。
Comments»
WiiRemoteプログラミングの著者です。
WiiFlash通信クラスのBalanceBoard対応をしてくれたのですね、すばらしい!
ありがとうございます!
著者の方ですか!コメントありがとうございます。WiiRemoteプログラミング、大変参考になりました。