2

我遇到的问题是:

  • 要在后台启动异步函数,我需要一个 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使用其他服务取消该服务?(我知道这是动作的用途,但我不能在这种情况下使用它们)。

4

0 回答 0