如果想要matplotlib动态更新画图,只能将matplotlib放在主线程中,如果放进子线程,就会报这个错
ValueError: set_wakeup_fd only works in main thread
但是如果要订阅ros的topic,主线程会被阻塞,matplotlib无法动态更新。
因此,通过将matplotlib嵌入tkinter中,实现一边订阅topic,一边动态更新画图
import math
import rospy
import message_filters
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from my_pkg.msg import MyArrayMessage
class ROS_Tkinter_App:
def __init__(self, master):
self.master = master
master.title("ROS Tkinter App")
# Matplotlib setup for scatter plot
self.figure = Figure(figsize=(10, 8), dpi=100)
self.scatter_plot = self.figure.add_subplot(111)
self.scatter_plot.set_title('Scatter Plot')
self.canvas = FigureCanvasTkAgg(self.figure, master=master)
self.canvas.get_tk_widget().pack()
# ROS Initialization
rospy.init_node('ros_tkinter_app', anonymous=True)
# Define subscribers for the two topics
sub_topic1 = message_filters.Subscriber("/global_path", MyArrayMessage)
sub_topic2 = message_filters.Subscriber("/vehicle_position", MyArrayMessage)
# Synchronize the subscribers using ApproximateTimeSynchronizer
ts = message_filters.ApproximateTimeSynchronizer([sub_topic1, sub_topic2], queue_size=10, slop=0.1)
ts.registerCallback(self.callback)
# Bind the update_plot_size function to the <Configure> event
# master.bind("<Configure>", self.update_plot_size)
def callback(self, data1, data2):
# This method will be called when a new message is received on the /ros_topic
rospy.loginfo("ROS Topic Data")
# 这里处理topic内的数据
# Update scatter plot with new data
self.update_scatter_plot(Target_Angle, Center_y, Center_x, waypoints_y, waypoints_x) # Assuming the data is a float, update accordingly
def update_scatter_plot(self, angle_radians, Center_x, Center_y, waypoints_x, waypoints_y):
# Update the scatter plot with new data
self.scatter_plot.clear()
self.scatter_plot.set_title('Scatter Plot')
self.scatter_plot.scatter(Center_x, Center_y, color='red', marker='o', label='Center Point')
self.scatter_plot.plot([Center_x, end_x], [Center_y, end_y], color='blue', linestyle='--', label='Line Segment')
self.scatter_plot.scatter(waypoints_x, waypoints_y, color='green', marker='o', label='Waypoint')
# 设置x轴和y轴的显示范围
self.scatter_plot.set_xlim(-100, 100) # 设置x轴的范围
self.scatter_plot.set_ylim(-100, 100) # 设置y轴的范围
# 设置 x 轴和 y 轴的相同比例尺
self.scatter_plot.set_aspect('equal')
# 设置坐标轴标签
self.scatter_plot.set_xlabel('CARLA Y Axis')
self.scatter_plot.set_ylabel('CARLA X Axis')
self.canvas.draw()
def update_plot_size(self, event):
# Update the plot size based on the new window size
new_width = event.width / self.canvas.figure.get_dpi()
new_height = event.height / self.canvas.figure.get_dpi()
self.figure.set_size_inches(new_width, new_height)
self.canvas.draw()
def main():
root = tk.Tk()
app = ROS_Tkinter_App(root)
root.mainloop()
if __name__ == '__main__':
main()