3

Windows Phone 7.1 (Mango) 用の小さなサンプル アプリケーションを作成しており、Combined Motion API を使用してデバイスの動きを表示したいと考えています。デバイスのすべてのセンサーをサポートしていないエミュレーターを使用するときにアプリケーションをテストできるようにするには、モック クラスを作成する必要があります。

コンパスをシミュレートする (回転デバイスをシミュレートするだけ) ための簡単なモック クラスと、エミュレータで実際に使用できる加速度計を既に作成しました。

ここで、モーション API 用の新しいモック オブジェクトを作成する必要がありますが、コンパスと加速度計の値を使用して、モーション オブジェクトに使用される値を計算できることを願っています。残念ながら、すでにこれを行っている単純な変換のサンプルは見つかりませんでした。

この変換を行うコードサンプルを知っている人はいますか? これが複雑になるのと同じくらい、解決策が既にある場合、私は自分でこれをやりたくありません。

4

2 に答える 2

1

モックアップ作業を行うための良い出発点は、モーション API と、それが内部でどのように機能するか、API コアで使用されるパラメーターを確認することです。

http://msdn.microsoft.com/en-us/library/hh202984%28VS.92%29.aspx

先に進む前に、Motion API は、さまざまな電話センサーの入力を組み合わせた複雑な数学的モデルであることを覚えておいてください。加速度、位置、および回転を組み合わせてモーションを計算するさまざまなモデルを見つけることができます。この記事で見つけることができる 1 つの適切な説明:

http://www.instructables.com/id/Accelerometer-Gyro-Tutorial/

したがって、実際には、上記の記事に示されている方程式と関数を使用して、自分で値を計算する必要があります。

単純なことではありませんが、このように可能です。

私はあなたを助けることができたことを願っています:)そしてあなたがそれをしたなら、コミュニティに知らせてください. コードプレックス プロジェクトは、Windows Phone モーション API 用の一種のモック ユーティリティを作成するのに適していると思います。

于 2012-03-14T16:59:27.130 に答える
1

Windows Phone 8 がリリースされ、まだテストするハンドセットを持っていないため、同じ問題に再び遭遇しました。

エミュレーターを使用する場合の WP7 Mock Microsoft.Devices.Sensors.Compassへの回答と同様に、モーション API と同じメソッドを使用してラッパー クラスを作成しました。実際の Motion API がサポートされている場合は、それが使用されます。それ以外の場合、デバッグ モードでは、ロール、ピッチ、およびヨーを変化させるモック データが返されます。


モーションラッパー

    /// <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();
        }
    }

モックモーションラッパー

    /// <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; }
}
于 2012-12-14T18:51:02.963 に答える