更新回调中的matplotlib图

问题描述

每当触发回调时,我都会尝试更新一个占用网格图。以下代码显示了回调,该回调将激光扫描数据作为输入(使用rospy),使用该数据更新占用网格图,然后为用户绘制网格图:

def lidar_callback(self,scan: LaserScan):
    scan_parameters = [scan.angle_min,scan.angle_max,scan.angle_increment]
    scan_ranges = np.array(scan.ranges)

    self.mapper.update_map(self.pose,scan_ranges,scan.angle_min,scan.angle_increment)

    fig = plt.figure()
    ax = self.fig.add_subplot(111)
    ax.matshow(self.mapper.probability_map(),cmap="Greys")
    plt.draw()

对于一次迭代,占用栅格图的输出如下:

Occupancy grid map for single lidar scan

但是,以上代码在触发回调时 都会创建一个新图,而不是保留一个图并在处理新的激光雷达数据时对其进行更新。由于lidar_callback()函数是更大的MapperNode类的一部分,因此我试图通过将fig变量移到__init__()的{​​{1}}构造函数中来解决此问题。类,提供以下代码

MapperNode

但是现在,在尝试定义class MapperNode: def __init__(self,pose: Pose,mapper: Mapper): self.pose = pose self.mapper = mapper rospy.Subscriber("scan",LaserScan,self.lidar_callback) rospy.Subscriber("odom",odometry,self.odometry_callback) self.fig = plt.figure() def lidar_callback(self,scan: LaserScan): scan_parameters = [scan.angle_min,scan.angle_increment] scan_ranges = np.array(scan.ranges) self.mapper.update_map(self.pose,scan.angle_increment) ax = self.fig.add_subplot(111) ax.matshow(self.mapper.probability_map(),cmap="Greys") plt.draw() 时使用self.fig时,出现以下错误

ax = self.fig.add_subplot(111)

因此,似乎无法在构造函数中定义ax = self.fig.add_subplot(111) AttributeError: 'MapperNode' object has no attribute 'fig' 对象,以后再在该类的另一个函数中使用它。有人知道我在尝试更新回调中的现有图形时犯什么错误吗?如果有更好的方法显示/更新占用率网格图,我将非常高兴知道这一点。谢谢!

解决方法

您可以尝试一下

import matplotlib.pyplot as plt
import rospy
import tf
from sensor_msgs.msg import LaserScan
from tf.transformations import quaternion_matrix
import numpy as np
from matplotlib.animation import FuncAnimation

class Visualiser:
    def __init__(self):
        self.fig,self.ax = plt.subplots()
        self.ln,= plt.plot([],[],'ro')
        self.max_x = 300
        self.max_y = 300
    
    def plot_init(self):
        self.ax.set_xlim(0,self.max_x)
        self.ax.set_ylim(0,self.max_y)
        return self.ln  

    def update_plot(self,frame):
        # data_map = np.random.randint(60,size=(60,60))
        # self.ax.matshow(data_map,cmap="Greys")
        self.ax.matshow(self.mapper.probability_map(),cmap="Greys")
        return self.ln
    
    def lidar_callback(self,scan):
        scan_parameters = [scan.angle_min,scan.angle_max,scan.angle_increment]
        scan_ranges = np.array(scan.ranges)
        self.mapper.update_map(self.pose,scan_ranges,scan.angle_min,scan.angle_increment)


rospy.init_node('lidar_visual_node')
vis = Visualiser()
sub = rospy.Subscriber('/scan',LaserScan,vis.lidar_callback)
ani = FuncAnimation(vis.fig,vis.update_plot,init_func=vis.plot_init)
plt.show(block=True) 

注意:我为随机映射测试了self.max_xself.max_y的正确值。让我知道这是否对您有用

例如enter image description here