ゲームコントローラーで戦車のモーターを制御するということで、以下の2つをくっつけます。
Raspberry Pi で戦車を作る(Bluetooth/PS3 Dualshock3編)
http://www.moonmile.net/blog/archives/6898
Raspberry Pi で戦車を作る(モーターシールド編)
http://www.moonmile.net/blog/archives/6910
ジョイスティックをイベント化する
https://github.com/moonmile/RaspiTank/blob/master/RaspiRobot/BPiJoystick.cs
– ジョイスティックの変更イベント OnChangedJoystick
– ボタン状態の変更イベント OnChangedButton
を作成します。ジョイスティックの場合は、XY軸がちょっとずれただけでイベントが発生するので、ボタンのON/OFFとは別にイベントを発生させます。
protected void OnLoop() { while (this.IsLoop) { js_event js; js.time = _br.ReadUInt32(); js.value = _br.ReadInt16(); js.type = _br.ReadByte(); js.number = _br.ReadByte(); // Console.WriteLine(js.ToString()); bool changedJoystick = false; bool changedButton = false; if (BPiJoystickData.IsAxis(js.type)) { if (this.Joystick.GetAxisValue(js.number) != js.value) { Joystick.SetValue(js.type, js.number, js.value); changedJoystick = true; } } else if (BPiJoystickData.IsButton(js.type)) { if (Joystick.GetButtonValue(js.number) != (js.value != 0)) { Joystick.SetValue(js.type, js.number, js.value); changedButton = true; } } // filter if (BPiJoystickData.IsAxis(js.type) && js.number >= 6) changedJoystick = false; if (BPiJoystickData.IsButton(js.type) && js.number >= 16) changedButton = false; // raise value change event if (changedJoystick) { if (OnChangedJoystick != null) { OnChangedJoystick(this, new JoystickEventArgs() { Joystick = this.Joystick, Raw = js }); } // Console.Write("{0} {1} {2} ", js.type, js.number, js.value ); // Console.WriteLine(j.ToString()); } if (changedButton) { if (OnChangedButton != null) { OnChangedButton(this, new JoystickEventArgs() { Joystick = this.Joystick, Raw = js }); } // Console.Write("{0} {1} {2} ", js.type, js.number, js.value ); // Console.WriteLine(j.ToString()); } } this._br.Close(); }
コントローラーの動きでモーターを制御する
アナログジョイスティックやボタンを押したときのモーター制御やLED点灯を行います。
https://github.com/moonmile/RaspiTank/blob/master/RaspiRobot/Program.cs
class Program { static void Main(string[] args) { new Program().main(); } BPiJoystick js; RaspiRobotNet.RaspiRobot robot; public void main() { robot = new RaspiRobotNet.RaspiRobot(); js = new BPiJoystick(); js.OnChangedJoystick += js_OnChangedJoystick; js.OnChangedButton += js_OnChangedButton; js.Setup(); Console.WriteLine("any key is stop."); var key = Console.ReadKey(); } /// <summary> /// ボタンが変更された /// </summary> /// <param name="arg1"></param> /// <param name="arg2"></param> void js_OnChangedButton(object sender, JoystickEventArgs e) { if (e.Joystick.Up == true) robot.Forward(); else if (e.Joystick.Down == true) robot.Back(); else if (e.Joystick.Left == true) robot.Left(); else if (e.Joystick.Right == true) robot.Right(); else { if (e.Joystick.Up == false && e.Joystick.Down == false && e.Joystick.Left == false && e.Joystick.Right == false) robot.Stop(); } /// LED1,2 を点灯する robot.SetLED1( e.Joystick.Circle ); robot.SetLED2( e.Joystick.Cross ); } /// <summary> /// ジョイスティックを変更 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void js_OnChangedJoystick(object sender, JoystickEventArgs e) { int ly = e.Joystick.LeftAxisY; int ry = e.Joystick.RightAxisY; Console.WriteLine("joystick {0} {1}", ly, ry); int sp1 = ly / (32767 / 200); int sp2 = ry / (32767 / 200); if (e.Joystick.Up == false && e.Joystick.Down == false && e.Joystick.Left == false && e.Joystick.Right == false) { move_bot(sp1, sp2); } } void move_bot(int sp1, int sp2) { if (sp1 > 0 && sp2 > 0) { robot.Forward(); } if (sp1 < 0 && sp2 > 0) { robot.Right(); } if (sp1 > 0 && sp2 < 0) { robot.Left(); } if (sp1 < 0 && sp2 < 0) { robot.Reverse(); } // 停止 if (sp1 == 0 && sp2 == 0) { robot.Stop(); } // 右だけ動かす if (sp1 == 0) { if ( sp2 > 0 ) robot.SetMotors(false, false, true, false); if (sp2 < 0) robot.SetMotors(false, false, true, true); } // 左だけ動かす if (sp2 == 0) { if (sp1 > 0) robot.SetMotors(true, false, false, false); if (sp1 < 0) robot.SetMotors(true, true, false, false); } } }
このプログラム自体はターミナルで起動することを想定しているので、最終的には /etc/ini.d を利用して初期起動させます。WiFi のドングルが結構な電力を食っているので、これを外すだけでもかなり RasPi の動作が安定します。ただし、外側から RasPi の状態が見えなくなってしまうので、何らかのモニタリングが必要ですよね。あとで、RasPi にミニ液晶を付けて状態を監視できるようにします。
上記ではジョイスティックといくつかの○×ボタンを単独で感知していますが、同時押しとかR/Lボタンも取得ができます。ちなみに、ジョイスティックの傾きも取れるので、スマートフォンを傾けたときのような動作も可能です。このあたりは、RasPi 戦車に限らず、RasPi 自体を媒介させることで、ゲームコントローラー -> RasPi -> Windows PC というパターンが組めます。Windows 自体はゲームコントローラを認識するのですが、なぜか 8.1 から PS3 Dualshock3 は認識しないんですよね。