加速度センサーやジャイロスコープセンサーを使った、3つのセンサーサンプル

2012年6月29日(金)
PROJECT KySS

ジャイロスコープセンサーを使った、カウンターのサンプル

2つ目は、ジャイロスコープセンサーを使った「カウンター」の作り方です。

加速度センサーもジャイロスコープも、どちらも元の状態からの移動を検出するものですが、ジャイロスコープでは、1秒間に何ラジアン回転したか、つまり、どのようにデバイスの姿勢が変化したかを検出できます。

実機を傾けた時の処理には加速度センサーを、実機を振ったり回転させたりした時の処理にはジャイロスコープを使ってみるとよいでしょう。

  1. このサンプルでは、ページをロードした時点では、X、Y、Zそれぞれのカウンターの値は「0」です。
  2. スライダーで検出レベルを設定してから「開始」ボタンをタップして実機を振ると、カウンターが加算されていきます。
  3. 「停止」ボタンをタップすると、センシングは停止します。

スライダーの値が小さい時は、実機を少し振ってもカウントします。一方、スライダーの値を大きくすると、実機をリズミカルに力強く振らなければカウントしません(図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
  • センサーを使ったアプリのサンプル

四国のSOHO。薬師寺国安(VBプログラマ)と、薬師寺聖(デザイナ、エンジニア)によるコラボレーション・ユニット。1997年6月、Dynamic HTMLとDirectAnimationの普及を目的として結成。共同開発やユニット名義での執筆活動を行う。XMLおよび.NETに関する著書や連載多数。最新刊は「Silverlight実践プログラミング」両名とも、Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。http://www.PROJECTKySS.NET/

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています