Windows phone 7 WP7:将加速度计和指南针数据转换为模拟运动API

Windows phone 7 WP7:将加速度计和指南针数据转换为模拟运动API,windows-phone-7,accelerometer,windows-phone-7.1,motion,Windows Phone 7,Accelerometer,Windows Phone 7.1,Motion,我正在为WindowsPhone7.1(Mango)编写一个小示例应用程序,并希望使用组合运动API来显示设备的运动。我需要编写模拟类,以便在使用不支持设备所有传感器的仿真器时能够测试我的应用程序 我已经编写了一个简单的模拟类来模拟指南针(它只是模拟一个旋转的设备)以及模拟器中实际可用的加速计 现在,我必须为运动API编写一个新的模拟对象,但我希望可以使用来自指南针和加速计的值来计算运动对象使用的值。不幸的是,我没有找到一个简单转换的示例,这个转换已经在进行了 有人知道进行这种转换的代码示例吗?

我正在为WindowsPhone7.1(Mango)编写一个小示例应用程序,并希望使用组合运动API来显示设备的运动。我需要编写模拟类,以便在使用不支持设备所有传感器的仿真器时能够测试我的应用程序

我已经编写了一个简单的模拟类来模拟指南针(它只是模拟一个旋转的设备)以及模拟器中实际可用的加速计

现在,我必须为运动API编写一个新的模拟对象,但我希望可以使用来自指南针和加速计的值来计算运动对象使用的值。不幸的是,我没有找到一个简单转换的示例,这个转换已经在进行了


有人知道进行这种转换的代码示例吗?尽管如此复杂,如果已经有解决方案的话,我不想自己做这件事。

做模型工作的一个很好的起点是看看运动API,看看它内部是如何工作的,API核心使用了哪些参数:

在继续之前,请记住,运动API是一个复杂的数学模型,它结合了不同手机传感器的输入。通过结合加速度、位置和旋转,可以找到许多不同的模型来计算运动。。您可以在本文中找到一个很好的描述:

所以事实上,你必须使用上面文章中的方程和函数,然后自己计算这些值

这不是一件简单的事情,而是一种可能


我希望我能帮助你:)并让社区知道,如果你做到了。我认为一个codeplex项目将很好地为windows phone运动API编写一种模拟实用程序。

现在windows phone 8已经推出,我还没有手机可供测试,我又遇到了同样的问题

就像答案一样,我创造了。当支持实际运动API时,将使用它。否则,在调试模式下,将返回改变横摇、俯仰和偏航的模拟数据


MotionWrapper

    /// <summary>
    /// Provides Windows Phone applications information about the device’s orientation and motion.
    /// </summary>
    public class MotionWrapper //: SensorBase<MotionReading> // No public constructors, nice one.
    {
        private Motion motion;

        public event EventHandler<SensorReadingEventArgs<MockMotionReading>> CurrentValueChanged;

        #region Properties
        /// <summary>
        /// Gets or sets the preferred time between Microsoft.Devices.Sensors.SensorBase<TSensorReading>.CurrentValueChanged events.
        /// </summary>
        public virtual TimeSpan TimeBetweenUpdates
        {
            get
            {
                return motion.TimeBetweenUpdates;
            }
            set
            {
                motion.TimeBetweenUpdates = value;
            }
        }

        /// <summary>
        /// Gets or sets whether the device on which the application is running supports the sensors required by the Microsoft.Devices.Sensors.Motion class.
        /// </summary>
        public static bool IsSupported
        {
            get
            {
#if(DEBUG)
                return true;
#else
                return Motion.IsSupported;
#endif

            }
        }
        #endregion

        #region Constructors
        protected MotionWrapper()
        {
        }

        protected MotionWrapper(Motion motion)
        {
            this.motion = motion;
            this.motion.CurrentValueChanged += motion_CurrentValueChanged;
        }
        #endregion

        /// <summary>
        /// Get an instance of the MotionWrappper that supports the Motion API
        /// </summary>
        /// <returns></returns>
        public static MotionWrapper Instance()
        {
#if(DEBUG)
            if (!Motion.IsSupported)
            {
                return new MockMotionWrapper();
            }
#endif
            return new MotionWrapper(new Motion());
        }

        /// <summary>
        /// The value from the underlying Motion API has changed. Relay it on within a MockMotionReading.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            var f = new SensorReadingEventArgs<MockMotionReading>();
            f.SensorReading = new MockMotionReading(e.SensorReading);
   RaiseValueChangedEvent(sender, f);
        }

        protected void RaiseValueChangedEvent(object sender, SensorReadingEventArgs<MockMotionReading> e)
        {
            if (CurrentValueChanged != null)
            {
                CurrentValueChanged(this, e);
            }
        }

        /// <summary>
        /// Starts acquisition of data from the sensor.
        /// </summary>
        public virtual void Start()
        {
            motion.Start();
        }

        /// <summary>
        /// Stops acquisition of data from the sensor.
        /// </summary>
        public virtual void Stop()
        {
            motion.Stop();
        }
    }
