原文:
与众不同 windows phone (19) - Device(设备)之陀螺仪传感器, Motion API
与众不同 windows phone (19) - Device(设备)之陀螺仪传感器, Motion API
作者:webabcd
介绍
与众不同 windows phone 7.5 (sdk 7.1) 之设备
- 陀螺仪传感器
- Motion API(运动 API)
示例
1、演示如何使用陀螺仪传感器
GyroscopeDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Device.GyroscopeDemo" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Name="lblGyroscopeSupported" /> <Button Name="btnStart" Content="打开陀螺仪" Click="btnStart_Click" /> <Button Name="btnStop" Content="关闭陀螺仪" Click="btnStop_Click" /> <TextBlock Name="lblGyroscopeStatus" /> <TextBlock Name="lblTimeBetweenUpdates" /> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
GyroscopeDemo.xaml.cs
/* * 演示如何使用陀螺仪传感器 * * Gyroscope - 用于访问设备中的陀螺仪 * IsSupported - 设备是否支持陀螺仪 * IsDataValid - 是否可从陀螺仪中获取到有效数据 * CurrentValue - 陀螺仪当前的数据,GyroscopeReading 类型 * TimeBetweenUpdates - 触发 CurrentValueChanged 事件的时间间隔,如果设置的值小于 Gyroscope 允许的最小值,则此属性的值将被设置为 Gyroscope 允许的最小值 * Start() - 打开陀螺仪 * Stop() - 关闭陀螺仪 * CurrentValueChanged - 陀螺仪传感器获取到的数据发生改变时所触发的事件,属性 TimeBetweenUpdates 的值决定触发此事件的时间间隔 * * GyroscopeReading - 陀螺仪传感器数据 * RotationRate - 获取围绕设备各轴旋转的旋转速率(单位:弧度/秒) * DateTimeOffset - 从陀螺仪传感器中获取到数据的时间点 * * * * 手机坐标系:以手机位置为参照,假设手机垂直水平面放(竖着放),屏幕对着你,那么 * 1、左右是 X 轴,右侧为正方向,左侧为负方向 * 2、上下是 Y 轴,上侧为正方向,下侧为负方向 * 3、里外是 Z 轴,靠近你为正方向,远离你为负方向 * 以上可以用相对于手机位置的右手坐标系来理解 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Devices.Sensors; using Microsoft.Xna.Framework; namespace Demo.Device { public partial class GyroscopeDemo : PhoneApplicationPage { private Gyroscope _gyroscope; public GyroscopeDemo() { InitializeComponent(); // 判断设备是否支持陀螺仪 if (Gyroscope.IsSupported) { lblGyroscopeStatus.Text = "此设备支持陀螺仪"; } else { lblGyroscopeStatus.Text = "此设备不支持陀螺仪"; btnStart.IsEnabled = false; btnStop.IsEnabled = false; } } private void btnStart_Click(object sender, RoutedEventArgs e) { if (_gyroscope == null) { // 实例化 Gyroscope,注册相关事件 _gyroscope = new Gyroscope(); _gyroscope.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1); _gyroscope.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<GyroscopeReading>>(_gyroscope_CurrentValueChanged); lblTimeBetweenUpdates.Text = "TimeBetweenUpdates 设置为 1 毫秒,实际为 " + _gyroscope.TimeBetweenUpdates.TotalMilliseconds.ToString() + " 毫秒"; } try { // 打开陀螺仪 _gyroscope.Start(); lblGyroscopeStatus.Text = "陀螺仪已打开"; } catch (Exception ex) { lblGyroscopeStatus.Text = "陀螺仪打开失败"; MessageBox.Show(ex.ToString()); } } private void btnStop_Click(object sender, RoutedEventArgs e) { if (_gyroscope != null) { // 关闭陀螺仪 _gyroscope.Stop(); lblGyroscopeStatus.Text = "陀螺仪已关闭"; } } void _gyroscope_CurrentValueChanged(object sender, SensorReadingEventArgs<GyroscopeReading> e) { // 注:此方法是在后台线程运行的,所以需要更新 UI 的话注意要调用 UI 线程 Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading)); } private DateTimeOffset _lastUpdateTime = DateTimeOffset.MinValue; // 上一次获取陀螺仪数据的时间 private Vector3 _rotationTotal = Vector3.Zero; // 陀螺仪各轴的累积旋转弧度 // 更新 UI private void UpdateUI(GyroscopeReading gyroscopeReading) { // 以下用于计算陀螺仪各轴的累积旋转弧度 if (_lastUpdateTime.Equals(DateTimeOffset.MinValue)) { _lastUpdateTime = gyroscopeReading.Timestamp; } else { TimeSpan timeSinceLastUpdate = gyroscopeReading.Timestamp - _lastUpdateTime; // 陀螺仪当前旋转速率 * 计算此速率所经过的时间 = 此时间段内旋转的弧度 _rotationTotal += gyroscopeReading.RotationRate * (float)(timeSinceLastUpdate.TotalSeconds); _lastUpdateTime = gyroscopeReading.Timestamp; } Vector3 rotationRate = gyroscopeReading.RotationRate; // 显示陀螺仪当前各轴的旋转速率(单位:弧度/秒) lblMsg.Text += "RotationRate.X: " + rotationRate.X.ToString("0.0"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "RotationRate.Y: " + rotationRate.Y.ToString("0.0"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "RotationRate.Z: " + rotationRate.Z.ToString("0.0"); lblMsg.Text += Environment.NewLine; // 显示陀螺仪各轴的累积旋转角度 lblMsg.Text += "RotationTotal.X: " + MathHelper.ToDegrees(_rotationTotal.X).ToString("0.00"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "RotationTotal.Y: " + MathHelper.ToDegrees(_rotationTotal.X).ToString("0.00"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "RotationTotal.Z: " + MathHelper.ToDegrees(_rotationTotal.X).ToString("0.00"); } } }
2、演示如何使用 Motion API
MotionDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Device.MotionDemo" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Name="lblMotionSupported" /> <Button Name="btnStart" Content="打开 Motion 监测" Click="btnStart_Click" /> <Button Name="btnStop" Content="关闭 Motion 监测" Click="btnStop_Click" /> <TextBlock Name="lblMotionStatus" /> <TextBlock Name="lblTimeBetweenUpdates" /> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
MotionDemo.xaml.cs
/* * 演示如何使用 Motion API * * Motion - Motion API,其作用为:整合各个传感器 Accelerometer, Gyroscope, Compass 的数据,通过复杂的运算计算出易用的数据 * IsSupported - 设备是否支持 Motion API * IsDataValid - 是否可从 Motion API 中获取到有效数据 * CurrentValue - Motion API 当前的数据,MotionReading 类型 * TimeBetweenUpdates - 触发 CurrentValueChanged 事件的时间间隔,如果设置的值小于 Motion API 允许的最小值,则此属性的值将被设置为 Motion API 允许的最小值 * Start() - 打开 Motion 监测 * Stop() - 关闭 Motion 监测 * CurrentValueChanged - 当 Motion API 获取到的数据发生改变时所触发的事件,属性 TimeBetweenUpdates 的值决定触发此事件的时间间隔 * Calibrate - 当系统检测到 Motion API 用到的数字罗盘传感器需要校准时所触发的事件 * * MotionReading - Motion API 数据 * AttitudeReading - 设备的姿态(AttitudeReading 类型,可以获得 Yaw Pitch Roll 数据) * DeviceAcceleration - 设备的加速度(Vector3 类型) * DeviceRotationRate - 设备的旋转速率(Vector3 类型) * Gravity - 重力(Vector3 类型) * DateTimeOffset - 从 Motion API 中获取到数据的时间点 * * 注: * 如果设备缺少必要的传感器,那么 Motion API 将无法正常工作 * 例如,如果只有 Accelerometer, Compass 而没有 Gyroscope,那么虽然 Motion API 是被支持的,但是部分数据是不精准的 * 例如,如果只有 Accelerometer 而没有 Compass, Gyroscope,那么 Motion API 是不被支持的 * * * * 手机坐标系:以手机位置为参照,假设手机垂直水平面放(竖着放),屏幕对着你,那么 * 1、左右是 X 轴,右侧为正方向,左侧为负方向 * 2、上下是 Y 轴,上侧为正方向,下侧为负方向 * 3、里外是 Z 轴,靠近你为正方向,远离你为负方向 * 以上可以用相对于手机位置的右手坐标系来理解 * * Yaw - 围绕 Y 轴旋转 * Pitch - 围绕 X 轴旋转 * Roll - 围绕 Z 轴旋转 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using System.Windows.Navigation; using Microsoft.Devices.Sensors; using Microsoft.Xna.Framework; namespace Demo.Device { public partial class MotionDemo : PhoneApplicationPage { private Motion _motion; public MotionDemo() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 判断设备是否支 Motion API if (Motion.IsSupported) { lblMotionStatus.Text = "此设备支持 Motion API"; } else { lblMotionStatus.Text = "此设备不支持 Motion API"; btnStart.IsEnabled = false; btnStop.IsEnabled = false; } } private void btnStart_Click(object sender, RoutedEventArgs e) { if (_motion == null) { // 实例化 Motion,注册相关事件 _motion = new Motion(); _motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1); _motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(_motion_CurrentValueChanged); lblTimeBetweenUpdates.Text = "TimeBetweenUpdates 设置为 1 毫秒,实际为 " + _motion.TimeBetweenUpdates.TotalMilliseconds.ToString() + " 毫秒"; } try { // 打开 Motion 监测 _motion.Start(); lblMotionStatus.Text = "Motion 监测已打开"; } catch (Exception ex) { lblMotionStatus.Text = "Motion 监测打开失败"; MessageBox.Show(ex.ToString()); } } private void btnStop_Click(object sender, RoutedEventArgs e) { if (_motion != null) { // 关闭 Motion 监测 _motion.Stop(); lblMotionStatus.Text = "Motion 监测已关闭"; } } void _motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e) { // 注:此方法是在后台线程运行的,所以需要更新 UI 的话注意要调用 UI 线程 Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading)); } // 更新 UI private void UpdateUI(MotionReading motionReading) { AttitudeReading attitude = motionReading.Attitude; Vector3 deviceAcceleration = motionReading.DeviceAcceleration; Vector3 deviceRotationRate = motionReading.DeviceRotationRate; Vector3 gravity = motionReading.Gravity; // 在 UI 上显示相关参数 lblMsg.Text = "yaw: " + MathHelper.ToDegrees(attitude.Yaw).ToString("0.0"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "pitch: " + MathHelper.ToDegrees(attitude.Pitch).ToString("0.0"); lblMsg.Text += Environment.NewLine; lblMsg.Text += "roll: " + MathHelper.ToDegrees(attitude.Roll).ToString("0.0"); } } }
OK
[源码下载]