GPSによる位置情報の取得と加速度センサー

2011年11月11日(金)
PROJECT KySS

加速度センサーで、傾斜角度を測る

Windows Phone 7では、端末に内蔵された3軸加速度センサーで加速度を検出し、数値として取得することができます。

地球上の物体である実機は、平らなデスクの上に置いても、ひっくり返しても、傾けて置いても、重力の影響を受けていますが、この重力によって生じる重力加速度は、重力を受けている物体が自由落下する時の加速度で表すことができます。したがって、加速度センサーで取得した値から、重力のはたらく方向に対する物体(実機)の各軸の角度を知ることができます。

例えば、加速度センサーにより0.5という値が検出された場合、0.5 = 1/2 ですから、実機は、対辺が1、斜辺が2の直角三角形の斜辺上に置かれた状態にあります。sinθ=1/2の時、θは30ですから、実機は30度傾いた状態であることが分かります。0.7071が検出されたなら、0.7071≒1/√2ですから、実機は、対辺が1、斜辺が√2の直角三角形の斜辺上に置かれた状態にあります。実機の傾きθは約45度です(図5)。

図5:重力加速度と傾斜角度の関係(クリックで拡大)

Windows Phone 7 では、X、Y、Z の3軸に対して検出された値がプラスかマイナスかによって、実機の向きが分かります。プラスの値が検出されたら、実機の軸は重力のはたらく方向に向いています。マイナスの値が検出されたら、実機の軸は重力のはたらく方向とは逆向きです。

例えば実機を平らな机の上に置いた時、X軸に対して0、Y軸に対して0、Z軸に対して-1というようにマイナスの値が検出されたら、実機のZ軸は重力のはたらく方向とは逆向きです。このことから、実機の画面は天の方を向いていることが分かります。

このように、加速度センサーを用いると、加速度の値から、実機の傾きの状態が分かります。

検出される値と実機の状態との関係は、エミュレーターを使うと確認することができます。

図6は、エミュレーターの画面です。実機の置き方の方向を選択し、オレンジのをドラッグして動かすと、その傾きに応じたX、Y、Zの各軸に対する加速度の値が表示されます。

  • Portrait Standingでは、実機を垂直に立て、正面から画面を見ている状態での動きをシミュレートできます。
  • Portrait Flatでは、水平な台に実機を縦向きに置き、上から見下ろした状態の動きをシミュレートできます。
  • Landscape Standingでは、実機を横向きにして、正面から画面を見ている状態での動きをシミュレートできます。
  • Landscape Flatでは、水平な台に実機を横向きに置き、上から見下ろした状態の動きをシミュレートできます。

図6:エミュレーターにより、加速度と実機の傾きをシミュレートできる(クリックで拡大)

ただし、エミュレーター上ではシミュレーションはできますが、実際の動作をイメージしにくいので、動作確認は、できるだけ実機で行うことをおすすめします。

今回は、実機を坂道やスロープや棚や床などの平らな面に置いた時、縦方向に何度傾いているのかを視覚的に示すサンプルを紹介します。それには、実機のY軸方向(縦方向)にはたらく加速度から傾斜角度をもとめ、得られた角度に連動して画像を傾けて表示します(図7)。

図7:実機(IS12T)を平面に置いた時、縦方向の傾きの角度が表示され、連動して矢印の画像が傾いて表示される。※図はハメコミ合成によるイメージです(クリックで拡大)

このサンプルのように、検出された値をSilverlightアプリケーションで利用するにあたっては、注意しなければならないことが1つあります。それは、Silverlightにおける、オブジェクトの回転角度の適用方法です。

画面上に配置した画像を、ごく単純に回転させるには、Silverlightアプリケーションの画面の奥から手前に向かうZ軸を基準として回転させる必要があります。

したがって、このサンプルのように画像(前掲図7中のブルーの矢印)を傾けて表示するには、加速度センサーから取得した実機のY軸の傾斜角度の値を、SilverlightでZ軸の周りを回転するオブジェクトの回転角度を示すPlaneProjectionのRotationZプロパティに対して指定する必要があります(図8)。

図8:傾斜角度と回転軸の関係(クリックで拡大)

サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。

動画は下記で確認できます

プロジェクトの作成

VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]を選択します。次に、「Windows Phone アプリケーション」を選択して、「名前(N)」に任意のプロジェクト名を指定します。ここでは「WP71_ Accelerometer」という名前を付けています。Windows Phoneのバージョンは7.1を選択します。

ソリューションエクスプローラー内にImageというフォルダを作成し、画像を追加してください。ダウンロードされたサンプルには画像ファイル(ブルーの矢印)は追加済みです。

MainPage.xamlの編集とコントロールの追加

x:NameがPageTitleというTextBlockのTextプロパティに「Accelerometer」と指定します。

x:NameがContentPanelという要素のBackground(背景色)プロパティにWhiteを指定します。

ツールボックスから、角度を表示するためのTextBlockコントロールを1個配置します。

次に、Rectangleコントロールを1個配置します。WidthとHeightは400×400とし、Fillプロパティに任意の色を指定して塗りつぶしておきます。その上に、Imageコントロールを1個配置します。SourceプロパティにImageフォルダ内の画像を指定します(図9)。

図9:Imageコントロールを配置し、SourceプロパティにImageフォルダ内の画像を指定した(クリックで拡大)

コントロールを配置できたら、XAMLコードをリスト3のように編集します。

リスト3 (Mainpage.xaml)

(1)先のサンプルで説明した通り、日本語フォントを正しく表示するために、<phone:PhoneApplicationPage>要素内に、Language="ja-JP" と指定しておきます。
(2)<Image.Projection>プロパティ要素内に<PlaneProjection>要素を配置し、x:NameにmyPlaneProjectionと指定しておきます。<Image.Projection>プロパティ要素では、UIElementのレンダリング時に射影を設定できます。<PlaneProjection>はオブジェクトに対する遠近法変換を表す要素です。

