ゲームコントローラーで戦車のモーターを制御するということで、以下の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とは別にイベントを発生させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 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 は認識しないんですよね。