与指南针和陀螺仪的传感器融合:0 到 360 度之间
我正在开发一个小型室内导航应用程序,其中使用陀螺仪和指南针来确定设备方向。我使用陀螺仪来平滑指南针数据。我的传感器融合如下所示。这是我的motionHandler,一切都发生在其中。
// Listen to events from the motionManager
motionHandler = ^ (CMDeviceMotion *motion, NSError *error) {
__block float heading;
heading = mHeading;
CMAttitude *currentAttitude = motion.attitude;
//Initial heading setting
if (lastHeading == 0 && heading != 0) {
updatedHeading = heading;
}
lastHeading = heading;
if (oldQuaternion.w != 0 || oldQuaternion.x != 0 || oldQuaternion.y != 0 || oldQuaternion.z != 0){
diffQuaternion = [self multiplyQuaternions:[self inverseQuaternion:oldQuaternion] :currentAttitude.quaternion];
diffQuaternion = [self normalizeQuaternion:diffQuaternion];
}
oldQuaternion = currentAttitude.quaternion;
diffYaw = RADIANS_TO_DEGREES([self yawFromQuaternion:diffQuaternion]);
quaternion = currentAttitude.quaternion;
//Get Pitch
rpy.pitch = -[self pitchFromQuaternion:quaternion];
rpy.pitch += M_PI/2;
//Use Yaw-Difference for Heading
updatedHeading = updatedHeading - diffYaw;
//Heading has to be between 0 and 360 degrees
if (updatedHeading < 0) {
updatedHeading = 360 + updatedHeading;
}
else if (updatedHeading > 360) {
updatedHeading -= 360;
}
//fusionate gyro estimated heading with new magneticHeading
updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
//generate queternion
rotation = [self createFromAxisAngle:0 :rpy.pitch :DEGREES_TO_RADIANS(updatedHeading)];
};
实际的传感器融合公式如下:updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
。 这是我的 didUpdateHeading 函数,它接收最新的航向信息:
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// Get new heading
mHeading = newHeading.magneticHeading;
mHeading += 90;
if (mHeading > 360) {
mHeading -= 360;
}
}
diffYaw 是陀螺仪计算的航向的变化。 rotation
是最终的四元数。 除了一种特殊情况:在 0 度和 360 度之间的过渡处,这一切都很完美。
如果 updatedHeading
接近但小于 360,并且 mHeading
略高于 0,则结果会沿圆圈移动。例如,如果 updatedHeading
= 355 且 mHeading
= 5,正确的结果应该在 360 到 5 之间。但是我的公式计算出 337.5 度,这显然是完全错误的!
我认为这个问题必须有任何通用的解决方法......
I'm developing a small indoor navigation app in which I use the gyro and the compass for the device orientation. I use the gyro to smooth the compass data. My sensor fusion looks like the following. This is my motionHandler where everything happens.
// Listen to events from the motionManager
motionHandler = ^ (CMDeviceMotion *motion, NSError *error) {
__block float heading;
heading = mHeading;
CMAttitude *currentAttitude = motion.attitude;
//Initial heading setting
if (lastHeading == 0 && heading != 0) {
updatedHeading = heading;
}
lastHeading = heading;
if (oldQuaternion.w != 0 || oldQuaternion.x != 0 || oldQuaternion.y != 0 || oldQuaternion.z != 0){
diffQuaternion = [self multiplyQuaternions:[self inverseQuaternion:oldQuaternion] :currentAttitude.quaternion];
diffQuaternion = [self normalizeQuaternion:diffQuaternion];
}
oldQuaternion = currentAttitude.quaternion;
diffYaw = RADIANS_TO_DEGREES([self yawFromQuaternion:diffQuaternion]);
quaternion = currentAttitude.quaternion;
//Get Pitch
rpy.pitch = -[self pitchFromQuaternion:quaternion];
rpy.pitch += M_PI/2;
//Use Yaw-Difference for Heading
updatedHeading = updatedHeading - diffYaw;
//Heading has to be between 0 and 360 degrees
if (updatedHeading < 0) {
updatedHeading = 360 + updatedHeading;
}
else if (updatedHeading > 360) {
updatedHeading -= 360;
}
//fusionate gyro estimated heading with new magneticHeading
updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
//generate queternion
rotation = [self createFromAxisAngle:0 :rpy.pitch :DEGREES_TO_RADIANS(updatedHeading)];
};
The actual sensor fusion formula is this line: updatedHeading = (19.0*updatedHeading + 1.0*heading)/20.0;
.
And this is my didUpdateHeading-function which receives the newest heading-information:
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// Get new heading
mHeading = newHeading.magneticHeading;
mHeading += 90;
if (mHeading > 360) {
mHeading -= 360;
}
}
diffYaw
is the change of the heading computed by the gyroscope. rotation
ist the final quaternion.
This works perfect, except one particular case: at the transition between 0 und 360 degrees.
If updatedHeading
is near to but smaller than 360 and mHeading
is just above 0 the result moves in a circle. For example if updatedHeading
= 355 and mHeading
= 5, the correct result should be between 360 and 5. But my formula computes 337,5 degrees, which is clearly completly wrong!
There have to be any common workarounds for this problem, I think…
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我通常在这些类型的角度计算中执行类似以下操作:
其中angleDiff() 是:
您可能希望在此之后将updatedHeading 返回到0-360 范围内:
您的示例通过此计算给出了355.5。
I usually do something like the following in these types of angle computations:
where angleDiff() is:
You may want to get updatedHeading back in the 0-360 range after this by:
Your example gives 355.5 with this computation.