簡體   English   中英

ros2主題持續多條消息

[英]ros2 topic persisting more than one message

我對 ros2 主題有一個非常棘手的問題,由於某種原因,它保留了不止一條消息。 我的項目相當簡單:我有一個計划器,我可以在其中創建目標並對其進行編輯。 規划器由幾個節點組成,一個用於更改目標的每個值。 我的節點列表:

/add_target  
/change_comment  
/change_target_index  
/clear_state  
/remove_target  
/rename_target  
/set_target  
/toggle_select_target  
/toggle_visible  

每個節點都擴展了 StateNode(參見下面的實現),這有助於為每個節點保持相同的狀態。

這個想法很簡單:一個節點接收到一個服務調用,例如/planner/rename_target,從節點的狀態中找到具體的目標,修改它,並將新的狀態發布到/planner/state。 每個節點都訂閱 /planner/state 並將狀態設置為收到的消息。 這個想法是在所有節點之間保持狀態一致,因此每個節點都可以訪問所有狀態數據並可以對其進行修改。

我已將我的服務質量配置文件設置為僅保留最新消息。 但是,我的問題是,在對不同節點使用服務調用后,有時在運行時

ros2 topic echo --qos-history keep_last --qos-depth 1 --qos-durability transient_local --qos-reliability reliable /planner/state

我收到條消息。 消息的順序隨機變化。 每個節點的狀態似乎是相同的,但似乎有消息在主題中“漂浮”。 我的 qos 應該只允許保留最新消息。

例如,如果我第一次服務調用兩次

ros2 service call /planner/add_target mtms_interfaces/srv/AddTarget "{target: {position:{x: 0.0,y: 0.0,z: 0.0}, orientation: {alpha: 0.0,beta: 0.0,gamma: 0.0}}}"

我的主題回聲看起來很正常,但如果我那時

ros2 service call /planner/rename_target mtms_interfaces/srv/RenameTarget "{name: 'Target-0', new_name: 'example'}"

突然我的主題回聲顯示兩條消息。 在其中一條消息中,目標未被修改,而在另一條消息中,目標已被修改。

這里可能是什么問題?

這是我的節點的一些示例

狀態節點實現:

class StateNode(Node):

    def __init__(self, name):
        super().__init__(name)

        # Persist the latest sample.
        qos = QoSProfile(
            depth=1,
            durability=DurabilityPolicy.TRANSIENT_LOCAL,
            history=HistoryPolicy.KEEP_LAST,
            reliability=ReliabilityPolicy.RELIABLE
        )

        self._state_publisher = self.create_publisher(
            PlannerState,
            "/planner/state",
            qos
        )
        self._state_subscriber = self.create_subscription(
            PlannerState,
            '/planner/state',
            self.state_updated,
            10
        )
        self._state = None

    def state_updated(self, msg):
        self._state = msg

重命名目標節點實現:

class RenameTargetNode(StateNode):

    def __init__(self):
        super().__init__('rename_target')
        self.create_service(RenameTarget, '/planner/rename_target', self.rename_target_callback)

    def rename_target_callback(self, request, response):

        state = self._state
        if state is None:
            response.success = False
            return response

        self.get_logger().info('Renaming {} to {}'.format(request.name, request.new_name))
        
        i = 0
        for target in state.targets:

            # Name already exists
            if target.name == request.new_name: 
                response.success = False
                return response
            
            # Save index of target in case new_name is unique
            if target.name == request.name:
                i = state.targets.index(target) 
        
        state.targets[i].name = request.new_name

        self._state_publisher.publish(state)

        response.success = True
        return response

AddTargetNode 實現

class AddTargetNode(StateNode):

    def __init__(self):
        super().__init__('add_target')
        self.create_service(AddTarget, '/planner/add_target', self.add_target_callback)

    def first_available_target_name(self):
        if self._state is None:
            return "Target-0"

        target_names = [target.name for target in self._state.targets]
        idx = 0
        while True:
            target_name = "Target-{}".format(idx)
            if target_name not in target_names:
                break
            idx += 1
        return target_name

    def create_new_target(self, pose):
        target = Target()

        target.name = self.first_available_target_name()
        target.type = "Target"
        target.comment = ""
        target.selected = False
        target.target = False  # XXX: Misnomer
        target.pose = pose

        target.intensity = 100.0
        target.iti = 100.0

        return target

    def add_target_callback(self, request, response):
        self.get_logger().info('Incoming request')

        target = self.create_new_target(
            pose=request.target  # XXX: Misnomer
        )

        if self._state is None:
            msg = PlannerState()
            msg.targets = [
                target
            ]
        else:
            msg = self._state
            msg.targets.append(target)

        self._state_publisher.publish(msg)

        response.success = True
        return response

系統信息:Ubuntu 20.04,內核5.14.0-1042-oem,x86_64

我正在使用 osrf/ros:galactic-desktop 創建的一個 docker 容器中運行 ros 節點。

這里的問題是,我有幾個發布者使用 DurabilityPolicy.TRANSIENT_LOCAL 來處理同一主題,描述如下:“發布者負責為‘后期加入’訂閱保留樣本。” 在實踐中,這意味着當一個新的訂閱者加入時,每個發布者都會向他們發送他們的最后一條消息 --> 訂閱者會收到多條消息。

對此有幾種解決方案,例如創建一個主節點,該主節點訂閱由每個節點更新的內部狀態,但只有主節點負責發布“外部”狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM