Skip to content

Commit 60a0acd

Browse files
author
Felix Exner
committed
Update sjtc to newest upstream API
1 parent 814408f commit 60a0acd

File tree

1 file changed

+142
-109
lines changed

1 file changed

+142
-109
lines changed

ur_controllers/src/scaled_joint_trajectory_controller.cpp

Lines changed: 142 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ controller_interface::CallbackReturn ScaledJointTrajectoryController::on_activat
7474
}
7575

7676
controller_interface::return_type ScaledJointTrajectoryController::update(const rclcpp::Time& time,
77-
const rclcpp::Duration& /*period*/)
77+
const rclcpp::Duration& period)
7878
{
7979
if (state_interfaces_.back().get_name() == scaled_params_.speed_scaling_interface_name) {
8080
scaling_factor_ = state_interfaces_.back().get_value();
@@ -87,189 +87,222 @@ controller_interface::return_type ScaledJointTrajectoryController::update(const
8787
return controller_interface::return_type::OK;
8888
}
8989

90-
auto resize_joint_trajectory_point = [&](trajectory_msgs::msg::JointTrajectoryPoint& point, size_t size) {
91-
point.positions.resize(size);
92-
if (has_velocity_state_interface_) {
93-
point.velocities.resize(size);
94-
}
95-
if (has_acceleration_state_interface_) {
96-
point.accelerations.resize(size);
97-
}
98-
};
99-
auto compute_error_for_joint = [&](JointTrajectoryPoint& error, int index, const JointTrajectoryPoint& current,
90+
auto compute_error_for_joint = [&](JointTrajectoryPoint& error, size_t index, const JointTrajectoryPoint& current,
10091
const JointTrajectoryPoint& desired) {
10192
// error defined as the difference between current and desired
102-
error.positions[index] = angles::shortest_angular_distance(current.positions[index], desired.positions[index]);
103-
if (has_velocity_state_interface_ && has_velocity_command_interface_) {
93+
if (normalize_joint_error_[index]) {
94+
// if desired, the shortest_angular_distance is calculated, i.e., the error is
95+
// normalized between -pi<error<pi
96+
error.positions[index] = angles::shortest_angular_distance(current.positions[index], desired.positions[index]);
97+
} else {
98+
error.positions[index] = desired.positions[index] - current.positions[index];
99+
}
100+
if (has_velocity_state_interface_ && (has_velocity_command_interface_ || has_effort_command_interface_)) {
104101
error.velocities[index] = desired.velocities[index] - current.velocities[index];
105102
}
106103
if (has_acceleration_state_interface_ && has_acceleration_command_interface_) {
107104
error.accelerations[index] = desired.accelerations[index] - current.accelerations[index];
108105
}
109106
};
110107

108+
// don't update goal after we sampled the trajectory to avoid any racecondition
109+
const auto active_goal = *rt_active_goal_.readFromRT();
110+
111111
// Check if a new external message has been received from nonRT threads
112112
auto current_external_msg = traj_external_point_ptr_->get_trajectory_msg();
113113
auto new_external_msg = traj_msg_external_point_ptr_.readFromRT();
114-
if (current_external_msg != *new_external_msg) {
114+
// Discard, if a goal is pending but still not active (somewhere stuck in goal_handle_timer_)
115+
if (current_external_msg != *new_external_msg && (*(rt_has_pending_goal_.readFromRT()) && !active_goal) == false) {
115116
fill_partial_goal(*new_external_msg);
116117
sort_to_local_joint_order(*new_external_msg);
118+
// TODO(denis): Add here integration of position and velocity
117119
traj_external_point_ptr_->update(*new_external_msg);
118120
}
119121

120-
JointTrajectoryPoint state_current, state_desired, state_error;
121-
const auto joint_num = params_.joints.size();
122-
resize_joint_trajectory_point(state_current, joint_num);
123-
124-
// current state update
125-
auto assign_point_from_interface = [&, joint_num](std::vector<double>& trajectory_point_interface,
126-
const auto& joint_inteface) {
127-
for (auto index = 0ul; index < joint_num; ++index) {
128-
trajectory_point_interface[index] = joint_inteface[index].get().get_value();
129-
}
130-
};
131-
auto assign_interface_from_point = [&, joint_num](auto& joint_inteface,
132-
const std::vector<double>& trajectory_point_interface) {
133-
for (auto index = 0ul; index < joint_num; ++index) {
134-
joint_inteface[index].get().set_value(trajectory_point_interface[index]);
122+
// TODO(anyone): can I here also use const on joint_interface since the reference_wrapper is not
123+
// changed, but its value only?
124+
auto assign_interface_from_point = [&](auto& joint_interface, const std::vector<double>& trajectory_point_interface) {
125+
for (size_t index = 0; index < dof_; ++index) {
126+
joint_interface[index].get().set_value(trajectory_point_interface[index]);
135127
}
136128
};
137129

138-
state_current.time_from_start.set__sec(0);
139-
140-
// Assign values from the hardware
141-
// Position states always exist
142-
assign_point_from_interface(state_current.positions, joint_state_interface_[0]);
143-
// velocity and acceleration states are optional
144-
if (has_velocity_state_interface_) {
145-
assign_point_from_interface(state_current.velocities, joint_state_interface_[1]);
146-
// Acceleration is used only in combination with velocity
147-
if (has_acceleration_state_interface_) {
148-
assign_point_from_interface(state_current.accelerations, joint_state_interface_[2]);
149-
} else {
150-
// Make empty so the property is ignored during interpolation
151-
state_current.accelerations.clear();
152-
}
153-
} else {
154-
// Make empty so the property is ignored during interpolation
155-
state_current.velocities.clear();
156-
state_current.accelerations.clear();
157-
}
130+
// current state update
131+
state_current_.time_from_start.set__sec(0);
132+
read_state_from_hardware(state_current_);
158133

159-
// currently carrying out a trajectory
134+
// currently carrying out a trajectory.
160135
if (has_active_trajectory()) {
161136
// Main Speed scaling difference...
162137
// Adjust time with scaling factor
163138
TimeData time_data;
164139
time_data.time = time;
165-
rcl_duration_value_t period = (time_data.time - time_data_.readFromRT()->time).nanoseconds();
166-
time_data.period = rclcpp::Duration::from_nanoseconds(scaling_factor_ * period);
140+
rcl_duration_value_t t_period = (time_data.time - time_data_.readFromRT()->time).nanoseconds();
141+
time_data.period = rclcpp::Duration::from_nanoseconds(scaling_factor_ * t_period);
167142
time_data.uptime = time_data_.readFromRT()->uptime + time_data.period;
168-
rclcpp::Time traj_time = time_data_.readFromRT()->uptime + rclcpp::Duration::from_nanoseconds(period);
143+
rclcpp::Time traj_time = time_data_.readFromRT()->uptime + rclcpp::Duration::from_nanoseconds(t_period);
169144
time_data_.writeFromNonRT(time_data);
170145

146+
bool first_sample = false;
171147
// if sampling the first time, set the point before you sample
172148
if (!traj_external_point_ptr_->is_sampled_already()) {
173-
traj_external_point_ptr_->set_point_before_trajectory_msg(traj_time, state_current);
149+
first_sample = true;
150+
if (params_.open_loop_control) {
151+
traj_external_point_ptr_->set_point_before_trajectory_msg(traj_time, last_commanded_state_);
152+
} else {
153+
traj_external_point_ptr_->set_point_before_trajectory_msg(traj_time, state_current_);
154+
}
174155
}
175-
resize_joint_trajectory_point(state_error, joint_num);
176156

177157
// find segment for current timestamp
178158
joint_trajectory_controller::TrajectoryPointConstIter start_segment_itr, end_segment_itr;
179-
const bool valid_point = traj_external_point_ptr_->sample(
180-
traj_time, joint_trajectory_controller::interpolation_methods::InterpolationMethod::VARIABLE_DEGREE_SPLINE,
181-
state_desired, start_segment_itr, end_segment_itr);
159+
const bool valid_point = traj_external_point_ptr_->sample(traj_time, interpolation_method_, state_desired_,
160+
start_segment_itr, end_segment_itr);
182161

183162
if (valid_point) {
184-
bool abort = false;
163+
bool tolerance_violated_while_moving = false;
185164
bool outside_goal_tolerance = false;
165+
bool within_goal_time = true;
166+
double time_difference = 0.0;
186167
const bool before_last_point = end_segment_itr != traj_external_point_ptr_->end();
187168

188-
// set values for next hardware write()
189-
if (has_position_command_interface_) {
190-
assign_interface_from_point(joint_command_interface_[0], state_desired.positions);
191-
}
192-
if (has_velocity_command_interface_) {
193-
assign_interface_from_point(joint_command_interface_[1], state_desired.velocities);
194-
}
195-
if (has_acceleration_command_interface_) {
196-
assign_interface_from_point(joint_command_interface_[2], state_desired.accelerations);
197-
}
198-
199-
for (size_t index = 0; index < joint_num; ++index) {
200-
// set values for next hardware write()
201-
compute_error_for_joint(state_error, index, state_current, state_desired);
169+
// Check state/goal tolerance
170+
for (size_t index = 0; index < dof_; ++index) {
171+
compute_error_for_joint(state_error_, index, state_current_, state_desired_);
202172

203-
if (before_last_point &&
204-
!check_state_tolerance_per_joint(state_error, index, default_tolerances_.state_tolerance[index], true)) {
205-
abort = true;
173+
// Always check the state tolerance on the first sample in case the first sample
174+
// is the last point
175+
if ((before_last_point || first_sample) &&
176+
!check_state_tolerance_per_joint(state_error_, index, default_tolerances_.state_tolerance[index], false)) {
177+
tolerance_violated_while_moving = true;
206178
}
207179
// past the final point, check that we end up inside goal tolerance
208180
if (!before_last_point && !check_state_tolerance_per_joint(
209-
state_error, index, default_tolerances_.goal_state_tolerance[index], true)) {
181+
state_error_, index, default_tolerances_.goal_state_tolerance[index], false)) {
210182
outside_goal_tolerance = true;
183+
184+
if (default_tolerances_.goal_time_tolerance != 0.0) {
185+
std::cout << default_tolerances_.goal_time_tolerance << std::endl;
186+
// if we exceed goal_time_tolerance set it to aborted
187+
const rclcpp::Time traj_start = traj_external_point_ptr_->get_trajectory_start_time();
188+
const rclcpp::Time traj_end = traj_start + start_segment_itr->time_from_start;
189+
190+
time_difference = time.seconds() - traj_end.seconds();
191+
192+
if (time_difference > default_tolerances_.goal_time_tolerance) {
193+
within_goal_time = false;
194+
}
195+
}
196+
}
197+
}
198+
199+
// set values for next hardware write() if tolerance is met
200+
if (!tolerance_violated_while_moving && within_goal_time) {
201+
if (use_closed_loop_pid_adapter_) {
202+
// Update PIDs
203+
for (auto i = 0ul; i < dof_; ++i) {
204+
tmp_command_[i] = (state_desired_.velocities[i] * ff_velocity_scale_[i]) +
205+
pids_[i]->computeCommand(state_error_.positions[i], state_error_.velocities[i],
206+
(uint64_t)period.nanoseconds());
207+
}
208+
}
209+
210+
// set values for next hardware write()
211+
if (has_position_command_interface_) {
212+
assign_interface_from_point(joint_command_interface_[0], state_desired_.positions);
213+
}
214+
if (has_velocity_command_interface_) {
215+
if (use_closed_loop_pid_adapter_) {
216+
assign_interface_from_point(joint_command_interface_[1], tmp_command_);
217+
} else {
218+
assign_interface_from_point(joint_command_interface_[1], state_desired_.velocities);
219+
}
220+
}
221+
if (has_acceleration_command_interface_) {
222+
assign_interface_from_point(joint_command_interface_[2], state_desired_.accelerations);
211223
}
224+
if (has_effort_command_interface_) {
225+
assign_interface_from_point(joint_command_interface_[3], tmp_command_);
226+
}
227+
228+
// store the previous command. Used in open-loop control mode
229+
last_commanded_state_ = state_desired_;
212230
}
213231

214-
const auto active_goal = *rt_active_goal_.readFromRT();
215232
if (active_goal) {
216233
// send feedback
217234
auto feedback = std::make_shared<FollowJTrajAction::Feedback>();
218235
feedback->header.stamp = time;
219236
feedback->joint_names = params_.joints;
220237

221-
feedback->actual = state_current;
222-
feedback->desired = state_desired;
223-
feedback->error = state_error;
238+
feedback->actual = state_current_;
239+
feedback->desired = state_desired_;
240+
feedback->error = state_error_;
224241
active_goal->setFeedback(feedback);
225242

226243
// check abort
227-
if (abort || outside_goal_tolerance) {
244+
if (tolerance_violated_while_moving) {
228245
auto result = std::make_shared<FollowJTrajAction::Result>();
229-
230-
if (abort) {
231-
RCLCPP_WARN(get_node()->get_logger(), "Aborted due to state tolerance violation");
232-
result->set__error_code(FollowJTrajAction::Result::PATH_TOLERANCE_VIOLATED);
233-
} else if (outside_goal_tolerance) {
234-
RCLCPP_WARN(get_node()->get_logger(), "Aborted due to goal tolerance violation");
235-
result->set__error_code(FollowJTrajAction::Result::GOAL_TOLERANCE_VIOLATED);
236-
}
246+
result->set__error_code(FollowJTrajAction::Result::PATH_TOLERANCE_VIOLATED);
237247
active_goal->setAborted(result);
248+
// TODO(matthew-reynolds): Need a lock-free write here
249+
// See https://github.com/ros-controls/ros2_controllers/issues/168
238250
rt_active_goal_.writeFromNonRT(RealtimeGoalHandlePtr());
239-
}
251+
rt_has_pending_goal_.writeFromNonRT(false);
252+
253+
RCLCPP_WARN(get_node()->get_logger(), "Aborted due to state tolerance violation");
240254

241-
// check goal tolerance
242-
if (!before_last_point) {
255+
traj_msg_external_point_ptr_.reset();
256+
traj_msg_external_point_ptr_.initRT(set_hold_position());
257+
} else if (!before_last_point) { // check goal tolerance
243258
if (!outside_goal_tolerance) {
244259
auto res = std::make_shared<FollowJTrajAction::Result>();
245260
res->set__error_code(FollowJTrajAction::Result::SUCCESSFUL);
246261
active_goal->setSucceeded(res);
262+
// TODO(matthew-reynolds): Need a lock-free write here
263+
// See https://github.com/ros-controls/ros2_controllers/issues/168
247264
rt_active_goal_.writeFromNonRT(RealtimeGoalHandlePtr());
265+
rt_has_pending_goal_.writeFromNonRT(false);
248266

249267
RCLCPP_INFO(get_node()->get_logger(), "Goal reached, success!");
250-
} else if (default_tolerances_.goal_time_tolerance != 0.0) {
251-
// if we exceed goal_time_toleralance set it to aborted
252-
const rclcpp::Time traj_start = traj_external_point_ptr_->get_trajectory_start_time();
253-
const rclcpp::Time traj_end = traj_start + start_segment_itr->time_from_start;
254268

255-
// TODO(anyone): This will break in speed scaling we have to discuss how to handle the goal
256-
// time when the robot scales itself down.
257-
const double difference = time.seconds() - traj_end.seconds();
258-
if (difference > default_tolerances_.goal_time_tolerance) {
259-
auto result = std::make_shared<FollowJTrajAction::Result>();
260-
result->set__error_code(FollowJTrajAction::Result::GOAL_TOLERANCE_VIOLATED);
261-
active_goal->setAborted(result);
262-
rt_active_goal_.writeFromNonRT(RealtimeGoalHandlePtr());
263-
RCLCPP_WARN(get_node()->get_logger(), "Aborted due goal_time_tolerance exceeding by %f seconds",
264-
difference);
265-
}
269+
traj_msg_external_point_ptr_.reset();
270+
traj_msg_external_point_ptr_.initRT(set_hold_position());
271+
} else if (!within_goal_time) {
272+
auto result = std::make_shared<FollowJTrajAction::Result>();
273+
result->set__error_code(FollowJTrajAction::Result::GOAL_TOLERANCE_VIOLATED);
274+
active_goal->setAborted(result);
275+
// TODO(matthew-reynolds): Need a lock-free write here
276+
// See https://github.com/ros-controls/ros2_controllers/issues/168
277+
rt_active_goal_.writeFromNonRT(RealtimeGoalHandlePtr());
278+
rt_has_pending_goal_.writeFromNonRT(false);
279+
280+
RCLCPP_WARN(get_node()->get_logger(), "Aborted due goal_time_tolerance exceeding by %f seconds",
281+
time_difference);
282+
283+
traj_msg_external_point_ptr_.reset();
284+
traj_msg_external_point_ptr_.initRT(set_hold_position());
266285
}
267286
}
287+
} else if (tolerance_violated_while_moving && *(rt_has_pending_goal_.readFromRT()) == false) {
288+
// we need to ensure that there is no pending goal -> we get a race condition otherwise
289+
RCLCPP_ERROR(get_node()->get_logger(), "Holding position due to state tolerance violation");
290+
291+
traj_msg_external_point_ptr_.reset();
292+
traj_msg_external_point_ptr_.initRT(set_hold_position());
293+
} else if (!before_last_point && !within_goal_time && *(rt_has_pending_goal_.readFromRT()) == false) {
294+
RCLCPP_ERROR(get_node()->get_logger(), "Exceeded goal_time_tolerance: holding position...");
295+
296+
traj_msg_external_point_ptr_.reset();
297+
traj_msg_external_point_ptr_.initRT(set_hold_position());
268298
}
299+
// else, run another cycle while waiting for outside_goal_tolerance
300+
// to be satisfied (will stay in this state until new message arrives)
301+
// or outside_goal_tolerance violated within the goal_time_tolerance
269302
}
270303
}
271304

272-
publish_state(time, state_desired, state_current, state_error);
305+
publish_state(time, state_desired_, state_current_, state_error_);
273306
return controller_interface::return_type::OK;
274307
}
275308

0 commit comments

Comments
 (0)