<phone:PhoneApplicationPage 
  x:Class="WP71_Accelerometer.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
  FontFamily="{StaticResource PhoneFontFamilyNormal}"
  FontSize="{StaticResource PhoneFontSizeNormal}"
  Foreground="{StaticResource PhoneForegroundBrush}"
  SupportedOrientations="Portrait" Orientation="Portrait"
  shell:SystemTray.IsVisible="True" Language=”ja-JP”> ■(1)

  <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
  <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
 
    <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
    <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="Accelerometer" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
 
    <!--ContentPanel - 追加コンテンツをここに入力します-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="White">
      <TextBlock Height="40" HorizontalAlignment="Left" Margin="30,60,0,0" Name="TextBlock1" Text="傾き" VerticalAlignment="Top" Width="300" Foreground="Black" FontSize="32" />
      <Rectangle Height="400" HorizontalAlignment="Left" Margin="30,130,0,0" Name="Rectangle1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="400" Fill="Silver" />
      <Image Height="54" HorizontalAlignment="Left" Margin="30,303,0,0" Name="Image1" Stretch="Uniform" VerticalAlignment="Top" Width="400" Source="/WP71_Accelerometer;component/Image/line.png">
        <Image.Projection>■(2)
          <PlaneProjection x:Name="myPlainProjection"/>■(2)
        </Image.Projection>■(2)
      </Image>
    </Grid>
  </Grid>
  
  <!--ApplicationBar の使用法を示すサンプル コード-->
 ~コード略~
</phone:PhoneApplicationPage>

次に、「プロジェクト/参照の追加」から、Microsoft.Device.Sensors 名前空間と、Microsoft.Xna.Framework名前空間への参照を追加しておきます。

MainPage.xamlを展開して表示されるMainPage.xaml.vbをダブルクリックして開き、リスト4のロジックコードを記述します。

ロジックコードを記述する

リスト4 (MainPage.xaml.vb)

Option Strict On
加速度計にアクセスする API を提供するMicrosoft.Devices.Sensors名前空間をインポートします。
Imports Microsoft.Devices.Sensors

Partial Public Class MainPage
  Inherits PhoneApplicationPage
 
  ' コンストラクター
  Public Sub New()
    InitializeComponent()
  End Sub

Accelerometerクラスの新しいインスタンスであるmyAccelerometerメンバ変数を宣言します。Accelerometerクラスは、デバイスの加速度センサーにアクセスするWindows Phoneアプリケーションを提供するクラスです。
  Dim myAccelerometer As New Accelerometer

ページが読み込まれた時の処理

AddHandlerメソッドで、センサーからの新しいデータが到着した時に発生する、CurrentValueChangedイベントにイベントハンドラを追加します。イベントハンドラ内では、Dispatcher が関連付けられているスレッドで、デリゲートを非同期的に実行するCurrentValueChangedイベントを、BeginInvokeメソッドで呼び出します。
Startメソッドで、加速度計からのデータ取得を開始します。
  Private Sub MainPage_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
    AddHandler myAccelerometer.CurrentValueChanged, Sub(senderValue As Object, eValue As SensorReadingEventArgs(Of AccelerometerReading))
  
Deployment.Current.Dispatcher.BeginInvoke(Sub() CurrentValueChanged(eValue.SensorReading))
End Sub
    myAccelerometer.Start()
  End Sub

非同期で呼び出される処理CurrentValueChangedイベントの処理

加速度センサーで検出される値は基本的に-1~1の範囲ですが、上限下限を超えないように整えます。
AccelerometerReadingEventArgs.YプロパティでY軸に対する加速度を取得し、この絶対値をもとに逆三角関数を用いて、実機が置かれた面の、縦方向の傾斜角度をもとめます。Math.asin関数の戻り値はラジアンであるため、これを度に変換します。
ImageコントロールのProjectionプロパティに指定した、PlaneProjectionのRotationZの値に、もとめた角度を適用して、画像を傾けて表示します。
角度の値はDouble型で、そのままでは小数点以下が長々と表示されるようになるため、分かりやすいように丸めてからTextBlock内に表示しています。
  Private Sub CurrentValueChanged(myReading As AccelerometerReading)
    Dim myAcceleration = myReading.Acceleration
    If myAcceleration.Y > 1 Then
      myAcceleration.Y = 1
    ElseIf myAcceleration.Y < -1 Then
      myAcceleration.Y = -1
    End If
 
    myPlainProjection.RotationZ = Math.Asin(Math.Abs(myAcceleration.Y)) * 180 / Math.PI
 
    TextBlock1.Text = CStr(Math.Round(myPlainProjection.RotationZ)) & "°傾いています。"
  End Sub

アプリケーション終了時の処理

Stopメソッドで加速度計からのデータ収集を停止します。
  Private Sub MainPage_Unloaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Unloaded
    myAccelerometer.Stop()
    myAccelerometer = Nothing
  End Sub
End Class

コードが書けたら、実機でデバッグしてみましょう。VS2010からデプロイ先に「Windows Phone Device」を選択して、「デバッグ(D) /デバッグ開始(S)」と選択します。実機を傾けると、傾斜角度が表示され、それに応じて矢印の画像も傾きます。

Windows Phone 7 のセンサーは、アイデア次第で、ゲームプログラミングや、シミュレーションのプロットに利用できることでしょう。

  • 「GPSによる位置情報の取得」サンプルプログラム

  • 「加速度センサーで、傾斜角度を測る」サンプルプログラム

四国の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メルマガ会員のサービス内容を見る

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