【问题标题】:I need to use the gyroscope sensor to get the orientation我需要使用陀螺仪传感器来获取方向
【发布时间】:2018-04-12 19:03:53
【问题描述】:

我正在研究 Xamarin,当我将手机在 0-360 度范围内转动时,我只需要使用陀螺仪传感器来获取手机在桌子上的方向。我已经使用这个传感器与加速度计的融合进行了探索,但我在 java 或 C# 中找不到可理解的代码。我还尝试使用陀螺仪读数来计算角度,但是当我快速转动它或延迟旋转手机时,传感器往往会给我带来不好的读数,同样会增加减少它们的度数。我在参考书目中读到应该将过滤器应用于计算,但我没有在 java 或 C# 中找到代码来测试。在这里,我放置了仅用于陀螺仪的代码。请原谅我的英语。

if (e.Sensor.Type == SensorType.Gyroscope)
                    {
                        mAzimuth = this.gyroFunction(e);
                    }   

public float gyroFunction(SensorEvent e)
             {
                        float[] deltaVector = new float[4];
                    if (timestamp != 0)
                    {
                        float dT = (e.Timestamp - timestamp) * NS2S;
                        Array.Copy(e.Values.ToArray(), 0, gyro, 0, 3);
                        getRotationVectorFromGyro(gyro, deltaVector, dT / 2.0f);
                    }

                    // measurement done, save current time for next interval
                    timestamp = e.Timestamp;

                    // convert rotation vector into rotation matrix
                    float[] deltaMatrix = new float[9];
                    SensorManager.GetRotationMatrixFromVector(deltaMatrix, deltaVector);

                    // apply the new rotation interval on the gyroscope based rotation matrix
                    gyroMatrix = matrixMultiplication(gyroMatrix, deltaMatrix);

                    // get the gyroscope based orientation from the rotation matrix
                    var angles = SensorManager.GetOrientation(gyroMatrix, gyroOrientation);
                    mAzimuth = (float)(this.RadianToDegree(angles[0]) + 360) % 360;
                    return mAzimuth;
             }

              private void getRotationVectorFromGyro(float[] gyroValues,
                                               float[] deltaRotationVector,
                                               float timeFactor)
        {
            float[] normValues = new float[3];

            // Calculate the angular speed of the sample
            float omegaMagnitude =
                (float)Math.Sqrt(gyroValues[0] * gyroValues[0] +
                                 gyroValues[1] * gyroValues[1] +
                                 gyroValues[2] * gyroValues[2]);

            // Normalize the rotation vector if it's big enough to get the axis
            if (omegaMagnitude > EPSILON)
            {
                normValues[0] = gyroValues[0] / omegaMagnitude;
                normValues[1] = gyroValues[1] / omegaMagnitude;
                normValues[2] = gyroValues[2] / omegaMagnitude;
            }

            // Integrate around this axis with the angular speed by the timestep
            // in order to get a delta rotation from this sample over the timestep
            // We will convert this axis-angle representation of the delta rotation
            // into a quaternion before turning it into the rotation matrix.
            float thetaOverTwo = omegaMagnitude * timeFactor;
            float sinThetaOverTwo = (float)Math.Sin(thetaOverTwo);
            float cosThetaOverTwo = (float)Math.Cos(thetaOverTwo);
            deltaRotationVector[0] = sinThetaOverTwo * normValues[0];
            deltaRotationVector[1] = sinThetaOverTwo * normValues[1];
            deltaRotationVector[2] = sinThetaOverTwo * normValues[2];
            deltaRotationVector[3] = cosThetaOverTwo;
        }

         private float[] matrixMultiplication(float[] A, float[] B)
        {
            float[] result = new float[9];

            result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6];
            result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7];
            result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8];

            result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6];
            result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7];
            result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8];

            result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6];
            result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7];
            result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8];

            return result;
        }

        private double RadianToDegree(
            double angle)
        {
            return angle * (180.0 / Math.PI);
        }

【问题讨论】:

    标签: xamarin android-sensors gyroscope


    【解决方案1】:

    我设法获得了一个工作代码版本,用于获取加速度计的位置。我正在使用 Xamarin.Essentials Nuget 数据包,代码如下:

    1. 首先,从微软文档中获得并稍作修改,我打开加速度计:

      public void ToggleAcceleromter()
      {
          try
          {
              if (Accelerometer.IsMonitoring)
              {
                  Accelerometer.Stop();
                  Accelerometer.ReadingChanged -= Accelerometer_ReadingChanged;
                  UserDialogs.Instance.Toast("Gyroscope mode disabled, tap again to enable.");
              }
              else
              {
                  Accelerometer.Start(SensorSpeed.Ui);
                  Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
                  UserDialogs.Instance.Toast("Gyroscope mode enabled, tap again to disable.");
              }
          }
          catch (FeatureNotSupportedException fnsEx)
          {
              UserDialogs.Instance.Toast("Gyroscope mode not supported in this device.");
          }
          catch (Exception ex)
          {
              UserDialogs.Instance.Toast("Gyroscope unkown error, please report tu bugs@xxxx.com");
          }
      }
      

    然后,在处理程序中,我使用了以下代码:

        void Accelerometer_ReadingChanged(AccelerometerChangedEventArgs e)
        {
            var data = e.Reading;
    
            var roll = Math.Atan(data.Acceleration.Y / Math.Sqrt(Math.Pow(data.Acceleration.X, 2.0) + Math.Pow(data.Acceleration.Z, 2.0)));
            var pitch = Math.Atan(data.Acceleration.X / Math.Sqrt(Math.Pow(data.Acceleration.Y, 2.0) + Math.Pow(data.Acceleration.Z, 2.0)));
            var yaw = Math.Atan(Math.Sqrt(Math.Pow(data.Acceleration.X, 2.0) + Math.Pow(data.Acceleration.Z, 2.0)) / data.Acceleration.Z);
    
            Debug.WriteLine("roll: " + roll.ToString() + ", pitch: " + pitch.ToString() + "yaw: " + yaw.ToString());
        }
    

    在这三个变量中,我们可以看到代表设备在三个不同轴上的位置的稳定数字。就我而言,我想获得一个从 0 到 100 的数字来表示前轴(俯仰)的运动。我用这段代码做到了,它显示了条目中的值并移动了一个滑块:

        double unsignedYaw = 0;
            if (pitch < 0) {
                unsignedYaw = pitch * -1;
            } else {
                unsignedYaw = pitch;
            }
    
            double scaleMiddle = 50;
            var scaledYaw = unsignedYaw * scaleMiddle / 0.5;
    
            double finalValue;
            if (pitch > 0) {
                finalValue = scaleMiddle + scaledYaw; 
            } else {
                finalValue = scaleMiddle - scaledYaw;
            }
    
            if (finalValue < 1) {
                moveValue.Text = "1";
                sliderSteps.Value = 1;
            } else if (finalValue > 1 && finalValue <= 100) {
                moveValue.Text = finalValue.ToString();
                sliderSteps.Value = finalValue;
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-07
      相关资源
      最近更新 更多