Windows Phone 7 - 了解Sensor – Accelerometer
在了解<Windows Phone 7 - 了解Sensor – Combined Motion API>介紹的內容後,該篇針對Accelerometer加以說明,
學習如何使用原始數據資訊,進一步處理需要的功能。由於Accelerometer影響的是線性加速度,因此運作的原理
是了解Accelerometer的重要部分,以下先介紹其運作原理。
〉方向性的運作概念圖:
擷取<Using the Accelerometer on Windows Phone 7>中的一圖,說明Accelerometer採用三個維度:X、Y、Z,解釋設備
在空間運行的方式。透過一個公式來說三軸目前存在的意義:「G-forces (1G = 9.81 m/s2)」,因此,Z軸=1.0時,代表
目前手機的正面正往上方,相反地,Z軸=-1時,代表手機正面正往下方;
可參考<Windows Phone 7 Game Development: A Beginner’s Guide (Accelerometer)>介紹的圖示,更容易理解三軸的定義:
不過對於上圖的說明,如果你跟我一樣對空間概念比較不熟悉的話,可以捉住幾個重點:
‧X軸:代表手機的兩側,手機直立時,往右下角壓:X軸是正數增加;相反地,往左下角壓:X軸是負數增加;
‧Y軸:代表手機的頂部與底部,橫著拿時(左手捉住頂部,右手捉住底部),往右下角壓:Y軸是負數增加;往左下角壓:Y軸是正數增加;
‧Z軸:代表手機的正面與背面,正面對著天空時:Z軸是負數增加;背面對著天空時:Z軸是正數增加;
記熟這三個要點後,舉個例子來說明:
1. 假設想要做直立手機時進行左右搖擺,觸發一個事件,該注意那一個軸的變化?
=>答案是:X軸;因為左右搖,改變最大數值是X軸與它速度的變化;
2. 假設想要做一個手機面對自己,做出求籤的動作時,該注意那一個軸的變數?
=>答案是:Z軸;因為求籤時需正面與背面的晃動,因此它變數量最多;
3. 假設想要做手機放在口袋,手機頂部朝向地面時,該注意那一個軸的變數?
=>答案是:Y軸;因為手機直立時,底部向下,如同橫立時往右下角壓,所以是負數,但頂部朝地,
也代表,往左下角壓,Y軸會變成正數,剛好觸發事件。
以上是針對運作原理的說明,往下便開始針對WP7 SDK裡針對Accelerometer加以說明。
該API主要用於測量加速力,例如:重力、移動所產生的力量。所有的Windows Phone設備至少一定有Accelerometer,
它支援Silverlight與XNA做為另一種輸入的方式。它屬於一種管理型的函式庫,放置於「Microsoft.Devices.Sensors」之中。
(A) 重點屬性:
屬性 | 說明 |
IsSupported | 設定/取得設備是否支援Accelerometer執行時所需要的感應器。該屬性不需要實例化Accelerometer類型可直接使用。 |
IsDataValid | 取得感應器的資料是否具有效性。 |
CurrentValue | 取得一個實作ISensorReading的物件,該物件包含感應器所收集的當前值。該物件可能是下列類型的其中一種: ‧AccelerometerReading ‧CompassReading ‧GyroscopeReading ‧MotionReading |
TimeBetweenUpdates | 設定/取得CurrentValueChanged事件之間發生的首選時間(preferred time)。 |
State | 取得目前Acceelerometer的狀態。詳細資料來自SensorState列舉,如下: ‧NotSupported ‧Ready ‧Initializing ‧NoData ‧NoPermissions ‧Disabled |
上述這些屬性均是在實作應用程式時,一定會使用的,包括檢查設備是否支援Accelerometer,是否取得的資料是有效的,
進一步使用當前的值去進行處理。
(B) 重點事件:
事件 | 說明 |
CurrentValueChanged | 該事件發生當有新的數據資料被Sensor擷取到時。 發生的頻率,根據TimeBetweenUpdates屬性設定時間而定。 |
(B-1) SensorReadingEventArgs<AccelerometerReading>:
實作CurrentValueChanged事件時,SensorReadingEventArgs<T> Class該類別提供CurrentValueChanged事件主要的觸發來源,
以AccelerometerReading來說,它是主要記錄目前設備在這個時間點的Accelerometer所擷取到的數據資料,往下說明其結構:
屬性 | 說明 |
Acceleration | 取得設備的線性加速度(linear acceleration),以G力(gravitational)為單位。 |
Timestamp | 取得AccelerometerReading計算的時間戳的時間,這可用於關聯整個Sensor取得數據與計算原始資料的演算法。 |
在上述了解完Accelerometer的基本結構後,往下便說明如何使用該API。
〉範例說明:
在說明範例時,如果沒有實體設備可以測試的話,可以參考<How to: Test Applications that Use the Accelerometer>
的介紹,透過模擬器一樣可以模擬Accelerometer的功能協助範例的測試。
該範例為呈現當橫著拿時(左手捉住頂部,右手捉住底部)時,監測Accelerometer在Y軸變化時,圖示自動往左或往右的簡易範例,:
(1) 加入Microsoft.Devices.Sensors與using Microsoft.Xna.Framework參考與增加MainPage.xaml中要呈現的圖示;
1: <!--ContentPanel - place additional content here-->
2: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
3: <Button Content="Start" Height="72" HorizontalAlignment="Left" Margin="20,10,0,0" Name="startButton" VerticalAlignment="Top" Width="160" Click="startButton_Click" />
4: <Button Content="Stop" Height="72" HorizontalAlignment="Right" Margin="0,10,20,0" Name="stopButton" VerticalAlignment="Top" Width="160" Click="stopButton_Click"/>
5: <TextBlock Height="30" HorizontalAlignment="Left" Margin="20,100,0,0" Name="xTextBlock" Text="X: 1.0" VerticalAlignment="Top" Foreground="Red" FontSize="28" FontWeight="Bold"/>
6: <TextBlock Height="30" HorizontalAlignment="Center" Margin="0,100,0,0" Name="yTextBlock" Text="Y: 1.0" VerticalAlignment="Top" Foreground="Green" FontSize="28" FontWeight="Bold"/>
7: <TextBlock Height="30" HorizontalAlignment="Right" Margin="0,100,20,0" Name="zTextBlock" Text="Z: 1.0" VerticalAlignment="Top" Foreground="Blue" FontSize="28" FontWeight="Bold"/>
8: <TextBlock Height="30" HorizontalAlignment="Center" Margin="6,571,6,0" Name="statusTextBlock" Text="TextBlock" VerticalAlignment="Top" Width="444" />
9: <!-- 加上要呈現的圖示範圍 -->
10: <!-- 設定Margin以調整圖示於中間 -->
11: <Canvas x:Name="cvsImg" Margin="150,250,0,0">
12: <Image x:Name="imgSource" Width="150"
13: Height="200" Source="/Images/a.jpg">
14: <!-- 定義RenderTransform做為效果呈現的功能-->
15: <Image.RenderTransform>
16: <TranslateTransform x:Name="translation" />
17: </Image.RenderTransform>
18: </Image>
19: </Canvas>
20: </Grid>
圖示放置於Images目錄裡,並且設定圖示呈現的樣式。
(2) 註冊Accelerometer,並檢查設備是否支援Accelerometer感應器;
1: public MainPage()
2: {
3: InitializeComponent();
4: //在建構子即檢查是否支援Accelerometer感應器
5: Init();
6: }
7:
8: Accelerometer gAccelerometer;
9:
10: /// <summary>
11: /// 檢查該設備是否支援Accelerometer感應器;
12: /// </summary>
13: private void Init()
14: {
15: if (!Accelerometer.IsSupported)
16: {
17: statusTextBlock.Text = "設備不支援Accelerometer感應器。";
18: startButton.IsEnabled = false;
19: stopButton.IsEnabled = false;
20: }
21: }
(2) 註冊啟動與關閉Accelerometer感應器,並設定啟動監控CurrentValueChanged;
1: private void startButton_Click(object sender, RoutedEventArgs e)
2: {
3: if (gAccelerometer == null)
4: {
5: // 實例化Accelerometer
6: gAccelerometer = new Accelerometer();
7: // 設定擷取Accelerometer的首選時間
8: gAccelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
9: // 註冊處理CurrentValueChanged的事件
10: gAccelerometer.CurrentValueChanged +=
11: new EventHandler<SensorReadingEventArgs<AccelerometerReading>>
12: (accelerometer_CurrentValueChanged);
13: }
14:
15: try
16: {
17: statusTextBlock.Text = "啟動... accelerometer感應器";
18: // 正式啟動
19: gAccelerometer.Start();
20: }
21: catch (InvalidOperationException ex)
22: {
23: //啟動失敗
24: statusTextBlock.Text = "無法啟動... accelerometer感應器";
25: }
26: }
27:
28: private void stopButton_Click(object sender, RoutedEventArgs e)
29: {
30: if (gAccelerometer != null)
31: {
32: // 關閉Accelerometer感應器.
33: gAccelerometer.Stop();
34: statusTextBlock.Text = "關閉... accelerometer感應器";
35: }
36: }
(3) 處理發生CurrentValueChanged事件時,Y軸正/負值影響圖示移動的方式;
1: /// <summary>
2: /// 處理Accelerometer感應器取得的數據資料,使用AccelerometerReading物件;
3: /// </summary>
4: void accelerometer_CurrentValueChanged(object sender,
5: SensorReadingEventArgs<AccelerometerReading> e)
6: {
7: // 由於Accelerometer與UI Thread屬於不同的Thread,呼叫Dispatcher來更新UI Thread的內容。
8: // 將SensorReading (AccelerometerReading)送至UpdateUI方法中。
9: Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
10: }
11:
12: /// <summary>
13: /// 實際更新畫面元件的方法。
14: /// </summary>
15: private void UpdateUI(AccelerometerReading accelerometerReading)
16: {
17: statusTextBlock.Text = "取得資料...";
18: //將AccelerometerReading的值轉成Vertor3,三維度的內容值。
19: Vector3 acceleration = accelerometerReading.Acceleration;
20:
21: //顯示三軸變化的數據。
22: xTextBlock.Text = "X: " + acceleration.X.ToString("0.00");
23: yTextBlock.Text = "Y: " + acceleration.Y.ToString("0.00");
24: zTextBlock.Text = "Z: " + acceleration.Z.ToString("0.00");
25:
26: //使用Image定義的RenderTransform來進行圖示的移動
27:
28: if (acceleration.Y < 0)
29: // Y為負,代表右下角被往下壓,要往畫面右邊,要將Y轉成正數
30: translation.X = Math.Abs(acceleration.Y) * 200;
31: else
32: // Y為正,代表左下角被往下壓,要往畫面左邊,要將Y轉成負數
33: translation.X = acceleration.Y * -200;
34: }
(4) 執行結果:
4-0. 執行前的樣子;
4-1. 移動Y軸,讓Y軸形成為-1值,圖示由左移動至右;
4-2. 移動Y軸,讓Y軸形成為1值,圖示由右移動至左;
======
以上是介紹有關Accelerometer的使用,對於Sensor的使用在Silverlight Application使用的情境蠻多的,
可以讓整個App增加不少樂趣,也可以當作另一種的輸入方式,不妨思考一下自己的App那裡可以使用,
但也別忘記要識別該設備是否有支援該Sensor。分享給大家,希望有所幫助。
References:
‧Accelerometer for Windows Phone (重要)
‧Using the Accelerometer on Windows Phone 7 (重要)
‧Sensors for Windows Phone & Sensors Overview for Windows Phone
‧How to: Get Data from the Accelerometer Sensor for Windows Phone
‧How to: Use Reactive Extensions to Emulate and Filter Accelerometer Data for Windows Phone
‧How-to: 利用Web Camera模拟Windows Phone 7的重力加速度传感器
‧给你的Windows Phone 7模拟器加入GPS和加速度传感器模拟功能
‧Retrieving Accelerometer Input (Windows Phone)
‧Introduction to using WP7 Accelerometer
‧WP7 Code: Using the Accelerometer API
‧Windows Phone 7 Game Development: A Beginner’s Guide (Accelerometer)