
SpheroとそのSDKの機能を引き続き調査します 。
アジェンダでは、タブレットの加速度計を使用してロボットを制御し、障害物との衝突を検出しています。
理論のビット
前回の記事では、既にSpheroが誰であるかと、 Visual Studio 2013を使用してWindows 8.1でプログラムによる管理を開始する方法を検討しました。
次に、より複雑なものを扱います。 タブレットをさまざまな方向に傾けてロボットを「操縦」し、障害物との衝突を検出する方法を学習します。 これを行うには、タブレットの加速度計とロボットの外界との衝突センサーを使用します。
加速度計
Windows 8.1オペレーティングシステムとWinRTオブジェクトモデルは、もちろんデバイスに搭載されていない限り、次のセンサーの使用をサポートしています。
- 加速度計;
- コンパス
- ジャイロメーター;
- 光センサー;
- 傾斜計;
- ジオロケーション。
加速度計は、3方向の動きを測定するモジュールです。 このモジュールには多くの最新のデバイスが搭載されています。 加速度計データにアクセスするには、 Accelerometerオブジェクトにアクセスする必要があります。Accelerometerオブジェクトは、次のプロパティでAccelerometerReadingオブジェクトへのアクセスを提供します。
- AccelerationX:X軸に沿って加速度を表示します。
- AccelerationY:Y軸に沿って加速度を表示します。
- AccelerationZ:Z軸に沿って加速度を表示します。
- タイムスタンプ:データのキャプチャにかかる時間を定義します。
加速度計の読み取り値が変化したときにイベントにサブスクライブし、読み取り値に応じてロボットを加速、減速、または方向転換します。

加速度計の読み取りイベントに登録できます。
加速度計イベントサブスクリプション
protected override void OnNavigatedTo(NavigationEventArgs e) { … Accelerometer _accelerometer = Accelerometer.GetDefault(); _accelerometer.ReadingChanged += new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged); … } async private void ReadingChanged(object sender, AccelerometerReadingChangedEventArgs e) { … }
引越し
タブレットから加速度計データを取得したとします。 次に、それらを使用してSpheroを宇宙で移動する必要があります。
Windows 8.1用のSphero SDKには、Spheroの動きを処理し、2つのパラメーターを受け入れるRollメソッドがあります。
- ヘディング-動きの角度。
次のように計算されます。
0から359の範囲の値を取ります。 - 速度-動きの速度。
0-移動しません。
255-最高速度。
デフォルトでは、Spheroはインジケーターx = 0、y = 0、見出し= 0、速度= 0で作業を開始します。
衝突検知器
Spheroは、 衝突検出などの楽しい機能をサポートしています。 座標の違いに対して、非常に原始的に機能します。
Windows 8.1用Sphero SDKには、既成のCollisionDetectedEventイベントが既にあり、これを使用して、実際のオブジェクトとの衝突をサブスクライブおよびキャッチできます。
イベントの説明
最初に衝突センサーをオンにすることを忘れない場合、イベントがトリガーされます:
センサーが不要になったら、オフにします。
private void OnRobotConnected(object sender, Robot robot) { … robot.CollisionControl.StartDetectionForWallCollisions(); robot.CollisionControl.CollisionDetectedEvent += OnCollisionDetectedEvent; … }
最初に衝突センサーをオンにすることを忘れない場合、イベントがトリガーされます:
robot.CollisionControl.StartDetectionForWallCollisions();
センサーが不要になったら、オフにします。
robot.CollisionControl.StopDetection();
Sphero SDKのいくつかの便利な機能
ロボットを使用するには、Windows 8.1用の次のSphero SDKメソッドも必要です。
SetBackLED(強度)-ロボットのバックライトをオンにして、どこに行くかを理解できるようにします。 値:
1.0f-フルパワーでオンになります。
0.0f-無効にします。
SetHeading(見出し)-ロボットを回転させます。 0から359の値を取ります。
SetRGBLED(赤、緑、青)-ボールの色を設定します。
ロール(見出し、速度)-移動の方向と移動の速度を設定します。
見出し-動きの角度。 0から359の範囲の値を取ります。
速度-動きの速度。 0-移動しません。 255-最高速度。
スリープ()-ロボットをスリープ状態にします。
開発
挑戦する
加速度計を使用してロボットを動かします。 障害に遭遇した場合は、ロボットを赤く塗ります。
ツール
- Microsoft Surface 2 Proタブレット
- OS Windows 8.1
- 開発環境: Visual Studio 2013
- 言語:C#
- Windows 8.1用Sphero SDK
プロセス
1. Visual Studio 2013を開き、プロジェクトFile / New / Project / Blank Appを作成します。

