I and at least 1 other person and several other people online ran into this issue where if you
rclpy.spin (say in a thread) it will not execute any callbacks.
I googled and googled and found no answers. ROS1 to ROS2 migration documentation is still in a pretty sad state unfortunately since in ROS1 this stuff just works. Then I pulled my hair out for 3 hours and figured out a voodoo black magic answer. Here’s the answer, in case more people go googling and hopefully stumble upon this:
Create at least one subscriber before rclpy.spin(). It can be a dummy subscriber and doesn’t need to actually do anything
self.create_subscription(...), add a
self.guardsline. It looks weird like that on a line by itself, I have no idea what it does, but this magic incantation works. If you use the non-classy way to do it, i.e.
node.create_subscription(...), then it will be
Yes, literally like that.
class MyFooNode(Node): def __init__(self) super().__init__(node_name = "my_foo_node") self.create_subscriber(...) # any old dummy subscriber, won't work without a dummy threading.Thread(target = some_thread, daemon = True).start() def some_thread(self): # Dynamically subscribe to 10 topics for i in range(10): time.sleep(10) self.create_subscription( String, "/some_dynamic_topic_%d" % i, functools.partial(on_message, topic_num = i) # they took away the args= feature of ROS1 10 ) self.guards # MAGIC !! won't call the callback without this! def on_message(msg, topic_num = 0): print("Received a message on topic number %d:" % topic_num, msg) def main(args=None): # boilerplate verbose ros2 stuff rclpy.init(args=args) node = MyFooNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
If someone can can explain why this magic works I’d love it, but until then just posting a solution online for the other people googling for this!