ゲームコントローラーで戦車のモーターを制御するということで、以下の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 は認識しないんですよね。
