moveit2
The MoveIt Motion Planning Framework for ROS 2.
follow_joint_trajectory_controller_handle.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Unbounded Robotics Inc.
5  * Copyright (c) 2012, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Willow Garage nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 /* Author: Michael Ferguson, Ioan Sucan, E. Gil Jones */
37 
39 
40 using namespace std::placeholders;
41 
43 {
44 bool FollowJointTrajectoryControllerHandle::sendTrajectory(const moveit_msgs::msg::RobotTrajectory& trajectory)
45 {
46  RCLCPP_DEBUG_STREAM(LOGGER, "new trajectory to " << name_);
47 
48  if (!controller_action_client_)
49  return false;
50 
51  if (!isConnected())
52  {
53  RCLCPP_ERROR_STREAM(LOGGER, "Action client not connected to action server: " << getActionName());
54  return false;
55  }
56 
57  if (done_)
58  RCLCPP_INFO_STREAM(LOGGER, "sending trajectory to " << name_);
59  else
60  RCLCPP_INFO_STREAM(LOGGER, "sending continuation for the currently executed trajectory to " << name_);
61 
62  control_msgs::action::FollowJointTrajectory::Goal goal = goal_template_;
63  goal.trajectory = trajectory.joint_trajectory;
64  goal.multi_dof_trajectory = trajectory.multi_dof_joint_trajectory;
65 
66  rclcpp_action::Client<control_msgs::action::FollowJointTrajectory>::SendGoalOptions send_goal_options;
67  // Active callback
68  send_goal_options.goal_response_callback =
69  [this](
70  const rclcpp_action::Client<control_msgs::action::FollowJointTrajectory>::GoalHandle::SharedPtr& goal_handle) {
71  RCLCPP_INFO_STREAM(LOGGER, name_ << " started execution");
72  if (!goal_handle)
73  RCLCPP_WARN(LOGGER, "Goal request rejected");
74  else
75  RCLCPP_INFO(LOGGER, "Goal request accepted!");
76  };
77 
78  done_ = false;
80 
81  // Send goal
82  auto current_goal_future = controller_action_client_->async_send_goal(goal, send_goal_options);
83  current_goal_ = current_goal_future.get();
84  if (!current_goal_)
85  {
86  RCLCPP_ERROR(LOGGER, "Goal was rejected by server");
87  return false;
88  }
89  return true;
90 }
91 
92 // TODO(JafarAbdi): Revise parameter lookup
93 // void FollowJointTrajectoryControllerHandle::configure(XmlRpc::XmlRpcValue& config)
94 //{
95 // if (config.hasMember("path_tolerance"))
96 // configure(config["path_tolerance"], "path_tolerance", goal_template_.path_tolerance);
97 // if (config.hasMember("goal_tolerance"))
98 // configure(config["goal_tolerance"], "goal_tolerance", goal_template_.goal_tolerance);
99 // if (config.hasMember("goal_time_tolerance"))
100 // goal_template_.goal_time_tolerance = ros::Duration(parseDouble(config["goal_time_tolerance"]));
101 //}
102 
103 namespace
104 {
105 enum ToleranceVariables
106 {
107  POSITION,
108  VELOCITY,
109  ACCELERATION
110 };
111 template <ToleranceVariables>
112 double& variable(control_msgs::msg::JointTolerance& msg);
113 
114 template <>
115 inline double& variable<POSITION>(control_msgs::msg::JointTolerance& msg)
116 {
117  return msg.position;
118 }
119 template <>
120 inline double& variable<VELOCITY>(control_msgs::msg::JointTolerance& msg)
121 {
122  return msg.velocity;
123 }
124 template <>
125 inline double& variable<ACCELERATION>(control_msgs::msg::JointTolerance& msg)
126 {
127  return msg.acceleration;
128 }
129 
130 static std::map<ToleranceVariables, std::string> VAR_NAME = { { POSITION, "position" },
131  { VELOCITY, "velocity" },
132  { ACCELERATION, "acceleration" } };
133 static std::map<ToleranceVariables, decltype(&variable<POSITION>)> VAR_ACCESS = { { POSITION, &variable<POSITION> },
134  { VELOCITY, &variable<VELOCITY> },
135  { ACCELERATION,
136  &variable<ACCELERATION> } };
137 
138 const char* errorCodeToMessage(int error_code)
139 {
140  switch (error_code)
141  {
142  case control_msgs::action::FollowJointTrajectory::Result::SUCCESSFUL:
143  return "SUCCESSFUL";
144  case control_msgs::action::FollowJointTrajectory::Result::INVALID_GOAL:
145  return "INVALID_GOAL";
146  case control_msgs::action::FollowJointTrajectory::Result::INVALID_JOINTS:
147  return "INVALID_JOINTS";
148  case control_msgs::action::FollowJointTrajectory::Result::OLD_HEADER_TIMESTAMP:
149  return "OLD_HEADER_TIMESTAMP";
150  case control_msgs::action::FollowJointTrajectory::Result::PATH_TOLERANCE_VIOLATED:
151  return "PATH_TOLERANCE_VIOLATED";
152  case control_msgs::action::FollowJointTrajectory::Result::GOAL_TOLERANCE_VIOLATED:
153  return "GOAL_TOLERANCE_VIOLATED";
154  default:
155  return "unknown error";
156  }
157 }
158 } // namespace
159 
160 // TODO(JafarAbdi): Revise parameter lookup
161 // void FollowJointTrajectoryControllerHandle::configure(XmlRpc::XmlRpcValue& config, const std::string& config_name,
162 // std::vector<control_msgs::JointTolerance>& tolerances)
163 //{
164 // if (isStruct(config)) // config should be either a struct of position, velocity, acceleration
165 // {
166 // for (ToleranceVariables var : { POSITION, VELOCITY, ACCELERATION })
167 // {
168 // if (!config.hasMember(VAR_NAME[var]))
169 // continue;
170 // XmlRpc::XmlRpcValue values = config[VAR_NAME[var]];
171 // if (isArray(values, joints_.size()))
172 // {
173 // size_t i = 0;
174 // for (const auto& joint_name : joints_)
175 // VAR_ACCESS[var](getTolerance(tolerances, joint_name)) = parseDouble(values[i++]);
176 // }
177 // else
178 // { // use common value for all joints
179 // double value = parseDouble(values);
180 // for (const auto& joint_name : joints_)
181 // VAR_ACCESS[var](getTolerance(tolerances, joint_name)) = value;
182 // }
183 // }
184 // }
185 // else if (isArray(config)) // or an array of JointTolerance msgs
186 // {
187 // for (int i = 0; i < config.size(); ++i) // NOLINT(modernize-loop-convert)
188 // {
189 // control_msgs::JointTolerance& tol = getTolerance(tolerances, config[i]["name"]);
190 // for (ToleranceVariables var : { POSITION, VELOCITY, ACCELERATION })
191 // {
192 // if (!config[i].hasMember(VAR_NAME[var]))
193 // continue;
194 // VAR_ACCESS[var](tol) = parseDouble(config[i][VAR_NAME[var]]);
195 // }
196 // }
197 // }
198 // else
199 // ROS_WARN_STREAM_NAMED(LOGNAME, "Invalid " << config_name);
200 //}
201 
202 control_msgs::msg::JointTolerance&
203 FollowJointTrajectoryControllerHandle::getTolerance(std::vector<control_msgs::msg::JointTolerance>& tolerances,
204  const std::string& name)
205 {
206  auto it = std::lower_bound(tolerances.begin(), tolerances.end(), name,
207  [](const control_msgs::msg::JointTolerance& lhs, const std::string& rhs) {
208  return lhs.name < rhs;
209  });
210  if (it == tolerances.cend() || it->name != name)
211  { // insert new entry if not yet available
212  it = tolerances.insert(it, control_msgs::msg::JointTolerance());
213  it->name = name;
214  }
215  return *it;
216 }
217 
218 void FollowJointTrajectoryControllerHandle::controllerDoneCallback(
219  const rclcpp_action::ClientGoalHandle<control_msgs::action::FollowJointTrajectory>::WrappedResult& wrapped_result)
220 {
221  // Output custom error message for FollowJointTrajectoryResult if necessary
222  if (!wrapped_result.result)
223  RCLCPP_WARN_STREAM(LOGGER, "Controller '" << name_ << "' done, no result returned");
224  else if (wrapped_result.result->error_code == control_msgs::action::FollowJointTrajectory::Result::SUCCESSFUL)
225  RCLCPP_INFO_STREAM(LOGGER, "Controller '" << name_ << "' successfully finished");
226  else
227  RCLCPP_WARN_STREAM(LOGGER, "Controller '" << name_ << "' failed with error "
228  << errorCodeToMessage(wrapped_result.result->error_code) << ": "
229  << wrapped_result.result->error_string);
230  finishControllerExecution(wrapped_result.code);
231 }
232 
233 } // end namespace moveit_simple_controller_manager
name
Definition: setup.py:7