Skip to content

Commit f47ecb5

Browse files
MarqRazzJafarAbdi
andauthored
Parallel gripper controller (#3246)
* Add ParallelGripperCommand controller * only use max velocity/effor when specified * else if * clean up author and copyright comments * address review * single joint control, remove allow_stalling --------- Co-authored-by: Jafar Uruç <cafer.abdi@gmail.com>
1 parent e11cabb commit f47ecb5

File tree

8 files changed

+318
-34
lines changed

8 files changed

+318
-34
lines changed

moveit_plugins/moveit_ros_control_interface/CMakeLists.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ ament_target_dependencies(moveit_ros_control_interface_trajectory_plugin
3838
${THIS_PACKAGE_INCLUDE_DEPENDS} Boost)
3939

4040
add_library(moveit_ros_control_interface_gripper_plugin SHARED
41-
src/gripper_controller_plugin.cpp)
41+
src/gripper_command_controller_plugin.cpp)
4242
set_target_properties(
4343
moveit_ros_control_interface_gripper_plugin
4444
PROPERTIES VERSION "${moveit_ros_control_interface_VERSION}")
@@ -47,6 +47,16 @@ target_include_directories(moveit_ros_control_interface_gripper_plugin
4747
ament_target_dependencies(moveit_ros_control_interface_gripper_plugin
4848
${THIS_PACKAGE_INCLUDE_DEPENDS} Boost)
4949

50+
add_library(moveit_ros_control_interface_parallel_gripper_plugin SHARED
51+
src/parallel_gripper_command_controller_plugin.cpp)
52+
set_target_properties(
53+
moveit_ros_control_interface_parallel_gripper_plugin
54+
PROPERTIES VERSION "${moveit_ros_control_interface_VERSION}")
55+
target_include_directories(moveit_ros_control_interface_parallel_gripper_plugin
56+
PRIVATE include)
57+
ament_target_dependencies(moveit_ros_control_interface_parallel_gripper_plugin
58+
${THIS_PACKAGE_INCLUDE_DEPENDS} Boost)
59+
5060
add_library(moveit_ros_control_interface_empty_plugin SHARED
5161
src/empty_controller_plugin.cpp)
5262
set_target_properties(
@@ -65,6 +75,7 @@ set(TARGET_LIBRARIES
6575
moveit_ros_control_interface_plugin
6676
moveit_ros_control_interface_trajectory_plugin
6777
moveit_ros_control_interface_gripper_plugin
78+
moveit_ros_control_interface_parallel_gripper_plugin
6879
moveit_ros_control_interface_empty_plugin)
6980

7081
# Mark executables and/or libraries for installation

moveit_plugins/moveit_ros_control_interface/moveit_ros_control_interface_plugins.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
</class>
1111
</library>
1212
<library path="moveit_ros_control_interface_gripper_plugin">
13-
<class name="position_controllers/GripperActionController" type="moveit_ros_control_interface::GripperControllerAllocator" base_class_type="moveit_ros_control_interface::ControllerHandleAllocator">
13+
<class name="position_controllers/GripperActionController" type="moveit_ros_control_interface::GripperCommandControllerAllocator" base_class_type="moveit_ros_control_interface::ControllerHandleAllocator">
1414
<description></description>
1515
</class>
16-
<class name="effort_controllers/GripperActionController" type="moveit_ros_control_interface::GripperControllerAllocator" base_class_type="moveit_ros_control_interface::ControllerHandleAllocator">
16+
<class name="effort_controllers/GripperActionController" type="moveit_ros_control_interface::GripperCommandControllerAllocator" base_class_type="moveit_ros_control_interface::ControllerHandleAllocator">
17+
<description></description>
18+
</class>
19+
</library>
20+
<library path="moveit_ros_control_interface_parallel_gripper_plugin">
21+
<class name="parallel_gripper_action_controller/GripperActionController" type="moveit_ros_control_interface::ParallelGripperCommandControllerAllocator" base_class_type="moveit_ros_control_interface::ControllerHandleAllocator">
1722
<description></description>
1823
</class>
1924
</library>

moveit_plugins/moveit_ros_control_interface/src/gripper_controller_plugin.cpp renamed to moveit_plugins/moveit_ros_control_interface/src/gripper_command_controller_plugin.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,27 @@
3636

3737
#include <moveit_ros_control_interface/ControllerHandle.hpp>
3838
#include <pluginlib/class_list_macros.hpp>
39-
#include <moveit_simple_controller_manager/gripper_controller_handle.hpp>
39+
#include <moveit_simple_controller_manager/gripper_command_controller_handle.hpp>
4040
#include <rclcpp/node.hpp>
4141
#include <memory>
4242

4343
namespace moveit_ros_control_interface
4444
{
4545
/**
46-
* \brief Simple allocator for moveit_simple_controller_manager::FollowJointTrajectoryControllerHandle instances.
46+
* \brief Simple allocator for moveit_simple_controller_manager::GripperCommandControllerHandle instances.
4747
*/
48-
class GripperControllerAllocator : public ControllerHandleAllocator
48+
class GripperCommandControllerAllocator : public ControllerHandleAllocator
4949
{
5050
public:
5151
moveit_controller_manager::MoveItControllerHandlePtr alloc(const rclcpp::Node::SharedPtr& node,
5252
const std::string& name,
5353
const std::vector<std::string>& /* resources */) override
5454
{
55-
return std::make_shared<moveit_simple_controller_manager::GripperControllerHandle>(node, name, "gripper_cmd");
55+
return std::make_shared<moveit_simple_controller_manager::GripperCommandControllerHandle>(node, name, "gripper_cmd");
5656
}
5757
};
5858

5959
} // namespace moveit_ros_control_interface
6060

61-
PLUGINLIB_EXPORT_CLASS(moveit_ros_control_interface::GripperControllerAllocator,
61+
PLUGINLIB_EXPORT_CLASS(moveit_ros_control_interface::GripperCommandControllerAllocator,
6262
moveit_ros_control_interface::ControllerHandleAllocator);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*********************************************************************
2+
* Software License Agreement (BSD License)
3+
*
4+
* Copyright (c) 2025, Marq Rasmussen
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
*
11+
* * Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* * Redistributions in binary form must reproduce the above
14+
* copyright notice, this list of conditions and the following
15+
* disclaimer in the documentation and/or other materials provided
16+
* with the distribution.
17+
* * Neither the name of Marq Rasmussen nor the names of its
18+
* contributors may be used to endorse or promote products derived
19+
* from this software without specific prior written permission.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32+
* POSSIBILITY OF SUCH DAMAGE.
33+
*********************************************************************/
34+
35+
/* Author: Marq Rasmussen */
36+
37+
#include <moveit_ros_control_interface/ControllerHandle.hpp>
38+
#include <pluginlib/class_list_macros.hpp>
39+
#include <moveit_simple_controller_manager/parallel_gripper_command_controller_handle.hpp>
40+
#include <rclcpp/node.hpp>
41+
#include <memory>
42+
43+
namespace moveit_ros_control_interface
44+
{
45+
/**
46+
* \brief Simple allocator for moveit_simple_controller_manager::ParallelGripperCommandControllerHandle instances.
47+
*/
48+
class ParallelGripperCommandControllerAllocator : public ControllerHandleAllocator
49+
{
50+
public:
51+
moveit_controller_manager::MoveItControllerHandlePtr alloc(const rclcpp::Node::SharedPtr& node,
52+
const std::string& name,
53+
const std::vector<std::string>& /* resources */) override
54+
{
55+
return std::make_shared<moveit_simple_controller_manager::ParallelGripperCommandControllerHandle>(node, name,
56+
"gripper_cmd");
57+
}
58+
};
59+
60+
} // namespace moveit_ros_control_interface
61+
62+
PLUGINLIB_EXPORT_CLASS(moveit_ros_control_interface::ParallelGripperCommandControllerAllocator,
63+
moveit_ros_control_interface::ControllerHandleAllocator);

moveit_plugins/moveit_simple_controller_manager/include/moveit_simple_controller_manager/gripper_controller_handle.hpp renamed to moveit_plugins/moveit_simple_controller_manager/include/moveit_simple_controller_manager/gripper_command_controller_handle.hpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ namespace moveit_simple_controller_manager
4747
* This is an interface for a gripper using control_msgs/GripperCommandAction
4848
* action interface (single DOF).
4949
*/
50-
class GripperControllerHandle : public ActionBasedControllerHandle<control_msgs::action::GripperCommand>
50+
class GripperCommandControllerHandle : public ActionBasedControllerHandle<control_msgs::action::GripperCommand>
5151
{
5252
public:
5353
/* Topics will map to name/ns/goal, name/ns/result, etc */
54-
GripperControllerHandle(const rclcpp::Node::SharedPtr& node, const std::string& name, const std::string& ns,
55-
const double max_effort = 0.0)
54+
GripperCommandControllerHandle(const rclcpp::Node::SharedPtr& node, const std::string& name, const std::string& ns,
55+
const double max_effort = 0.0)
5656
: ActionBasedControllerHandle<control_msgs::action::GripperCommand>(
5757
node, name, ns, "moveit.simple_controller_manager.gripper_controller_handle")
5858
, allow_failure_(false)
@@ -98,23 +98,23 @@ class GripperControllerHandle : public ActionBasedControllerHandle<control_msgs:
9898
return false;
9999
}
100100

101-
std::vector<std::size_t> gripper_joint_indexes;
101+
std::vector<std::size_t> gripper_joint_indices;
102102
for (std::size_t i = 0; i < trajectory.joint_trajectory.joint_names.size(); ++i)
103103
{
104104
if (command_joints_.find(trajectory.joint_trajectory.joint_names[i]) != command_joints_.end())
105105
{
106-
gripper_joint_indexes.push_back(i);
106+
gripper_joint_indices.push_back(i);
107107
if (!parallel_jaw_gripper_)
108108
break;
109109
}
110110
}
111111

112-
if (gripper_joint_indexes.empty())
112+
if (gripper_joint_indices.empty())
113113
{
114114
RCLCPP_WARN(logger_, "No command_joint was specified for the MoveIt controller gripper handle. \
115-
Please see GripperControllerHandle::addCommandJoint() and \
116-
GripperControllerHandle::setCommandJoint(). Assuming index 0.");
117-
gripper_joint_indexes.push_back(0);
115+
Please see GripperCommandControllerHandle::addCommandJoint() and \
116+
GripperCommandControllerHandle::setCommandJoint(). Assuming index 0.");
117+
gripper_joint_indices.push_back(0);
118118
}
119119

120120
// goal to be sent
@@ -126,7 +126,7 @@ class GripperControllerHandle : public ActionBasedControllerHandle<control_msgs:
126126
RCLCPP_DEBUG(logger_, "Sending command from trajectory point %d", tpoint);
127127

128128
// fill in goal from last point
129-
for (std::size_t idx : gripper_joint_indexes)
129+
for (std::size_t idx : gripper_joint_indices)
130130
{
131131
if (trajectory.joint_trajectory.points[tpoint].positions.size() <= idx)
132132
{

moveit_plugins/moveit_simple_controller_manager/include/moveit_simple_controller_manager/gripper_controller_handle.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,5 @@
4848
/* Author: Michael Ferguson, Ioan Sucan, E. Gil Jones */
4949

5050
#pragma once
51-
#pragma message(".h header is obsolete. Please use the .hpp header instead.")
52-
#include <moveit_simple_controller_manager/gripper_controller_handle.hpp>
51+
#pragma message(".h header is obsolete. Please use the gripper_command_controller_handle.hpp header instead.")
52+
#include <moveit_simple_controller_manager/gripper_command_controller_handle.hpp>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*********************************************************************
2+
* Software License Agreement (BSD License)
3+
*
4+
* Copyright (c) 2025, Marq Rasmussen
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
*
11+
* * Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* * Redistributions in binary form must reproduce the above
14+
* copyright notice, this list of conditions and the following
15+
* disclaimer in the documentation and/or other materials provided
16+
* with the distribution.
17+
* * Neither the name of the Marq Rasmussen nor the names of its
18+
* contributors may be used to endorse or promote products derived
19+
* from this software without specific prior written permission.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32+
* POSSIBILITY OF SUCH DAMAGE.
33+
*********************************************************************/
34+
/* Design inspired by gripper_command_controller_handle.hpp */
35+
/* Author: Marq Rasmussen */
36+
37+
#pragma once
38+
39+
#include <moveit_simple_controller_manager/action_based_controller_handle.hpp>
40+
#include <control_msgs/action/parallel_gripper_command.hpp>
41+
#include <set>
42+
43+
namespace moveit_simple_controller_manager
44+
{
45+
/*
46+
* This is an interface for a gripper using the control_msgs/ParallelGripperCommand action interface.
47+
*/
48+
class ParallelGripperCommandControllerHandle
49+
: public ActionBasedControllerHandle<control_msgs::action::ParallelGripperCommand>
50+
{
51+
public:
52+
/* Topics will map to name/ns/goal, name/ns/result, etc */
53+
ParallelGripperCommandControllerHandle(const rclcpp::Node::SharedPtr& node, const std::string& name,
54+
const std::string& ns, const double max_effort = 0.0,
55+
const double max_velocity = 0.0)
56+
: ActionBasedControllerHandle<control_msgs::action::ParallelGripperCommand>(
57+
node, name, ns, "moveit.simple_controller_manager.parallel_gripper_controller_handle")
58+
, max_effort_(max_effort)
59+
, max_velocity_(max_velocity)
60+
{
61+
}
62+
63+
bool sendTrajectory(const moveit_msgs::msg::RobotTrajectory& trajectory) override
64+
{
65+
RCLCPP_DEBUG_STREAM(logger_, "Received new trajectory for " << name_);
66+
67+
if (!controller_action_client_)
68+
return false;
69+
70+
if (!isConnected())
71+
{
72+
RCLCPP_ERROR_STREAM(logger_, "Action client not connected to action server: " << getActionName());
73+
return false;
74+
}
75+
76+
if (!trajectory.multi_dof_joint_trajectory.points.empty())
77+
{
78+
RCLCPP_ERROR(logger_, "%s cannot execute multi-dof trajectories.", name_.c_str());
79+
return false;
80+
}
81+
82+
if (trajectory.joint_trajectory.points.empty())
83+
{
84+
RCLCPP_ERROR(logger_, "%s requires at least one joint trajectory point, but none received.", name_.c_str());
85+
return false;
86+
}
87+
88+
if (trajectory.joint_trajectory.joint_names.empty())
89+
{
90+
RCLCPP_ERROR(logger_, "%s received a trajectory with no joint names specified.", name_.c_str());
91+
return false;
92+
}
93+
94+
// goal to be sent
95+
control_msgs::action::ParallelGripperCommand::Goal goal;
96+
auto& cmd_state = goal.command;
97+
98+
auto& joint_names = trajectory.joint_trajectory.joint_names;
99+
auto it = std::find(joint_names.begin(), joint_names.end(), command_joint_);
100+
if (it != joint_names.end())
101+
{
102+
cmd_state.name.push_back(command_joint_);
103+
std::size_t gripper_joint_index = std::distance(joint_names.begin(), it);
104+
// send last trajectory point
105+
if (trajectory.joint_trajectory.points.back().positions.size() <= gripper_joint_index)
106+
{
107+
RCLCPP_ERROR(logger_, "ParallelGripperCommand expects a joint trajectory with one \
108+
point that specifies at least the position of joint \
109+
'%s', but insufficient positions provided.",
110+
trajectory.joint_trajectory.joint_names[gripper_joint_index].c_str());
111+
return false;
112+
}
113+
cmd_state.position.push_back(trajectory.joint_trajectory.points.back().positions[gripper_joint_index]);
114+
// only set the velocity or effort if the user has specified a positive non-zero max value
115+
if (max_velocity_ > 0.0)
116+
{
117+
cmd_state.velocity.push_back(max_velocity_);
118+
}
119+
if (max_effort_ > 0.0)
120+
{
121+
cmd_state.effort.push_back(max_effort_);
122+
}
123+
}
124+
else
125+
{
126+
RCLCPP_ERROR(logger_, "Received trajectory does not include a command for joint name %s.", command_joint_.c_str());
127+
return false;
128+
}
129+
130+
rclcpp_action::Client<control_msgs::action::ParallelGripperCommand>::SendGoalOptions send_goal_options;
131+
// Active callback
132+
send_goal_options.goal_response_callback =
133+
[this](const rclcpp_action::Client<control_msgs::action::ParallelGripperCommand>::GoalHandle::SharedPtr&
134+
/* unused-arg */) { RCLCPP_DEBUG_STREAM(logger_, name_ << " started execution."); };
135+
// Send goal
136+
auto current_goal_future = controller_action_client_->async_send_goal(goal, send_goal_options);
137+
current_goal_ = current_goal_future.get();
138+
if (!current_goal_)
139+
{
140+
RCLCPP_ERROR(logger_, "%s goal was rejected by server.", name_.c_str());
141+
return false;
142+
}
143+
144+
done_ = false;
145+
last_exec_ = moveit_controller_manager::ExecutionStatus::RUNNING;
146+
return true;
147+
}
148+
149+
void setCommandJoint(const std::string& name)
150+
{
151+
command_joint_ = name;
152+
}
153+
154+
private:
155+
void controllerDoneCallback(
156+
const rclcpp_action::ClientGoalHandle<control_msgs::action::ParallelGripperCommand>::WrappedResult& wrapped_result)
157+
override
158+
{
159+
finishControllerExecution(wrapped_result.code);
160+
}
161+
162+
/*
163+
* The ``max_effort`` used in the ParallelGripperCommand message.
164+
*/
165+
double max_effort_ = 0.0;
166+
167+
/*
168+
* The ``max_velocity_`` used in the ParallelGripperCommand message.
169+
*/
170+
double max_velocity_ = 0.0;
171+
172+
/*
173+
* The joint to command in the ParallelGripperCommand message
174+
*/
175+
std::string command_joint_;
176+
}; // namespace moveit_simple_controller_manager
177+
178+
} // end namespace moveit_simple_controller_manager

0 commit comments

Comments
 (0)