38 #include <tf2/LinearMath/Quaternion.h>
39 #include <tf2_eigen_kdl/tf2_eigen_kdl.hpp>
40 #include <tf2_eigen/tf2_eigen.hpp>
41 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
45 static const rclcpp::Logger
LOGGER = rclcpp::get_logger(
"moveit.pilz_industrial_motion_planner.trajectory_functions");
49 const std::string& group_name,
const std::string& link_name,
50 const Eigen::Isometry3d& pose,
const std::string&
frame_id,
51 const std::map<std::string, double>& seed,
52 std::map<std::string, double>& solution,
bool check_self_collision,
55 const moveit::core::RobotModelConstPtr& robot_model =
scene->getRobotModel();
56 if (!robot_model->hasJointModelGroup(group_name))
58 RCLCPP_ERROR_STREAM(LOGGER,
"Robot model has no planning group named as " << group_name);
62 if (!robot_model->getJointModelGroup(group_name)->canSetStateFromIK(link_name))
64 RCLCPP_ERROR_STREAM(LOGGER,
"No valid IK solver exists for " << link_name <<
" in planning group " << group_name);
68 if (
frame_id != robot_model->getModelFrame())
70 RCLCPP_ERROR_STREAM(LOGGER,
"Given frame (" <<
frame_id <<
") is unequal to model frame("
71 << robot_model->getModelFrame() <<
")");
76 rstate.setVariablePositions(seed);
81 const double* joint_group_variable_values) {
83 joint_group_variable_values);
87 if (rstate.setFromIK(robot_model->getJointModelGroup(group_name), pose, link_name, timeout, ik_constraint_function))
90 for (
const auto& joint_name : robot_model->getJointModelGroup(group_name)->getActiveJointModelNames())
92 solution[joint_name] = rstate.getVariablePosition(joint_name);
98 RCLCPP_ERROR(LOGGER,
"Unable to find IK solution.");
106 const std::string& group_name,
const std::string& link_name,
107 const geometry_msgs::msg::Pose& pose,
const std::string&
frame_id,
108 const std::map<std::string, double>& seed,
109 std::map<std::string, double>& solution,
bool check_self_collision,
110 const double timeout)
112 Eigen::Isometry3d pose_eigen;
113 tf2::convert<geometry_msgs::msg::Pose, Eigen::Isometry3d>(pose, pose_eigen);
119 const std::string& link_name,
120 const std::map<std::string, double>& joint_state,
121 Eigen::Isometry3d& pose)
126 if (!rstate.knowsFrameTransform(link_name))
128 RCLCPP_ERROR_STREAM(LOGGER,
"The target link " << link_name <<
" is not known by robot.");
132 rstate.setVariablePositions(joint_state);
136 pose = rstate.getFrameTransform(link_name);
142 const std::map<std::string, double>& position_last,
const std::map<std::string, double>& velocity_last,
143 const std::map<std::string, double>& position_current,
double duration_last,
double duration_current,
146 const double epsilon = 10e-6;
147 if (duration_current <= epsilon)
149 RCLCPP_ERROR(LOGGER,
"Sample duration too small, cannot compute the velocity");
153 double velocity_current, acceleration_current;
155 for (
const auto& pos : position_current)
157 velocity_current = (pos.second - position_last.at(pos.first)) / duration_current;
159 if (!
joint_limits.verifyVelocityLimit(pos.first, velocity_current))
161 RCLCPP_ERROR_STREAM(LOGGER,
"Joint velocity limit of "
162 << pos.first <<
" violated. Set the velocity scaling factor lower!"
163 <<
" Actual joint velocity is " << velocity_current <<
", while the limit is "
164 <<
joint_limits.getLimit(pos.first).max_velocity <<
". ");
168 acceleration_current = (velocity_current - velocity_last.at(pos.first)) / (duration_last + duration_current) * 2;
170 if (fabs(velocity_last.at(pos.first)) <= fabs(velocity_current))
172 if (
joint_limits.getLimit(pos.first).has_acceleration_limits &&
173 fabs(acceleration_current) > fabs(
joint_limits.getLimit(pos.first).max_acceleration))
175 RCLCPP_ERROR_STREAM(LOGGER,
"Joint acceleration limit of "
176 << pos.first <<
" violated. Set the acceleration scaling factor lower!"
177 <<
" Actual joint acceleration is " << acceleration_current
178 <<
", while the limit is " <<
joint_limits.getLimit(pos.first).max_acceleration
186 if (
joint_limits.getLimit(pos.first).has_deceleration_limits &&
187 fabs(acceleration_current) > fabs(
joint_limits.getLimit(pos.first).max_deceleration))
189 RCLCPP_ERROR_STREAM(LOGGER,
"Joint deceleration limit of "
190 << pos.first <<
" violated. Set the acceleration scaling factor lower!"
191 <<
" Actual joint deceleration is " << acceleration_current
192 <<
", while the limit is " <<
joint_limits.getLimit(pos.first).max_deceleration
203 const planning_scene::PlanningSceneConstPtr&
scene,
205 const std::string& group_name,
const std::string& link_name,
206 const std::map<std::string, double>& initial_joint_position,
const double& sampling_time,
207 trajectory_msgs::msg::JointTrajectory& joint_trajectory, moveit_msgs::msg::MoveItErrorCodes& error_code,
208 bool check_self_collision)
210 RCLCPP_DEBUG(LOGGER,
"Generate joint trajectory from a Cartesian trajectory.");
212 const moveit::core::RobotModelConstPtr& robot_model =
scene->getRobotModel();
214 rclcpp::Time generation_begin = clock.now();
217 const double epsilon = 10e-06;
218 std::vector<double> time_samples;
219 for (
double t_sample = 0.0; t_sample < trajectory.Duration() - epsilon; t_sample += sampling_time)
221 time_samples.push_back(t_sample);
223 time_samples.push_back(trajectory.Duration());
226 Eigen::Isometry3d pose_sample;
227 std::map<std::string, double> ik_solution_last, ik_solution, joint_velocity_last;
228 ik_solution_last = initial_joint_position;
229 for (
const auto& item : ik_solution_last)
231 joint_velocity_last[item.first] = 0.0;
234 for (std::vector<double>::const_iterator time_iter = time_samples.begin(); time_iter != time_samples.end();
237 tf2::transformKDLToEigen(trajectory.Pos(*time_iter), pose_sample);
239 if (!
computePoseIK(
scene, group_name, link_name, pose_sample, robot_model->getModelFrame(), ik_solution_last,
240 ik_solution, check_self_collision))
242 RCLCPP_ERROR(LOGGER,
"Failed to compute inverse kinematics solution for sampled Cartesian pose.");
243 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
244 joint_trajectory.points.clear();
249 double duration_current_sample = sampling_time;
251 if (time_iter == (time_samples.end() - 1) && time_samples.size() > 1)
253 duration_current_sample = *time_iter - *(time_iter - 1);
255 if (time_samples.size() == 1)
257 duration_current_sample = *time_iter;
261 if (time_iter != time_samples.begin() &&
265 RCLCPP_ERROR_STREAM(LOGGER,
"Inverse kinematics solution at "
267 <<
"s violates the joint velocity/acceleration/deceleration limits.");
268 error_code.val = moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED;
269 joint_trajectory.points.clear();
274 trajectory_msgs::msg::JointTrajectoryPoint point;
277 joint_trajectory.joint_names.clear();
278 for (
const auto& start_joint : initial_joint_position)
280 joint_trajectory.joint_names.push_back(start_joint.first);
283 point.time_from_start = rclcpp::Duration::from_seconds(*time_iter);
284 for (
const auto& joint_name : joint_trajectory.joint_names)
286 point.positions.push_back(ik_solution.at(joint_name));
288 if (time_iter != time_samples.begin() && time_iter != time_samples.end() - 1)
290 double joint_velocity =
291 (ik_solution.at(joint_name) - ik_solution_last.at(joint_name)) / duration_current_sample;
292 point.velocities.push_back(joint_velocity);
293 point.accelerations.push_back((joint_velocity - joint_velocity_last.at(joint_name)) /
294 (duration_current_sample + sampling_time) * 2);
295 joint_velocity_last[joint_name] = joint_velocity;
299 point.velocities.push_back(0.);
300 point.accelerations.push_back(0.);
301 joint_velocity_last[joint_name] = 0.;
306 joint_trajectory.points.push_back(point);
307 ik_solution_last = ik_solution;
310 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
311 double duration_ms = (clock.now() - generation_begin).seconds() * 1000;
312 RCLCPP_DEBUG_STREAM(LOGGER,
"Generate trajectory (N-Points: "
313 << joint_trajectory.points.size() <<
") took " << duration_ms <<
" ms | "
314 << duration_ms / joint_trajectory.points.size() <<
" ms per Point");
320 const planning_scene::PlanningSceneConstPtr&
scene,
323 const std::string& link_name,
const std::map<std::string, double>& initial_joint_position,
324 const std::map<std::string, double>& initial_joint_velocity,
325 trajectory_msgs::msg::JointTrajectory& joint_trajectory, moveit_msgs::msg::MoveItErrorCodes& error_code,
326 bool check_self_collision)
328 RCLCPP_DEBUG(LOGGER,
"Generate joint trajectory from a Cartesian trajectory.");
330 const moveit::core::RobotModelConstPtr& robot_model =
scene->getRobotModel();
332 rclcpp::Time generation_begin = clock.now();
334 std::map<std::string, double> ik_solution_last = initial_joint_position;
335 std::map<std::string, double> joint_velocity_last = initial_joint_velocity;
336 double duration_last = 0;
337 double duration_current = 0;
338 joint_trajectory.joint_names.clear();
339 for (
const auto& joint_position : ik_solution_last)
341 joint_trajectory.joint_names.push_back(joint_position.first);
343 std::map<std::string, double> ik_solution;
344 for (
size_t i = 0; i < trajectory.
points.size(); ++i)
348 ik_solution_last, ik_solution, check_self_collision))
350 RCLCPP_ERROR(LOGGER,
"Failed to compute inverse kinematics solution for sampled "
352 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
353 joint_trajectory.points.clear();
360 duration_current = trajectory.
points.front().time_from_start.seconds();
361 duration_last = duration_current;
366 trajectory.
points.at(i).time_from_start.seconds() - trajectory.
points.at(i - 1).time_from_start.seconds();
369 if (!
verifySampleJointLimits(ik_solution_last, joint_velocity_last, ik_solution, duration_last, duration_current,
376 RCLCPP_ERROR_STREAM(LOGGER,
"Inverse kinematics solution of the "
378 <<
"th sample violates the joint "
379 "velocity/acceleration/deceleration limits.");
380 error_code.val = moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED;
381 joint_trajectory.points.clear();
387 trajectory_msgs::msg::JointTrajectoryPoint waypoint_joint;
388 waypoint_joint.time_from_start = trajectory.
points.at(i).time_from_start;
389 for (
const auto& joint_name : joint_trajectory.joint_names)
391 waypoint_joint.positions.push_back(ik_solution.at(joint_name));
392 double joint_velocity = (ik_solution.at(joint_name) - ik_solution_last.at(joint_name)) / duration_current;
393 waypoint_joint.velocities.push_back(joint_velocity);
394 waypoint_joint.accelerations.push_back((joint_velocity - joint_velocity_last.at(joint_name)) /
395 (duration_current + duration_last) * 2);
397 joint_velocity_last[joint_name] = joint_velocity;
401 joint_trajectory.points.push_back(waypoint_joint);
402 ik_solution_last = ik_solution;
403 duration_last = duration_current;
406 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
408 double duration_ms = (clock.now() - generation_begin).seconds() * 1000;
409 RCLCPP_DEBUG_STREAM(LOGGER,
"Generate trajectory (N-Points: "
410 << joint_trajectory.points.size() <<
") took " << duration_ms <<
" ms | "
411 << duration_ms / joint_trajectory.points.size() <<
" ms per Point");
417 const robot_trajectory::RobotTrajectoryPtr& first_trajectory,
418 const robot_trajectory::RobotTrajectoryPtr& second_trajectory,
double epsilon,
double& sampling_time)
422 std::size_t n1 = first_trajectory->getWayPointCount() - 1;
423 std::size_t n2 = second_trajectory->getWayPointCount() - 1;
424 if ((n1 < 2) && (n2 < 2))
426 RCLCPP_ERROR_STREAM(LOGGER,
"Both trajectories do not have enough points to determine sampling time.");
432 sampling_time = first_trajectory->getWayPointDurationFromPrevious(1);
436 sampling_time = second_trajectory->getWayPointDurationFromPrevious(1);
439 for (std::size_t i = 1; i < std::max(n1, n2); ++i)
443 if (fabs(sampling_time - first_trajectory->getWayPointDurationFromPrevious(i)) > epsilon)
445 RCLCPP_ERROR_STREAM(LOGGER,
"First trajectory violates sampline time " << sampling_time <<
" between points "
446 << (i - 1) <<
"and " << i
454 if (fabs(sampling_time - second_trajectory->getWayPointDurationFromPrevious(i)) > epsilon)
456 RCLCPP_ERROR_STREAM(LOGGER,
"Second trajectory violates sampline time " << sampling_time <<
" between points "
457 << (i - 1) <<
"and " << i
469 const std::string& joint_group_name,
double epsilon)
471 Eigen::VectorXd joint_position_1, joint_position_2;
476 if ((joint_position_1 - joint_position_2).norm() > epsilon)
478 RCLCPP_DEBUG_STREAM(LOGGER,
"Joint positions of the two states are different. state1: "
479 << joint_position_1 <<
" state2: " << joint_position_2);
483 Eigen::VectorXd joint_velocity_1, joint_velocity_2;
488 if ((joint_velocity_1 - joint_velocity_2).norm() > epsilon)
490 RCLCPP_DEBUG_STREAM(LOGGER,
"Joint velocities of the two states are different. state1: "
491 << joint_velocity_1 <<
" state2: " << joint_velocity_2);
495 Eigen::VectorXd joint_acc_1, joint_acc_2;
500 if ((joint_acc_1 - joint_acc_2).norm() > epsilon)
502 RCLCPP_DEBUG_STREAM(LOGGER,
"Joint accelerations of the two states are different. state1: "
503 << joint_acc_1 <<
" state2: " << joint_acc_2);
513 Eigen::VectorXd joint_variable;
515 if (joint_variable.norm() >
EPSILON)
517 RCLCPP_DEBUG(LOGGER,
"Joint velocities are not zero.");
521 if (joint_variable.norm() >
EPSILON)
523 RCLCPP_DEBUG(LOGGER,
"Joint accelerations are not zero.");
532 const robot_trajectory::RobotTrajectoryPtr& traj,
533 bool inverseOrder, std::size_t& index)
535 RCLCPP_DEBUG(LOGGER,
"Start linear search for intersection point.");
537 const size_t waypoint_num = traj->getWayPointCount();
541 for (
size_t i = waypoint_num - 1; i > 0; --i)
543 if (
intersectionFound(center_position, traj->getWayPointPtr(i)->getFrameTransform(link_name).translation(),
544 traj->getWayPointPtr(i - 1)->getFrameTransform(link_name).translation(),
r))
553 for (
size_t i = 0; i < waypoint_num - 1; ++i)
555 if (
intersectionFound(center_position, traj->getWayPointPtr(i)->getFrameTransform(link_name).translation(),
556 traj->getWayPointPtr(i + 1)->getFrameTransform(link_name).translation(),
r))
571 return ((p_current - p_center).norm() <=
r) && ((p_next - p_center).norm() >=
r);
575 const planning_scene::PlanningSceneConstPtr&
scene,
578 const double*
const ik_solution)
580 if (!test_for_self_collision)
591 scene->checkSelfCollision(collision_req, collision_res, *rstate);
598 tf2::convert<geometry_msgs::msg::Quaternion, tf2::Quaternion>(quat, q);
599 quat = tf2::toMsg(q.normalized());
603 const geometry_msgs::msg::Quaternion& orientation,
604 const geometry_msgs::msg::Vector3& offset)
606 Eigen::Quaterniond quat;
607 tf2::fromMsg(orientation, quat);
610 tf2::fromMsg(position, v);
612 Eigen::Isometry3d pose = Eigen::Translation3d(v) * quat;
614 tf2::fromMsg(offset, v);
615 pose.translation() -= quat * v;
621 return getConstraintPose(goal.position_constraints.front().constraint_region.primitive_poses.front().position,
622 goal.orientation_constraints.front().orientation,
623 goal.position_constraints.front().target_point_offset);
Representation of a robot's state. This includes position, velocity, acceleration and effort.
void copyJointGroupVelocities(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the velocity values of the variables that make up the group into another loca...
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
void update(bool force=false)
Update all transforms.
void copyJointGroupAccelerations(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the acceleration values of the variables that make up the group into another ...
Container for JointLimits, essentially a map with convenience functions. Adds the ability to as for l...
Vec3fX< details::Vec3Data< double > > Vector3d
std::function< bool(RobotState *robot_state, const JointModelGroup *joint_group, const double *joint_group_variable_values)> GroupStateValidityCallbackFn
Signature for functions that can verify that if the group joint_group in robot_state is set to joint_...
bool isStateColliding(const bool test_for_self_collision, const planning_scene::PlanningSceneConstPtr &scene, moveit::core::RobotState *state, const moveit::core::JointModelGroup *const group, const double *const ik_solution)
Checks if current robot state is in self collision.
bool generateJointTrajectory(const planning_scene::PlanningSceneConstPtr &scene, const JointLimitsContainer &joint_limits, const KDL::Trajectory &trajectory, const std::string &group_name, const std::string &link_name, const std::map< std::string, double > &initial_joint_position, const double &sampling_time, trajectory_msgs::msg::JointTrajectory &joint_trajectory, moveit_msgs::msg::MoveItErrorCodes &error_code, bool check_self_collision=false)
Generate joint trajectory from a KDL Cartesian trajectory.
bool linearSearchIntersectionPoint(const std::string &link_name, const Eigen::Vector3d ¢er_position, const double &r, const robot_trajectory::RobotTrajectoryPtr &traj, bool inverseOrder, std::size_t &index)
Performs a linear search for the intersection point of the trajectory with the blending radius.
bool isRobotStateStationary(const moveit::core::RobotState &state, const std::string &group, double EPSILON)
check if the robot state have zero velocity/acceleration
bool determineAndCheckSamplingTime(const robot_trajectory::RobotTrajectoryPtr &first_trajectory, const robot_trajectory::RobotTrajectoryPtr &second_trajectory, double EPSILON, double &sampling_time)
Determines the sampling time and checks that both trajectroies use the same sampling time.
bool verifySampleJointLimits(const std::map< std::string, double > &position_last, const std::map< std::string, double > &velocity_last, const std::map< std::string, double > &position_current, double duration_last, double duration_current, const JointLimitsContainer &joint_limits)
verify the velocity/acceleration limits of current sample (based on backward difference computation) ...
bool intersectionFound(const Eigen::Vector3d &p_center, const Eigen::Vector3d &p_current, const Eigen::Vector3d &p_next, const double &r)
bool computePoseIK(const planning_scene::PlanningSceneConstPtr &scene, const std::string &group_name, const std::string &link_name, const Eigen::Isometry3d &pose, const std::string &frame_id, const std::map< std::string, double > &seed, std::map< std::string, double > &solution, bool check_self_collision=true, const double timeout=0.0)
compute the inverse kinematics of a given pose, also check robot self collision
bool isRobotStateEqual(const moveit::core::RobotState &state1, const moveit::core::RobotState &state2, const std::string &joint_group_name, double epsilon)
Check if the two robot states have the same joint position/velocity/acceleration.
bool computeLinkFK(const planning_scene::PlanningSceneConstPtr &scene, const std::string &link_name, const std::map< std::string, double > &joint_state, Eigen::Isometry3d &pose)
compute the pose of a link at give robot state
const rclcpp::Logger LOGGER
Representation of a collision checking request.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)
bool verbose
Flag indicating whether information about detected collisions should be reported.
Representation of a collision checking result.
bool collision
True if collision was found, false otherwise.
std::vector< CartesianTrajectoryPoint > points
void normalizeQuaternion(geometry_msgs::msg::Quaternion &quat)
Eigen::Isometry3d getConstraintPose(const geometry_msgs::msg::Point &position, const geometry_msgs::msg::Quaternion &orientation, const geometry_msgs::msg::Vector3 &offset)
Adapt goal pose, defined by position+orientation, to consider offset.