robot_env_evaluator 1.0.1
Loading...
Searching...
No Matches
robot_env_evaluator.cpp
Go to the documentation of this file.
1
21
22#include <pinocchio/algorithm/frames.hpp>
23#include <pinocchio/algorithm/jacobian.hpp>
24#include <pinocchio/collision/collision.hpp>
25
26#include <iostream>
27#include <chrono>
28
29namespace robot_env_evaluator
30{
31 RobotEnvEvaluator::RobotEnvEvaluator(const pinocchio::Model& model,
32 const std::string& ee_name,
33 const std::vector<std::string>& joint_names,
34 const pinocchio::GeometryModel& collision_model,
35 const pinocchio::GeometryModel& visual_model)
36 : model_(model), data_(model), collision_model_(collision_model), visual_model_(visual_model)
37 {
38 // Constructor implementation
39 if (model_.existFrame(ee_name)){
40 ee_index_ = model_.getFrameId(ee_name);
41 }
42 else{
43 throw std::invalid_argument("The targeted end-effector frame [" + ee_name + "] does not exist in the model.");
44 }
45
46 // Check if the joint names are valid
47 joint_indices_.clear();
48 for (const auto& joint_name : joint_names)
49 {
50 if(model.existFrame(joint_name)){
51 joint_indices_.push_back(model.getFrameId(joint_name));
52 }
53 else{
54 throw std::invalid_argument("The joint name [" + joint_name + "] does not exist in the model.");
55 }
56 }
57 }
58
60 : model_(other.model_),
61 data_(other.model_), // data_ must be initialized from model_, not copied directly
62 collision_model_(other.collision_model_),
63 visual_model_(other.visual_model_)
64 {
65 // Copy configuration variables
72
73 // Copy computed indices and buffers
74 ee_index_ = other.ee_index_;
77
78 // If the other object has computed data for a specific configuration,
79 // we need to recompute it to ensure data_ is consistent with buffered_q_
80 if (buffered_q_.size() > 0) {
81 pinocchio::forwardKinematics(model_, data_, buffered_q_);
82 pinocchio::computeJointJacobians(model_, data_, buffered_q_);
83 pinocchio::updateFramePlacements(model_, data_);
84 }
85 }
86
87 void RobotEnvEvaluator::forwardKinematics(const Eigen::VectorXd& q,
88 Eigen::Matrix4d& T,
89 const int joint_index /* = -1 */)
90 {
92 if (joint_index == -1) {
93 T = data_.oMf[ee_index_].toHomogeneousMatrix();
94 } else if (joint_index == 0) {
95 T = data_.oMf[0].toHomogeneousMatrix();
96 } else {
97 if (joint_index < 0 || joint_index > joint_indices_.size()) {
98 throw std::out_of_range("joint_index [" + std::to_string(joint_index) + "] is out of range [0, " + std::to_string(joint_indices_.size()) + "]");
99 }
100 T = data_.oMf[joint_indices_[joint_index - 1]].toHomogeneousMatrix();
101 }
102 }
103
105 Eigen::Matrix4d& T,
106 const std::string& frame_name)
107 {
109 if (model_.existFrame(frame_name)) {
110 int frame_index = model_.getFrameId(frame_name);
111 T = data_.oMf[frame_index].toHomogeneousMatrix();
112 } else {
113 throw std::invalid_argument("forwardKinematicsByFrameName: The frame name [" + frame_name + "] does not exist in the model.");
114 }
115 }
116
117 void RobotEnvEvaluator::jacobian(const Eigen::VectorXd& q,
118 Eigen::MatrixXd& J,
119 const int joint_index /* = -1 */)
120 {
121 if (joint_index == -1) {
123 } else if (joint_index == 0) {
124 jacobianFrame(q, 0, J);
125 } else {
126 if (joint_index < 0 || joint_index > joint_indices_.size()) {
127 throw std::out_of_range("joint_index" + std::to_string(joint_index) + " is out of range [0, " + std::to_string(joint_indices_.size()) + "]");
128 }
129 jacobianFrame(q, joint_indices_[joint_index - 1], J);
130 }
131 }
132
133 void RobotEnvEvaluator::jacobianByFrameName(const Eigen::VectorXd& q,
134 Eigen::MatrixXd& J,
135 const std::string& frame_name)
136 {
138 if (model_.existFrame(frame_name)) {
139 int frame_index = model_.getFrameId(frame_name);
140 jacobianFrame(q, frame_index, J);
141 } else {
142 throw std::invalid_argument("The frame name [" + frame_name + "] does not exist in the model.");
143 }
144 }
145
146 void RobotEnvEvaluator::jacobianFrame(const Eigen::VectorXd& q,
147 const double frame_index,
148 Eigen::MatrixXd& J)
149 {
151 J = pinocchio::getFrameJacobian(model_, data_, frame_index, pinocchio::LOCAL_WORLD_ALIGNED);
152 }
153
154 void RobotEnvEvaluator::computeDistances(const Eigen::VectorXd& q,
155 const std::vector<obstacleInput>& obstacles,
156 std::vector<distanceResult>& distances)
157 {
159 distances.clear();
160
161 // 1. create a GeometryModel from the collision model. Disable all collision pairs if necessary.
162 pinocchio::GeometryModel geom_model(collision_model_);
163 pinocchio::GeometryModel broad_phase_geom_model(collision_model_);
164 int robot_geom_num = geom_model.ngeoms;
165 if(calculate_self_collision_ == false){
166 geom_model.removeAllCollisionPairs();
167 broad_phase_geom_model.removeAllCollisionPairs();
168 }
169
170 // 2. add the obstacles and add collision pairs for obstacles
171 int i_obstacle = 0;
172 for (const auto& obstacle : obstacles)
173 {
174 // 2.1 Construct the collision geometry
175 pinocchio::GeometryObject::CollisionGeometryPtr collision_geometry;
176 pinocchio::GeometryObject::CollisionGeometryPtr collision_geometry_broad;
177 std::string mesh_path = "";
178 Eigen::Vector3d mesh_scale = Eigen::Vector3d::Ones();
179 double broad_phase_collision_padding = broad_phase_collision_padding_;
180
181 std::visit([&collision_geometry, &collision_geometry_broad, &mesh_path, &mesh_scale, &broad_phase_collision_padding](auto&& arg) {
182 using T = std::decay_t<decltype(arg)>;
183 if constexpr (std::is_same_v<T, coal::Sphere>) {
184 collision_geometry = std::make_shared<coal::Sphere>(arg);
185 collision_geometry_broad = std::make_shared<coal::Sphere>(arg.radius + broad_phase_collision_padding);
186 mesh_path = "SPHERE";
187 mesh_scale = Eigen::Vector3d::Ones() * arg.radius;
188 }
189 }, obstacle.obstacle);
190
191 // 2.2 Add the obstacle to the narrow phase geometry model
192 pinocchio::GeometryObject geom_object(
193 "Obstacle_" + std::to_string(i_obstacle),
194 0,
195 pinocchio::SE3(obstacle.obstacle_pose),
196 collision_geometry,
197 mesh_path,
198 mesh_scale,
199 false,
200 Eigen::Vector4d(0.5, 0.5, 0.5, 1.0)
201 );
202 geom_model.addGeometryObject(geom_object);
203
204 // 2.3 Add the obstacle to the broad phase geometry model
205 pinocchio::GeometryObject broad_geom_object(
206 "Obstacle_" + std::to_string(i_obstacle),
207 0,
208 pinocchio::SE3(obstacle.obstacle_pose),
209 collision_geometry_broad,
210 mesh_path,
211 mesh_scale,
212 false,
213 Eigen::Vector4d(0.5, 0.5, 0.5, 1.0)
214 );
215 broad_phase_geom_model.addGeometryObject(broad_geom_object);
216
217 // 2.4 Add collision pairs between the robot and the obstacle for broad phase search
218 // for collision pairs, we always put the robot higher index body as the second one.
219 // This will help with the distance computation.
220 for(int i = 0; i < robot_geom_num; i++){
221 if(broad_phase_geom_model.geometryObjects[i].disableCollision == false){
222 broad_phase_geom_model.addCollisionPair(pinocchio::CollisionPair(robot_geom_num + i_obstacle, i));
223 }
224 }
225
226 i_obstacle++;
227 }
228
229 // 3. Broad phase search for collision pairs, then use this to construct the narrow phase collision pairs
230 pinocchio::GeometryData broad_phase_geom_data(broad_phase_geom_model);
232 // 3.1 Broad phase search for collision pairs
233 pinocchio::updateGeometryPlacements(model_, data_, broad_phase_geom_model, broad_phase_geom_data);
234 pinocchio::computeCollisions(broad_phase_geom_model, broad_phase_geom_data);
235 // 3.2 Filter the collision pairs based on the broad phase distance threshold
236 for (size_t i = 0; i < broad_phase_geom_data.collisionResults.size(); ++i) {
237 const auto& result = broad_phase_geom_data.collisionResults[i];
238 if (result.isCollision()) {
239 geom_model.addCollisionPair(pinocchio::CollisionPair(
240 broad_phase_geom_model.collisionPairs[i].first,
241 broad_phase_geom_model.collisionPairs[i].second));
242 }
243 }
244 } else {
245 for(int j_obstacle = 0; j_obstacle < i_obstacle; j_obstacle++)
246 {
247 for(int i = 0; i < robot_geom_num; i++){
248 if(geom_model.geometryObjects[i].disableCollision == false){
249 geom_model.addCollisionPair(pinocchio::CollisionPair(robot_geom_num + j_obstacle, i));
250 }
251 }
252 }
253 }
254
255 // 4. Narrow phase calculate distances between the robot and obstacles
256 pinocchio::GeometryData geom_data(geom_model);
257 pinocchio::updateGeometryPlacements(model_, data_, geom_model, geom_data);
258 pinocchio::computeDistances(geom_model, geom_data);
259
260 // 5. output the distances into the output structure
261 for (int i = 0; i < geom_data.distanceResults.size(); i++)
262 {
263 const auto& distance = geom_data.distanceResults[i];
264 const auto& robot_geom = geom_model.geometryObjects[geom_model.collisionPairs[i].second];
265 Eigen::Vector3d seperation_vector = (distance.nearest_points[1] - distance.nearest_points[0]).normalized();
266 Eigen::MatrixXd jacobian_matrix;
267 this->jacobianFrame(q, robot_geom.parentFrame, jacobian_matrix);
268 Eigen::VectorXd projector_control_to_dist = seperation_vector.transpose() * jacobian_matrix.topRows(3);
269 Eigen::VectorXd projector_dist_to_control;
272 projector_dist_to_control = (1.0 / projector_control_to_dist.norm() / projector_control_to_dist.norm()) * projector_control_to_dist.transpose();
273 } else {
274 // Compute the damped Jacobian pseudo-inverse using Jᵀ(JJᵀ + λ²I)⁻¹
275 Eigen::VectorXd seperation_twist = Eigen::VectorXd::Zero(6);
276 seperation_twist.head(3) = seperation_vector;
277 Eigen::MatrixXd JJt = jacobian_matrix * jacobian_matrix.transpose();
278 Eigen::MatrixXd damped_identity = robust_pinv_lambda_ * robust_pinv_lambda_ * Eigen::MatrixXd::Identity(JJt.rows(), JJt.cols());
279
280 projector_dist_to_control = jacobian_matrix.transpose() * (JJt + damped_identity).ldlt().solve(seperation_twist);
281 projector_control_to_dist = (1.0 / projector_dist_to_control.norm() * projector_dist_to_control.norm()) * projector_dist_to_control.transpose();
282 }
283 }
284
285 distances.push_back(distanceResult{
286 i,
287 distance.min_distance,
288 seperation_vector,
289 distance.nearest_points[1],
290 distance.nearest_points[0],
291 robot_geom.name,
292 projector_control_to_dist,
293 projector_dist_to_control
294 });
295 }
296 }
297
298 void RobotEnvEvaluator::computeModelData(const Eigen::VectorXd& q)
299 {
300 if (buffered_q_.size() == 0 || q != buffered_q_)
301 {
302 // Compute the model data
303 pinocchio::forwardKinematics(model_, data_, q);
304 pinocchio::computeJointJacobians(model_, data_, q);
305 pinocchio::updateFramePlacements(model_, data_);
306
307 // Update the buffered joint configuration
308 buffered_q_ = q;
309 }
310 }
311} // namespace robot_env_evaluator
The main functionality class, which provides functionalities for evaluating robot environment informa...
void forwardKinematics(const Eigen::VectorXd &q, Eigen::Matrix4d &T, const int joint_index=-1)
The forward kinematics function for a specific joint, specified by the index.
double broad_phase_collision_padding_
The threshold for the broad phase search, this margin will be appended to first into GJK test and dis...
pinocchio::Data data_
The robot data, initialized from the model.
void jacobianFrame(const Eigen::VectorXd &q, const double frame_index, Eigen::MatrixXd &J)
Get the Jacobian of specific frame.
bool calculate_self_collision_
Whether to calculate self-collision in distance computation.
Eigen::VectorXd buffered_q_
The buffered joint configuration. This is used to avoid unnecessary computation.
void forwardKinematicsByFrameName(const Eigen::VectorXd &q, Eigen::Matrix4d &T, const std::string &frame_name)
The forward kinematics function for a specific frame, specified by the name.
void computeModelData(const Eigen::VectorXd &q)
Compute the model data from the joint configuration.
double robust_pinv_lambda_
The lambda value for the robust pseudo-inverse projector.
bool broad_phase_search_enable_
Whether to enable the broad phase search for collision detection.
bool projector_dist_to_control_with_zero_orientation_
Whether to use the full Jacobian and set the orientation to zero when calculating the projector.
bool projector_dist_to_control_enable_
Whether to calculate the projector from distance to control space.
RobotEnvEvaluator(const pinocchio::Model &model, const std::string &ee_name, const std::vector< std::string > &joint_names, const pinocchio::GeometryModel &collision_model, const pinocchio::GeometryModel &visual_model=pinocchio::GeometryModel())
Construct a new Robot Env Evaluator object.
void jacobianByFrameName(const Eigen::VectorXd &q, Eigen::MatrixXd &J, const std::string &frame_name)
Get the jacobian of specific frame, specified by the name.
int ee_index_
The internal index for end-effector.frame.
std::vector< double > joint_indices_
The joint indices for the robot model.
void computeDistances(const Eigen::VectorXd &q, const std::vector< obstacleInput > &obstacles, std::vector< distanceResult > &distances)
The distance computation function between the robot and obstacles.
pinocchio::GeometryModel collision_model_
The collision model.
void jacobian(const Eigen::VectorXd &q, Eigen::MatrixXd &J, const int joint_index=-1)
The jacobian function for a specific joint, specified by the index.
pinocchio::Model model_
The robot model.
Header file for the RobotEnvEvaluator class, which provides functionalities for evaluating robot envi...
Store the distance result between objects.