Skill grasp
Version: 1.0.0
Default path:
/skill/graspDatatype: manipulation_skills/action/Grasp
Definition source:
package.xmlin ros4hri/manipulation_skills
Commands the robot to grasp a specified object. This skill sends a goal to the robot’s manipulation system to execute a grasping action using a specified strategy.
- Once invoked, the robot will:
Identify the target object.
Execute the grasping Behavior Tree strategy.
Report back feedback and a result message indicating success or failure.
Typical uses include picking up objects from tables, bins, or other surfaces.
The skill assumes that the robot’s hand is empty. See Skill place for the placing action.
Input parameters
object_id
string, requiredThe identifier of the object to be grasped.
side
string, default:""- Which hand or end-effector to use. Supported values:
left: Use the left hand.right: Use the right hand.default (empty string): Use the default hand.
strategy
string, default:""The strategy (optional, implementation-dependent) defines how the grasp implementation should perform the grasp. For instance, the strategy could refer to a specific behaviour-tree definition (if the skill implementation uses behaviour trees) or any other kind of ‘recipe’.
Output fields
result.error_msg
stringA string describing the execution outcome.
feedback
objectLive updates while the action runs. Can contain:
data_str: Text feedback (e.g., which hand, tree loaded, position, node
status..).
Quick snippets
Call the skill from the command-line
$ ros2 action send_goal /skill/grasp manipulation_skills/action/Grasp # then press Tab to complete the message prototype
Call the action from a Python script:
#!/usr/bin/env python
import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
from manipulation_skills.action import
class GraspActionClient(Node):
def __init__(self):
super().__init__('grasp_client')
self._action_client = ActionClient(self, , '/skill/grasp')
def send_goal(self, a, b):
goal_msg = .Goal()
# TODO: adapt to the action's parameters
# check the GraspGoal 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()
Call the action from a C++ program:
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <sstream>
#include <chrono>
#include "manipulation_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 GraspActionClient : public rclcpp::Node
{
public:
using = manipulation_skills::action::;
using GoalHandle = rclcpp_action::ClientGoalHandle<>;
explicit GraspActionClient(const rclcpp::NodeOptions & options)
: Node("grasp_action_client", options)
{
this->client_ptr_ = rclcpp_action::create_client<>(
this,
"");
this->timer_ = this->create_wall_timer(
500ms,
bind(&GraspActionClient::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 GraspGoal 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(&GraspActionClient::goal_response_callback, this, _1);
send_goal_options.feedback_callback =
bind(&GraspActionClient::feedback_callback, this, _1, _2);
send_goal_options.result_callback =
bind(&GraspActionClient::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<const ::Feedback> 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 GraspActionClient
RCLCPP_COMPONENTS_REGISTER_NODE(GraspActionClient)
You can call this skill from QML using the following code snippet. See ros_qml_plugin to learn more.
import Ros 2.0
// ...
GraspSkill {
id: mySkill
onResult: {
console.log("Skill result: " + result);
}
onFeedback: {
console.log("Skill feedback: " + feedback);
}
}
// Call the skill
mySkill.grasp();
See also
List of other Manipulation skills
List of other Motions skills