MultiThreadedExecutor in ROS2

yun·2024년 3월 4일
0

ROS2

목록 보기
5/5

UI에서 topic subscribe가 안 되어서, 구글링 중 발견한 내용(https://robotics.stackexchange.com/questions/100861/using-qt-designer-and-ros2-together-for-a-gui)을 참고해서 아래와 같이 MultiThreadedExecutor를 사용해서 해결했었다.

def main():
    rp.init()
    executor = MultiThreadedExecutor()
    
    app = QApplication(sys.argv)
    myWindows = WindowClass()
    myWindows.show()

    pi_cam_subscriber = PiCamSubscriber(myWindows)
    executor.add_node(pi_cam_subscriber)

    emergency_status_subscriber = EmergencySubscriber(myWindows)
    executor.add_node(emergency_status_subscriber)

    robot_status_subscriber = RobotStatusSubscriber(myWindows)
    executor.add_node(robot_status_subscriber)
    
    task_queue_subscriber = TaskQueueSubscriber(myWindows)
    executor.add_node(task_queue_subscriber)

    cctv_video_subscriber = CctvVideoSubscriber(myWindows)
    executor.add_node(cctv_video_subscriber)

    amcl_subscriber = AmclSubscriber()
    executor.add_node(amcl_subscriber)
    
    path_subscriber = PathSubscriber()
    executor.add_node(path_subscriber)
    
    done_task_subscriber = DoneTaskSubscriber()
    executor.add_node(done_task_subscriber)

    thread = Thread(target=executor.spin)
    thread.start()

이렇게 작성하고 나서는 deadlock도 발생하지 않는 것으로 보였고 Topic pub/sub에 문제가 없었기 때문에 멀티스레드를 잘 썼다고 생각했는데...

면접 질문을 받고 왠지 찜찜해서 알아보니까 (https://discourse.ros.org/t/how-to-use-callback-groups-in-ros2/25255)

요약하면, SingleThreadedExecutor는 말 그대로 싱글스레드로 실행되지만, MultiThreadedExecutor는 callbackgroup 설정에 따라 싱글스레드일 수도 있고, 멀티스레드일 수도 있다는 것.

callbackgroup은 따로 설정하지 않으면 MutuallyExclusiveCallbackGroup이며, 이 경우 executor의 callback은 하나씩 실행된다.

병렬로 실행되게 하려면 ReentrantCallbackGroup을 적용해야 한다. deadlock이 발생하지 않은 건 사실상 싱글스레드로 실행되고 있었기 때문이고, 멀티스레드를 적용하려면 callback_group을 따로 설정해 줬어야 하고, deadlock을 방지하는 방법도 고려해야 했을 것이다.

ROS2 공식문서(https://docs.ros2.org/foxy/api/rclpy/api/execution_and_callbacks.html#module-rclpy.callback_groups)를 보면 callback을 thread pool 안에서 실행한다는 내용이 있다.

그렇기 때문에 SingleThreadedExecutor에서는 아예 subscribe를 못했던 이슈가 MultiThreadedExecutor를 사용했을 때 해결된 것으로 보인다. 다만 여러 노드가 병렬로 동작한 것은 아니므로 MultiThread로 개발했다고 말할 수는 없다.

0개의 댓글