ros2中的磁力记如何校准

获取数据

磁力计由于自身精度与环境的影响都是有误差的,磁力计的X,Y,Z轴的数值在实际中是椭球的形状,下面代码可以获取ros2中的磁力计数值保存为一个名为data.txt的文件

import rclpy
from rclpy.node import Node

from nav_msgs.msg import Path,Odometry

from sensor_msgs.msg import NavSatFix,Imu
from geometry_msgs.msg import PoseStamped,Quaternion,Vector3,Pose,PoseWithCovariance,PoseArray,Point,Pose
from visualization_msgs.msg import Marker

import pyproj
import numpy as np

from tf_transformations import euler_from_quaternion,quaternion_from_euler
import math
import matplotlib.pyplot as plt

class controlNode(Node):
    def __init__(self):
        super().__init__('compass_node')  
        self.imu = self.create_subscription(
            Vector3,
            'compass',
            self.compass_callback,
            10)
        self.data = []
        timer_period = 0.1  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)


    def timer_callback(self):
        # print(len(self.data))
        # if len > 100:
        pass

    def compass_callback(self,msg):
        x = int(msg.x)
        y = int(msg.y)
        z = int(msg.z)
        # print(x,y,z)

        with open(file="./data.txt",mode="a",encoding="utf-8") as f:
            data=f.write(str(x) + ' ' + str(y) + ' '  + str(z) + '\r')
            print(data)

        # self.data.append([x,y,z])
        # print(x)

def main(args=None):
    rclpy.init(args=args)
    minimal_subscriber = controlNode()
    rclpy.spin(minimal_subscriber)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

数据的格式看起来是这个样子的
在这里插入图片描述

拟合球体

使用最小二乘法拟合磁力计的圆心位置,在python中有可以直接使用的工具scipy.optimize.leastsq,下面代码调用刚刚获取的磁力计数值,然后拟合出圆心的位置与直径

import numpy as np
from scipy.optimize import leastsq
import matplotlib.pyplot as plt
import threading
import time
import rclpy
from rclpy.node import Node

import compassAdjust


with open(file="./data.txt",mode="r",encoding="utf-8") as f:
    lines = f.read().split()

numbers = []
for line in lines:
    number = int(line)
    numbers.append(number)
arr = np.array(numbers).reshape(-1,3)
x = arr[:,0]
y = arr[:,1]
z = arr[:,2]

def sphere_func(params, x, y, z):
    x0, y0, z0, r = params
    return (((x - x0) ** 2 + (y - y0) ** 2 + (z - z0) ** 2) - r ** 2)

initial_params = np.array([0.0, 0.0, 0.0, 10.0])
# 拟合
params, covariance = leastsq(lambda p: sphere_func(p, x, y, z), initial_params)
print("拟合参数:", params)
print("误差:", covariance)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x,y,z)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

plt.show()

将磁力计数据绘制成了一个椭球,并且输出了圆心坐标与半径
在这里插入图片描述
在这里插入图片描述
将磁力计数值分别减去拟合的参数,重新获取数据然后拟合这个时候圆心的坐标已经很接近0了
在这里插入图片描述

方位角

磁力计是在每一个轴上的磁力数值,传感器正常使用肯定会有一点倾斜的,肯定会有roll和pitch角。只要飞机倾斜,磁力计测得的磁场强度就不是真正的水平X,Y轴上的分量了,下面代码head是方位角,ypr是传感器放置的yaw,pitch,row角度,error是刚拟合的圆心数值,这样就求出了准确的方位角了

void IMU::headCalcu(float *head,sensors_vec_t compass,float *ypr,float *error){
    float xh,yh;

    float x = compass.x - error[0];
    float y = compass.y - error[1];
    float z = compass.z - error[2];

    xh = x*cos(ypr[1]) + y*sin(ypr[2])*sin(ypr[1]) - z*cos(ypr[2])*sin(ypr[1]);
    yh = y*cos(ypr[2]) + z*sin(ypr[2]);

    *head = atan2(yh, xh) ;
}

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值