.. index:: navigate .. _skill-navigate: Skill ``navigate`` ----------------------------------------------------------- - **Version**: 1.0.0 - **Default path**: ``/skill/navigate`` - **Datatype**: :action:`navigation_skills/action/Navigate` - **Definition source**: ``package.xml`` in `ros4hri/navigation_skills `_ Autonomously navigate to to a given location. Additional advanced navigation options are exposed through the specialized :skill:`navigate_to_pose`, :skill:`navigate_to_waypoint` and :skill:`navigate_to_zone` skills. Input parameters ~~~~~~~~~~~~~~~~ - **pose** ``geometry_msgs/PoseStamped`` The coordinates of the pose that the robot must reach. If no reference frame is specified, the pose is assumed to be relative to the robot's current position. This parameter is mutually exclusive with `target`, and is ignored if `target` is provided. - **target** ``string`` The name of a predefined target that the robot must reach. Can be the name of a existing waypoint (:ref:`waypoint-navigation`) or zone (:ref:`environmental-annotations`). (in case of name conflict, waypoints are preferred over zones) - **meta.priority** ``integer``, default: ``128`` Between 0 and 255. Higher value means that this skill invokation will have higher priority. Quick snippets ~~~~~~~~~~~~~~ .. tabs:: .. tab:: Command-line Call the skill from the command-line .. code-block:: sh $ ros2 action send_goal /skill/navigate navigation_skills/action/Navigate # then press Tab to complete the message prototype .. tab:: ROS 2 action (Python) Call the action from a Python script: .. code-block:: python #!/usr/bin/env python import rclpy from rclpy.action import ActionClient from rclpy.node import Node from navigation_skills.action import class NavigateActionClient(Node): def __init__(self): super().__init__('navigate_client') self._action_client = ActionClient(self, , '/skill/navigate') def send_goal(self, a, b): goal_msg = .Goal() # TODO: adapt to the action's parameters # check the NavigateGoal message # definition for the possible goal parameters # goal_msg.a = a # goal_msg.b = b self._action_client.wait_for_server() return self._action_client.send_goal_async(goal_msg) if __name__ == '__main__': rclpy.init(args=args) action_client = ActionClient() # TODO: adapt to your action's parameters future = action_client.send_goal(a, b) rclpy.spin_until_future_complete(action_client, future) rclpy.shutdown() .. tab:: ROS 2 action (C++) Call the action from a C++ program: .. code-block:: cpp #include #include #include #include #include #include #include "navigation_skills/action/.hpp" #include "rclcpp/rclcpp.hpp" #include "rclcpp_action/rclcpp_hpp" #include "rclcpp_components/register_node_macro.hpp" using namespace std::chrono_literals; using namespace std; class NavigateActionClient : public rclcpp::Node { public: using = navigation_skills::action::; using GoalHandle = rclcpp_action::ClientGoalHandle<>; explicit NavigateActionClient(const rclcpp::NodeOptions & options) : Node("navigate_action_client", options) { this->client_ptr_ = rclcpp_action::create_client<>( this, ""); this->timer_ = this->create_wall_timer( 500ms, bind(&NavigateActionClient::send_goal, this)); } void send_goal() { using namespace std::placeholders; this->timer_->cancel(); if (!this->client_ptr_->wait_for_action_server()) { RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting"); rclcpp::shutdown(); } auto goal_msg = ::Goal(); // check the NavigateGoal message // definition for the possible goal parameters // goal_msg.... = ...; RCLCPP_INFO(this->get_logger(), "Sending goal"); auto send_goal_options = rclcpp_action::Client<>::SendGoalOptions(); send_goal_options.goal_response_callback = bind(&NavigateActionClient::goal_response_callback, this, _1); send_goal_options.feedback_callback = bind(&NavigateActionClient::feedback_callback, this, _1, _2); send_goal_options.result_callback = bind(&NavigateActionClient::result_callback, this, _1); this->client_ptr_->async_send_goal(goal_msg, send_goal_options); } private: rclcpp_action::Client<>::SharedPtr client_ptr_; rclcpp::TimerBase::SharedPtr timer_; void goal_response_callback(const GoalHandle::SharedPtr & goal_handle) { if (!goal_handle) { RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server"); } else { RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result"); } } void feedback_callback( GoalHandle::SharedPtr, const shared_ptr feedback) { stringstream ss; ss << "Next number in sequence received: "; for (auto number : feedback->partial_sequence) { ss << number << " "; } RCLCPP_INFO(this->get_logger(), ss.str().c_str()); } void result_callback(const GoalHandle::WrappedResult & result) { switch (result.code) { case rclcpp_action::ResultCode::SUCCEEDED: break; case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); return; case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(this->get_logger(), "Goal was canceled"); return; default: RCLCPP_ERROR(this->get_logger(), "Unknown result code"); return; } stringstream ss; ss << "Result received: "; for (auto number : result.result->sequence) { ss << number << " "; } RCLCPP_INFO(this->get_logger(), ss.str().c_str()); rclcpp::shutdown(); } }; // class NavigateActionClient RCLCPP_COMPONENTS_REGISTER_NODE(NavigateActionClient) .. tab:: QML You can call this skill from QML using the following code snippet. See :ref:`ros_qml_plugin` to learn more. .. code-block:: qml import Ros 2.0 // ... NavigateSkill { id: mySkill onResult: { console.log("Skill result: " + result); } onFeedback: { console.log("Skill feedback: " + feedback); } } // Call the skill mySkill.navigate(); See also ~~~~~~~~ * List of other :ref:`navigation_skills` skills