36 #include <rclcpp/logger.hpp>
37 #include <rclcpp/logging.hpp>
40 #include <Eigen/Geometry>
49 const rclcpp::Logger
LOGGER = rclcpp::get_logger(
"moveit_trajectory_processing.ruckig_traj_smoothing");
50 constexpr
double DEFAULT_MAX_VELOCITY = 5;
51 constexpr
double DEFAULT_MAX_ACCELERATION = 10;
52 constexpr
double DEFAULT_MAX_JERK = 1000;
53 constexpr
double MAX_DURATION_EXTENSION_FACTOR = 10.0;
54 constexpr
double DURATION_EXTENSION_FRACTION = 1.1;
58 const double max_velocity_scaling_factor,
59 const double max_acceleration_scaling_factor)
61 if (!validateGroup(trajectory))
67 if (num_waypoints < 2)
70 "Trajectory does not have enough points to smooth with Ruckig. Returning an unmodified trajectory.");
76 const size_t num_dof =
group->getVariableCount();
77 ruckig::InputParameter<ruckig::DynamicDOFs> ruckig_input{ num_dof };
78 if (!getRobotModelBounds(max_velocity_scaling_factor, max_acceleration_scaling_factor,
group, ruckig_input))
80 RCLCPP_ERROR(LOGGER,
"Error while retrieving kinematic limits (vel/accel/jerk) from RobotModel.");
84 return runRuckig(trajectory, ruckig_input);
88 const std::unordered_map<std::string, double>& velocity_limits,
89 const std::unordered_map<std::string, double>& acceleration_limits,
90 const std::unordered_map<std::string, double>& jerk_limits)
92 if (!validateGroup(trajectory))
98 if (num_waypoints < 2)
101 "Trajectory does not have enough points to smooth with Ruckig. Returning an unmodified trajectory.");
107 const size_t num_dof =
group->getVariableCount();
108 ruckig::InputParameter<ruckig::DynamicDOFs> ruckig_input{ num_dof };
109 double max_velocity_scaling_factor = 1.0;
110 double max_acceleration_scaling_factor = 1.0;
111 if (!getRobotModelBounds(max_velocity_scaling_factor, max_acceleration_scaling_factor,
group, ruckig_input))
113 RCLCPP_ERROR(LOGGER,
"Error while retrieving kinematic limits (vel/accel/jerk) from RobotModel.");
118 const std::vector<std::string>& vars =
group->getVariableNames();
119 const unsigned num_joints =
group->getVariableCount();
120 for (
size_t j = 0; j < num_joints; ++j)
123 auto it = velocity_limits.find(vars[j]);
124 if (it != velocity_limits.end())
126 ruckig_input.max_velocity.at(j) = it->second;
129 it = acceleration_limits.find(vars[j]);
130 if (it != acceleration_limits.end())
132 ruckig_input.max_acceleration.at(j) = it->second;
135 it = jerk_limits.find(vars[j]);
136 if (it != jerk_limits.end())
138 ruckig_input.max_jerk.at(j) = it->second;
142 return runRuckig(trajectory, ruckig_input);
150 RCLCPP_ERROR(LOGGER,
"The planner did not set the group the plan was computed for");
156 bool RuckigSmoothing::getRobotModelBounds(
const double max_velocity_scaling_factor,
157 const double max_acceleration_scaling_factor,
159 ruckig::InputParameter<ruckig::DynamicDOFs>& ruckig_input)
161 const size_t num_dof =
group->getVariableCount();
162 const std::vector<std::string>& vars =
group->getVariableNames();
164 for (
size_t i = 0; i < num_dof; ++i)
171 ruckig_input.max_velocity.at(i) = max_velocity_scaling_factor * bounds.
max_velocity_;
175 RCLCPP_WARN_STREAM_ONCE(LOGGER,
176 "Joint velocity limits are not defined. Using the default "
177 << DEFAULT_MAX_VELOCITY
178 <<
" rad/s. You can define velocity limits in the URDF or joint_limits.yaml.");
179 ruckig_input.max_velocity.at(i) = max_velocity_scaling_factor * DEFAULT_MAX_VELOCITY;
183 ruckig_input.max_acceleration.at(i) = max_acceleration_scaling_factor * bounds.
max_acceleration_;
187 RCLCPP_WARN_STREAM_ONCE(LOGGER,
188 "Joint acceleration limits are not defined. Using the default "
189 << DEFAULT_MAX_ACCELERATION
190 <<
" rad/s^2. You can define acceleration limits in the URDF or joint_limits.yaml.");
191 ruckig_input.max_acceleration.at(i) = max_acceleration_scaling_factor * DEFAULT_MAX_ACCELERATION;
196 ruckig_input.max_jerk.at(i) = bounds.
max_jerk_;
200 RCLCPP_WARN_STREAM_ONCE(LOGGER,
"Joint jerk limits are not defined. Using the default "
202 <<
" rad/s^3. You can define jerk limits in joint_limits.yaml.");
203 ruckig_input.max_jerk.at(i) = DEFAULT_MAX_JERK;
211 ruckig::InputParameter<ruckig::DynamicDOFs>& ruckig_input)
215 const size_t num_dof =
group->getVariableCount();
216 ruckig::OutputParameter<ruckig::DynamicDOFs> ruckig_output{ num_dof };
217 const std::vector<int>& move_group_idx =
group->getVariableIndexList();
224 std::unique_ptr<ruckig::Ruckig<ruckig::DynamicDOFs>> ruckig_ptr;
225 ruckig_ptr = std::make_unique<ruckig::Ruckig<ruckig::DynamicDOFs>>(num_dof, timestep);
232 ruckig::Result ruckig_result;
233 double duration_extension_factor = 1;
234 bool smoothing_complete =
false;
235 while ((duration_extension_factor < MAX_DURATION_EXTENSION_FACTOR) && !smoothing_complete)
237 for (
size_t waypoint_idx = 0; waypoint_idx < num_waypoints - 1; ++waypoint_idx)
239 moveit::core::RobotStatePtr next_waypoint = trajectory.
getWayPointPtr(waypoint_idx + 1);
241 getNextRuckigInput(trajectory.
getWayPointPtr(waypoint_idx), next_waypoint,
group, ruckig_input);
244 ruckig_result = ruckig_ptr->update(ruckig_input, ruckig_output);
246 if ((waypoint_idx == num_waypoints - 2) && ruckig_result == ruckig::Result::Finished)
248 smoothing_complete =
true;
253 if (ruckig_result != ruckig::Result::Finished)
255 duration_extension_factor *= DURATION_EXTENSION_FRACTION;
258 for (
size_t time_stretch_idx = 1; time_stretch_idx < num_waypoints; ++time_stretch_idx)
265 const auto prev_state = trajectory.
getWayPointPtr(time_stretch_idx - 1);
267 for (
size_t joint = 0; joint < num_dof; ++joint)
269 target_state->setVariableVelocity(move_group_idx.at(joint),
270 (1 / duration_extension_factor) *
271 target_state->getVariableVelocity(move_group_idx.at(joint)));
273 double prev_velocity = prev_state->getVariableVelocity(move_group_idx.at(joint));
274 double curr_velocity = target_state->getVariableVelocity(move_group_idx.at(joint));
275 target_state->setVariableAcceleration(move_group_idx.at(joint), (curr_velocity - prev_velocity) / timestep);
277 target_state->update();
279 ruckig_ptr = std::make_unique<ruckig::Ruckig<ruckig::DynamicDOFs>>(num_dof, timestep);
287 if (ruckig_result != ruckig::Result::Finished)
289 RCLCPP_ERROR_STREAM(LOGGER,
"Ruckig trajectory smoothing failed. Ruckig error: " << ruckig_result);
298 ruckig::InputParameter<ruckig::DynamicDOFs>& ruckig_input,
299 ruckig::OutputParameter<ruckig::DynamicDOFs>& ruckig_output)
304 std::vector<double> current_positions_vector(num_dof);
305 std::vector<double> current_velocities_vector(num_dof);
306 std::vector<double> current_accelerations_vector(num_dof);
308 for (
size_t i = 0; i < num_dof; ++i)
314 current_velocities_vector.at(i) =
315 std::clamp(current_velocities_vector.at(i), -ruckig_input.max_velocity.at(i), ruckig_input.max_velocity.at(i));
316 current_accelerations_vector.at(i) = std::clamp(
317 current_accelerations_vector.at(i), -ruckig_input.max_acceleration.at(i), ruckig_input.max_acceleration.at(i));
319 std::copy_n(current_positions_vector.begin(), num_dof, ruckig_input.current_position.begin());
320 std::copy_n(current_velocities_vector.begin(), num_dof, ruckig_input.current_velocity.begin());
321 std::copy_n(current_accelerations_vector.begin(), num_dof, ruckig_input.current_acceleration.begin());
323 ruckig_output.new_position = ruckig_input.current_position;
324 ruckig_output.new_velocity = ruckig_input.current_velocity;
325 ruckig_output.new_acceleration = ruckig_input.current_acceleration;
328 void RuckigSmoothing::getNextRuckigInput(
const moveit::core::RobotStatePtr& current_waypoint,
329 const moveit::core::RobotStatePtr& next_waypoint,
331 ruckig::InputParameter<ruckig::DynamicDOFs>& ruckig_input)
336 for (
size_t joint = 0; joint < num_dof; ++joint)
338 ruckig_input.current_position.at(joint) = current_waypoint->getVariablePosition(idx.at(joint));
339 ruckig_input.current_velocity.at(joint) = current_waypoint->getVariableVelocity(idx.at(joint));
340 ruckig_input.current_acceleration.at(joint) = current_waypoint->getVariableAcceleration(idx.at(joint));
343 ruckig_input.target_position.at(joint) = next_waypoint->getVariablePosition(idx.at(joint));
344 ruckig_input.target_velocity.at(joint) = next_waypoint->getVariableVelocity(idx.at(joint));
345 ruckig_input.target_acceleration.at(joint) = next_waypoint->getVariableAcceleration(idx.at(joint));
348 ruckig_input.current_velocity.at(joint) =
349 std::clamp(ruckig_input.current_velocity.at(joint), -ruckig_input.max_velocity.at(joint),
350 ruckig_input.max_velocity.at(joint));
351 ruckig_input.current_acceleration.at(joint) =
352 std::clamp(ruckig_input.current_acceleration.at(joint), -ruckig_input.max_acceleration.at(joint),
353 ruckig_input.max_acceleration.at(joint));
354 ruckig_input.target_velocity.at(joint) =
355 std::clamp(ruckig_input.target_velocity.at(joint), -ruckig_input.max_velocity.at(joint),
356 ruckig_input.max_velocity.at(joint));
357 ruckig_input.target_acceleration.at(joint) =
358 std::clamp(ruckig_input.target_acceleration.at(joint), -ruckig_input.max_acceleration.at(joint),
359 ruckig_input.max_acceleration.at(joint));
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< int > & getVariableIndexList() const
Get the index locations in the complete robot state for all the variables in this group.
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a specific variable. Throw an exception of variable is not found.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
double getVariableAcceleration(const std::string &variable) const
Get the acceleration of a particular variable. An exception is thrown if the variable is not known.
double getVariableVelocity(const std::string &variable) const
Get the velocity of a particular variable. An exception is thrown if the variable is not known.
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Maintain a sequence of waypoints and the time durations between these waypoints.
RobotTrajectory & setWayPointDurationFromPrevious(std::size_t index, double value)
double getAverageSegmentDuration() const
const moveit::core::JointModelGroup * getGroup() const
RobotTrajectory & unwind()
moveit::core::RobotStatePtr & getWayPointPtr(std::size_t index)
std::size_t getWayPointCount() const
double getWayPointDurationFromPrevious(std::size_t index) const
moveit::core::RobotStatePtr & getFirstWayPointPtr()
static bool applySmoothing(robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0)
const rclcpp::Logger LOGGER
bool acceleration_bounded_