ROS2 Flask Threading issue
Hi all,
I am trying to set up a ROS2 rclpy node that functions as a Flask socket server. This node needs to have a thread or timer-based process running (which handles a socket broadcast). The issue I am running into is that when I create a ROS2 timer, it seems that it never executes, and when I use a python thread, it seems to block the main process. The minimal code samples are below:
ROS2 Timer:
class MyNode(Node):
def __init__(self):
super(MyNode,self).__init__('my_node')
self.get_logger().info('Initializing My Node!') # Works fine
self.app = Flask(__name__) # Flask Stuff
self.my_ns = NS(self) # Custom Flask Socket Namespace
self.socketio = SocketIO(self.app, cors_allowed_origins="*") # Create Socket
self.socketio.on_namespace(self.my_ns) # Pair the namespace
self.process_timer = self.create_timer(.1,self.process)
self.get_logger().info('Initialized!') # Executes
def process(self):
self.get_logger().info('Running!') # Never Executes
def main(args=None):
rclpy.init(args=args)
node = MyNode()
node.socketio.run(node.app)
if __name__ == '__main__':
main()
Python Thread:
class MyNode(Node):
def __init__(self):
super(MyNode,self).__init__('my_node')
self.get_logger().info('Initializing My Node!') # Works fine
self.app = Flask(__name__) # Flask Stuff
self.my_ns = NS(self) # Custom Flask Socket Namespace
self.socketio = SocketIO(self.app, cors_allowed_origins="*") # Create Socket
self.socketio.on_namespace(self.my_ns) # Pair the namespace
self.process_thread = Thread(target=self.process,daemon=True)
self.process_thread.start()
self.get_logger().info('Initialized!') # Never Executes
def process(self):
alive = True
while alive:
try:
self.assert_liveliness()
self.get_logger().info('Running!') # Executes
except:
alive = False
def main(args=None):
rclpy.init(args=args)
node = MyNode()
node.socketio.run(node.app)
if __name__ == '__main__':
main()
Thanks for the suggestions, and I will try out those changes. I should share the original code I had, which is the following:
class WizardNode(Node):
def __init__(self):
super(WizardNode,self).__init__('wizard')
self.get_logger().info('Initializing Wizard Node!')
self.app = Flask(__name__)
self.cors = CORS(self.app)
self.wizard = Wizard(self)
self.socketio = SocketIO(self.app, cors_allowed_origins="*")
self.socketio.on_namespace(self.wizard)
self.socket_thread = Thread(target=lambda:self.socketio.run(self.app),daemon=True)
self.socket_thread.start()
self.process_timer = self.create_timer(.1,self.process)
self.get_logger().info('Initialized!')
self.printer = PrettyPrinter()
def process(self):
time = self.get_clock().now()
self.wizard.timestep()
def main(args=None):
rclpy.init(args=args)
node = WizardNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
node.destroy_node()
rclpy.shutdown()
In this version, it seems that the socket.io thread fails to do any sort of broadcasting/emitting, which was why I tried restructuring in the ways above. I should also say that in this example, using eventlet
's monkey_patch()
basically broke everything.
Due to my very limited experience with python+ROS2 I'm not sure if this will help you, or if this will just be a stupid comment. I also have no clue what Flask threading is.
Anyways, simply creating a ROS2 node and adding a timer, does not make that timer do anything. In C++ you need to spin() the node for anything to happen. Spinning is basically adding the node to an executor which, when the timer triggers, will execute the callback function. I'm not sure how this is setup in python, but could it be that you are missing this?
This is solely based on my c++ experience and the fact that I don't see a spin() anywhere :P so be gentle.