rospy通过matplotlib画出/odom轨迹图

注意事项

  1. Python没有回调函数这个东西,所以ROS中回调函数的实现其实是通过多线程来解决的
  2. 又因为是多线程,所以其实rospy.spin()并不是必须的,只要确保主线程(main)存活那么rospy中的回调函数就可以一直接收数据

代码

实现了同时监听两个 /odom 并画图进行对比

import rospy
from matplotlib import pyplot as plt
from nav_msgs.msg import Odometry
import numpy as np
import time

class DrawError(object):
    odom_time, cb_time = 0, 0
    x_odom = []
    y_odom = []
    x_rf2o = []
    y_rf2o = []
    def __init__(self):
        pass
    def isCBAlive(self):
        return False if self.cb_time - self.odom_time > 2 else True
    
    def odomCallBack(self, data):
        self.x_odom.append(data.pose.pose.position.x)
        self.y_odom.append(data.pose.pose.position.y)
        self.odom_time = time.time()

    def rf2oCallBack(self, data):
        self.x_rf2o.append(data.pose.pose.position.x)
        self.y_rf2o.append(data.pose.pose.position.y)

    # check if data is not received. If so, exit and plot the figure
    def cbMonitor(self, plt):
        self.cb_time = time.time()
        if not self.isCBAlive():
            rospy.logwarn("No data received!Exit!")
            return True
        else:
            return False


if __name__ == "__main__":
    rospy.init_node("drawingError")
    de = DrawError()

    # gazebo's odom, without nosie
    rospy.Subscriber("odom", Odometry, de.odomCallBack)
    # rf2o_odometry's odom
    rospy.Subscriber("odom_rf2o", Odometry, de.rf2oCallBack)
    rospy.Timer(rospy.Duration(2), de.cbMonitor)
    plt.title("odom display")

    while not rospy.is_shutdown():
        if de.cbMonitor(plt) == True:
            break
    plt.plot(de.x_odom, de.y_odom, color="b", label="/odom")
    plt.plot(de.x_rf2o, de.y_rf2o, color="r", label="/odom_rf2o")
    plt.legend()
    plt.show()

最终效果

在这里插入图片描述

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于ROS的扩展卡尔曼滤波算法的示例代码,其订阅了小车的里程计数据,并通过扩展卡尔曼滤波算法来估算出下一时刻小车的x轴和y轴坐标,并将估算出的坐标绘制成2D像。 ``` import rospy from nav_msgs.msg import Odometry from sensor_msgs.msg import Imu from geometry_msgs.msg import Twist, Pose, Point, Quaternion from std_msgs.msg import Int32MultiArray import numpy as np import math import tf class EKF: def __init__(self): self.P = np.eye(3) # 初始误差协方差矩阵 self.Q = np.diag([0.01, 0.01, 0.01]) # 系统噪声协方差矩阵 self.R = np.diag([0.01, 0.01, 0.01]) # 测量噪声协方差矩阵 self.x = np.zeros((3, 1)) # 状态矩阵 def predict(self, dt, v, w): # 计算状态转移矩阵 F = np.array([[1, 0, -v/w*math.cos(self.x[2])*dt], [0, 1, -v/w*math.sin(self.x[2])*dt], [0, 0, 1]]) # 计算输入控制矩阵 B = np.array([[math.cos(self.x[2])*dt, 0], [math.sin(self.x[2])*dt, 0], [0, dt]]) # 计算控制输入矩阵 u = np.array([[v], [w]]) # 计算状态转移方程 self.x = self.x + np.dot(F, self.x) + np.dot(B, u) # 计算误差协方差矩阵 self.P = np.dot(np.dot(F, self.P), F.T) + self.Q def update(self, z): # 计算观测矩阵 H = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # 计算卡尔曼增益 K = np.dot(np.dot(self.P, H.T), np.linalg.inv(np.dot(np.dot(H, self.P), H.T) + self.R)) # 更新状态矩阵和误差协方差矩阵 self.x = self.x + np.dot(K, (z - np.dot(H, self.x))) self.P = np.dot((np.eye(3) - np.dot(K, H)), self.P) class Car: def __init__(self): rospy.init_node('car_ekf', anonymous=True) self.rate = rospy.Rate(10) self.ekf = EKF() self.x = [] self.y = [] self.pub = rospy.Publisher('/car1/cmd_vel', Twist, queue_size=10) self.sub_odom = rospy.Subscriber('/car1/odom', Odometry, self.odom_callback) self.sub_imu = rospy.Subscriber('/car1/imu', Imu, self.imu_callback) self.sub_goal = rospy.Subscriber('/car1/goal', Int32MultiArray, self.goal_callback) def odom_callback(self, msg): # 获取里程计数据 x = msg.pose.pose.position.x y = msg.pose.pose.position.y theta = tf.transformations.euler_from_quaternion([msg.pose.pose.orientation.x, msg.pose.pose.orientation.y, msg.pose.pose.orientation.z, msg.pose.pose.orientation.w])[2] v = msg.twist.twist.linear.x w = msg.twist.twist.angular.z # 预测下一时刻的状态 self.ekf.predict(0.1, v, w) # 更新状态 self.ekf.update(np.array([[x], [y], [theta]])) # 记录估算出的位置 self.x.append(self.ekf.x[0, 0]) self.y.append(self.ekf.x[1, 0]) # 发布控制指令 cmd = Twist() cmd.linear.x = 0.1 cmd.angular.z = 0.1 self.pub.publish(cmd) def imu_callback(self, msg): pass def goal_callback(self, msg): pass def run(self): while not rospy.is_shutdown(): # 绘制估算出的位置 plt.figure() plt.plot(self.x, self.y) plt.show() self.rate.sleep() if __name__ == '__main__': car = Car() car.run() ``` 需要注意的是,上述代码的EKF类实现了扩展卡尔曼滤波算法,其predict方法用于预测下一时刻的状态,update方法用于更新状态,并且x矩阵的第1、2、3个元素分别表示小车的x轴和y轴坐标以及方向角度。在odom_callback方法,我们通过订阅小车的里程计数据,来获取小车的位置和速度信息,并使用扩展卡尔曼滤波算法来估算下一时刻小车的位置。最后,我们使用matplotlib库来绘制估算出的位置。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值