//
///提供有关设备方向和运动的Windows Phone应用程序信息。
/// 
公共类MotionWrapper//:SensorBase//没有公共构造函数,很好。
{
私人动议;
公共事件处理程序CurrentValueChanged;
#区域属性
/// 
///获取或设置Microsoft.Devices.Sensors.SensorBase.CurrentValueChanged事件之间的首选时间。
/// 
更新之间的公共虚拟时间跨度时间
{
得到
{
返回运动。更新之间的时间;
}
设置
{
motion.TimeBetweenUpdates=值;
}
}
/// 
///获取或设置运行应用程序的设备是否支持Microsoft.Devices.sensors.Motion类所需的传感器。
/// 
支持公共静态布尔值
{
得到
{
#如果(调试)
返回true;
#否则
返回运动.IsSupported;
#恩迪夫
}
}
#端区
#区域构造函数
受保护的MotionWrapper()
{
}
受保护的运动包装器(运动)
{
这个运动=运动;
this.motion.CurrentValueChanged+=运动\u CurrentValueChanged;
}
#端区
/// 
///获取支持运动API的MotionWrappper实例
/// 
/// 
公共静态MotionWrapper实例()
{
#如果(调试)
如果(!Motion.IsSupported)
{
返回新的MockMotionWrapper();
}
#恩迪夫
返回新的MotionWrapper(newmotion());
}
/// 
///基础运动API中的值已更改。请在MockMotionReading内将其中继。
/// 
/// 
/// 
私有无效运动\u CurrentValueChanged(对象发送器、传感器读取事件参数e)
{
var f=新传感器读取事件参数();
f、 传感器读数=新的模拟运动读数(如传感器读数);
RaiseValueChangedEvent(发送方,f);
}
受保护的void RaiseValueChangedEvent(对象发送方、SensorReadingEventArgs e)
{
如果(CurrentValueChanged!=null)
{
CurrentValueChanged(本,e);
}
}
/// 
///开始从传感器采集数据。
/// 
公共虚拟void Start()
{
运动。开始();
}
/// 
///停止从传感器采集数据。
/// 
公共虚拟无效停止()
{
运动。停止();
}
}

MockMotionWrapper

    /// <summary>
    /// Provides Windows Phone applications mock information about the device’s orientation and motion.
    /// </summary>
    public class MockMotionWrapper : MotionWrapper
    {
        /// <summary>
        /// Use a timer to trigger simulated data updates.
        /// </summary>
        private DispatcherTimer timer;

        private MockMotionReading lastCompassReading = new MockMotionReading(true);

        #region Properties
        /// <summary>
        /// Gets or sets the preferred time between Microsoft.Devices.Sensors.SensorBase<TSensorReading>.CurrentValueChanged events.
        /// </summary>
        public override TimeSpan TimeBetweenUpdates
        {
            get
            {
                return timer.Interval;
            }
            set
            {
                timer.Interval = value;
            }
        }
        #endregion

        #region Constructors
        public MockMotionWrapper()
        {
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(30);
            timer.Tick += new EventHandler(timer_Tick);
        }
        #endregion

        void timer_Tick(object sender, EventArgs e)
        {
            var reading = new Microsoft.Devices.Sensors.SensorReadingEventArgs<MockMotionReading>();
            lastCompassReading = new MockMotionReading(lastCompassReading);
            reading.SensorReading = lastCompassReading;

            //if (lastCompassReading.HeadingAccuracy > 20)
            //{
            //    RaiseValueChangedEvent(this, new CalibrationEventArgs());
            //}

            RaiseValueChangedEvent(this, reading);
        }

        /// <summary>
        /// Starts acquisition of data from the sensor.
        /// </summary>
        public override void Start()
        {
            timer.Start();
        }

        /// <summary>
        /// Stops acquisition of data from the sensor.
        /// </summary>
        public override void Stop()
        {
            timer.Stop();
        }

    }
//Microsoft.Devices.Sensors.MotionReading
/// <summary>
/// Contains information about the orientation and movement of the device.
/// </summary>
public struct MockMotionReading : Microsoft.Devices.Sensors.ISensorReading
{
    public static bool RequiresCalibration = false;

    #region Properties
    /// <summary>
    /// Gets the attitude (yaw, pitch, and roll) of the device, in radians.
    /// </summary>
    public MockAttitudeReading Attitude { get; internal set; }

    /// <summary>
    ///  Gets the linear acceleration of the device, in gravitational units.
    /// </summary>
    public Vector3 DeviceAcceleration { get; internal set; }

    /// <summary>
    /// Gets the rotational velocity of the device, in radians per second.
    /// </summary>
    public Vector3 DeviceRotationRate { get; internal set; }

    /// <summary>
    /// Gets the gravity vector associated with the Microsoft.Devices.Sensors.MotionReading.
    /// </summary>
    public Vector3 Gravity { get; internal set; }

    /// <summary>
    /// Gets a timestamp indicating the time at which the accelerometer reading was
    ///     taken. This can be used to correlate readings across sensors and provide
    ///     additional input to algorithms that process raw sensor data.
    /// </summary>
    public DateTimeOffset Timestamp { get; internal set; }
    #endregion

