using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace MSP_Input
{
public class GyroAccel : MonoBehaviour
{
public bool forceAccelerometer = false;
public float smoothingTime = 0.1f;
public float headingOffset;
public float pitchOffset = 30.0f;
public float pitchOffsetMinimum = -70f;
public float pitchOffsetMaximum = 70f;
public float gyroHeadingAmplifier = 1f;
public float gyroPitchAmplifier = 1f;
//
[HideInInspector]
private Quaternion rotation = Quaternion.identity;
[HideInInspector]
public float heading;
[HideInInspector]
public float pitch;
[HideInInspector]
public float roll;
[System.Serializable]
public class AutoUpdateList
{
public Transform targetTransform;
public bool copyHeading = true;
public bool copyPitch = true;
public bool copyRoll = true;
public bool enabled = true;
public float headingMin = -180f;
public float headingMax = 180f;
public float headingDefault = 0f;
public float pitchMin = -90f;
public float pitchMax = 90f;
public float pitchDefault = 0f;
public float rollMin = -180f;
public float rollMax = 180f;
public float rollDefault = 0f;
public float smoothingTime = 0f;
}
public AutoUpdateList selfUpdate;
public List<AutoUpdateList> autoUpdateList = new List<AutoUpdateList>();
// STATIC VARIABLES:
static private bool _forceAccelerometer;
static private float _smoothingTime;
static private float _headingOffset;
static private float _pitchOffset;
static private float _pitchOffsetMinimum;
static private float _pitchOffsetMaximum;
static private float _gyroHeadingAmplifier;
static private float _gyroPitchAmplifier;
//
static private Quaternion _rotation = Quaternion.identity;
static private float _heading;
static private float _pitch;
static private float _roll;
//
static private string _transformName;
static private AutoUpdateList _selfUpdate;
static private List<AutoUpdateList> _autoUpdateList = new List<AutoUpdateList>();
//================================================================================
void Awake()
{
Input.compensateSensors = true;
Input.gyro.enabled = true;
_forceAccelerometer = forceAccelerometer;
_smoothingTime = smoothingTime;
_headingOffset = headingOffset;
_pitchOffset = pitchOffset;
_pitchOffsetMinimum = pitchOffsetMinimum;
_pitchOffsetMaximum = pitchOffsetMaximum;
_gyroHeadingAmplifier = gyroHeadingAmplifier;
_gyroPitchAmplifier = gyroPitchAmplifier;
_selfUpdate = selfUpdate;
_autoUpdateList.Clear();
_autoUpdateList = autoUpdateList;
_transformName = transform.name;
}
//================================================================================
void Update()
{
if (!SystemInfo.supportsGyroscope)
{
forceAccelerometer = true;
ErrorHandling.LogError("Warning [GyroAccel]: No gyroscope available -> forcing accelerometer");
}
if (Application.isEditor && Input.gyro.attitude == Quaternion.identity)
{
MSP_Input.ErrorHandling.LogError("Warning [GyroAccel]: There seems to be a problem reading the gyroscope: did you set up Unity Remote correctly?");
}
//
forceAccelerometer = _forceAccelerometer;
smoothingTime = _smoothingTime;
headingOffset = _headingOffset;
pitchOffset = _pitchOffset;
pitchOffsetMinimum = _pitchOffsetMinimum;
pitchOffsetMaximum = _pitchOffsetMaximum;
gyroHeadingAmplifier = _gyroHeadingAmplifier;
gyroPitchAmplifier = _gyroPitchAmplifier;
selfUpdate = _selfUpdate;
autoUpdateList = _autoUpdateList;
//
CheckHeadingAndPitchBoundaries ();
//
if (!_forceAccelerometer && SystemInfo.supportsGyroscope) {
UpdateGyroscopeOrientation ();
} else {
UpdateAccelerometerOrientation ();
}
//
_rotation = rotation;
_heading = heading;
_pitch = pitch;
_roll = roll;
_headingOffset = headingOffset;
_pitchOffset = pitchOffset;
//
}
//================================================================================
void LateUpdate ()
{
AutoUpdate ();
}
//================================================================================
void UpdateGyroscopeOrientation()
{
Quaternion gyroQuat = Input.gyro.attitude;
Quaternion A = new Quaternion(0.5f,0.5f,-0.5f,0.5f);
Quaternion B = new Quaternion(0f,0f,1f,0f);
gyroQuat = A * gyroQuat * B;
//
float devicePitch;
float deviceRoll;
GetDevicePitchAndRollFromGravityVector(out devicePitch, out deviceRoll);
//
float rcosin = Mathf.Cos(Mathf.Deg2Rad * deviceRoll);
float rsinus = Mathf.Sin(Mathf.Deg2Rad * deviceRoll);
//
float deltaHeading;
deltaHeading = (-Input.gyro.rotationRateUnbiased.x * rsinus - Input.gyro.rotationRateUnbiased.y * rcosin);
gyroHeadingAmplifier = Mathf.Clamp(gyroHeadingAmplifier,0.1f,4f);
deltaHeading *= (gyroHeadingAmplifier-1f);
headingOffset += deltaHeading;
//
float deltaPitch;
deltaPitch = (-Input.gyro.rotationRateUnbiased.y * rsinus + Input.gyro.rotationRateUnbiased.x * rcosin);
gyroPitchAmplifier = Mathf.Clamp(gyroPitchAmplifier,0.1f,4f);
deltaPitch *= (gyroPitchAmplifier-1f);
if (devicePitch > pitchOffsetMinimum && devicePitch < pitchOffsetMaximum) {
pitchOffset += deltaPitch;
}
if (devicePitch <= pitchOffsetMinimum) {
pitchOffset -= Mathf.Abs(deltaPitch);
}
if (devicePitch >= pitchOffsetMaximum) {
pitchOffset += Mathf.Abs(deltaPitch);
}
//
CheckHeadingAndPitchBoundaries();
// PITCH OFFSET:
Vector3 gyro_forward = gyroQuat * Vector3.forward;
Vector3 rotAxis = Vector3.Cross(Vector3.up,gyro_forward);
AnimationCurve devicePitchAdjustmentCurve = new AnimationCurve(new Keyframe(-90f, 0f), new Keyframe(pitchOffset, -pitchOffset), new Keyframe(90f, 0f));
Quaternion extra_pitch = Quaternion.AngleAxis(devicePitchAdjustmentCurve.Evaluate(devicePitch),rotAxis);
gyroQuat = extra_pitch * gyroQuat;
// HEADING OFFSET:
Quaternion extra_heading = Quaternion.AngleAxis(headingOffset,Vector3.up);
gyroQuat = extra_heading * gyroQuat;
// Smooth gyro quaternion
float smoothFactor = (smoothingTime > Time.deltaTime) ? Time.deltaTime / smoothingTime : 1f;
rotation = Quaternion.Slerp(rotation, gyroQuat, smoothFactor);
// Compute heading, pitch, roll
Vector3 rf = rotation * Vector3.forward;
Vector3 prf = Vector3.Cross(Vector3.up,Vector3.Cross(rf,Vector3.up));
float newHeading = Vector3.Angle(Vector3.forward,prf) * Mathf.Sign (rf.x);
AnimationCurve headingSmoothCurve = new AnimationCurve(new Keyframe(-90f, 0f, 0f, 0f),
new Keyframe(-85, smoothFactor, 0f, 0f),
new Keyframe(85f, smoothFactor, 0f, 0f),
new Keyframe(90f,0f,0f,0f));
heading = Mathf.LerpAngle(heading,newHeading,headingSmoothCurve.Evaluate(pitch));
pitch = Mathf.LerpAngle(pitch,devicePitch+devicePitchAdjustmentCurve.Evaluate(devicePitch),smoothFactor);
roll = Mathf.LerpAngle(roll,deviceRoll,smoothFactor);
} // void UpdateGyroscopeOrientation()
//================================================================================
void UpdateAccelerometerOrientation()
{
float devicePitch;
float deviceRoll;
GetDevicePitchAndRollFromGravityVector(out devicePitch, out deviceRoll);
//
AnimationCurve devicePitchAdjustmentCurve = new AnimationCurve(new Keyframe(-90f, 0f), new Keyframe(pitchOffset, -pitchOffset), new Keyframe(90f, 0f));
Quaternion accelQuat = Quaternion.identity;
accelQuat = GetQuaternionFromHeadingPitchRoll(headingOffset, devicePitch+devicePitchAdjustmentCurve.Evaluate(devicePitch), deviceRoll);
// Smooth gyro quaternion
float smoothFactor = (smoothingTime > Time.deltaTime) ? Time.deltaTime / smoothingTime : 1f;
rotation = Quaternion.Slerp(rotation, accelQuat, smoothFactor);
// Compute heading, pitch, roll
heading = Mathf.LerpAngle(heading,headingOffset,smoothFactor);
pitch = Mathf.LerpAngle(pitch,devicePitch+devicePitchAdjustmentCurve.Evaluate(devicePitch),smoothFactor);
roll = Mathf.LerpAngle(roll,deviceRoll,smoothFactor);
} // void UpdateAccelerometerOrientation()
//================================================================================
void AutoUpdate()
{
float h;
float p;
float r;
Quaternion rot;
float smoothFactor;
if (selfUpdate.enabled)
{
if (selfUpdate.copyHeading && selfUpdate.copyPitch && selfUpdate.copyRoll && selfUpdate.headingMin == -180f && selfUpdate.headingMax == 180f && selfUpdate.pitchMin == -90f && selfUpdate.pitchMax == 90f && selfUpdate.rollMin
== -180f && selfUpdate.rollMax == 180f)
{
smoothFactor = (selfUpdate.smoothingTime > Time.deltaTime) ? Time.deltaTime / selfUpdate.smoothingTime : 1f;
transform.rotation = Quaternion.Lerp(transform.rotation,_rotation,smoothFactor);
} else {
h = selfUpdate.copyHeading ? _heading : selfUpdate.headingDefault;
if (h>180f) h-=360f;
h = Mathf.Clamp(h,selfUpdate.headingMin,selfUpdate.headingMax);
//
p = selfUpdate.copyPitch ? _pitch : selfUpdate.pitchDefault;
p = Mathf.Clamp(p,selfUpdate.pitchMin,selfUpdate.pitchMax);
//
r = selfUpdate.copyRoll ? _roll : selfUpdate.rollDefault;
if (r>180f) r-=360f;
r = Mathf.Clamp(r,selfUpdate.rollMin,selfUpdate.rollMax);
//
rot = MSP_Input.GyroAccel.GetQuaternionFromHeadingPitchRoll(h,p,r);
smoothFactor = (selfUpdate.smoothingTime > Time.deltaTime) ? Time.deltaTime / selfUpdate.smoothingTime : 1f;
transform.rotation = Quaternion.Lerp(transform.rotation,rot,smoothFactor);
}
}
foreach (AutoUpdateList aut in autoUpdateList)
{
if (aut.targetTransform && aut.enabled)
{
if (aut.copyHeading && aut.copyPitch && aut.copyRoll && aut.headingMin == -180f && aut.headingMax == 180f && aut.pitchMin == -90f && aut.pitchMax == 90f && aut.rollMin == -180f && aut.rollMax == 180f)
{
smoothFactor = (aut.smoothingTime > Time.deltaTime) ? Time.deltaTime / aut.smoothingTime : 1f;
aut.targetTransform.rotation = Quaternion.Lerp(aut.targetTransform.rotation,_rotation,smoothFactor);
} else {
h = aut.copyHeading ? _heading : aut.headingDefault;
if (h>180f) h-=360f;
h = Mathf.Clamp(h,aut.headingMin,aut.headingMax);
//
p = aut.copyPitch ? _pitch : aut.pitchDefault;
p = Mathf.Clamp(p,aut.pitchMin,aut.pitchMax);
//
r = aut.copyRoll ? _roll : aut.rollDefault;
if (r>180f) r-=360f;
r = Mathf.Clamp(r,aut.rollMin,aut.rollMax);
//
rot = MSP_Input.GyroAccel.GetQuaternionFromHeadingPitchRoll(h,p,r);
smoothFactor = (aut.smoothingTime > Time.deltaTime) ? Time.deltaTime / aut.smoothingTime : 1f;
aut.targetTransform.rotation = Quaternion.Lerp(aut.targetTransform.rotation,rot,smoothFactor);
}
}
}
} // void AutoUpdate()
//================================================================================
static public void GetDevicePitchAndRollFromGravityVector(out float devicePitch, out float deviceRoll)
{
if (!SystemInfo.supportsGyroscope && !SystemInfo.supportsAccelerometer)
{
devicePitch = 0f;
deviceRoll = 0f;
} else {
Input.gyro.enabled = true;
// Vector holding the direction of gravity
Vector3 gravity = Input.gyro.gravity;
// find the projections of the gravity vector on the YZ-plane
Vector3 gravityProjectedOnXYplane = Vector3.Cross (Vector3.forward, Vector3.Cross (gravity, Vector3.forward));
// calculate the pitch = rotation around x-axis ("dive forward/backward")
devicePitch = Vector3.Angle (gravity, Vector3.forward) - 90;
// calculate the roll = rotation around z-axis ("steer left/right")
deviceRoll = Vector3.Angle (gravityProjectedOnXYplane, -Vector3.up) * Mathf.Sign (Vector3.Cross (gravityProjectedOnXYplane, Vector3.down).z);
AnimationCurve rollAdjustmentCurve = new AnimationCurve (new Keyframe (-90f, 0f), new Keyframe (-80f, 1f), new Keyframe (80f, 1f), new Keyframe (90f, 0f));
deviceRoll *= rollAdjustmentCurve.Evaluate (devicePitch);
}
} // static public void GetDevicePitchAndRollFromGravityVector(out float devicePitch, out float deviceRoll)
//================================================================================
void CheckHeadingAndPitchBoundaries()
{
if (heading > 360f)
{
heading -=360f;
}
if (heading < 0f)
{
heading += 360f;
}
//
if (pitchOffset < pitchOffsetMinimum)
{
pitchOffset = pitchOffsetMinimum;
}
if (pitchOffset > pitchOffsetMaximum)
{
pitchOffset = pitchOffsetMaximum;
}
} // void CheckHeadingAndPitchBoundaries()
//================================================================================
static public Quaternion GetQuaternionFromHeadingPitchRoll(float inputHeading, float inputPitch, float inputRoll)
{
Quaternion returnQuat = Quaternion.Euler(0f,inputHeading,0f) * Quaternion.Euler(inputPitch,0f,0f) * Quaternion.Euler(0f,0f,inputRoll);
return returnQuat;
} // static public Quaternion GetQuaternionFromHeadingPitchRoll(float inputHeading, float inputPitch, float inputRoll)
//================================================================================
// public Get functions:
//================================================================================
static public Quaternion GetRotation()
{
return _rotation;
}
//================================================================================
static public float GetHeading()
{
return _heading;
}
//================================================================================
static public float GetPitch()
{
return _pitch;
}
//================================================================================
static public float GetRoll()
{
return _roll;
}
//================================================================================
static public void GetHeadingPitchRoll(out float h, out float p, out float r)
{
h = _heading;
p = _pitch;
r = _roll;
}
//================================================================================
static public float GetHeadingOffset()
{
return _headingOffset;
}
//================================================================================
static public float GetPitchOffset()
{
return _pitchOffset;
}
//================================================================================
static public float GetSmoothingTime()
{
return _smoothingTime;
}
//================================================================================
static public float GetGyroHeadingAmplifier()
{
return _gyroHeadingAmplifier;
}
//================================================================================
static public float GetGyroPitchAmplifier()
{
return _gyroPitchAmplifier;
}
//================================================================================
static public bool GetForceAccelerometer()
{
return _forceAccelerometer;
}
//================================================================================
// public Set/Add functions:
//================================================================================
static public void SetHeading(float newHeading)
{
while (newHeading < -180f)
{
newHeading += 360f;
}
while (newHeading > 180f)
{
newHeading -= 360f;
}
SetHeadingOffset(_headingOffset - _heading + newHeading);
}
//================================================================================
static public void SetHeadingOffset(float newHeadingOffset)
{
_headingOffset = newHeadingOffset;
}
//================================================================================
static public void SetPitch(float newPitch)
{
newPitch = Mathf.Clamp (newPitch, -90f, 90f);
float devicePitch;
float deviceRoll;
GetDevicePitchAndRollFromGravityVector(out devicePitch, out deviceRoll);
SetPitchOffset (devicePitch - newPitch);
}
//================================================================================
static public void SetPitchOffset(float newPitchOffset)
{
_pitchOffset = newPitchOffset;
}
//================================================================================
static public void SetPitchOffsetMinumumMaximum(float newPitchOffsetMinimum, float newPitchOffsetMaximum)
{
_pitchOffsetMinimum = newPitchOffsetMinimum;
_pitchOffsetMaximum = newPitchOffsetMaximum;
}
//================================================================================
static public void SetGyroHeadingAmplifier(float newValue)
{
_gyroHeadingAmplifier = newValue;
}
//================================================================================
static public void SetGyroPitchAmplifier(float newValue)
{
_gyroPitchAmplifier = newValue;
}
//================================================================================
static public void SetSmoothingTime(float smoothTime)
{
_smoothingTime = smoothTime;
}
//================================================================================
static public void SetForceAccelerometer(bool newValue)
{
_forceAccelerometer = newValue;
}
//================================================================================
static public void AddFloatToHeadingOffset(float extraHeadingOffset)
{
_headingOffset += extraHeadingOffset;
}
//================================================================================
static public void AddFloatToPitchOffset(float extraPitchOffset)
{
_pitchOffset += extraPitchOffset;
}
//================================================================================
static public void EnableAutoUpdate()
{
_selfUpdate.enabled = true;
return;
}
//================================================================================
static public void EnableAutoUpdate(string name)
{
if (name == "self" || name == "Self" || name == _transformName)
{
_selfUpdate.enabled = true;
return;
}
foreach (AutoUpdateList aut in _autoUpdateList)
{
if (name == aut.targetTransform.name)
{
aut.enabled = true;
return;
}
}
MSP_Input.ErrorHandling.LogError("Warning [GyroAccel]: You are trying to enable AutoUpdate on object "+name+", but this object doesn't exist in the AutoUpdateList.");
return;
}
//================================================================================
static public void DisableAutoUpdate()
{
_selfUpdate.enabled = false;
return;
}
//================================================================================
static public void DisableAutoUpdate(string name)
{
if (name == "self" || name == "Self" || name == _transformName)
{
_selfUpdate.enabled = false;
return;
}
foreach (AutoUpdateList aut in _autoUpdateList)
{
if (name == aut.targetTransform.name)
{
aut.enabled = false;
return;
}
}
MSP_Input.ErrorHandling.LogError("Warning [GyroAccel]: You are trying to disable AutoUpdate on object "+name+", but this object doesn't exist in the AutoUpdateList.");
return;
}
//================================================================================
} // public class GyroAccel : MonoBehaviour
} // namespace MSP_Input
unity 陀螺儀的腳本
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
STC15F2K60S2/STC15系列讀取MPU6050陀螺儀角度加速度串口顯示程序代碼
程序猎人-007
2018-08-22 03:00:27
A Robust and Easy to Implement Method for IMU Calibration without
木独
2020-06-26 15:40:28
MPU9250和ICM20948區別(含詳細對比和遷移方案)電源設計部分要注意
灵魂新纪元
2020-05-21 00:52:27
更改MPU6050的IIC端口
大写的小写字母
2020-05-03 03:24:44
無人機中的IMU單元(MEMS 三軸加速計、三軸陀螺儀、三軸磁力計)
qq_35379989
2020-03-02 20:39:37
基於無跡卡爾曼濾波器(UKF)的9軸IMU姿態解算算法
木独
2020-02-23 00:39:32
ios檢測設備攝像頭、指南針、錄音、陀螺儀的狀態
穿马甲的小样
2020-02-22 20:22:48
iOS 搖一搖,陀螺儀,距離傳感器,計步器簡單介紹
sw_gegewu
2020-02-22 06:47:07
Allan Variance:傳感器隨機誤差實驗代碼(matlab)
print("滚去学习")
2020-02-21 15:17:50
安卓系統通過"陀螺儀"計算當前座標(焦點位置)
大昱
2019-02-03 02:22:35
Unity3D中的地形轉成模型
2537God
2018-09-04 06:08:39
【翻譯】加速度計和陀螺儀指南
gmdjmawy
2018-08-28 13:04:06
四元數,歐拉角和旋轉矩陣之間的互相轉換
taohaiwu
2018-08-27 22:07:51
ios中的陀螺儀和加速計
Kevin_Rao
2018-08-23 02:33:22
STC15W4K32S4讀取MPU6050陀螺儀角度加速度串口顯示程序代碼
程序猎人-007
2018-08-22 03:00:27