小鱼 ROS 2 新书上线!点击链接查看, 新书配套视频点击链接查看。
提问前必看的发帖注意事项—— 提问前必看!不符合要求的问题拒绝回答!!
社区使用指南—如何添加标签修改密码
ros2 humble python调用ActionServer自定义goal_callback报错
-
背景:
ros2 humble python调用ActionServer自定义goal_callback报错
问题描述:
自定义ActionServer内goal_callback,报错:AttributeError: 'Nav_Goal' object has no attribute 'request';打印goal_handle发现它的类型是base_interfaces_demo.action._nav.Nav_Goal,而不是rclpy.action.server.ServerGoalHandle
具体细节和上下文:
接口Nav.action
float32 goal_x float32 goal_y float32 goal_theta --- float32 turtle_x float32 turtle_y float32 turtle_theta --- float32 distance
服务端
from rclpy.action import ActionServer self.server = ActionServer( self, Nav, 'nav', self.execute_callback, goal_callback=self.goal_callback, cancel_callback=self.cancel_callback ) def goal_callback(self, goal_handle): self.get_logger().info("*********%s"%type(goal_handle)) # 访问目标数据 goal = goal_handle.request # 检查目标的合法性 if (goal.goal_x < 0 or goal.goal_x > 11.08 or goal.goal_y < 0 or goal.goal_y > 11.08): goal_handle.canceled() # 取消目标 return None # 返回 None 表示没有接受目标 # 目标合法,接受目标 goal_handle.accept() return goal_handle # 返回 goal_handle 以便进一步处理
报错信息
[exer03_action_server-2] [INFO] [1723443526.653815246] [exer03_action_server_node_py]: *********<class 'base_interfaces_demo.action._nav.Nav_Goal'> [exer03_action_server-2] Traceback (most recent call last): [exer03_action_server-2] File "/home/ws01_plumbing/install/py07_exercise/lib/py07_exercise/exer03_action_server", line 33, in <module> [exer03_action_server-2] sys.exit(load_entry_point('py07-exercise==0.0.0', 'console_scripts', 'exer03_action_server')()) [exer03_action_server-2] File "/home/ws01_plumbing/install/py07_exercise/lib/python3.10/site-packages/py07_exercise/exer03_action_server.py", line 94, in main [exer03_action_server-2] rclpy.spin(Exer03ActionServer()) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/__init__.py", line 222, in spin [exer03_action_server-2] executor.spin_once() [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 739, in spin_once [exer03_action_server-2] self._spin_once_impl(timeout_sec) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 736, in _spin_once_impl [exer03_action_server-2] raise handler.exception() [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/task.py", line 239, in __call__ [exer03_action_server-2] self._handler.send(None) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 437, in handler [exer03_action_server-2] await call_coroutine(entity, arg) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 403, in _execute_waitable [exer03_action_server-2] await waitable.execute(data) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/action/server.py", line 492, in execute [exer03_action_server-2] await self._execute_goal_request(taken_data['goal']) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/action/server.py", line 280, in _execute_goal_request [exer03_action_server-2] response = await await_or_execute(self._goal_callback, goal_request.goal) [exer03_action_server-2] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 107, in await_or_execute [exer03_action_server-2] return callback(*args) [exer03_action_server-2] File "/home/ws01_plumbing/install/py07_exercise/lib/python3.10/site-packages/py07_exercise/exer03_action_server.py", line 29, in goal_callback [exer03_action_server-2] goal = goal_handle.request [exer03_action_server-2] AttributeError: 'Nav_Goal' object has no attribute 'request' [ERROR] [exer03_action_server-2]: process has died [pid 16798, exit code 1, cmd '/home/ws01_plumbing/install/py07_exercise/lib/py07_exercise/exer03_action_server --ros-args'].
-
在 ROS 2 的
rclpy
框架中,当你定义一个 Action Server 的goal_callback
时,你需要正确地处理传入的参数。在你的代码中,goal_callback
被错误地期望接收一个ServerGoalHandle
对象,但实际上在 ROS 2 的较新版本中(包括 Humble),goal_callback
直接接收的是 Action 的目标(Goal)对象,而不是ServerGoalHandle
。解决方案
你需要修改
goal_callback
以直接接收Nav_Goal
类型的对象,而不是ServerGoalHandle
。同时,你需要从goal_handle
中获取goal
的方式需要改变,因为你现在直接处理的就是goal
对象。修改后的
goal_callback
应该像这样:def goal_callback(self, goal): self.get_logger().info("Received goal: x={}, y={}, theta={}".format(goal.goal_x, goal.goal_y, goal.goal_theta)) # 检查目标的合法性 if (goal.goal_x < 0 or goal.goal_x > 11.08 or goal.goal_y < 0 or goal.goal_y > 11.08): # 这里你不需要直接调用 goal_handle.canceled(),因为在这个回调中没有 goal_handle # 你需要在 execute_callback 中处理取消逻辑 return rclpy.action.GoalResponse.REJECT # 目标合法,返回 ACCEPT 表示接受目标 return rclpy.action.GoalResponse.ACCEPT
注意:
goal_callback
现在直接接收goal
对象。goal_callback
需要返回一个GoalResponse
,而不是执行goal_handle.accept()
或goal_handle.canceled()
。这是因为goal_callback
是在决定是否接受或拒绝目标时调用的,而实际的处理(如接受或取消)将在execute_callback
中进行。
完整的 Action Server 示例
这里是一个简化的 Action Server 示例,展示如何设置
goal_callback
和execute_callback
:from rclpy.action import ActionServer, GoalResponse from rclpy.node import Node from your_package.action import Nav class NavActionServer(Node): def __init__(self): super().__init__('nav_action_server') self.server = ActionServer( self, Nav, 'nav', self.execute_callback, goal_callback=self.goal_callback, cancel_callback=self.cancel_callback ) def goal_callback(self, goal): # 检查目标合法性 if (goal.goal_x < 0 or goal.goal_x > 11.08 or goal.goal_y < 0 or goal.goal_y > 11.08): return GoalResponse.REJECT return GoalResponse.ACCEPT def execute_callback(self, goal_handle): self.get_logger().info('Executing goal...') # 这里是实际执行目标的地方 # 假设执行成功 result = Nav.Result() result.distance = 10.0 # 假设的距离 goal_handle.succeed(result) def cancel_callback(self, goal_handle): self.get_logger().info('Goal canceled') goal_handle.canceled() def main(args=None): rclpy.init(args=args) nav_server = NavActionServer() rclpy.spin(nav_server) nav_server.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
注意:你需要根据你的具体包名和命名空间调整代码中的
from your_package.action import Nav
。
以上为生成回答,仅供参考~
-
@luminuo 提供下完整代码,看不太懂
-
@小鱼 按上面那个回复解决了,但是要怎么把未解决改成已解决