ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange |
1 | initial version |
This turned out to be a bit of a fun puzzle to get ROS2 and Eventlet working together. In the end, the solution makes a lot of sense, but it just isn't super intuitive. Basically, the solution is first to import eventlet
and run monkey_patch()
before any other imports.
import eventlet
eventlet.monkey_patch()
from flask import Flask, request, jsonify, make_response
from flask_socketio import SocketIO, emit, Namespace
...
The issue is that when monkey-patching, it basically turns all the threads into blocking threads, which need to be explicitly slept so that other threads can process (i.e. the rest of the code). So the trick is to combine rclpy
's spin_once()
with the eventlet.greenthread.sleep()
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.ros_thread = Thread(target=self.process,daemon=True)
self.ros_thread.start()
self.get_logger().info('Initialized!')
def process(self):
alive = True
while alive:
try:
# Check that the ROS node is still alive
self.assert_liveliness()
# Spin the ROS node once...
rclpy.spin_once(self,timeout_sec=0.0)
# ...and then momentarily sleep so the other process (socket.io) can run.
eventlet.greenthread.sleep()
except:
alive = False
def main(args=None):
rclpy.init(args=args)
node = MyNode()
# SocketIO's run has eventlet sleeps incorporated when eventlet is imported
node.socketio.run(node.app)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()