我遇到的问题是:
要在后台启动异步函数,我需要一个 asycio 事件循环。
这个事件循环通常存在于主线程中,并且在启动时会阻塞该线程的执行(即,在事件循环开始后的代码行直到事件循环被取消才会运行)。
然而,ROS2 有它自己的事件循环(执行器),它通常也运行在主线程中并阻止执行。这意味着很难同时运行两个事件循环
我尝试的解决方案是在单独的线程中启动 asyncio 事件循环。这在 Node 构造函数中启动,并在 Node 解构后停止。
这看起来像这样:
class IncrementPercentDoneServiceNode(Node):
def __create_task(self, f: Awaitable):
self.__task = self.__loop.create_task(f)
def __init__(self):
super().__init__('increment_percent_done_service_node')
self.__loop = asyncio.new_event_loop()
self.__task: Optional[Task] = None
self.__thread = threading.Thread(target=self.__loop.run_forever)
self.__thread.start()
self.done = False
self.create_service(Trigger, 'start_incrementing',
callback=lambda request, responce : (
self.get_logger().info("Starting service"),
self.__loop.call_soon_threadsafe(self.__create_task, self.__increment_percent_complete()),
TriggerResponse(success=True, message='')
)[-1]
)
def __del__(self):
print("stopping loop")
self.done = True
if self.__task is not None:
self.__task.cancel()
self.__loop.stop()
self.__thread.join()
async def __increment_percent_complete(self):
timeout_start = time.time()
duration = 5
while time.time() < (timeout_start + duration):
time_since_start = time.time() - timeout_start
percent_complete = (time_since_start / duration) * 100.0
self.get_logger().info("Percent complete: {}%".format(percent_complete))
await asyncio.sleep(0.5)
self.get_logger().info("leaving async function")
self.done = True
if __name__ == '__main__':
rclpy.init()
test = IncrementPercentDoneServiceNode()
e = MultiThreadedExecutor()
e.add_node(test)
e.spin()
这是一种明智的做法吗?有没有更好的办法?我将如何start_incrementing
使用其他服务取消该服务?(我知道这是动作的用途,但我不能在这种情况下使用它们)。