00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00037 #include <chomp_motion_planner/chomp_collision_space.h>
00038 #include <planning_environment/util/construct_object.h>
00039 #include <sstream>
00040
00041 namespace chomp
00042 {
00043
00044 ChompCollisionSpace::ChompCollisionSpace():
00045 node_handle_("~"),distance_field_(NULL),monitor_(NULL)
00046
00047 {
00048 }
00049
00050 ChompCollisionSpace::~ChompCollisionSpace()
00051 {
00052 if(distance_field_) {
00053 delete distance_field_;
00054 }
00055
00056
00057
00058 }
00059
00060 bool ChompCollisionSpace::init(planning_environment::CollisionSpaceMonitor* monitor, double max_radius_clearance, std::string& reference_frame)
00061 {
00062 double size_x, size_y, size_z;
00063 double origin_x, origin_y, origin_z;
00064 double resolution;
00065
00066 reference_frame_ = reference_frame;
00067
00068 node_handle_.param("collision_space/size_x", size_x, 2.0);
00069 node_handle_.param("collision_space/size_y", size_y, 3.0);
00070 node_handle_.param("collision_space/size_z", size_z, 4.0);
00071 node_handle_.param("collision_space/origin_x", origin_x, 0.1);
00072 node_handle_.param("collision_space/origin_y", origin_y, -1.5);
00073 node_handle_.param("collision_space/origin_z", origin_z, -2.0);
00074 node_handle_.param("collision_space/resolution", resolution, 0.02);
00075 node_handle_.param("collision_space/field_bias_x", field_bias_x_, 0.0);
00076 node_handle_.param("collision_space/field_bias_y", field_bias_y_, 0.0);
00077 node_handle_.param("collision_space/field_bias_z", field_bias_z_, 0.0);
00078 resolution_ = resolution;
00079 max_expansion_ = max_radius_clearance;
00080
00081
00082
00083 distance_field_ = new distance_field::PropagationDistanceField(size_x, size_y, size_z, resolution, origin_x, origin_y, origin_z, max_radius_clearance);
00084
00085 monitor_ = monitor;
00086
00087 loadRobotBodies();
00088
00089 XmlRpc::XmlRpcValue coll_ops;
00090
00091 if(!node_handle_.hasParam("chomp_collision_operations")) {
00092 ROS_WARN("No default collision operations specified");
00093 } else {
00094
00095 node_handle_.getParam("chomp_collision_operations", coll_ops);
00096
00097 if(coll_ops.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00098 ROS_WARN("chomp_collision_operations is not an array");
00099 } else {
00100
00101 if(coll_ops.size() == 0) {
00102 ROS_WARN("No collision operations in chomp collision operations");
00103 } else {
00104
00105 for(int i = 0; i < coll_ops.size(); i++) {
00106 if(!coll_ops[i].hasMember("object1") || !coll_ops[i].hasMember("object2") || !coll_ops[i].hasMember("operation")) {
00107 ROS_WARN("All collision operations must have two objects and an operation");
00108 continue;
00109 }
00110 std::string object1 = std::string(coll_ops[i]["object1"]);
00111 std::string object2 = std::string(coll_ops[i]["object2"]);
00112 std::string operation = std::string(coll_ops[i]["operation"]);
00113 if(operation == "enable") {
00114 if(planning_group_link_names_.find(object1) == planning_group_link_names_.end()) {
00115 ROS_WARN_STREAM("Object 1 must be a recognized planning group and " << object1 << " is not");
00116 continue;
00117 }
00118 if(distance_include_links_.find(object1) == distance_include_links_.end()) {
00119 std::vector<std::string> emp;
00120 distance_include_links_[object1] = emp;
00121 }
00122 std::vector<std::string>& include_links = distance_include_links_[object1];
00123 if(planning_group_link_names_.find(object2) == planning_group_link_names_.end()) {
00124 include_links.push_back(object2);
00125 ROS_DEBUG_STREAM("Link " << object1 << " adding include for link " << object2);
00126 } else {
00127 ROS_DEBUG_STREAM("Link " << object1 << " adding include for group " << object2 << " size " << planning_group_link_names_.find(object2)->second.size() );
00128 include_links.insert(include_links.end(), planning_group_link_names_.find(object2)->second.begin(),
00129 planning_group_link_names_.find(object2)->second.end());
00130 }
00131 } else if(operation == "disable") {
00132 if(planning_group_link_names_.find(object1) == planning_group_link_names_.end()) {
00133 ROS_WARN_STREAM("Object 1 must be a recognized planning group and " << object1 << " is not");
00134 continue;
00135 }
00136 if(distance_exclude_links_.find(object1) == distance_exclude_links_.end()) {
00137 std::vector<std::string> emp;
00138 distance_exclude_links_[object1] = emp;
00139 }
00140 std::vector<std::string>& exclude_links = distance_exclude_links_[object1];
00141 if(planning_group_link_names_.find(object2) == planning_group_link_names_.end()) {
00142 exclude_links.push_back(object2);
00143 ROS_DEBUG_STREAM("Link " << object1 << " adding exclude for link " << object2);
00144 } else {
00145 ROS_DEBUG_STREAM("Link " << object1 << " adding exclude for group " << object2 << " size " << planning_group_link_names_.find(object2)->second.size() );
00146 exclude_links.insert(exclude_links.end(), planning_group_link_names_.find(object2)->second.begin(),
00147 planning_group_link_names_.find(object2)->second.end());
00148 }
00149 } else {
00150 ROS_WARN_STREAM("Unrecognized collision operation " << operation << ". Must be enable or disable");
00151 continue;
00152 }
00153 }
00154 }
00155 }
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 ROS_INFO("Initialized chomp collision space in %s reference frame with %f expansion radius.", reference_frame_.c_str(), max_expansion_);
00167 return true;
00168 }
00169
00170 void ChompCollisionSpace::setStartState(const ChompRobotModel::ChompPlanningGroup& planning_group, const motion_planning_msgs::RobotState& robot_state) {
00171
00172 ros::WallTime start = ros::WallTime::now();
00173
00174 monitor_->waitForState();
00175
00176 planning_models::KinematicState state(monitor_->getKinematicModel());
00177
00178 distance_field_->reset();
00179
00180 std::vector<btVector3> all_points;
00181
00182 monitor_->getEnvironmentModel()->lock();
00183 monitor_->setRobotStateAndComputeTransforms(robot_state, state);
00184
00185 monitor_->setCollisionSpace();
00186
00187 std::string root_name = monitor_->getKinematicModel()->getRoot()->getName();
00188
00189
00190 const btTransform& cur = state.getJointState(root_name)->getVariableTransform();
00191 btTransform cur_copy(cur);
00192
00193
00194 btTransform id;
00195 id.setIdentity();
00196 state.getJointState(root_name)->setJointStateValues(id);
00197 state.updateKinematicLinks();
00198
00199 updateRobotBodiesPoses(state);
00200
00201 addAllBodiesButExcludeLinksToPoints(planning_group.name_, all_points);
00202 addCollisionObjectsToPoints(all_points, cur_copy);
00203
00204 ROS_INFO_STREAM("All points size " << all_points.size());
00205
00206 distance_field_->addPointsToField(all_points);
00207 distance_field_->visualize(0.0*max_expansion_, 0.01*max_expansion_, monitor_->getWorldFrameId(), cur_copy, ros::Time::now());
00208
00209 monitor_->getEnvironmentModel()->unlock();
00210
00211 ros::WallDuration t_diff = ros::WallTime::now() - start;
00212 ROS_INFO_STREAM("Took " << t_diff.toSec() << " to set distance field");
00213 }
00214
00215 void ChompCollisionSpace::addCollisionObjectsToPoints(std::vector<btVector3>& points, const btTransform& cur_transform) {
00216
00217 btTransform inv = cur_transform.inverse();
00218
00219 const collision_space::EnvironmentObjects *eo = monitor_->getEnvironmentModel()->getObjects();
00220 std::vector<std::string> ns = eo->getNamespaces();
00221 for (unsigned int i = 0 ; i < ns.size() ; ++i)
00222 {
00223 const collision_space::EnvironmentObjects::NamespaceObjects &no = eo->getObjects(ns[i]);
00224 const unsigned int n = no.shape.size();
00225
00226
00227 if(ns[i] == "points") {
00228
00229 for(unsigned int j = 0; j < n; ++j)
00230 {
00231 points.push_back(inv*no.shapePose[j].getOrigin());
00232 }
00233 continue;
00234 }
00235 for(unsigned int j = 0; j < n; j++) {
00236 if (no.shape[j]->type == shapes::MESH) {
00237 bodies::Body *body = bodies::createBodyFromShape(no.shape[j]);
00238 body->setPose(inv*no.shapePose[j]);
00239 std::vector<btVector3> body_points;
00240 getVoxelsInBody(*body, body_points);
00241 points.insert(points.end(), body_points.begin(), body_points.end());
00242 delete body;
00243 } else {
00244 geometric_shapes_msgs::Shape object;
00245 if(!planning_environment::constructObjectMsg(no.shape[j], object)) {
00246 ROS_WARN("Shap cannot be converted");
00247 continue;
00248 }
00249 geometry_msgs::Pose pose;
00250 tf::poseTFToMsg(no.shapePose[j], pose);
00251 KDL::Rotation rotation = KDL::Rotation::Quaternion(pose.orientation.x,
00252 pose.orientation.y,
00253 pose.orientation.z,
00254 pose.orientation.w);
00255 KDL::Vector position(pose.position.x, pose.position.y, pose.position.z);
00256 KDL::Frame f(rotation, position);
00257 if (object.type == geometric_shapes_msgs::Shape::CYLINDER)
00258 {
00259 if (object.dimensions.size() != 2) {
00260 ROS_INFO_STREAM("Cylinder must have exactly 2 dimensions, not "
00261 << object.dimensions.size());
00262 continue;
00263 }
00264
00265 double radius = object.dimensions[0];
00266
00267
00268 double xlow = pose.position.x - object.dimensions[0];
00269 double ylow = pose.position.y - object.dimensions[0];
00270 double zlow = pose.position.z - object.dimensions[1]/2.0;
00271
00272
00273
00274 for(double x = xlow; x <= xlow+object.dimensions[0]*2.0+resolution_; x += resolution_) {
00275 for(double y = ylow; y <= ylow+object.dimensions[0]*2.0+resolution_; y += resolution_) {
00276 for(double z = zlow; z <= zlow+object.dimensions[1]+resolution_; z += resolution_) {
00277 double xdist = fabs(pose.position.x-x);
00278 double ydist = fabs(pose.position.y-y);
00279
00280
00281
00282 if(sqrt(xdist*xdist+ydist*ydist) <= radius) {
00283 KDL::Vector p(pose.position.x-x,pose.position.y-y,pose.position.z-z);
00284 KDL::Vector p2;
00285 p2 = f*p;
00286 points.push_back(inv*btVector3(p2(0),p2(1),p2(2)));
00287 }
00288 }
00289 }
00290 }
00291 } else if (object.type == geometric_shapes_msgs::Shape::BOX) {
00292 if(object.dimensions.size() != 3) {
00293 ROS_INFO_STREAM("Box must have exactly 3 dimensions, not "
00294 << object.dimensions.size());
00295 continue;
00296 }
00297
00298 double xlow = pose.position.x - object.dimensions[0]/2.0;
00299 double ylow = pose.position.y - object.dimensions[1]/2.0;
00300 double zlow = pose.position.z - object.dimensions[2]/2.0;
00301
00302 for(double x = xlow; x <= xlow+object.dimensions[0]+resolution_; x += resolution_) {
00303 for(double y = ylow; y <= ylow+object.dimensions[1]+resolution_; y += resolution_) {
00304 for(double z = zlow; z <= zlow+object.dimensions[2]+resolution_; z += resolution_) {
00305 KDL::Vector p(pose.position.x-x,pose.position.y-y,pose.position.z-z);
00306 KDL::Vector p2;
00307 p2 = f*p;
00308 points.push_back(inv*btVector3(p2(0),p2(1),p2(2)));
00309 }
00310 }
00311 }
00312 }
00313 }
00314 }
00315 }
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 static std::string intToString(int i)
00465 {
00466 std::ostringstream oss;
00467 oss << i;
00468 return oss.str();
00469 }
00470
00471 void ChompCollisionSpace::initCollisionCuboids()
00472 {
00473 int index=1;
00474 while (node_handle_.hasParam(std::string("collision_space/cuboids/cuboid")+intToString(index)+"/size_x"))
00475 {
00476 addCollisionCuboid(std::string("collision_space/cuboids/cuboid")+intToString(index));
00477 index++;
00478 }
00479
00480 }
00481
00482 void ChompCollisionSpace::addCollisionCuboid(const std::string param_name)
00483 {
00484 double size_x, size_y, size_z;
00485 double origin_x, origin_y, origin_z;
00486 if (!node_handle_.getParam(param_name+"/size_x", size_x))
00487 return;
00488 if (!node_handle_.getParam(param_name+"/size_y", size_y))
00489 return;
00490 if (!node_handle_.getParam(param_name+"/size_z", size_z))
00491 return;
00492 if (!node_handle_.getParam(param_name+"/origin_x", origin_x))
00493 return;
00494 if (!node_handle_.getParam(param_name+"/origin_y", origin_y))
00495 return;
00496 if (!node_handle_.getParam(param_name+"/origin_z", origin_z))
00497 return;
00498
00499 if (size_x<0 || size_y<0 || size_z<0)
00500 return;
00501
00502
00503 int num_points=0;
00504 for (double x=origin_x; x<=origin_x+size_x; x+=resolution_)
00505 for (double y=origin_y; y<=origin_y+size_y; y+=resolution_)
00506 for (double z=origin_z; z<=origin_z+size_z; z+=resolution_)
00507 {
00508 cuboid_points_.push_back(btVector3(x,y,z));
00509 ++num_points;
00510 }
00511 ROS_INFO("Added %d points for collision cuboid %s", num_points, param_name.c_str());
00512 }
00513
00514 void ChompCollisionSpace::loadRobotBodies() {
00515 planning_group_link_names_.clear();
00516
00517 planning_group_link_names_ = monitor_->getCollisionModels()->getPlanningGroupLinks();
00518
00519 ROS_DEBUG_STREAM("Planning group links size " << planning_group_link_names_.size());
00520
00521 for(std::map<std::string, std::vector<std::string> >::iterator it1 = planning_group_link_names_.begin();
00522 it1 != planning_group_link_names_.end();
00523 it1++)
00524 {
00525 ROS_DEBUG_STREAM("Chomp loading group " << it1->first);
00526
00527 for(std::vector<std::string>::iterator it2 = it1->second.begin();
00528 it2 != it1->second.end();
00529 it2++) {
00530 const planning_models::KinematicModel::LinkModel* link = monitor_->getCollisionModels()->getKinematicModel()->getLinkModel(*it2);
00531 if(link != NULL) {
00532 planning_group_bodies_[it1->first].push_back(bodies::createBodyFromShape(link->getLinkShape()));
00533 } else {
00534 ROS_WARN_STREAM("Error - no link for name " << *it2);
00535 }
00536
00537 }
00538 }
00539 }
00540
00541 void ChompCollisionSpace::updateRobotBodiesPoses(const planning_models::KinematicState& state) {
00542 for(std::map<std::string, std::vector<bodies::Body *> >::iterator it1 = planning_group_bodies_.begin();
00543 it1 != planning_group_bodies_.end();
00544 it1++) {
00545 std::vector<std::string>& v = planning_group_link_names_[it1->first];
00546 for(unsigned int i = 0; i < it1->second.size(); i++) {
00547 (it1->second)[i]->setPose(state.getLinkState(v[i])->getGlobalLinkTransform());
00548 }
00549 }
00550 }
00551
00552 void ChompCollisionSpace::addBodiesInGroupToPoints(const std::string& group, std::vector<btVector3>& body_points) {
00553
00554 if(group == std::string("all")) {
00555 for(std::map<std::string, std::vector<bodies::Body *> >::iterator it1 = planning_group_bodies_.begin();
00556 it1 != planning_group_bodies_.end();
00557 it1++) {
00558 for(unsigned int i = 0; i < it1->second.size(); i++) {
00559 std::vector<btVector3> single_body_points;
00560 getVoxelsInBody((*it1->second[i]), single_body_points);
00561 ROS_DEBUG_STREAM("Group " << it1->first << " link num " << i << " points " << single_body_points.size());
00562 body_points.insert(body_points.end(), single_body_points.begin(), single_body_points.end());
00563 }
00564 }
00565 } else {
00566 if(planning_group_bodies_.find(group) != planning_group_bodies_.end()) {
00567 std::vector<bodies::Body *>& bodies = planning_group_bodies_[group];
00568 for(unsigned int i = 0; i < bodies.size(); i++) {
00569 std::vector<btVector3> single_body_points;
00570 getVoxelsInBody(*(bodies[i]), single_body_points);
00571 ROS_DEBUG_STREAM("Group " << group << " link num " << i << " points " << single_body_points.size());
00572 body_points.insert(body_points.end(), single_body_points.begin(), single_body_points.end());
00573 }
00574 } else {
00575 ROS_WARN_STREAM("Group " << group << " not found in planning groups");
00576 }
00577 }
00578 }
00579
00580 void ChompCollisionSpace::addAllBodiesButExcludeLinksToPoints(std::string group_name, std::vector<btVector3>& body_points) {
00581
00582 std::vector<std::string> exclude_links;
00583 if(distance_exclude_links_.find(group_name) != distance_exclude_links_.end())
00584 {
00585 exclude_links = distance_exclude_links_[group_name];
00586 }
00587
00588
00589 if(distance_include_links_.find(group_name) != distance_include_links_.end()) {
00590 for(std::vector<std::string>::iterator it = distance_include_links_[group_name].begin();
00591 it != distance_include_links_[group_name].end();
00592 it++) {
00593 std::vector<std::string>::iterator f = find(exclude_links.begin(), exclude_links.end(), *it);
00594 if(f != exclude_links.end()) {
00595 exclude_links.erase(f);
00596 }
00597 }
00598 }
00599
00600 for(std::map<std::string, std::vector<bodies::Body *> >::iterator it1 = planning_group_bodies_.begin();
00601 it1 != planning_group_bodies_.end();
00602 it1++) {
00603 std::vector<std::string>& group_link_names = planning_group_link_names_[it1->first];
00604
00605 for(unsigned int i = 0; i < it1->second.size(); i++) {
00606 if(find(exclude_links.begin(), exclude_links.end(),group_link_names[i]) == exclude_links.end()) {
00607 std::vector<btVector3> single_body_points;
00608 getVoxelsInBody((*it1->second[i]), single_body_points);
00609 ROS_DEBUG_STREAM("Group " << it1->first << " link " << group_link_names[i] << " points " << single_body_points.size());
00610 body_points.insert(body_points.end(), single_body_points.begin(), single_body_points.end());
00611 }
00612 }
00613 }
00614 }
00615
00616 void ChompCollisionSpace::getVoxelsInBody(const bodies::Body &body, std::vector<btVector3> &voxels)
00617 {
00618 bodies::BoundingSphere bounding_sphere;
00619
00620 body.computeBoundingSphere(bounding_sphere);
00621 int x,y,z,x_min,x_max,y_min,y_max,z_min,z_max;
00622 double xw,yw,zw;
00623 btVector3 v;
00624
00625 worldToGrid(bounding_sphere.center,bounding_sphere.center.x()-bounding_sphere.radius,bounding_sphere.center.y()-bounding_sphere.radius,
00626 bounding_sphere.center.z()-bounding_sphere.radius, x_min,y_min,z_min);
00627 worldToGrid(bounding_sphere.center,bounding_sphere.center.x()+bounding_sphere.radius,bounding_sphere.center.y()+bounding_sphere.radius,
00628 bounding_sphere.center.z()+bounding_sphere.radius, x_max,y_max,z_max);
00629
00630
00631
00632
00633 for(x = x_min; x <= x_max; ++x)
00634 {
00635 for(y = y_min; y <= y_max; ++y)
00636 {
00637 for(z = z_min; z <= z_max; ++z)
00638 {
00639 gridToWorld(bounding_sphere.center,x,y,z,xw,yw,zw);
00640 if(body.containsPoint(xw,yw,zw))
00641 {
00642 v.setX(xw);
00643 v.setY(yw);
00644 v.setZ(zw);
00645
00646 voxels.push_back(v);
00647 }
00648 }
00649 }
00650 }
00651
00652
00653 }
00654
00655 }