211 : BT::ActionNodeBase(instance_name, config),
logger_(context.getLogger()), context_(context)
219 auto portIt = config.input_ports.find(
"action_name");
220 if (portIt != config.input_ports.end())
222 const std::string& bb_service_name = portIt->second;
224 if (isBlackboardPointer(bb_service_name))
227 action_name_should_be_checked_ = true;
229 else if (!bb_service_name.empty())
232 createClient(bb_service_name);
236 if (!client_instance_ && !context_.default_port_name.empty())
238 createClient(context_.default_port_name);
319 auto& executor = client_instance_->callback_executor;
320 if (!goal_response_ && future_goal_handle_.valid())
323 auto ret = executor.spin_until_future_complete(future_goal_handle_, getRosContext().request_timeout);
324 if (ret != rclcpp::FutureReturnCode::SUCCESS)
329 goal_handle_ = future_goal_handle_.get();
330 future_goal_handle_ = {};
341 auto future_cancel = client_instance_->action_client->async_cancel_goal(goal_handle_);
342 if (
const auto code = executor.spin_until_future_complete(future_cancel, getRosContext().request_timeout);
343 code != rclcpp::FutureReturnCode::SUCCESS)
345 RCLCPP_WARN(logger_,
"%s - Failed to wait until cancellation of action '%s' is complete (Received: %s). Ignoring.",
346 getFullName().c_str(), action_name_.c_str(), rclcpp::to_string(code).c_str());
366 return BT::NodeStatus::FAILURE;
372 if (!client_instance_ || (status() == BT::NodeStatus::IDLE && action_name_should_be_checked_))
374 std::string action_name;
375 getInput(
"action_name", action_name);
376 if (action_name_ != action_name)
378 createClient(action_name);
382 if (!client_instance_)
385 " - You must specify an action name either by using a default value or by "
386 "passing a value to the corresponding dynamic input port.");
389 auto& action_client = client_instance_->action_client;
392 auto check_status = [
this](BT::NodeStatus status) {
393 if (!isStatusCompleted(status))
401 if (status() == BT::NodeStatus::IDLE)
403 setStatus(BT::NodeStatus::RUNNING);
405 goal_response_ =
false;
406 future_goal_handle_ = {};
407 on_feedback_state_change_ = BT::NodeStatus::RUNNING;
416 typename ActionClient::SendGoalOptions goal_options;
419 goal_options.feedback_callback = [
this](
typename GoalHandle::SharedPtr,
420 const std::shared_ptr<const Feedback> feedback) {
421 on_feedback_state_change_ = onFeedback(feedback);
422 if (on_feedback_state_change_ == BT::NodeStatus::IDLE)
424 throw std::logic_error(getFullName() +
" - onFeedback() must not return IDLE.");
429 goal_options.result_callback = [
this](
const WrappedResult& result) {
431 throw std::logic_error(getFullName() +
" - goal_handle_ is nullptr in result callback.");
432 if (goal_handle_->get_goal_id() == result.goal_id)
435 goal_handle_ =
nullptr;
441 if (!action_client->action_server_is_ready())
446 future_goal_handle_ = action_client->async_send_goal(goal, goal_options);
447 time_goal_sent_ = getRosContext().getCurrentTime();
449 return BT::NodeStatus::RUNNING;
452 if (status() == BT::NodeStatus::RUNNING)
454 std::unique_lock<std::mutex> lock(getMutex());
455 client_instance_->callback_executor.spin_some();
461 client_instance_->callback_executor.spin_until_future_complete(future_goal_handle_, std::chrono::seconds(0));
462 if (ret != rclcpp::FutureReturnCode::SUCCESS)
464 if ((getRosContext().getCurrentTime() - time_goal_sent_) > getRosContext().request_timeout)
468 return BT::NodeStatus::RUNNING;
472 goal_response_ =
true;
473 goal_handle_ = future_goal_handle_.get();
474 future_goal_handle_ = {};
478 RCLCPP_ERROR(logger_,
"%s - Goal was rejected by server.", getFullName().c_str());
481 RCLCPP_DEBUG(logger_,
"%s - Goal accepted by server, waiting for result.", getFullName().c_str());
486 if (on_feedback_state_change_ != BT::NodeStatus::RUNNING)
489 return on_feedback_state_change_;
493 if (result_.code != rclcpp_action::ResultCode::UNKNOWN)
494 return check_status(onResultReceived(result_));
496 return BT::NodeStatus::RUNNING;