    #region Constructors

    /// <summary>
    /// Initialize an instance from an actual MotionReading
    /// </summary>
    /// <param name="cr"></param>
    public MockMotionReading(MotionReading cr)
        : this()
    {
        this.Attitude = new MockAttitudeReading(cr.Attitude);
        this.DeviceAcceleration = cr.DeviceAcceleration;
        this.DeviceRotationRate = cr.DeviceRotationRate;
        this.Gravity = cr.Gravity;
        this.Timestamp = cr.Timestamp;
    }

    /// <summary>
    /// Create an instance initialized with testing data
    /// </summary>
    /// <param name="test"></param>
    public MockMotionReading(bool test) 
        : this()
    {
        float pitch = 0.01f;
        float roll = 0.02f;
        float yaw = 0.03f;

        this.Attitude = new MockAttitudeReading()
        {
            Pitch = pitch,
            Roll = roll,
            Yaw = yaw,
            RotationMatrix = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll),  
            Quaternion = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll), 

            Timestamp = DateTimeOffset.Now
        };

        // TODO: pull data from the Accelerometer
        this.Gravity = new Vector3(0, 0, 1f);
    }

    /// <summary>
    /// Create a new mock instance based on the previous mock instance
    /// </summary>
    /// <param name="lastCompassReading"></param>
    public MockMotionReading(MockMotionReading lastCompassReading)
        : this()
    {
        // Adjust the pitch, roll, and yaw as required.

        // -90 to 90 deg
        float pitchDegrees = MathHelper.ToDegrees(lastCompassReading.Attitude.Pitch) - 0.5f;
        //pitchDegrees = ((pitchDegrees + 90) % 180) - 90;

        // -90 to 90 deg
        float rollDegrees = MathHelper.ToDegrees(lastCompassReading.Attitude.Roll);
        //rollDegrees = ((rollDegrees + 90) % 180) - 90;

        // 0 to 360 deg
        float yawDegrees = MathHelper.ToDegrees(lastCompassReading.Attitude.Yaw) + 0.5f;
        //yawDegrees = yawDegrees % 360;

        float pitch = MathHelper.ToRadians(pitchDegrees);
        float roll = MathHelper.ToRadians(rollDegrees);
        float yaw = MathHelper.ToRadians(yawDegrees);

        this.Attitude = new MockAttitudeReading()
        {
            Pitch = pitch,
            Roll = roll,
            Yaw = yaw,
            RotationMatrix = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll),
            Quaternion = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll),

            Timestamp = DateTimeOffset.Now
        };

        this.DeviceAcceleration = lastCompassReading.DeviceAcceleration;
        this.DeviceRotationRate = lastCompassReading.DeviceRotationRate;
        this.Gravity = lastCompassReading.Gravity;
        Timestamp = DateTime.Now;

    }
    #endregion



}
public struct MockAttitudeReading : ISensorReading
{
    public MockAttitudeReading(AttitudeReading attitudeReading) : this()
    {
        Pitch = attitudeReading.Pitch;
        Quaternion = attitudeReading.Quaternion;
        Roll = attitudeReading.Roll;
        RotationMatrix = attitudeReading.RotationMatrix;
        Timestamp = attitudeReading.Timestamp;
        Yaw = attitudeReading.Yaw;
    }

    /// <summary>
    /// Gets the pitch of the attitude reading in radians.
    /// </summary>
    public float Pitch { get; set; }

    /// <summary>
    /// Gets the quaternion representation of the attitude reading.
    /// </summary>
    public Quaternion Quaternion { get; set; }

    /// <summary>
    /// Gets the roll of the attitude reading in radians.
    /// </summary>
    public float Roll { get; set; }

    /// <summary>
    /// Gets the matrix representation of the attitude reading.
    /// </summary>
    public Matrix RotationMatrix { get; set; }

    /// <summary>
    /// Gets a timestamp indicating the time at which the accelerometer reading was
    ///     taken. This can be used to correlate readings across sensors and provide
    ///     additional input to algorithms that process raw sensor data.
    /// </summary>
    public DateTimeOffset Timestamp { get; set; }

    /// <summary>
    /// Gets the yaw of the attitude reading in radians.
    /// </summary>
    public float Yaw { get; set; }
}
//
///提供有关设备方向和运动的Windows Phone应用程序模拟信息。
/// 
公共类MockMotionWrapper:MotionWrapper
{
/// 
///使用计时器触发模拟数据更新。
/// 
专用调度定时器;
private MockMotionReading lastCompassReading=新建MockMotionReading(真);
#区域属性
/// 
///获取或设置Microsoft.Devices.Sensors.SensorBase.CurrentValueChanged事件之间的首选时间。
/// 
更新之间的公共覆盖时间跨度时间
{
得到
{
返回计时器。间隔;
}
设置
{
计时器。间隔=值;
}
}
#端区
#区域构造函数
公共模拟包装器()
{
计时器=新调度程序();
计时器间隔=Ti