2.アセンブリRobotKit.dllをWindows 8.1のSphero SDKから接続します

3.アプリケーションにBluetooth RFCOMMサポートを追加します。 Package.appxmanifestをコード編集モードで開き、以下のコードを機能セクションに追加します。
アプリケーションのBluetooth RFCOMMサポート
<wb:DeviceCapability Name="bluetooth.rfcomm"> <wb:Device Id="any"> <wb:Function Type="serviceId:00001101-0000-1000-8000-00805F9B34FB" /> </wb:Device> </wb:DeviceCapability>
4.アプリケーションのメイン画面で、次を入力します。
- ロボットステータススイッチ(接続済み\未接続);
- ステータスを表示するテキストフィールド。
- ゲームを開始および停止する[開始]および[停止]ボタン。
MainPage.xamlファイルを開き、そこにすべて追加します。
アプリケーションのメイン画面
<Page x:Class="SpheroRace.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:SpheroRace" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" > <Grid Margin="100" > <Grid.RowDefinitions > <RowDefinition Height="60"/> <RowDefinition Height="60"/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock x:Name="SpheroName" Grid.Row="0" Grid.Column="0" Text="No Sphero Connected" FontSize="24"/> <ToggleSwitch x:Name="ConnectionToggle" Grid.Row="1" Grid.Column="0" Toggled="ConnectionToggle_Toggled" /> <Button Name="StartBtn" Click="StartBtn_Click" Grid.Row="2" Grid.Column="0" Content="Start" VerticalAlignment="Bottom" HorizontalAlignment="Left" Padding="100" ></Button> <Button Name="StopBtn" Click="StopBtn_Click" Grid.Row="2" Grid.Column="1" Content="Stop" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="100" IsEnabled="False" ></Button> </Grid> </Page>
5. MainPage.xaml.csに移動して、ゲームのロジックを説明します。 Spheroと通信するには、SDKが提供するオブジェクトモデルを使用します。
ゲームロジック
public sealed partial class MainPage : Page { private Sphero m_robot = null; private long m_lastTimeMs; private double m_currentX = 0; private double m_currentY = 0; private bool m_isStarted = false; private const string c_noSpheroConnected = "No Sphero Connected"; private const string c_connectingToSphero = "Connecting to {0}"; private const string c_spheroConnected = "Connected to {0}"; public MainPage() { this.InitializeComponent(); } // . protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); SetupRobotConnection(); Application app = Application.Current; app.Suspending += OnSuspending; Accelerometer _accelerometer = Accelerometer.GetDefault(); _accelerometer.ReadingChanged += new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged); } // . protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); ShutdownRobotConnection(); Application app = Application.Current; app.Suspending -= OnSuspending; Accelerometer _accelerometer = Accelerometer.GetDefault(); _accelerometer.ReadingChanged -= new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged); } //handle the application entering the background private void OnSuspending(object sender, SuspendingEventArgs args) { ShutdownRobotConnection(); } // private void SetupRobotConnection() { SpheroName.Text = c_noSpheroConnected; RobotProvider provider = RobotProvider.GetSharedProvider(); provider.DiscoveredRobotEvent += OnRobotDiscovered; provider.NoRobotsEvent += OnNoRobotsEvent; provider.ConnectedRobotEvent += OnRobotConnected; provider.FindRobots(); } // private void ShutdownRobotConnection() { if (m_robot != null && m_robot.ConnectionState == ConnectionState.Connected) { m_robot.SensorControl.StopAll(); m_robot.CollisionControl.StopDetection(); m_robot.Sleep(); m_robot.Disconnect(); ConnectionToggle.OffContent = "Disconnected"; SpheroName.Text = c_noSpheroConnected; SetRedColor(); RobotProvider provider = RobotProvider.GetSharedProvider(); provider.DiscoveredRobotEvent -= OnRobotDiscovered; provider.NoRobotsEvent -= OnNoRobotsEvent; provider.ConnectedRobotEvent -= OnRobotConnected; } } // ! private void OnRobotDiscovered(object sender, Robot robot) { if (m_robot == null) { RobotProvider provider = RobotProvider.GetSharedProvider(); provider.ConnectRobot(robot); ConnectionToggle.OnContent = "Connecting..."; m_robot = (Sphero)robot; SpheroName.Text = string.Format(c_connectingToSphero, robot.BluetoothName); } } // :( private void OnNoRobotsEvent(object sender, EventArgs e) { MessageDialog dialog = new MessageDialog(c_noSpheroConnected); dialog.DefaultCommandIndex = 0; dialog.CancelCommandIndex = 1; dialog.ShowAsync(); } // private void OnRobotConnected(object sender, Robot robot) { ConnectionToggle.IsOn = true; ConnectionToggle.OnContent = "Connected"; SpheroName.Text = string.Format(c_spheroConnected, robot.BluetoothName); if (m_robot != null && m_robot.ConnectionState == ConnectionState.Connected) { m_robot.CollisionControl.StartDetectionForWallCollisions(); m_robot.CollisionControl.CollisionDetectedEvent += OnCollisionDetectedEvent; SetRedColor(); } } // async private void ReadingChanged(object sender, AccelerometerReadingChangedEventArgs e) { if (!m_isStarted) return; await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { Windows.Devices.Sensors.AccelerometerReading reading = e.Reading; SendRollCommand(reading.AccelerationX, reading.AccelerationY, reading.AccelerationZ); }); } // private void OnCollisionDetectedEvent(object sender, RobotKit.CollisionData data) { SetRedColor(); m_robot.Roll(0, 0); } // private void ConnectionToggle_Toggled(object sender, RoutedEventArgs e) { ConnectionToggle.OnContent = "Connecting..."; if (ConnectionToggle.IsOn) { if (m_robot == null || m_robot.ConnectionState != ConnectionState.Connected) { SetupRobotConnection(); } } else { ShutdownRobotConnection(); } } // private void StartBtn_Click(object sender, RoutedEventArgs e) { m_isStarted = true; StartBtn.IsEnabled = false; StopBtn.IsEnabled = true; SetGreenColor(); m_robot.Roll(0, 0); } // private void StopBtn_Click(object sender, RoutedEventArgs e) { m_isStarted = false; StartBtn.IsEnabled = true; StopBtn.IsEnabled = false; SetRedColor(); m_robot.Roll(0, 0); } // . private void SetGreenColor() { m_robot.SetHeading(0); m_robot.SetBackLED(1.0f); m_robot.SetRGBLED(0, 255, 0); } // private void SetRedColor() { m_robot.SetHeading(0); m_robot.SetBackLED(1.0f); m_robot.SetRGBLED(255, 0, 0); } // private async void SendRollCommand(double newX, double newY, double newZ) { float x = (float)newX; float y = (float)newY; float z = (float)newZ; float speed = Math.Abs(z); speed = (speed == 0) ? 0 : (float)Math.Sqrt(speed); if (speed > 1f) speed = 0.01f; int heading = Convert.ToInt32(Math.PI / 2.0 - Math.Atan2((double)y - m_currentY, (double)x - m_currentX)); long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if ((milliseconds - m_lastTimeMs) > 1000) { SetGreenColor(); m_robot.Roll(heading, speed); m_lastTimeMs = milliseconds; m_currentX = x; m_currentY = y; } } }
6. Bluetooth経由でSpheroに接続する

7.アプリケーションを起動します。

8. [スタート]ボタンをクリックし、実際にゲームを確認します。

結果
簡単なおもちゃができました。 マルチプレイヤーロボットレースをアレンジしたり、ペットと遊ぶために使用できます。
作品の結果はビデオで見ることができます。
ソースはこちらから入手できます: github.com/MissUFO/SpheroRace
便利なリンク
Windows 8でロボットをプログラミングします。Spheromagic ball
Sphero公式ウェブサイト
Sphero開発者センター
Windows 8.1用Sphero SDK
Windows 8.1用のSphero SDKの例
Windows 8.1での加速度計の例
Sphero YouTube開発者チャンネル
Visual Studio 2013をダウンロードする
Visual Studio Onlineの詳細をご覧ください。
Visual Studio Onlineにサインアップする