scaled_joint_trajectory_controller.h
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // Copyright 2019 FZI Forschungszentrum Informatik
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 // -- END LICENSE BLOCK ------------------------------------------------
18 
19 //----------------------------------------------------------------------
26 //----------------------------------------------------------------------
27 #ifndef UR_CONTROLLERS_SCALED_TRAJECTORY_CONTROLLER_H_INCLUDED
28 #define UR_CONTROLLERS_SCALED_TRAJECTORY_CONTROLLER_H_INCLUDED
29 
32 
33 namespace ur_controllers
34 {
35 template <class SegmentImpl, class HardwareInterface>
37  : public joint_trajectory_controller::JointTrajectoryController<SegmentImpl, HardwareInterface>
38 {
39 public:
41  virtual ~ScaledJointTrajectoryController() = default;
42 
43  void update(const ros::Time& time, const ros::Duration& period)
44  {
45  this->scaling_factor_ = this->joints_[0].getScalingFactor();
46  // Get currently followed trajectory
47  typename Base::TrajectoryPtr curr_traj_ptr;
48  this->curr_trajectory_box_.get(curr_traj_ptr);
49  typename Base::Trajectory& curr_traj = *curr_traj_ptr;
50 
51  // Update time data
52  typename Base::TimeData time_data;
53  time_data.time = time; // Cache current time
54  time_data.period = ros::Duration(this->scaling_factor_ * period.toSec()); // Cache current control period
55  time_data.uptime = this->time_data_.readFromRT()->uptime + time_data.period; // Update controller uptime
56  ros::Time traj_time = this->time_data_.readFromRT()->uptime + period;
57  this->time_data_.writeFromNonRT(time_data); // TODO: Grrr, we need a lock-free data structure here!
58 
59  // NOTE: It is very important to execute the two above code blocks in the specified sequence: first get current
60  // trajectory, then update time data. Hopefully the following paragraph sheds a bit of light on the rationale.
61  // The non-rt thread responsible for processing new commands enqueues trajectories that can start at the _next_
62  // control cycle (eg. zero start time) or later (eg. when we explicitly request a start time in the future).
63  // If we reverse the order of the two blocks above, and update the time data first; it's possible that by the time
64  // we fetch the currently followed trajectory, it has been updated by the non-rt thread with something that starts
65  // in the next control cycle, leaving the current cycle without a valid trajectory.
66 
67  // Update current state and state error
68  for (unsigned int i = 0; i < this->joints_.size(); ++i)
69  {
70  this->current_state_.position[i] = this->joints_[i].getPosition();
71  this->current_state_.velocity[i] = this->joints_[i].getVelocity();
72  // There's no acceleration data available in a joint handle
73 
74  typename Base::TrajectoryPerJoint::const_iterator segment_it =
75  sample(curr_traj[i], traj_time.toSec(), this->desired_joint_state_);
76  if (curr_traj[i].end() == segment_it)
77  {
78  // Non-realtime safe, but should never happen under normal operation
79  ROS_ERROR_NAMED(this->name_, "Unexpected error: No trajectory defined at current time. Please contact the "
80  "package "
81  "maintainer.");
82  return;
83  }
84  this->desired_state_.position[i] = this->desired_joint_state_.position[0];
85  this->desired_state_.velocity[i] = this->desired_joint_state_.velocity[0];
86  this->desired_state_.acceleration[i] = this->desired_joint_state_.acceleration[0];
87  ;
88 
89  this->state_joint_error_.position[0] =
90  angles::shortest_angular_distance(this->current_state_.position[i], this->desired_joint_state_.position[0]);
91  this->state_joint_error_.velocity[0] = this->desired_joint_state_.velocity[0] - this->current_state_.velocity[i];
92  this->state_joint_error_.acceleration[0] = 0.0;
93 
94  this->state_error_.position[i] =
95  angles::shortest_angular_distance(this->current_state_.position[i], this->desired_joint_state_.position[0]);
96  this->state_error_.velocity[i] = this->desired_joint_state_.velocity[0] - this->current_state_.velocity[i];
97  this->state_error_.acceleration[i] = 0.0;
98 
99  // Check tolerances
100  const typename Base::RealtimeGoalHandlePtr rt_segment_goal = segment_it->getGoalHandle();
101  if (rt_segment_goal && rt_segment_goal == this->rt_active_goal_)
102  {
103  // Check tolerances
104  if (time_data.uptime.toSec() < segment_it->endTime())
105  {
106  // Currently executing a segment: check path tolerances
108  segment_it->getTolerances();
109  if (!checkStateTolerancePerJoint(this->state_joint_error_, joint_tolerances.state_tolerance))
110  {
111  if (this->verbose_)
112  {
113  ROS_ERROR_STREAM_NAMED(this->name_, "Path tolerances failed for joint: " << this->joint_names_[i]);
114  checkStateTolerancePerJoint(this->state_joint_error_, joint_tolerances.state_tolerance, true);
115  }
116  rt_segment_goal->preallocated_result_->error_code =
117  control_msgs::FollowJointTrajectoryResult::PATH_TOLERANCE_VIOLATED;
118  rt_segment_goal->setAborted(rt_segment_goal->preallocated_result_);
119  this->rt_active_goal_.reset();
120  this->successful_joint_traj_.reset();
121  }
122  }
123  else if (segment_it == --curr_traj[i].end())
124  {
125  if (this->verbose_)
127  "Finished executing last segment, checking goal "
128  "tolerances");
129 
130  // Controller uptime
131  const ros::Time uptime = this->time_data_.readFromRT()->uptime;
132 
133  // Checks that we have ended inside the goal tolerances
135  segment_it->getTolerances();
136  const bool inside_goal_tolerances =
138 
139  if (inside_goal_tolerances)
140  {
141  this->successful_joint_traj_[i] = 1;
142  }
143  else if (uptime.toSec() < segment_it->endTime() + tolerances.goal_time_tolerance)
144  {
145  // Still have some time left to meet the goal state tolerances
146  }
147  else
148  {
149  if (this->verbose_)
150  {
151  ROS_ERROR_STREAM_NAMED(this->name_, "Goal tolerances failed for joint: " << this->joint_names_[i]);
152  // Check the tolerances one more time to output the errors that occurs
154  }
155 
156  rt_segment_goal->preallocated_result_->error_code =
157  control_msgs::FollowJointTrajectoryResult::GOAL_TOLERANCE_VIOLATED;
158  rt_segment_goal->setAborted(rt_segment_goal->preallocated_result_);
159  this->rt_active_goal_.reset();
160  this->successful_joint_traj_.reset();
161  }
162  }
163  }
164  }
165 
166  // If there is an active goal and all segments finished successfully then set goal as succeeded
167  typename Base::RealtimeGoalHandlePtr current_active_goal(this->rt_active_goal_);
168  if (current_active_goal && this->successful_joint_traj_.count() == this->joints_.size())
169  {
170  current_active_goal->preallocated_result_->error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
171  current_active_goal->setSucceeded(current_active_goal->preallocated_result_);
172  current_active_goal.reset(); // do not publish feedback
173  this->rt_active_goal_.reset();
174  this->successful_joint_traj_.reset();
175  }
176 
177  // Hardware interface adapter: Generate and send commands
178  this->hw_iface_adapter_.updateCommand(time_data.uptime, time_data.period, this->desired_state_, this->state_error_);
179 
180  // Set action feedback
181  if (current_active_goal)
182  {
183  current_active_goal->preallocated_feedback_->header.stamp = this->time_data_.readFromRT()->time;
184  current_active_goal->preallocated_feedback_->desired.positions = this->desired_state_.position;
185  current_active_goal->preallocated_feedback_->desired.velocities = this->desired_state_.velocity;
186  current_active_goal->preallocated_feedback_->desired.accelerations = this->desired_state_.acceleration;
187  current_active_goal->preallocated_feedback_->actual.positions = this->current_state_.position;
188  current_active_goal->preallocated_feedback_->actual.velocities = this->current_state_.velocity;
189  current_active_goal->preallocated_feedback_->error.positions = this->state_error_.position;
190  current_active_goal->preallocated_feedback_->error.velocities = this->state_error_.velocity;
191  current_active_goal->setFeedback(current_active_goal->preallocated_feedback_);
192  }
193 
194  // Publish state
195  this->publishState(time_data.uptime);
196  }
197 
198 protected:
201 
202 private:
203  /* data */
204 };
205 } // namespace ur_controllers
206 
207 #endif // ifndef UR_CONTROLLERS_SCALED_TRAJECTORY_CONTROLLER_H_INCLUDED
#define ROS_ERROR_STREAM_NAMED(name, args)
Trajectory::const_iterator sample(const Trajectory &trajectory, const typename Trajectory::value_type::Time &time, typename Trajectory::value_type::State &state)
std::vector< TrajectoryPerJoint > Trajectory
bool checkStateTolerancePerJoint(const State &state_error, const StateTolerances< typename State::Scalar > &state_tolerance, bool show_errors=false)
void update(const ros::Time &time, const ros::Duration &period)
void updateCommand(const ros::Time &, const ros::Duration &, const typename Segment::State &, const typename Segment::State &)
realtime_tools::RealtimeBuffer< TimeData > time_data_
#define ROS_ERROR_NAMED(name,...)
#define ROS_DEBUG_STREAM_THROTTLE_NAMED(period, name, args)
def shortest_angular_distance(from_angle, to_angle)


ur_controllers
Author(s):
autogenerated on Sun Aug 22 2021 02:38:05