[英]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.