加速度センサーやジャイロスコープセンサーを使った、3つのセンサーサンプル
ジャイロスコープセンサーを使った、カウンターのサンプル
2つ目は、ジャイロスコープセンサーを使った「カウンター」の作り方です。
加速度センサーもジャイロスコープも、どちらも元の状態からの移動を検出するものですが、ジャイロスコープでは、1秒間に何ラジアン回転したか、つまり、どのようにデバイスの姿勢が変化したかを検出できます。
実機を傾けた時の処理には加速度センサーを、実機を振ったり回転させたりした時の処理にはジャイロスコープを使ってみるとよいでしょう。
- このサンプルでは、ページをロードした時点では、X、Y、Zそれぞれのカウンターの値は「0」です。
- スライダーで検出レベルを設定してから「開始」ボタンをタップして実機を振ると、カウンターが加算されていきます。
- 「停止」ボタンをタップすると、センシングは停止します。
スライダーの値が小さい時は、実機を少し振ってもカウントします。一方、スライダーの値を大きくすると、実機をリズミカルに力強く振らなければカウントしません(図4)。
図4:ジャイロスコープセンサーの働きにより、実機を振るとカウントする(クリックで拡大) |
プロジェクトの作成
VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]と選択します。次に、「Windows Phone アプリケーション」を選択して、「名前(N)」に任意のプロジェクト名を指定します。ここでは「GyroscopeSample」という名前を付けています。Windows Phoneのバージョンは7.1を選択します。
MainPage.xamlの編集とコントロールの追加
ツールボックスからButtonコントロールを1個、TextBlockコントロールを5個配置します。
また、Sliderコントロールを1個配置します。SliderのプロパティウィンドウでSmallChange、LargeChange、Value、Maximum、Minimumの値を指定して、1~5まで1刻みで設定できるようにします。
色や書体を指定したXAMLコードはリスト3のようになります。
リスト3 各プロパティを指定したXAMLコード(MainPage.xaml)
~前略~ <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="ジャイロスコープセンサー" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="カウンター" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Slider Height="120" HorizontalAlignment="Left" Margin="20,10,0,0" Name="Slider1" VerticalAlignment="Top" Width="300" SmallChange="1" Maximum="5" LargeChange="1" Value="2" Minimum="1" /> <TextBlock Height="80" HorizontalAlignment="Left" Margin="350,30,0,0" Name="LevelTextBlock" Text="0.2" VerticalAlignment="Top" Width="100" FontSize="40"/> <Button Content="開始" Height="100" HorizontalAlignment="Left" Margin="80,150,0,0" Name="Button1" VerticalAlignment="Top" Width="300" IsEnabled="False" /> <TextBlock Height="60" HorizontalAlignment="Left" Margin="100,280,0,0" Name="TextBlockX" Text="X:0" VerticalAlignment="Top" Width="300" FontSize="48" Foreground="SkyBlue"/> <TextBlock Height="60" HorizontalAlignment="Left" Margin="100,360,0,0" Name="TextBlockY" Text="Y:0" VerticalAlignment="Top" Width="300" FontSize="48" Foreground="OrangeRed"/> <TextBlock Height="60" HorizontalAlignment="Left" Margin="100,440,0,0" Name="TextBlockZ" Text="Z:0" VerticalAlignment="Top" Width="300" FontSize="48" Foreground="LimeGreen" /> <TextBlock Height="37" HorizontalAlignment="Left" Margin="10,540,0,0" Name="StatusTextBlock" Text="センサーの状態" VerticalAlignment="Top" Width="400" FontSize="20" /> </Grid> </Grid> <!--ApplicationBar の使用法を示すサンプル コード--> ~後略~
ロジックコードを記述する前に、「プロジェクト/参照の追加」で、Microsoft.Devices.Sensors名前空間と、Microsoft.Xna.Framework名前空間への参照を追加しておきます。
MainPage.xaml.vbを開いて、ロジックコードを記述します(●リスト4)。
ロジックコードを記述する
リスト4 (MainPage.xaml.vb)
名前空間のインポートと変数の宣言
Microsoft.Devices.Sensors名前空間とXna.Framework名前空間をインポートしておきます。
このサンプルでは、計測間隔に200を指定して、200ミリ秒ごとに計測を実行させています。計測値と比較する値と、カウンターの値を設定しておきます。
Option Strict On Imports Microsoft.Devices.Sensors Imports Microsoft.Xna.Framework Partial Public Class MainPage Inherits PhoneApplicationPage ' Constructor Public Sub New() InitializeComponent() End Sub Dim MyGyro As Gyroscope 'ジャイロスコープセンサー Dim MyTimeSpan As Integer = 200 '計測間隔 Dim MyCurrentRotationRate As Vector3 = Vector3.Zero 'センサーデータ Dim CompareValue As Double = 0.2 '検出値設定用のスライダーの値を10で除算した値 Dim MyCountX As Integer = 0 'カウンターの値 Dim MyCountY As Integer = 0 Dim MyCountZ As Integer = 0 Dim CounterLevel As Double = 1 'デフォルトの比較値
このページがロードされた時の処理
デバイスがセンサーをサポートしているかどうかをチェックして、サポートしていなければ、メッセージを表示します。
Private Sub MainPage_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded 'ジャイロスコープがサポートされていない機種への対応 If Gyroscope.IsSupported = False Then MessageBox.Show("このデバイスはジャイロスコープセンサーをサポートしていません。") Button1.IsEnabled = False Exit Sub Else Button1.IsEnabled = True End If End Sub
スライダーの値が変化した時の処理
センサーにより取得されるRotationRateの値(rad/sec)と比較する値を、スライダーの設定値と計測間隔から求めておきます。
Private Sub Slider1_ValueChanged(sender As Object, e As System.Windows.RoutedPropertyChangedEventArgs(Of Double)) Handles Slider1.ValueChanged CompareValue = CInt(Slider1.Value) / 10 LevelTextBlock.Text = CStr(CompareValue) CounterLevel = CompareValue * 1000 / MyTimeSpan End Sub
ボタンがタップされた時の処理
このサンプルでは、1個のボタンで、センシングの開始と停止を切り替えます。センサーオブジェクトが有効であれば、センサーを停止し、ボタンの文字列を「開始」にします。
センサーオブジェクトが空であれば、ジャイロスコープの新しいインスタンスを作成して、ボタンの文字列を「停止」にしたうえで、センシングを実行します。
Private Sub Button1_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs) Handles Button1.Tap If MyGyro IsNot Nothing AndAlso MyGyro.IsDataValid Then Try MyGyro.Stop() MyGyro = Nothing StatusTextBlock.Text = "ジャイロスコープセンサーを停止しました。" Slider1.IsEnabled = True Button1.Content = "開始" Catch MessageBox.Show("ジャイロスコープセンサーの停止に失敗しました。") End Try Else If MyGyro Is Nothing Then MyGyro = New Gyroscope MyGyro.TimeBetweenUpdates = TimeSpan.FromMilliseconds(MyTimeSpan) AddHandler MyGyro.CurrentValueChanged, Sub(senderValue As Object, eValue As SensorReadingEventArgs(Of GyroscopeReading)) Deployment.Current.Dispatcher.BeginInvoke(Sub() UpdateUI(eValue.SensorReading)) End Sub End If Try Slider1.IsEnabled = False Button1.Content = "停止" StatusTextBlock.Text = "ジャイロスコープセンサーを開始しました。" MyGyro.Start() Catch MessageBox.Show("ジャイロスコープセンサーを開始できません。") End Try End If End Sub
センサーデータが更新された時の処理
GyroscopeReading 構造のRotationRate プロパティを用いて、取得されたセンサーデータを3軸に分解します。それぞれの軸の絶対値が、スライダーで設定した検出レベル以上であればカウントします。
Private Sub UpdateUI(MyReading As GyroscopeReading) MyCurrentRotationRate = MyReading.RotationRate '単位はrad/sec 'デバイスのX, Y, Zの各軸の回転速度 (rad/sec) 'GyroscopeReading 構造 RotationRate プロパティで取得される値 Dim MyValueX As Double = MyCurrentRotationRate.X Dim MyValueY As Double = MyCurrentRotationRate.Y Dim MyValueZ As Double = MyCurrentRotationRate.Z 'カウンターの加算と表示 '計測値をスライダーで設定したレベルと比較 '3軸の値がそれぞれ設定値以上であればカウントする If Math.Abs(MyValueX) >= CounterLevel Then MyCountX = MyCountX + 1 TextBlockX.Text = "X:" & CStr(MyCountX) End If If Math.Abs(MyValueY) >= CounterLevel Then MyCountY = MyCountY + 1 TextBlockY.Text = "Y:" & CStr(MyCountY) End If If Math.Abs(MyValueZ) >= CounterLevel Then MyCountZ = MyCountZ + 1 TextBlockZ.Text = "Z:" & CStr(MyCountZ) End If End Sub End Class
センサーを使ったアプリのサンプル