〖ROS2 源码解析〗rclcpp_action/src/server_goal_handle.cpp

一、简要介绍

这段代码展示了 ROS 2 中rclcpp_action命名空间下ServerGoalHandleBase类的成员函数实现。ServerGoalHandleBase在动作服务器中扮演着关键的角色,负责与目标交互并管理其状态。

1. 文件核心功能

析构函数
  • ServerGoalHandleBase::~ServerGoalHandleBase():空的析构函数,在对象销毁时可能执行一些清理操作,但目前没有具体实现。
状态判断方法
  • is_canceling():通过锁定互斥锁,获取目标的状态,并判断是否处于取消中状态。如果获取状态过程中出现错误,会抛出相应的异常。
  • is_active():锁定互斥锁后,直接调用底层函数判断目标是否处于活跃状态。
  • is_executing():与is_canceling()类似,获取目标状态并判断是否处于执行中状态。
状态改变方法
  • _abort()_succeed()_cancel_goal()_canceled()_execute():这些方法分别用于改变目标的状态为中止、成功、请求取消、已取消和开始执行。每个方法都通过锁定互斥锁,调用底层的rcl_action函数来更新目标状态。如果更新过程中出现错误,会抛出异常。
尝试取消方法
  • try_canceling():这个方法首先检查目标是否可取消,如果可取消则尝试将目标状态转换为取消中,然后再次获取状态判断是否成功取消。如果任何步骤出现错误,返回false

2. 使用场景

在 ROS 2 的动作服务器中,ServerGoalHandleBase的这些成员函数被用于管理和操作目标的状态。例如,当需要判断目标是否正在被取消、是否活跃或是否执行中时,可以调用相应的状态判断方法。当需要改变目标的状态,如中止目标、标记目标成功或取消目标时,可以调用对应的状态改变方法。而try_canceling()方法则在需要尝试取消目标时使用,例如在对象销毁前如果目标未达到终端状态,可以尝试取消目标以避免资源泄漏。

3. 总结

这段代码实现了ServerGoalHandleBase类的关键成员函数,为 ROS 2 动作服务器提供了强大的目标状态管理功能。通过这些函数,动作服务器可以准确地判断目标的状态,并在需要时改变目标的状态,确保动作服务器的稳定运行和正确响应。

二、源码与解析

// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>

#include "rcl_action/action_server.h"
#include "rcl_action/goal_handle.h"

#include "rclcpp_action/server_goal_handle.hpp"
#include "rclcpp/exceptions.hpp"

namespace rclcpp_action
{
   
   
ServerGoalHandleBase::~ServerGoalHandleBase()
{
   
   
}

bool
ServerGoalHandleBase::is_canceling() const
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
  rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
  }
  return GOAL_STATE_CANCELING == state;
}

bool
ServerGoalHandleBase::is_active() const
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  return rcl_action_goal_handle_is_active(rcl_handle_.get());
}

bool
ServerGoalHandleBase::is_executing() const
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
  rcl_ret_t ret = rcl_action_goal_handle_get_status(rcl_handle_.get(), &state);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to get goal handle state");
  }
  return GOAL_STATE_EXECUTING == state;
}

void
ServerGoalHandleBase::_abort()
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions::throw_from_rcl_error(ret);
  }
}

void
ServerGoalHandleBase::_succeed()
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_SUCCEED);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions::throw_from_rcl_error(ret);
  }
}

void
ServerGoalHandleBase::_cancel_goal()
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCEL_GOAL);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions::throw_from_rcl_error(ret);
  }
}

