子供の頃、両親は木製の迷路ゲームをくれました。 私は彼女が本当に好きでした。 迷宮自体が私を心配したことはないと思いますが、傾斜機構は興味深く、非常にシンプルでした。
後でこのゲームを思い出し、このゲームとパントリーで私の古い迷路をオンラインで見つけることにしました。
現在、携帯電話の加速度計を使用した同様のゲームが数多くありますが、グラフィックスは貧弱です。 それが私が写真のようにリアルなバージョンを作った理由です;-)
![](https://habrastorage.org/storage2/e94/773/dc9/e94773dc9fbd7986b01b15e7e50b3b97.jpg)
目標は、ゲームの古いバージョンと最新バージョンを組み合わせた迷路を作ることでした。 そこで、NetduinoでBluetooth経由で物理迷路の傾きを制御するために電話を使用しました。 ラビリンスは、3Dプリンターで印刷され、2つのサーボによって傾けられた単純なモデルです。 最後にスイッチを追加することのボーナスは、電話からのフィードバックであり、ゲームの終了を知らせます。
必要なもの:
•2つのかなり強力なサーボ。 HobbyKingのTurnigy TGY-9018MG Metal Gear Servoを使用しました
•Bluetoothモジュール
•Netduino
•小さな正方形の迷路
•10kΩ抵抗器
•導電性材料で作られたボール
メカニズム:
技術的な詳細に入る前に、傾斜メカニズムを理解する価値があります。 説明が難しいため、以下の説明は混乱を招く可能性があります。 混乱していると感じたら、下の写真を見てください。
2つの方向への傾斜は、木製ゲームとの類推によって実装されます。 1つのサーボがおもちゃの内側に取り付けられ、次に2番目のサーボが外側のケーシングに取り付けられます。 木製の迷路では、ポストの最初の写真に見られるように、3つの箱が上下に置かれていることに注意してください。 私は同じ理論を使用しましたが、やや単純化しました。 両方の軸の下部は真に水平ではありません。つまり、迷路は本質的に条件付き内部コアの周りを回転します。
したがって、2つのサーボが互いに90度の角度で配置されているだけです。 1つ目は2つ目を回転させます。 そして、2番目は、迷路自体に取り付けられたスタンドを回転させます。 以下は、上記を説明する2つの写真です。
![](https://habrastorage.org/storage2/196/5df/928/1965df92880c9a0c534943800d41a730.png)
![](https://habrastorage.org/storage2/4a4/ded/dba/4a4deddba074ba884573f3232ccc42db.png)
さらに明確にするため、実際の動作を次に示します。
ドライブを接続するには、弾性バンドでしっかりと引っ張りました。 下のサーボを古いドライブマウントに接着し、平らなベースに固定しました。
ラビリンス:
ラビリンスモデルでは少し苦労しましたが、とにかく、投稿の最後のモデルは非常に機能しているので、必要に応じて自分のプリンターで印刷できます。 9 x 9 cmのサイズで印刷しました。 これは、Makerbot Thing-O-Maticで印刷できる最大サイズです。
![](https://habrastorage.org/storage2/483/272/62c/48327262c778bbf6cab14b3488fdf970.png)
モデルを作成するために、まずwww.mazegenerator.netにアクセスし 、そこに9x9の迷路を作成しました。 次に、結果をSketchUpにインポートし、線を描画して壁を構築しました。 壁を非常に高くして、ボールが迷路から落ちないようにしただけでなく、立ち往生しませんでした。
Netduino:
電子部品はそれほど複雑ではありません。
![](https://habrastorage.org/storage2/498/253/9e2/4982539e29deeaf56602a5b39f36d0ac.jpg)
注:一般的なワイヤは、より見やすいように配置されています。
Bluetoothモジュール:
この場合、彼は以前のプロジェクトと同様に参加します。 コードはまったく同じであるため、詳細は次のとおりです。
blog.roguecode.co.za/Post/ControllingaNetduinooverBluetoothwithWP8
blog.roguecode.co.za/Post/MoreNetduino%2bWP8%2bBluetoothfun-3Dreconstruction
blog.roguecode.co.za/Post/Netduino%2bSonar%2bWP8%2bBluetooth-Controllingsoundwithyourmind
ドライブ
このセクションは、サーボをNetduino電源コネクタに直接接続することから始めました。 一般に、これはエネルギーの大量消費につながるため、推奨されていませんが、コンセプトを開始するためにはこれが許容されるべきであると理解しています。
さらに、電力消費以外の問題もありました。サーボが起動するとすぐに、Bluetoothモジュールがオフになりました。 これはノイズ/干渉のために理解できますが、明示的に他のコンポーネントに影響を与えるような方法はありません。
そこで、私はそれらを4.8Vバッテリーパックに接続しました。 バッテリーアースをNetduinoに接続する必要があることを覚えておくことが重要です。 信号線はPWM接点に接続されます。
迷路の終点:
迷路の終点の接点を作成するために、2つの金属ストリップを切断し、1つを終点に水平に配置し、2つ目を垂直に、1つ目に対して小さなギャップを置いて配置しました。 ボールが迷路の終わりに到達すると、2つのサイト間の接触を閉じ、スイッチをアクティブにします。
![](https://habrastorage.org/storage2/040/70a/ada/04070aada4a6172a0b718592e54cc765.png)
コード:
(上記のリンクを介して)Bluetoothコードを追加すると、残りは非常に簡単になります。
static SerialPort bt; static string buffer = ""; static Servo servoX; static Servo servoY; static InterruptPort endStopPort; static bool isRunning = false; public static void Main() { servoX = new Servo(Pins.GPIO<em>PIN</em>D5); servoY = new Servo(Pins.GPIO<em>PIN</em>D9); bt = new SerialPort(SerialPorts.COM1, 9600, Parity.None, 8, StopBits.One); bt.Open(); endStopPort = new InterruptPort(Pins.GPIO<em>PIN</em>D10, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLevelHigh); endStopPort.OnInterrupt += new NativeEventHandler(endStopPort<em>OnInterrupt); bt.DataReceived += new SerialDataReceivedEventHandler(bt</em>DataReceived); servoX.Degree = 90; servoY.Degree = 105; while (true) { //do some other stuff here Thread.Sleep(1000); } } static void endStopPort_OnInterrupt(uint data1, uint data2, DateTime time) { if (isRunning) { isRunning = false; byte[] bytes = Encoding.UTF8.GetBytes("done|"); bt.Write(bytes, 0, bytes.Length); } Thread.Sleep(1); endStopPort.ClearInterrupt(); }
まず、迷路の終わりにあるパッドにサーボ、Bluetooth、およびスイッチの両方をインストールします。 Netduinoでスイッチが機能する方法と理由を理解するには、リンクを参照してください 。 次に、迷路が水平になるようにサーボを調整します。
輪ゴムを保持しない理想的な世界では、両方の値は90度になります。 ここでドライブのクラスを取り上げます 。
イベントハンドラのコードにより、ボールが接点を閉じるとスイッチが作動します。 しかし、これを何度も繰り返したくないので、現在のゲームが実行されていることを確認します(isRunning boolを使用)。
コードの最後の部分で、Netduinoは電話からのメッセージを処理します。
private static void DoSomething(string buffer) { if (buffer == "start") { isRunning = true; } else { string[] split = buffer.Split(new char[] { ',' }); if (split.Length == 2) { int x = int.Parse(split[0]); int y = int.Parse(split[1]); servoX.Degree = x + 3; servoY.Degree = y + 12; Debug.Print(x + " " + y); } } }
プレーヤーが電話の[GO]ボタンを押すと、Bluetoothを介して「開始」コマンドが送信されます。 そこで、boolをtrueに設定して、ゲームが開始されたことを示します。
メッセージが開始メッセージではない場合、これらは加速度計の値であることがわかります。 コードの電話部分から明らかなように、このデータをX、Y軸に沿って値として送信し、コードはそれらを分離し、int値に変換してサーボを設定します。 前述したように、ドライブのレベルが完全に調整されていないため、少しバイアスを追加します。
WP8:
電話コードは完全にシンプルです。 実行する基本的な機能は次のとおりです。
-GOボタンが押されたときに「開始」を送信します
-表示タイマー
-X軸とY軸に沿って加速度計の値を送信する
-「完了」の受信時に最終ゲーム時間を表示する
そして、それぞれのコードは次のとおりです。
GOボタンが押されたときに「開始」を送信し、タイマーを表示します
private void goBtn<em>Click</em>1(object sender, RoutedEventArgs e) { Write("start"); secTxt.Text = ""; msText.Text = ""; <em>startedDT = DateTime.Now; TimeSpan timeTaken; _timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 51) }; _timer.Tick += (s, ev) => { timeTaken = DateTime.Now.Subtract(</em>startedDT); secTxt.Text = timeTaken.Seconds.ToString(); msText.Text = timeTaken.Milliseconds.ToString(); }; _timer.Start(); goBtn.Visibility = System.Windows.Visibility.Collapsed; stopBtn.Visibility = System.Windows.Visibility.Visible; timerDisplayContainer.Visibility = System.Windows.Visibility.Visible; }
このような高頻度でDispatcherTimerを使用することは、おそらく最良のアイデアではないことに注意してください。 また、本当に必要な場合以外は使用しないでください。
X軸とY軸に沿って加速度計の値を送信する
void <em>acc</em>ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args) { Write(Convert(args.Reading.AccelerationX) + "," + Convert(-args.Reading.AccelerationY) + "|"); Dispatcher.BeginInvoke(() => { xRight.Opacity = args.Reading.AccelerationX * 2; xLeft.Opacity = -args.Reading.AccelerationX * 2; yTop.Opacity = args.Reading.AccelerationY * 2; yBottom.Opacity = -args.Reading.AccelerationY * 2; }); } private string Convert(double val) { return ((int)((Clamp((val * 2d), -1, 1) * 10) + 90)).ToString(); //first double it so full range is -45deg to 45deg //clamp the above value to the max of -1 and 1 //then multiple by the max angle we want the servos to goto //then add 90 because servos go from 0 to 180, not -90 to 90 } private double Clamp(double value, double min, double max) { return value < min ? min : value > max ? max : value; }
XNAでMathHelper.Clampを使用した人は、機能を学習する必要があります。 値が設定された制限を超えたり、減少したりするのを単に停止します。 Dispatcher内のコードは、UIで角度を表示するためにいくつかの視覚的な手順を実行します。
「完了」を受け取った後の最終時刻を表示します。
private void DoSomethingWithReceivedString(string <em>receivedBuffer) { if (</em>receivedBuffer == "done") { <em>timer.Stop(); stopBtn.Visibility = System.Windows.Visibility.Collapsed; goBtn.Visibility = System.Windows.Visibility.Visible; TimeSpan timeTaken = DateTime.Now.Subtract(</em>startedDT); MessageBox.Show(string.Format("You took {0}:{1}", timeTaken.Seconds, timeTaken.Milliseconds), "Done!", MessageBoxButton.OK); } }
基本的には以上です。 BTおよびUIの例については、ソースを参照してください。
ダウンロード:
zipファイルには、Netduinoのソリューション、WP8のソリューション、および印刷用のSTLモデルが含まれています。
WP8を使用したプロジェクトを共有してください!