40 #include <rclcpp/duration.hpp>
41 #include <rclcpp/logger.hpp>
42 #include <rclcpp/logging.hpp>
43 #include <rclcpp/time.hpp>
44 #include <tf2_eigen/tf2_eigen.hpp>
51 : robot_model_(robot_model), group_(nullptr)
56 : robot_model_(robot_model), group_(
group.empty() ? nullptr : robot_model->getJointModelGroup(
group))
62 : robot_model_(robot_model), group_(
group)
72 for (
const auto& waypoint : other.waypoints_)
74 waypoints_.emplace_back(std::make_shared<moveit::core::RobotState>(*waypoint));
83 static const std::string EMPTY;
89 return std::accumulate(duration_from_previous_.begin(), duration_from_previous_.end(), 0.0);
94 if (duration_from_previous_.empty())
96 RCLCPP_WARN(
rclcpp::get_logger(
"RobotTrajectory"),
"Too few waypoints to calculate a duration. Returning 0.");
101 if (duration_from_previous_[0] == 0)
103 if (duration_from_previous_.size() <= 1)
105 RCLCPP_WARN(
rclcpp::get_logger(
"RobotTrajectory"),
"First and only waypoint has a duration of 0.");
109 return getDuration() /
static_cast<double>(duration_from_previous_.size() - 1);
112 return getDuration() /
static_cast<double>(duration_from_previous_.size());
117 robot_model_.swap(other.robot_model_);
118 std::swap(group_, other.group_);
119 waypoints_.swap(other.waypoints_);
120 duration_from_previous_.swap(other.duration_from_previous_);
125 end_index = std::min(end_index, source.waypoints_.size());
126 if (start_index >= end_index)
128 waypoints_.insert(waypoints_.end(), std::next(source.waypoints_.begin(), start_index),
129 std::next(source.waypoints_.begin(), end_index));
130 std::size_t index = duration_from_previous_.size();
131 duration_from_previous_.insert(duration_from_previous_.end(),
132 std::next(source.duration_from_previous_.begin(), start_index),
133 std::next(source.duration_from_previous_.begin(), end_index));
134 if (duration_from_previous_.size() > index)
135 duration_from_previous_[index] = dt;
142 std::reverse(waypoints_.begin(), waypoints_.end());
143 for (moveit::core::RobotStatePtr& waypoint : waypoints_)
146 waypoint->invertVelocity();
148 if (!duration_from_previous_.empty())
150 duration_from_previous_.push_back(duration_from_previous_.front());
151 std::reverse(duration_from_previous_.begin(), duration_from_previous_.end());
152 duration_from_previous_.pop_back();
160 if (waypoints_.empty())
163 const std::vector<const moveit::core::JointModel*>& cont_joints =
169 double running_offset = 0.0;
170 double last_value = waypoints_[0]->getJointPositions(cont_joint)[0];
171 cont_joint->enforcePositionBounds(&last_value);
172 waypoints_[0]->setJointPositions(cont_joint, &last_value);
174 for (std::size_t j = 1; j < waypoints_.size(); ++j)
176 double current_value = waypoints_[j]->getJointPositions(cont_joint)[0];
177 cont_joint->enforcePositionBounds(¤t_value);
178 if (last_value > current_value + M_PI)
180 running_offset += 2.0 * M_PI;
182 else if (current_value > last_value + M_PI)
184 running_offset -= 2.0 * M_PI;
187 last_value = current_value;
188 current_value += running_offset;
189 waypoints_[j]->setJointPositions(cont_joint, ¤t_value);
192 for (moveit::core::RobotStatePtr& waypoint : waypoints_)
202 if (waypoints_.empty())
205 const std::vector<const moveit::core::JointModel*>& cont_joints =
211 double reference_value = reference_value0;
212 cont_joint->enforcePositionBounds(&reference_value);
215 double running_offset = reference_value0 - reference_value;
217 double last_value = waypoints_[0]->getJointPositions(cont_joint)[0];
218 cont_joint->enforcePositionBounds(&last_value);
219 if (last_value > reference_value + M_PI)
221 running_offset -= 2.0 * M_PI;
223 else if (last_value < reference_value - M_PI)
225 running_offset += 2.0 * M_PI;
227 double current_start_value = last_value + running_offset;
228 waypoints_[0]->setJointPositions(cont_joint, ¤t_start_value);
230 for (std::size_t j = 1; j < waypoints_.size(); ++j)
232 double current_value = waypoints_[j]->getJointPositions(cont_joint)[0];
233 cont_joint->enforcePositionBounds(¤t_value);
234 if (last_value > current_value + M_PI)
236 running_offset += 2.0 * M_PI;
238 else if (current_value > last_value + M_PI)
240 running_offset -= 2.0 * M_PI;
243 last_value = current_value;
244 current_value += running_offset;
245 waypoints_[j]->setJointPositions(cont_joint, ¤t_value);
248 for (moveit::core::RobotStatePtr& waypoint : waypoints_)
257 const std::vector<std::string>& joint_filter)
const
259 trajectory = moveit_msgs::msg::RobotTrajectory();
260 if (waypoints_.empty())
262 const std::vector<const moveit::core::JointModel*>& jnts =
265 std::vector<const moveit::core::JointModel*> onedof;
266 std::vector<const moveit::core::JointModel*> mdof;
267 trajectory.joint_trajectory.joint_names.clear();
268 trajectory.multi_dof_joint_trajectory.joint_names.clear();
273 if (!joint_filter.empty() &&
274 std::find(joint_filter.begin(), joint_filter.end(), active_joint->getName()) == joint_filter.end())
277 if (active_joint->getVariableCount() == 1)
279 trajectory.joint_trajectory.joint_names.push_back(active_joint->getName());
280 onedof.push_back(active_joint);
284 trajectory.multi_dof_joint_trajectory.joint_names.push_back(active_joint->getName());
285 mdof.push_back(active_joint);
291 trajectory.joint_trajectory.header.frame_id = robot_model_->getModelFrame();
292 trajectory.joint_trajectory.header.stamp = rclcpp::Time(0, 0, RCL_ROS_TIME);
293 trajectory.joint_trajectory.points.resize(waypoints_.size());
298 trajectory.multi_dof_joint_trajectory.header.frame_id = robot_model_->getModelFrame();
299 trajectory.multi_dof_joint_trajectory.header.stamp = rclcpp::Time(0, 0, RCL_ROS_TIME);
300 trajectory.multi_dof_joint_trajectory.points.resize(waypoints_.size());
303 static const auto ZERO_DURATION = rclcpp::Duration::from_seconds(0);
304 double total_time = 0.0;
305 for (std::size_t i = 0; i < waypoints_.size(); ++i)
307 if (duration_from_previous_.size() > i)
308 total_time += duration_from_previous_[i];
312 trajectory.joint_trajectory.points[i].positions.resize(onedof.size());
313 trajectory.joint_trajectory.points[i].velocities.reserve(onedof.size());
315 for (std::size_t j = 0; j < onedof.size(); ++j)
317 trajectory.joint_trajectory.points[i].positions[j] =
318 waypoints_[i]->getVariablePosition(onedof[j]->getFirstVariableIndex());
320 if (waypoints_[i]->hasVelocities())
322 trajectory.joint_trajectory.points[i].velocities.push_back(
323 waypoints_[i]->getVariableVelocity(onedof[j]->getFirstVariableIndex()));
325 if (waypoints_[i]->hasAccelerations())
327 trajectory.joint_trajectory.points[i].accelerations.push_back(
328 waypoints_[i]->getVariableAcceleration(onedof[j]->getFirstVariableIndex()));
330 if (waypoints_[i]->hasEffort())
332 trajectory.joint_trajectory.points[i].effort.push_back(
333 waypoints_[i]->getVariableEffort(onedof[j]->getFirstVariableIndex()));
337 if (trajectory.joint_trajectory.points[i].velocities.size() != onedof.size())
338 trajectory.joint_trajectory.points[i].velocities.clear();
340 if (trajectory.joint_trajectory.points[i].accelerations.size() != onedof.size())
341 trajectory.joint_trajectory.points[i].accelerations.clear();
343 if (trajectory.joint_trajectory.points[i].effort.size() != onedof.size())
344 trajectory.joint_trajectory.points[i].effort.clear();
346 if (duration_from_previous_.size() > i)
348 trajectory.joint_trajectory.points[i].time_from_start = rclcpp::Duration::from_seconds(total_time);
352 trajectory.joint_trajectory.points[i].time_from_start = ZERO_DURATION;
357 trajectory.multi_dof_joint_trajectory.points[i].transforms.resize(mdof.size());
358 for (std::size_t j = 0; j < mdof.size(); ++j)
360 geometry_msgs::msg::TransformStamped ts = tf2::eigenToTransform(waypoints_[i]->getJointTransform(mdof[j]));
361 trajectory.multi_dof_joint_trajectory.points[i].transforms[j] = ts.transform;
363 if (waypoints_[i]->hasVelocities() && (mdof[j]->getType() == moveit::core::JointModel::JointType::PLANAR))
365 const std::vector<std::string> names = mdof[j]->getVariableNames();
366 const double* velocities = waypoints_[i]->getJointVelocities(mdof[j]);
368 geometry_msgs::msg::Twist point_velocity;
370 for (std::size_t k = 0; k < names.size(); ++k)
372 if (names[k].find(
"/x") != std::string::npos)
374 point_velocity.linear.x = velocities[k];
376 else if (names[k].find(
"/y") != std::string::npos)
378 point_velocity.linear.y = velocities[k];
380 else if (names[k].find(
"/z") != std::string::npos)
382 point_velocity.linear.z = velocities[k];
384 else if (names[k].find(
"/theta") != std::string::npos)
386 point_velocity.angular.z = velocities[k];
389 trajectory.multi_dof_joint_trajectory.points[i].velocities.push_back(point_velocity);
392 if (duration_from_previous_.size() > i)
394 trajectory.multi_dof_joint_trajectory.points[i].time_from_start = rclcpp::Duration::from_seconds(total_time);
398 trajectory.multi_dof_joint_trajectory.points[i].time_from_start = ZERO_DURATION;
405 const trajectory_msgs::msg::JointTrajectory& trajectory)
410 std::size_t state_count = trajectory.points.size();
411 rclcpp::Time last_time_stamp = trajectory.header.stamp;
412 rclcpp::Time this_time_stamp = last_time_stamp;
414 for (std::size_t i = 0; i < state_count; ++i)
416 this_time_stamp = rclcpp::Time(trajectory.header.stamp) + trajectory.points[i].time_from_start;
417 auto st = std::make_shared<moveit::core::RobotState>(copy);
418 st->setVariablePositions(trajectory.joint_names, trajectory.points[i].positions);
419 if (!trajectory.points[i].velocities.empty())
420 st->setVariableVelocities(trajectory.joint_names, trajectory.points[i].velocities);
421 if (!trajectory.points[i].accelerations.empty())
422 st->setVariableAccelerations(trajectory.joint_names, trajectory.points[i].accelerations);
423 if (!trajectory.points[i].effort.empty())
424 st->setVariableEffort(trajectory.joint_names, trajectory.points[i].effort);
426 last_time_stamp = this_time_stamp;
433 const moveit_msgs::msg::RobotTrajectory& trajectory)
439 std::size_t state_count =
440 std::max(trajectory.joint_trajectory.points.size(), trajectory.multi_dof_joint_trajectory.points.size());
441 rclcpp::Time last_time_stamp = trajectory.joint_trajectory.points.empty() ?
442 trajectory.multi_dof_joint_trajectory.header.stamp :
443 trajectory.joint_trajectory.header.stamp;
444 rclcpp::Time this_time_stamp = last_time_stamp;
446 for (std::size_t i = 0; i < state_count; ++i)
448 auto st = std::make_shared<moveit::core::RobotState>(copy);
449 if (trajectory.joint_trajectory.points.size() > i)
451 st->setVariablePositions(trajectory.joint_trajectory.joint_names, trajectory.joint_trajectory.points[i].positions);
452 if (!trajectory.joint_trajectory.points[i].velocities.empty())
454 st->setVariableVelocities(trajectory.joint_trajectory.joint_names,
455 trajectory.joint_trajectory.points[i].velocities);
457 if (!trajectory.joint_trajectory.points[i].accelerations.empty())
459 st->setVariableAccelerations(trajectory.joint_trajectory.joint_names,
460 trajectory.joint_trajectory.points[i].accelerations);
462 if (!trajectory.joint_trajectory.points[i].effort.empty())
463 st->setVariableEffort(trajectory.joint_trajectory.joint_names, trajectory.joint_trajectory.points[i].effort);
464 this_time_stamp = rclcpp::Time(trajectory.joint_trajectory.header.stamp) +
465 trajectory.joint_trajectory.points[i].time_from_start;
467 if (trajectory.multi_dof_joint_trajectory.points.size() > i)
469 for (std::size_t j = 0; j < trajectory.multi_dof_joint_trajectory.joint_names.size(); ++j)
471 Eigen::Isometry3d t = tf2::transformToEigen(trajectory.multi_dof_joint_trajectory.points[i].transforms[j]);
472 st->setJointPositions(trajectory.multi_dof_joint_trajectory.joint_names[j], t);
474 this_time_stamp = rclcpp::Time(trajectory.multi_dof_joint_trajectory.header.stamp) +
475 trajectory.multi_dof_joint_trajectory.points[i].time_from_start;
479 last_time_stamp = this_time_stamp;
485 const moveit_msgs::msg::RobotState& state,
486 const moveit_msgs::msg::RobotTrajectory& trajectory)
505 std::size_t index = 0, num_points = waypoints_.size();
506 double running_duration = 0.0;
507 for (; index < num_points; ++index)
509 running_duration += duration_from_previous_[index];
510 if (running_duration >= duration)
513 before = std::max<int>(index - 1, 0);
514 after = std::min<int>(index, num_points - 1);
517 double before_time = running_duration - duration_from_previous_[index];
524 blend = (duration - before_time) / duration_from_previous_[index];
530 if (duration_from_previous_.empty())
532 if (index >= duration_from_previous_.size())
533 index = duration_from_previous_.size() - 1;
536 for (std::size_t i = 0; i <= index; ++i)
537 time += duration_from_previous_[i];
542 moveit::core::RobotStatePtr& output_state)
const
548 int before = 0, after = 0;
553 waypoints_[before]->interpolate(*waypoints_[after], blend, *output_state);
562 out <<
"Empty trajectory.";
566 std::ios::fmtflags old_settings = out.flags();
567 int old_precision = out.precision();
568 out << std::fixed << std::setprecision(3);
570 out <<
"Trajectory has " << num_points <<
" points over " <<
getDuration() <<
" seconds\n";
572 if (variable_indexes.empty())
581 variable_indexes.resize(robot_model_->getVariableCount());
582 std::iota(variable_indexes.begin(), variable_indexes.end(), 0);
586 for (
size_t p_i = 0; p_i < num_points; ++p_i)
589 out <<
" waypoint " << std::setw(3) << p_i;
592 for (
int index : variable_indexes)
599 for (
int index : variable_indexes)
607 for (
int index : variable_indexes)
615 for (
int index : variable_indexes)
623 out.flags(old_settings);
624 out.precision(old_precision);
630 trajectory.
print(out);
636 auto trajectory_length = 0.0;
639 const auto& first = trajectory.
getWayPoint(index - 1);
640 const auto& second = trajectory.
getWayPoint(index);
641 trajectory_length += first.
distance(second);
643 return trajectory_length;
665 double acos_value = (a * a + b * b - cdist * cdist) / (2.0 * a * b);
666 if (acos_value > -1.0 && acos_value < 1.0)
669 double angle = (M_PI - acos(acos_value));
672 double u = 2.0 * angle;
const std::vector< const JointModel * > & getActiveJointModels() const
Get the active joints in this group (that have controllable DOF). This does not include mimic joints.
const std::string & getName() const
Get the name of the joint group.
const std::vector< const JointModel * > & getContinuousJointModels() const
Get the array of continuous joints used in this group (may include mimic joints).
const std::vector< int > & getVariableIndexList() const
Get the index locations in the complete robot state for all the variables in this group.
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
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.
const double * getJointPositions(const std::string &joint_name) const
bool hasVelocities() const
By default, if velocities are never set or initialized, the state remembers that there are no velocit...
double getVariableVelocity(const std::string &variable) const
Get the velocity of a particular variable. An exception is thrown if the variable is not known.
bool hasAccelerations() const
By default, if accelerations are never set or initialized, the state remembers that there are no acce...
bool hasEffort() const
By default, if effort is never set or initialized, the state remembers that there is no effort set....
double * getVariableEffort()
Get raw access to the effort of the variables that make up this state. The values are in the same ord...
double distance(const RobotState &other) const
Return the sum of joint distances to "other" state. An L1 norm. Only considers active joints.
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 & reverse()
void swap(robot_trajectory::RobotTrajectory &other)
const std::string & getGroupName() const
void findWayPointIndicesForDurationAfterStart(double duration, int &before, int &after, double &blend) const
Finds the waypoint indices before and after a duration from start.
double getWayPointDurationFromStart(std::size_t index) const
Returns the duration after start that a waypoint will be reached.
RobotTrajectory(const moveit::core::RobotModelConstPtr &robot_model)
construct a trajectory for the whole robot
double getAverageSegmentDuration() const
void print(std::ostream &out, std::vector< int > variable_indexes=std::vector< int >()) const
Print information about the trajectory.
bool getStateAtDurationFromStart(const double request_duration, moveit::core::RobotStatePtr &output_state) const
Gets a robot state corresponding to a supplied duration from start for the trajectory,...
void getRobotTrajectoryMsg(moveit_msgs::msg::RobotTrajectory &trajectory, const std::vector< std::string > &joint_filter=std::vector< std::string >()) const
RobotTrajectory & unwind()
RobotTrajectory & addSuffixWayPoint(const moveit::core::RobotState &state, double dt)
Add a point to the trajectory.
RobotTrajectory & setRobotTrajectoryMsg(const moveit::core::RobotState &reference_state, const trajectory_msgs::msg::JointTrajectory &trajectory)
Copy the content of the trajectory message into this class. The trajectory message itself is not requ...
RobotTrajectory & append(const RobotTrajectory &source, double dt, size_t start_index=0, size_t end_index=std::numeric_limits< std::size_t >::max())
Add a specified part of a trajectory to the end of the current trajectory. The default (when start_in...
std::size_t getWayPointCount() const
RobotTrajectory & clear()
const moveit::core::RobotState & getWayPoint(std::size_t index) const
double getDuration() const
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::msg::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
Convert a robot state msg (with accompanying extra transforms) to a MoveIt robot state.
rclcpp::Logger get_logger()
std::optional< double > waypointDensity(const RobotTrajectory &trajectory)
Calculate the waypoint density of a trajectory.
std::optional< double > smoothness(const RobotTrajectory &trajectory)
Calculate the smoothness of a given trajectory.
double pathLength(const RobotTrajectory &trajectory)
Calculate the path length of a given trajectory based on the accumulated robot state distances....
std::ostream & operator<<(std::ostream &out, const RobotTrajectory &trajectory)
Operator overload for printing trajectory to a stream.