44 #include <rclcpp/logger.hpp>
45 #include <rclcpp/logging.hpp>
46 #include <eigen3/Eigen/Core>
47 #include <eigen3/Eigen/LU>
49 #include <visualization_msgs/msg/marker_array.hpp>
64 : full_trajectory_(trajectory)
66 , planning_group_(planning_group)
67 , parameters_(parameters)
68 , group_trajectory_(*full_trajectory_, planning_group_, DIFF_RULE_LENGTH)
71 , start_state_(start_state)
74 RCLCPP_INFO(
getLogger(),
"Active collision detector is: %s",
planning_scene->getCollisionDetectorName().c_str());
80 RCLCPP_WARN(
getLogger(),
"Could not initialize hybrid collision world from planning scene");
87 void ChompOptimizer::initialize()
101 const auto wt = std::chrono::system_clock::now();
102 hy_env_->
getCollisionGradients(req, res, state_, &planning_scene_->getAllowedCollisionMatrix(), gsr_);
103 RCLCPP_INFO(
getLogger(),
"First coll check took %f sec",
104 std::chrono::duration<double>(std::chrono::system_clock::now() - wt).count());
105 num_collision_points_ = 0;
108 num_collision_points_ += gradient.
gradients.size();
112 joint_costs_.reserve(num_joints_);
114 double max_cost_scale = 0.0;
116 joint_model_group_ = planning_scene_->getRobotModel()->getJointModelGroup(planning_group_);
118 const std::vector<const moveit::core::JointModel*> joint_models = joint_model_group_->
getActiveJointModels();
119 for (
size_t i = 0; i < joint_models.size(); ++i)
121 double joint_cost = 1.0;
123 std::vector<double> derivative_costs(3);
127 joint_costs_.push_back(ChompCost(group_trajectory_, i, derivative_costs, parameters_->
ridge_factor_));
128 double cost_scale = joint_costs_[i].getMaxQuadCostInvValue();
129 if (max_cost_scale < cost_scale)
130 max_cost_scale = cost_scale;
134 for (
int i = 0; i < num_joints_; ++i)
136 joint_costs_[i].scale(max_cost_scale);
140 smoothness_increments_ = Eigen::MatrixXd::Zero(num_vars_free_, num_joints_);
141 collision_increments_ = Eigen::MatrixXd::Zero(num_vars_free_, num_joints_);
142 final_increments_ = Eigen::MatrixXd::Zero(num_vars_free_, num_joints_);
143 smoothness_derivative_ = Eigen::VectorXd::Zero(num_vars_all_);
144 jacobian_ = Eigen::MatrixXd::Zero(3, num_joints_);
145 jacobian_pseudo_inverse_ = Eigen::MatrixXd::Zero(num_joints_, 3);
146 jacobian_jacobian_tranpose_ = Eigen::MatrixXd::Zero(3, 3);
147 random_state_ = Eigen::VectorXd::Zero(num_joints_);
148 joint_state_velocities_ = Eigen::VectorXd::Zero(num_joints_);
150 group_trajectory_backup_ = group_trajectory_.
getTrajectory();
153 collision_point_joint_names_.resize(num_vars_all_, std::vector<std::string>(num_collision_points_));
154 collision_point_pos_eigen_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_collision_points_));
155 collision_point_vel_eigen_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_collision_points_));
156 collision_point_acc_eigen_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_collision_points_));
157 joint_axes_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_joints_));
158 joint_positions_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_joints_));
160 collision_point_potential_.resize(num_vars_all_, std::vector<double>(num_collision_points_));
161 collision_point_vel_mag_.resize(num_vars_all_, std::vector<double>(num_collision_points_));
162 collision_point_potential_gradient_.resize(num_vars_all_, EigenSTL::vector_Vector3d(num_collision_points_));
164 collision_free_iteration_ = 0;
165 is_collision_free_ =
false;
166 state_is_in_collision_.resize(num_vars_all_);
167 point_is_in_collision_.resize(num_vars_all_, std::vector<int>(num_collision_points_));
169 last_improvement_iteration_ = -1;
178 multivariate_gaussian_.clear();
179 stochasticity_factor_ = 1.0;
180 for (
int i = 0; i < num_joints_; ++i)
182 multivariate_gaussian_.push_back(
183 MultivariateGaussian(Eigen::VectorXd::Zero(num_vars_free_), joint_costs_[i].getQuadraticCostInverse()));
186 std::map<std::string, std::string> fixed_link_resolution_map;
187 for (
int i = 0; i < num_joints_; ++i)
192 fixed_link_resolution_map[joint_names_[i]] = joint_names_[i];
197 if (!jm->getParentLinkModel())
200 fixed_link_resolution_map[jm->getName()] = jm->getParentLinkModel()->getParentJointModel()->getName();
206 if (fixed_link_resolution_map.find(link->getParentJointModel()->getName()) == fixed_link_resolution_map.end())
209 bool found_root =
false;
213 if (parent_model ==
nullptr)
215 parent_model = link->getParentJointModel();
220 for (
const std::string& joint_name : joint_names_)
222 if (parent_model->
getName() == joint_name)
229 fixed_link_resolution_map[link->getParentJointModel()->getName()] = parent_model->
getName();
233 int start = free_vars_start_;
234 int end = free_vars_end_;
235 for (
int i = start; i <= end; ++i)
242 if (fixed_link_resolution_map.find(info.
joint_name) != fixed_link_resolution_map.end())
244 collision_point_joint_names_[i][j] = fixed_link_resolution_map[info.
joint_name];
265 bool found_root =
false;
267 if (model == robot_model_->getRootJoint())
272 if (parent_model ==
nullptr)
276 RCLCPP_ERROR(
getLogger(),
"Model %s not root but has nullptr link model parent", model->
getName().c_str());
281 RCLCPP_ERROR(
getLogger(),
"Model %s not root but has nullptr joint model parent", model->
getName().c_str());
288 if (parent_model == robot_model_->getRootJoint())
297 joint_parent_map_[model->
getName()][parent_model->
getName()] =
true;
303 bool optimization_result = 0;
305 const auto start_time = std::chrono::system_clock::now();
308 int cost_window = 10;
309 std::vector<double> costs(cost_window, 0.0);
311 bool should_break_out =
false;
314 for (iteration_ = 0; iteration_ < parameters_->
max_iterations_; ++iteration_)
316 performForwardKinematics();
317 double c_cost = getCollisionCost();
318 double s_cost = getSmoothnessCost();
319 double cost = c_cost + s_cost;
321 RCLCPP_DEBUG(
getLogger(),
"Collision cost %f, smoothness cost: %f", c_cost, s_cost);
346 best_group_trajectory_cost_ = cost;
347 last_improvement_iteration_ = iteration_;
349 else if (cost < best_group_trajectory_cost_)
352 best_group_trajectory_cost_ = cost;
353 last_improvement_iteration_ = iteration_;
355 calculateSmoothnessIncrements();
356 calculateCollisionIncrements();
357 calculateTotalIncrements();
365 addIncrementsToTrajectory();
377 updateFullTrajectory();
379 if (iteration_ % 10 == 0)
381 RCLCPP_DEBUG(
getLogger(),
"iteration: %d", iteration_);
382 if (isCurrentTrajectoryMeshToMeshCollisionFree())
384 num_collision_free_iterations_ = 0;
385 RCLCPP_INFO(
getLogger(),
"Chomp Got mesh to mesh safety at iter %d. Breaking out early.", iteration_);
386 is_collision_free_ =
true;
388 should_break_out =
true;
419 if (c_cost < parameters_->collision_threshold_)
422 is_collision_free_ =
true;
424 should_break_out =
true;
432 if (std::chrono::duration<double>(std::chrono::system_clock::now() - start_time).count() >
435 RCLCPP_WARN(
getLogger(),
"Breaking out early due to time limit constraints.");
488 if (should_break_out)
490 collision_free_iteration_++;
491 if (num_collision_free_iterations_ == 0)
495 else if (collision_free_iteration_ > num_collision_free_iterations_)
507 if (is_collision_free_)
509 optimization_result =
true;
510 RCLCPP_INFO(
getLogger(),
"Chomp path is collision free");
514 optimization_result =
false;
515 RCLCPP_ERROR(
getLogger(),
"Chomp path is not collision free!");
519 updateFullTrajectory();
521 RCLCPP_INFO(
getLogger(),
"Terminated after %d iterations, using path from iteration %d", iteration_,
522 last_improvement_iteration_);
523 RCLCPP_INFO(
getLogger(),
"Optimization core finished in %f sec",
524 std::chrono::duration<double>(std::chrono::system_clock::now() - start_time).count());
525 RCLCPP_INFO(
getLogger(),
"Time per iteration %f sec",
526 std::chrono::duration<double>(std::chrono::system_clock::now() - start_time).count() / (iteration_ * 1.0));
528 return optimization_result;
531 bool ChompOptimizer::isCurrentTrajectoryMeshToMeshCollisionFree()
const
533 moveit_msgs::msg::RobotTrajectory traj;
534 traj.joint_trajectory.joint_names = joint_names_;
536 for (
size_t i = 0; i < group_trajectory_.
getNumPoints(); ++i)
538 trajectory_msgs::msg::JointTrajectoryPoint point;
539 for (
size_t j = 0; j < group_trajectory_.
getNumJoints(); ++j)
541 point.positions.push_back(best_group_trajectory_(i, j));
543 traj.joint_trajectory.points.push_back(point);
545 moveit_msgs::msg::RobotState start_state_msg;
547 return planning_scene_->isPathValid(start_state_msg, traj, planning_group_);
550 void ChompOptimizer::calculateSmoothnessIncrements()
552 for (
int i = 0; i < num_joints_; ++i)
554 joint_costs_[i].getDerivative(group_trajectory_.
getJointTrajectory(i), smoothness_derivative_);
555 smoothness_increments_.col(i) = -smoothness_derivative_.segment(group_trajectory_.
getStartIndex(), num_vars_free_);
559 void ChompOptimizer::calculateCollisionIncrements()
566 Eigen::Matrix3d orthogonal_projector;
570 collision_increments_.setZero(num_vars_free_, num_joints_);
573 int end_point = free_vars_end_;
579 start_point =
static_cast<int>(rsl::uniform_real(0., 1.) * (free_vars_end_ - free_vars_start_) + free_vars_start_);
580 if (start_point < free_vars_start_)
581 start_point = free_vars_start_;
582 if (start_point > free_vars_end_)
583 start_point = free_vars_end_;
584 end_point = start_point;
588 start_point = free_vars_start_;
591 for (
int i = start_point; i <= end_point; ++i)
593 for (
int j = 0; j < num_collision_points_; ++j)
595 potential = collision_point_potential_[i][j];
597 if (potential < 0.0001)
600 potential_gradient = -collision_point_potential_gradient_[i][j];
602 vel_mag = collision_point_vel_mag_[i][j];
603 vel_mag_sq = vel_mag * vel_mag;
607 normalized_velocity = collision_point_vel_eigen_[i][j] / vel_mag;
608 orthogonal_projector = Eigen::Matrix3d::Identity() - (normalized_velocity * normalized_velocity.transpose());
609 curvature_vector = (orthogonal_projector * collision_point_acc_eigen_[i][j]) / vel_mag_sq;
610 cartesian_gradient = vel_mag * (orthogonal_projector * potential_gradient - potential * curvature_vector);
613 getJacobian(i, collision_point_pos_eigen_[i][j], collision_point_joint_names_[i][j], jacobian_);
617 calculatePseudoInverse();
618 collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_pseudo_inverse_ * cartesian_gradient;
622 collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_.transpose() * cartesian_gradient;
636 void ChompOptimizer::calculatePseudoInverse()
638 jacobian_jacobian_tranpose_ =
640 jacobian_pseudo_inverse_ = jacobian_.transpose() * jacobian_jacobian_tranpose_.inverse();
643 void ChompOptimizer::calculateTotalIncrements()
645 for (
int i = 0; i < num_joints_; ++i)
647 final_increments_.col(i) =
648 parameters_->
learning_rate_ * (joint_costs_[i].getQuadraticCostInverse() *
654 void ChompOptimizer::addIncrementsToTrajectory()
656 const std::vector<const moveit::core::JointModel*>& joint_models = joint_model_group_->
getActiveJointModels();
657 for (
size_t i = 0; i < joint_models.size(); ++i)
660 double max = final_increments_.col(i).maxCoeff();
661 double min = final_increments_.col(i).minCoeff();
664 if (max_scale < scale)
666 if (min_scale < scale)
674 void ChompOptimizer::updateFullTrajectory()
679 void ChompOptimizer::debugCost()
682 for (
int i = 0; i < num_joints_; ++i)
684 std::cout <<
"Cost = " << cost <<
'\n';
687 double ChompOptimizer::getTrajectoryCost()
689 return getSmoothnessCost() + getCollisionCost();
692 double ChompOptimizer::getSmoothnessCost()
694 double smoothness_cost = 0.0;
696 for (
int i = 0; i < num_joints_; ++i)
702 double ChompOptimizer::getCollisionCost()
704 double collision_cost = 0.0;
706 double worst_collision_cost = 0.0;
707 worst_collision_cost_state_ = -1;
710 for (
int i = free_vars_start_; i <= free_vars_end_; ++i)
712 double state_collision_cost = 0.0;
713 for (
int j = 0; j < num_collision_points_; ++j)
715 state_collision_cost += collision_point_potential_[i][j] * collision_point_vel_mag_[i][j];
717 collision_cost += state_collision_cost;
718 if (state_collision_cost > worst_collision_cost)
720 worst_collision_cost = state_collision_cost;
721 worst_collision_cost_state_ = i;
728 void ChompOptimizer::computeJointProperties(
int trajectory_point)
730 for (
int j = 0; j < num_joints_; ++j)
741 (robot_model_->getLinkModel(child_link_name)->getJointOriginTransform() *
747 if (revolute_joint !=
nullptr)
749 axis = revolute_joint->
getAxis();
751 else if (prismatic_joint !=
nullptr)
753 axis = prismatic_joint->
getAxis();
757 axis = Eigen::Vector3d::Identity();
760 axis = joint_transform * axis;
762 joint_axes_[trajectory_point][j] = axis;
763 joint_positions_[trajectory_point][j] = joint_transform.translation();
767 template <
typename Derived>
768 void ChompOptimizer::getJacobian(
int trajectory_point,
Eigen::Vector3d& collision_point_pos, std::string& joint_name,
769 Eigen::MatrixBase<Derived>& jacobian)
const
771 for (
int j = 0; j < num_joints_; ++j)
773 if (isParent(joint_name, joint_names_[j]))
776 Eigen::Vector3d(collision_point_pos(0), collision_point_pos(1), collision_point_pos(2)) -
777 joint_positions_[trajectory_point][j]);
779 jacobian.col(j)[0] = column.x();
780 jacobian.col(j)[1] = column.y();
781 jacobian.col(j)[2] = column.z();
785 jacobian.col(j)[0] = 0.0;
786 jacobian.col(j)[1] = 0.0;
787 jacobian.col(j)[2] = 0.0;
792 void ChompOptimizer::handleJointLimits()
794 const std::vector<const moveit::core::JointModel*> joint_models = joint_model_group_->
getActiveJointModels();
795 for (
size_t joint_i = 0; joint_i < joint_models.size(); ++joint_i)
811 double joint_max = -DBL_MAX;
812 double joint_min = DBL_MAX;
816 if (bound.min_position_ < joint_min)
821 if (bound.max_position_ > joint_max)
823 joint_max = bound.max_position_;
829 bool violation =
false;
832 double max_abs_violation = 1e-6;
833 double max_violation = 0.0;
834 int max_violation_index = 0;
836 for (
int i = free_vars_start_; i <= free_vars_end_; ++i)
839 double absolute_amount = 0.0;
840 if (group_trajectory_(i, joint_i) > joint_max)
842 amount = joint_max - group_trajectory_(i, joint_i);
843 absolute_amount = fabs(amount);
845 else if (group_trajectory_(i, joint_i) < joint_min)
847 amount = joint_min - group_trajectory_(i, joint_i);
848 absolute_amount = fabs(amount);
850 if (absolute_amount > max_abs_violation)
852 max_abs_violation = absolute_amount;
853 max_violation = amount;
854 max_violation_index = i;
861 int free_var_index = max_violation_index - free_vars_start_;
863 max_violation / joint_costs_[joint_i].getQuadraticCostInverse()(free_var_index, free_var_index);
865 multiplier * joint_costs_[joint_i].getQuadraticCostInverse().col(free_var_index);
873 void ChompOptimizer::performForwardKinematics()
876 double inv_time_sq = inv_time * inv_time;
879 int start = free_vars_start_;
880 int end = free_vars_end_;
884 end = num_vars_all_ - 1;
887 is_collision_free_ =
true;
889 auto total_dur = std::chrono::duration<double>::zero();
892 for (
int i = start; i <= end; ++i)
898 setRobotStateFromPoint(group_trajectory_, i);
899 auto grad = std::chrono::system_clock::now();
902 total_dur += (std::chrono::system_clock::now() - grad);
903 computeJointProperties(i);
904 state_is_in_collision_[i] =
false;
917 collision_point_potential_[i][j] =
919 collision_point_potential_gradient_[i][j][0] = info.
gradients[k].x();
920 collision_point_potential_gradient_[i][j][1] = info.
gradients[k].y();
921 collision_point_potential_gradient_[i][j][2] = info.
gradients[k].z();
925 if (point_is_in_collision_[i][j])
927 state_is_in_collision_[i] =
true;
928 is_collision_free_ =
false;
937 for (
int i = free_vars_start_; i <= free_vars_end_; ++i)
939 for (
int j = 0; j < num_collision_points_; ++j)
943 for (
int k = -DIFF_RULE_LENGTH / 2; k <= DIFF_RULE_LENGTH / 2; ++k)
945 collision_point_vel_eigen_[i][j] +=
946 (inv_time * DIFF_RULES[0][k + DIFF_RULE_LENGTH / 2]) * collision_point_pos_eigen_[i + k][j];
947 collision_point_acc_eigen_[i][j] +=
948 (inv_time_sq * DIFF_RULES[1][k + DIFF_RULE_LENGTH / 2]) * collision_point_pos_eigen_[i + k][j];
952 collision_point_vel_mag_[i][j] = collision_point_vel_eigen_[i][j].norm();
957 void ChompOptimizer::setRobotStateFromPoint(ChompTrajectory& group_trajectory,
int i)
959 const Eigen::MatrixXd::RowXpr& point = group_trajectory.getTrajectoryPoint(i);
961 std::vector<double> joint_states;
962 joint_states.reserve(group_trajectory.getNumJoints());
963 for (
size_t j = 0; j < group_trajectory.getNumJoints(); ++j)
964 joint_states.emplace_back(point(0, j));
970 void ChompOptimizer::perturbTrajectory()
973 if (worst_collision_cost_state_ < 0)
975 int mid_point = worst_collision_cost_state_;
979 std::vector<double> vals;
981 double* ptr = &vals[0];
982 Eigen::Map<Eigen::VectorXd> random_matrix(ptr, vals.size());
990 joint_state_velocities_.normalize();
991 random_matrix = (Eigen::MatrixXd::Identity(num_joints_, num_joints_) -
992 joint_state_velocities_ * joint_state_velocities_.transpose()) *
995 int mp_free_vars_index = mid_point - free_vars_start_;
996 for (
int i = 0; i < num_joints_; ++i)
999 joint_costs_[i].getQuadraticCostInverse().col(mp_free_vars_index) * random_state_(i);
ChompOptimizer(ChompTrajectory *trajectory, const planning_scene::PlanningSceneConstPtr &planning_scene, const std::string &planning_group, const ChompParameters *parameters, const moveit::core::RobotState &start_state)
virtual ~ChompOptimizer()
double collision_threshold_
double planning_time_limit_
double smoothness_cost_weight_
double smoothness_cost_jerk_
double smoothness_cost_acceleration_
bool use_stochastic_descent_
double pseudo_inverse_ridge_factor_
double smoothness_cost_velocity_
int max_iterations_after_collision_free_
double joint_update_limit_
double obstacle_cost_weight_
Represents a discretized joint-space trajectory for CHOMP.
Eigen::Block< Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic > getFreeTrajectoryBlock()
Gets the block of the trajectory which can be optimized.
void updateFromGroupTrajectory(const ChompTrajectory &group_trajectory)
Updates the full trajectory (*this) from the group trajectory.
size_t getEndIndex() const
Gets the end index.
size_t getStartIndex() const
Gets the start index.
double getDiscretization() const
Gets the discretization time interval of the trajectory.
size_t getNumPoints() const
Gets the number of points in the trajectory.
Eigen::Block< Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic > getFreeJointTrajectoryBlock(size_t joint)
Gets the block of free (optimizable) trajectory for a single joint.
void getJointVelocities(size_t traj_point, Eigen::MatrixBase< Derived > &velocities)
Gets the joint velocities at the given trajectory point.
size_t getNumJoints() const
Gets the number of joints in each trajectory point.
Eigen::MatrixXd::RowXpr getTrajectoryPoint(int traj_point)
Eigen::MatrixXd::ColXpr getJointTrajectory(int joint)
Eigen::MatrixXd & getTrajectory()
Gets the entire trajectory matrix.
size_t getNumFreePoints() const
Gets the number of points (that are free to be optimized) in the trajectory.
This hybrid collision environment combines FCL and a distance field. Both can be used to calculate co...
void getCollisionGradients(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state, const AllowedCollisionMatrix *acm, GroupStateRepresentationPtr &gsr) const
const std::vector< const JointModel * > & getFixedJointModels() const
Get the fixed joints that are part of this group.
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::vector< const LinkModel * > & getUpdatedLinkModels() const
Get the names of the links that are to be updated when the state of this group changes....
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
const LinkModel * getParentLinkModel() const
Get the link that this joint connects to. The robot is assumed to start with a joint,...
const LinkModel * getChildLinkModel() const
Get the link that this joint connects to. There will always be such a link.
std::vector< VariableBounds > Bounds
The datatype for the joint bounds.
const std::string & getName() const
Get the name of the joint.
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
JointType getType() const
Get the type of joint.
A link from the robot. Contains the constant transform applied to the link and its geometry.
const JointModel * getParentJointModel() const
Get the joint model whose child this link is. There will always be a parent joint.
const std::string & getName() const
The name of this link.
const Eigen::Vector3d & getAxis() const
Get the axis of translation.
bool isContinuous() const
Check if this joint wraps around.
const Eigen::Vector3d & getAxis() const
Get the axis of rotation.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
const Eigen::Isometry3d & getGlobalLinkTransform(const std::string &link_name)
Get the link transform w.r.t. the root link (model frame) of the RobotModel. This is typically the ro...
const JointModel * getJointModel(const std::string &joint) const
Get the model of a particular joint.
const Eigen::Isometry3d & getJointTransform(const std::string &joint_name)
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...
const JointModelGroup * getJointModelGroup(const std::string &group) const
Get the model of a particular joint group.
void setToRandomPositions()
Set all joints to random values. Values will be within default bounds.
void update(bool force=false)
Update all transforms.
rclcpp::Logger getLogger()
Vec3fX< details::Vec3Data< double > > Vector3d
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
This namespace includes the central class for representing planning contexts.
Representation of a collision checking request.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)....
Representation of a collision checking result.
EigenSTL::vector_Vector3d gradients
std::vector< double > distances
std::vector< double > sphere_radii
EigenSTL::vector_Vector3d sphere_locations