cartesian_trajectory_controller.hpp
Go to the documentation of this file.
1 // -- BEGIN LICENSE BLOCK ----------------------------------------------
2 // Copyright 2020 FZI Forschungszentrum Informatik
3 // Created on behalf of Universal Robots A/S
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // -- END LICENSE BLOCK ------------------------------------------------
17 
18 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
26 
29 
31 {
32 template <class HWInterface>
34  ros::NodeHandle& controller_nh)
35 {
36  if (!ControlPolicy::init(hw, nh, controller_nh))
37  {
38  return false;
39  }
40 
41  // Use speed scaling interface if available
42  auto speed_scaling_interface = hw->get<scaled_controllers::SpeedScalingInterface>();
43  if (!speed_scaling_interface)
44  {
45  ROS_INFO_STREAM(controller_nh.getNamespace() << ": Your RobotHW seems not to provide speed scaling. Starting "
46  "without this feature.");
47  speed_scaling_ = nullptr;
48  }
49  else
50  {
51  speed_scaling_ = std::make_unique<scaled_controllers::SpeedScalingHandle>(speed_scaling_interface->getHandle("speed"
52  "_scal"
53  "ing_"
54  "facto"
55  "r"));
56  }
57 
58  // Action server
60  controller_nh, "follow_cartesian_trajectory",
61  std::bind(&CartesianTrajectoryController::executeCB, this, std::placeholders::_1), false));
62 
63  action_server_->registerPreemptCallback(std::bind(&CartesianTrajectoryController::preemptCB, this));
64 
65  action_server_->start();
66 
67  return true;
68 }
69 
70 template <class HWInterface>
72 {
73  // Start where we are
74  ControlPolicy::updateCommand(ControlPolicy::getState());
75 }
76 
77 template <class HWInterface>
79 {
80  if (action_server_->isActive())
81  {
82  // Set canceled flag in the action result
83  action_server_->setPreempted();
84  }
85 }
86 
87 template <class HWInterface>
89 {
90  if (action_server_->isActive() && !done_.load())
91  {
92  // Apply speed scaling if available.
93  const double factor = (speed_scaling_) ? *speed_scaling_->getScalingFactor() : 1.0;
94  trajectory_duration_.now += period * factor;
95 
96  // Sample the Cartesian trajectory's target state and command that to
97  // the control policy.
98  if (trajectory_duration_.now < trajectory_duration_.end)
99  {
100  std::lock_guard<std::mutex> lock_trajectory(lock_);
101 
103  trajectory_.sample(trajectory_duration_.now.toSec(), desired);
104 
105  ControlPolicy::updateCommand(desired);
106 
107  // Give feedback
108  auto actual = ControlPolicy::getState();
109  auto error = desired - actual;
110 
111  cartesian_control_msgs::FollowCartesianTrajectoryFeedback f;
112  auto now = trajectory_duration_.now.toSec();
113  f.desired = desired.toMsg(now);
114  f.actual = actual.toMsg(now);
115  f.error = error.toMsg(now);
116 
117  action_server_->publishFeedback(f);
118 
119  // Check tolerances and set terminal conditions for the
120  // action server if special criteria are met.
121  monitorExecution(error);
122  }
123  else // Time is up. Check goal tolerances and set terminal state.
124  {
125  timesUp();
126  }
127  }
128 }
129 
130 template <class HWInterface>
132  const cartesian_control_msgs::FollowCartesianTrajectoryGoalConstPtr& goal)
133 {
134  // Upon entering this callback, the simple action server has already
135  // preempted the previously active goal (if any) and has accepted the new goal.
136 
137  if (!this->isRunning())
138  {
139  ROS_ERROR("Can't accept new action goals. Controller is not running.");
140  cartesian_control_msgs::FollowCartesianTrajectoryResult result;
141  result.error_code = cartesian_control_msgs::FollowCartesianTrajectoryResult::INVALID_GOAL;
142  action_server_->setAborted(result);
143  return;
144  }
145 
146  path_tolerances_ = goal->path_tolerance;
147  goal_tolerances_ = goal->goal_tolerance;
148 
149  // Start where we are by adding the current state as first trajectory
150  // waypoint.
151  auto state = ControlPolicy::getState();
152  {
153  std::lock_guard<std::mutex> lock_trajectory(lock_);
154 
155  cartesian_control_msgs::CartesianTrajectory traj = goal->trajectory;
156  traj.points.insert(traj.points.begin(), state.toMsg(0)); // start time zero
157 
158  if (!trajectory_.init(traj))
159  {
160  ROS_ERROR("Action goal has invalid trajectory.");
161  cartesian_control_msgs::FollowCartesianTrajectoryResult result;
162  result.error_code = cartesian_control_msgs::FollowCartesianTrajectoryResult::INVALID_GOAL;
163  action_server_->setAborted(result);
164  return;
165  }
166  }
167 
168  // Time keeping
169  trajectory_duration_.now = ros::Duration(0.0);
170  trajectory_duration_.end = goal->trajectory.points.back().time_from_start + goal->goal_time_tolerance;
171 
172  done_ = false;
173 
174  while (!done_.load())
175  {
176  ros::Duration(0.01).sleep();
177  }
178 }
179 
180 template <class HWInterface>
182 {
183  cartesian_control_msgs::FollowCartesianTrajectoryResult result;
184  result.error_string = "preempted";
185  action_server_->setPreempted(result);
186 
187  done_ = true;
188 }
189 
190 template <class HWInterface>
192 {
193  using Result = cartesian_control_msgs::FollowCartesianTrajectoryResult;
194  Result result;
195 
196  // When time is over, sampling gives us the last waypoint.
198  {
199  std::lock_guard<std::mutex> lock_trajectory(lock_);
200  trajectory_.sample(trajectory_duration_.now.toSec(), goal);
201  }
202 
203  // TODO: What should happen when speed scaling was active?
204  // Only check position and orientation in that case?
205  // Address this once we know more edge cases during beta testing.
206 
207  // Check if goal was reached.
208  // Abort if any of the dimensions exceeds its goal tolerance
209  auto error = goal - ControlPolicy::getState();
210 
211  if (!withinTolerances(error, goal_tolerances_))
212  {
213  result.error_code = Result::GOAL_TOLERANCE_VIOLATED;
214  action_server_->setAborted(result);
215  }
216  else // Succeed
217  {
218  result.error_code = Result::SUCCESSFUL;
219  action_server_->setSucceeded(result);
220  }
221 
222  done_ = true;
223 }
224 
225 template <class HWInterface>
228 {
229  if (!withinTolerances(error, path_tolerances_))
230  {
231  using Result = cartesian_control_msgs::FollowCartesianTrajectoryResult;
232  Result result;
233  result.error_code = Result::PATH_TOLERANCE_VIOLATED;
234  action_server_->setAborted(result);
235  done_ = true;
236  }
237 }
238 
239 template <class HWInterface>
241  const ros_controllers_cartesian::CartesianState& error, const cartesian_control_msgs::CartesianTolerance& tolerance)
242 {
243  // Uninitialized tolerances do not need checking
244  cartesian_control_msgs::CartesianTolerance uninitialized;
245  std::stringstream str_1;
246  std::stringstream str_2;
247  str_1 << tolerance;
248  str_2 << uninitialized;
249 
250  if (str_1.str() == str_2.str())
251  {
252  return true;
253  }
254 
255  auto not_within_limits = [](const auto& a, const auto& b) { return a.x() > b.x || a.y() > b.y || a.z() > b.z; };
256 
257  // Check each individual dimension separately.
258  if (not_within_limits(error.p, tolerance.position_error) ||
259  not_within_limits(error.rot(), tolerance.orientation_error) ||
260  not_within_limits(error.v, tolerance.twist_error.linear) ||
261  not_within_limits(error.w, tolerance.twist_error.angular) ||
262  not_within_limits(error.v_dot, tolerance.acceleration_error.linear) ||
263  not_within_limits(error.w_dot, tolerance.acceleration_error.angular))
264  {
265  return false;
266  }
267 
268  return true;
269 }
270 
271 } // namespace cartesian_trajectory_controller
f
void update(const ros::Time &time, const ros::Duration &period) override
void monitorExecution(const ros_controllers_cartesian::CartesianState &error)
cartesian_control_msgs::CartesianTrajectoryPoint toMsg(int time_from_start=0) const
#define ROS_ERROR(...)
bool withinTolerances(const ros_controllers_cartesian::CartesianState &error, const cartesian_control_msgs::CartesianTolerance &tolerance)
void executeCB(const cartesian_control_msgs::FollowCartesianTrajectoryGoalConstPtr &goal)
bool init(hardware_interface::RobotHW *hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh) override
#define ROS_INFO_STREAM(args)
const std::string & getNamespace() const
bool sleep() const


cartesian_trajectory_controller
Author(s):
autogenerated on Thu Feb 23 2023 03:10:48