WiiRemoteを使ってみた
以前、Wiiリモコンの重力センサーについて書きましたがC#でWiiリモコンを使用出来る、WiimoteLibを使ってみました。
このライブラリは1本のリモコンしか操作出来ないのですが、ソースが公開されているので複数本に対応させる事も可能です。
以下のプログラムは、PCとリモコンをペアリングさせてから実行して下さい。
先ずは簡単に加速度センサーの値を取得してみます。
using System; using System.Collections.Generic; using System.Text; using System.Threading; using WiimoteLib; namespace WiiRemote { class Program { static Wiimote wii; static Mutex mx; static void Main(string[] args) { try { wii = new Wiimote(); mx = new Mutex(); //イベントハンドラを登録 wii.WiimoteChanged += new WiimoteChangedEventHandler(wii_WiimoteChanged); wii.Connect(); //リモコンにつなぐ wii.SetReportType(Wiimote.InputReport.ButtonsAccel, true); //リモコンのイベント取得条件を設定 wii.SetLEDs(true,false,false,true); //LEDを設定してみる } catch (Exception ex) { } } static void wii_WiimoteChanged(object sender, WiimoteChangedEventArgs args) { mx.WaitOne(); WiimoteState ws = args.WiimoteState; Console.WriteLine("X:{0} Y:{1} Z:{2}", ws.AccelState.X, ws.AccelState.Y, ws.AccelState.Z); mx.ReleaseMutex(); } } }
簡単ですね。
Mutexを使っているのは、同時にイベントが実行されないようにするためです。
SetReportTypeでどのような条件でイベントを呼び出すか設定できます。
このソースの設定だと、ボタンと加速度の変化で呼び出されます。
つまり、コンソールにガンガン流れてきます。
このほかにボタンの押下時のみや加速度センサーのみも設定可能です。
LEDをセットするにはTrueかFalseを入れるだけです。
左からリモコンのLEDに対応しています。
次はGUIを使ってみます。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using WiimoteLib; namespace WiiTest { public partial class Form1 : Form { private delegate void WiiStatChangeDelegate(WiimoteChangedEventArgs args); private Wiimote wii = null; private Mutex mx = null; private bool isRumble = true; private WiimoteState gStat; readonly private int rumbleInterval = 100; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { try { this.mx = new Mutex(); this.wii = new Wiimote(); this.wii.WiimoteChanged += new WiimoteChangedEventHandler(wii_WiimoteChanged); this.wii.Connect(); this.wii.SetReportType(Wiimote.InputReport.ButtonsAccel, true); this.wii.SetLEDs(false, false, false, false); } catch (Exception ex) { MessageBox.Show( "エラーが発生したので起動出来ませんでした\n" + ex.Message,"起動エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); Application.Exit(); } } void wii_WiimoteChanged(object sender, WiimoteChangedEventArgs args) { BeginInvoke(new WiiStatChangeDelegate(GetWiiRemotStat), args); } private void GetWiiRemotStat(WiimoteChangedEventArgs args) { try { this.mx.WaitOne(); WiimoteState wiiStat = args.WiimoteState; this.gStat = wiiStat; if (wiiStat.ButtonState.B) { if (this.isRumble) { this.isRumble = true; timer1.Stop(); } this.wii.SetRumble(!wiiStat.Rumble); Thread.Sleep(100); } if (wiiStat.ButtonState.A) { this.wii.SetLEDs(!wiiStat.LEDState.LED1, !wiiStat.LEDState.LED2, !wiiStat.LEDState.LED3, !wiiStat.LEDState.LED4); Thread.Sleep(100); } if (wiiStat.ButtonState.Plus) { this.isRumble = false; if (timer1.Interval - this.rumbleInterval <= 0) { timer1.Interval = 20; } else { timer1.Interval = timer1.Interval - 100; } Thread.Sleep(100); } if (wiiStat.ButtonState.Minus) { this.isRumble = false; timer1.Interval = timer1.Interval + this.rumbleInterval; Thread.Sleep(100); } if (wiiStat.ButtonState.Home) { timer1.Stop(); this.wii.SetRumble(false); this.wii.SetLEDs(false,false,false,false); } if (!this.isRumble) { timer1.Start(); this.wii.SetRumble(false); this.isRumble = true; } this.progressBar1.Value = (wiiStat.Battery > 0xc8 ? 0xc8 : (int)wiiStat.Battery); float f = (((100.0f * 48.0f * (float)(wiiStat.Battery / 48.0f))) / 192.0f); label2.Text = f.ToString("F"); notifyIcon1.Text = label2.Text + "%"; this.mx.ReleaseMutex(); }catch(Exception ex){} } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { this.wii.Disconnect(); } private void Form1_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { this.Visible = false; this.ShowInTaskbar = false; } } private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) { this.Visible = true; this.ShowInTaskbar = true; this.WindowState = FormWindowState.Normal; this.Activate(); } private void timer1_Tick(object sender, EventArgs e) { this.wii.SetRumble(!this.gStat.Rumble); } } }
このソースはリモコンの+で振動を遅く、マイナスで早く、AボタンでLEDを点灯します。
また、GUI上にバッテリー残量を表示します。
振動はスタートとストップなのでその間隔を変化させてみました。
ソースを呼んでもらえればわかりますが、各ボタンのイベントかどうかを判断するのは簡単ですね。
また、生データからバッテリー残量の%表示の方法もソース中の式で算出出来ます。
注意する事というか、当然なのですがイベントハンドラ内でGUIの内容を変化させる場合はInvokeする必要があります。
他にも色々なフィールドなどがあるのでドキュメントを読んで下さい。
IRセンサーやヌンチャクの情報なども取得出来ます。
クラコンなどを挿したりするとイベントが発生します。
しかし、純粋にリモコンと通信をしたいな。
このライブラリでは音がならせないので鳴らしたいな。
結論
リモコンすげーな