Need help using matplotlib inside callback function

asked 2021-06-21 14:46:28 -0500

Michdo93 gravatar image

updated 2021-06-21 14:47:21 -0500

Hi,

at first I tried this code without ROS and the Raspberry Pi sense hat emulator and it works as expected:

#!/usr/bin/env python
import os
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
import numpy as np
from sense_emu import SenseHat # start with sense_emu_gui
# from sense_hat import SenseHat

sense = SenseHat()

fig = plt.figure(num='Compass', figsize=[5, 3])
ax = plt.subplot(projection='polar')

def animate(i):    
    north = sense.get_compass()
    ax.clear()
    ax.set_theta_zero_location("N")
    ax.set_theta_direction(-1)
    ax.set_ylim(top=1)

    # arrow at 45 degree
    plt.arrow(north/180.*np.pi, 0.0, 0, 1, alpha = 0.5, width = 0.015,
                    edgecolor = 'black', facecolor = 'green', lw = 2, zorder = 5)

ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()

The final result looks like:

compass

So instead of using the animate function I want to use a callback function from my subscriber. Of course I have a working publisher and the Sense HAT is working on my robot which is controlled via an Raspberry Pi. In other program I also use an subscriber to get data from my publisher. And in other programs I use also matplotlib and I can see different diagrams or plots or whatever it is called.

But in this example the figure is black.

#!/usr/bin/env python
import os
import sys
import re
import socket
import rospy
from robotcar_msgs.msg import Magnetometer
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style

plt.style.use('seaborn')
plt.ion()

class CompassPlotter(object):

    def __init__(self, robot_host):
        """Configure subscriber."""
        # Create a subscriber with appropriate topic, custom message and name of
        # callback function.
        self.robot_host = robot_host
        self.sub = rospy.Subscriber(self.robot_host + '/imu/magnetometer', Magnetometer, self.callback)

        # Initialize message variables.
        self.enable = False
        self.data = ""

        self.fig = plt.figure(num='Compass', figsize=[5, 3])
        self.ax = plt.subplot(projection='polar')

        if self.enable:
            self.start()
        else:
            self.stop()

    def start(self):
        self.enable = True
        self.sub = rospy.Subscriber(self.robot_host + '/imu/magnetometer', Magnetometer, self.callback)

    def stop(self):
        """Turn off subscriber."""
        self.enable = False
        self.sub.unregister()

    def callback(self, data):
        """Handle subscriber data."""
        # Simply print out values in our custom message.
        self.data = data
        msg = "Got imu/magnetometer: North: %s" % self.data.north
        rospy.loginfo(rospy.get_caller_id() + msg)

        self.ax.clear()
        self.ax.set_theta_zero_location("N")
        self.ax.set_theta_direction(-1)
        self.ax.set_ylim(top=1)

        # arrow at 45 degree
        plt.arrow(self.data.north/180.*np.pi, 0.0, 0, 1, alpha = 0.5, width = 0.015,
                        edgecolor = 'black', facecolor = 'green', lw = 2, zorder = 5)

        plt.show()
        plt.pause(.000001)

if __name__ == '__main__':
    # Initialize the node and name it.
    node_name = re.sub("-", "_", socket.gethostname()) + "_CompassPlotter"
    rospy.init_node(node_name, anonymous=False)

    compass = CompassPlotter("robotcar")

    # Go to the main loop
    try:
        compass.start()
        # Wait for messages on topic, go to callback function when new messages arrive.
        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
    # Stop with Ctrl + C ...
(more)
edit retag flag offensive close merge delete