void
ServerGoalHandleBase::_canceled()
{
   
   
  std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
  rcl_ret_t ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_CANCELED);
  if (RCL_RET_OK != ret) {
   
   
    rclcpp::exceptions
<think>好的,我现在需要帮助用户解决在ROS2中使用C++发送目标(send_goal)的问题。首先,我得回想一下ROS2的基本结构和动作客户端的使用方法。用户需要一个具体的示例,所以应该从创建动作客户端开始。 我记得ROS2中的动作(action)是基于主题和服务的组合,分为目标、反馈和结果。使用动作客户端需要先定义动作类型,比如导航常用的MoveBase.action。用户可能在使用导航相关的功能,所以可能需要引用move_base_msgs包。 接下来,创建动作客户端的步骤。首先需要包含必要的头文件,比如rclcpp和动作客户端的头文件。然后创建一个继承自rclcpp::Node的类,并在其中声明动作客户端。构造时需要指定动作名称,比如"move_base"。 发送目标前需要确保动作服务器已经存在,因此可能需要使用wait_for_server()函数。然后构造目标消息,设置目标位姿,比如在导航中的目标位置和姿态。发送目标时可能需要注册回调函数来处理反馈、结果等。 用户可能需要异步发送目标,所以应该使用async_send_goal并处理返回的future对象。此外,处理反馈和结果需要定义相应的回调函数,比如在反馈回调中输出进度,在结果回调中处理最终状态。 还需要考虑节点的生命周期,比如在main函数中初始化rclcpp,创建节点并调用相关函数。可能需要使用多线程执行器来同时处理多个回调。 检查是否有相关的引用内容可以支持回答。例如,引用[3]提到了使用move_base的SimpleActionClient,但那是ROS1的示例,ROS2中可能有所不同。需要注意区分ROS1和ROS2的差异,确保示例代码符合ROS2的语法,比如使用rclcpp::Node而不是ROS1的节点句柄。 另外,用户可能遇到依赖问题,需要确保在package.xml和CMakeLists.txt中添加正确的依赖项,比如rclcppaction_msgs等。编译和运行步骤也是需要提及的。 可能的相关问题包括如何处理动作服务器的响应超时,如何取消目标,或者如何处理反馈数据。用户可能还需要了解如何调试动作通信,比如查看当前存在的动作服务器列表。 最后,确保代码示例正确无误,语法符合ROS2的标准,比如使用std::bind绑定回调函数,使用using namespace std::placeholders来占位符参数。同时,提醒用户注意动作消息的类型是否与服务器端一致,避免消息类型不匹配导致的错误。</think>### 如何在ROS2中使用C++发送目标(send_goal) #### 1. 准备工作 确保已安装ROS2基础库和动作相关依赖: ```bash sudo apt install ros-<distro>-rclcpp-action ros-<distro>-action-msgs ``` #### 2. 创建动作客户端节点 以下是完整代码示例: ```cpp #include "rclcpp/rclcpp.hpp" #include "rclcpp_action/rclcpp_action.hpp" #include "geometry_msgs/msg/pose_stamped.hpp" #include "nav2_msgs/action/navigate_to_pose.hpp" using NavigateToPose = nav2_msgs::action::NavigateToPose; using GoalHandle = rclcpp_action::ClientGoalHandle<NavigateToPose>; class NavigationClient : public rclcpp::Node { public: NavigationClient() : Node("navigation_client") { client_ = rclcpp_action::create_client<NavigateToPose>( this, "navigate_to_pose" ); } void send_goal() { if (!client_->wait_for_action_server(std::chrono::seconds(5))) { RCLCPP_ERROR(get_logger(), "Action server not available"); return; } auto goal_msg = NavigateToPose::Goal(); goal_msg.pose.header.stamp = this->now(); goal_msg.pose.header.frame_id = "map"; goal_msg.pose.pose.position.x = 2.0; goal_msg.pose.pose.orientation.w = 1.0; auto send_goal_options = rclcpp_action::Client<NavigateToPose>::SendGoalOptions(); send_goal_options.goal_response_callback = std::bind(&NavigationClient::goal_response_callback, this, std::placeholders::_1); send_goal_options.feedback_callback = std::bind(&NavigationClient::feedback_callback, this, std::placeholders::_1, std::placeholders::_2); send_goal_options.result_callback = std::bind(&NavigationClient::result_callback, this, std::placeholders::_1); client_->async_send_goal(goal_msg, send_goal_options); } private: rclcpp_action::Client<NavigateToPose>::SharedPtr client_; void goal_response_callback(const GoalHandle::SharedPtr & goal_handle) { if (!goal_handle) { RCLCPP_ERROR(get_logger(), "Goal rejected"); } else { RCLCPP_INFO(get_logger(), "Goal accepted"); } } void feedback_callback( GoalHandle::SharedPtr, const std::shared_ptr<const NavigateToPose::Feedback> feedback) { RCLCPP_INFO(get_logger(), "Remaining distance: %.2f meters", feedback->distance_remaining); } void result_callback(const GoalHandle::WrappedResult & result) { switch (result.code) { case rclcpp_action::ResultCode::SUCCEEDED: RCLCPP_INFO(get_logger(), "Goal achieved!"); break; case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(get_logger(), "Goal aborted"); break; case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(get_logger(), "Goal canceled"); break; default: RCLCPP_ERROR(get_logger(), "Unknown result code"); break; } } }; int main(int argc, char ** argv) { rclcpp::init(argc, argv); auto node = std::make_shared<NavigationClient>(); node->send_goal(); rclcpp::spin(node); rclcpp::shutdown(); return 0; } ``` #### 3. 关键代码解析 1. **动作客户端创建** ```cpp client_ = rclcpp_action::create_client<NavigateToPose>(this, "navigate_to_pose"); ``` 使用`nav2_msgs/action/NavigateToPose`动作类型,连接到名为`navigate_to_pose`的动作服务器[^3] 2. **目标发送流程** - `wait_for_action_server()`确保服务器可用 - 构造目标消息(包含位姿信息) - 设置回调函数三元组(目标响应/反馈/结果) 3. **回调函数处理** - `goal_response_callback`处理服务器是否接受目标 - `feedback_callback`接收导航过程中的实时反馈 - `result_callback`处理最终执行结果 #### 4. 编译配置(CMakeLists.txt) ```cmake find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(rclcpp_action REQUIRED) find_package(geometry_msgs REQUIRED) find_package(nav2_msgs REQUIRED) add_executable(navigation_client src/navigation_client.cpp) ament_target_dependencies(navigation_client rclcpp rclcpp_action geometry_msgs nav2_msgs ) install(TARGETS navigation_client DESTINATION lib/${PROJECT_NAME}) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值