00001 #include <carl_moveit/carl_moveit.h>
00002 #include <carl_moveit/eigen_pinv.hpp>
00003
00004 using namespace std;
00005
00006 CarlMoveIt::CarlMoveIt() :
00007 tfListener(tfBuffer),
00008 armTrajectoryClient("jaco_arm/joint_velocity_controller/trajectory"),
00009 moveToPoseServer(n, "carl_moveit_wrapper/move_to_pose", boost::bind(&CarlMoveIt::moveToPose, this, _1), false),
00010 moveToJointPoseServer(n, "carl_moveit_wrapper/move_to_joint_pose", boost::bind(&CarlMoveIt::moveToJointPose, this, _1), false)
00011 {
00012 armJointStateSubscriber = n.subscribe("joint_states", 1, &CarlMoveIt::armJointStatesCallback, this);
00013 cartesianControlSubscriber = n.subscribe("carl_moveit_wrapper/cartesian_control", 1, &CarlMoveIt::cartesianControlCallback, this);
00014 armHomedSubscriber = n.subscribe("jaco_arm/arm_homed", 1, &CarlMoveIt::armHomedCallback, this);
00015 recognizedObjectsSubscriber = n.subscribe("object_recognition_listener/recognized_objects", 1, &CarlMoveIt::recognizedObjectsCallback, this);
00016
00017 angularCmdPublisher = n.advertise<wpi_jaco_msgs::AngularCommand>("jaco_arm/angular_cmd", 1);
00018 trajectoryVisPublisher = n.advertise<moveit_msgs::DisplayTrajectory>("carl_moveit/computed_trajectory", 1);
00019
00020 ikClient = n.serviceClient<moveit_msgs::GetPositionIK>("compute_ik");
00021 clearOctomapClient = n.serviceClient<std_srvs::Empty>("clear_octomap");
00022
00023 armGroup = new move_group_interface::MoveGroup("arm");
00024 armGroup->startStateMonitor();
00025
00026 planningSceneInterface = new move_group_interface::PlanningSceneInterface();
00027
00028
00029 cartesianPathServer = n.advertiseService("carl_moveit_wrapper/cartesian_path", &CarlMoveIt::cartesianPathCallback, this);
00030 ikServer = n.advertiseService("carl_moveit_wrapper/call_ik", &CarlMoveIt::ikCallback, this);
00031 attachObjectServer = n.advertiseService("carl_moveit_wrapper/attach_closest_object", &CarlMoveIt::attachClosestSceneObject, this);
00032 detachObjectServer = n.advertiseService("carl_moveit_wrapper/detach_objects", &CarlMoveIt::detachSceneObjects, this);
00033
00034
00035 moveToPoseServer.start();
00036 moveToJointPoseServer.start();
00037 }
00038
00039 CarlMoveIt::~CarlMoveIt()
00040 {
00041 delete armGroup;
00042 delete planningSceneInterface;
00043 }
00044
00045 void CarlMoveIt::armHomedCallback(const std_msgs::Bool &msg)
00046 {
00047 if (msg.data)
00048 {
00049 std_srvs::Empty srv;
00050 if (!clearOctomapClient.call(srv))
00051 ROS_INFO("Failed to call clear octomap service.");
00052 }
00053 }
00054
00055 void CarlMoveIt::armJointStatesCallback(const sensor_msgs::JointState &msg)
00056 {
00057 jointState = msg;
00058 }
00059
00064 static inline double simplify_angle(double angle)
00065 {
00066 double previous_rev = floor(angle / (2.0 * M_PI)) * 2.0 * M_PI;
00067 double next_rev = ceil(angle / (2.0 * M_PI)) * 2.0 * M_PI;
00068 double current_rev;
00069 if (fabs(angle - previous_rev) < fabs(angle - next_rev))
00070 return angle - previous_rev;
00071 return angle - next_rev;
00072 }
00073
00079 static inline double nearest_equivalent(double desired, double current)
00080 {
00081
00082 double previous_rev = floor(current / (2 * M_PI));
00083 double next_rev = ceil(current / (2 * M_PI));
00084 double current_rev;
00085 if (fabs(current - previous_rev * 2 * M_PI) < fabs(current - next_rev * 2 * M_PI))
00086 current_rev = previous_rev;
00087 else
00088 current_rev = next_rev;
00089
00090
00091 double lowVal = (current_rev - 1) * 2 * M_PI + desired;
00092 double medVal = current_rev * 2 * M_PI + desired;
00093 double highVal = (current_rev + 1) * 2 * M_PI + desired;
00094 if (fabs(current - lowVal) <= fabs(current - medVal) && fabs(current - lowVal) <= fabs(current - highVal))
00095 return lowVal;
00096 if (fabs(current - medVal) <= fabs(current - lowVal) && fabs(current - medVal) <= fabs(current - highVal))
00097 return medVal;
00098 return highVal;
00099 }
00100
00101 void CarlMoveIt::moveToPose(const rail_manipulation_msgs::MoveToPoseGoalConstPtr &goal)
00102 {
00103 moveit_msgs::GetPositionIK::Response ikRes = callIK(goal->pose);
00104
00105 rail_manipulation_msgs::MoveToPoseResult result;
00106 if (ikRes.error_code.val == ikRes.error_code.SUCCESS)
00107 {
00108 ROS_INFO("IK service call succeeded");
00109
00110
00111 int jacoStartIndex = 0;
00112 for (unsigned int i = 0; i < jointState.name.size(); i++)
00113 {
00114 if (jointState.name[i].compare("jaco_joint_1") == 0)
00115 {
00116 jacoStartIndex = i;
00117 break;
00118 }
00119 }
00120
00121 std::vector<double> jointGoal;
00122 jointGoal.resize(6);
00123
00124 for (unsigned int i = jacoStartIndex; i < jacoStartIndex + NUM_JACO_JOINTS; i++)
00125 {
00126 jointGoal[i - jacoStartIndex] = nearest_equivalent(simplify_angle(ikRes.solution.joint_state.position[i]), jointState.position[i]);
00127 }
00128
00129
00130 armGroup->setPlannerId("arm[KPIECEkConfigDefault]");
00131 if (goal->planningTime == 0.0)
00132 armGroup->setPlanningTime(5.0);
00133 else
00134 armGroup->setPlanningTime(goal->planningTime);
00135 armGroup->setStartStateToCurrentState();
00136 armGroup->setJointValueTarget(jointGoal);
00137 ROS_INFO("Planning and moving...");
00138
00139 move_group_interface::MoveItErrorCode errorCode = armGroup->move();
00140 ROS_INFO("Finished plan and move");
00141 if (errorCode == moveit_msgs::MoveItErrorCodes::SUCCESS)
00142 {
00143 ROS_INFO("Succeeded");
00144 result.success = true;
00145 }
00146 else
00147 {
00148 ROS_INFO("Failed with MoveIt error code: %d", errorCode.val);
00149 result.success = false;
00150 }
00151 }
00152 else
00153 {
00154 ROS_INFO("IK service call failed with error code: %d", ikRes.error_code.val);
00155 result.success = false;
00156 }
00157
00158 moveToPoseServer.setSucceeded(result);
00159 }
00160
00161 void CarlMoveIt::moveToJointPose(const rail_manipulation_msgs::MoveToJointPoseGoalConstPtr &goal)
00162 {
00163
00164 int jacoStartIndex = 0;
00165 for (unsigned int i = 0; i < jointState.name.size(); i++)
00166 {
00167 if (jointState.name[i].compare("jaco_joint_1") == 0)
00168 {
00169 jacoStartIndex = i;
00170 break;
00171 }
00172 }
00173
00174 vector<double> jointGoal;
00175 jointGoal.resize(NUM_JACO_JOINTS);
00176
00177 for (unsigned int i = jacoStartIndex; i < jacoStartIndex + NUM_JACO_JOINTS; i++)
00178 {
00179 jointGoal[i - jacoStartIndex] = nearest_equivalent(simplify_angle(goal->joints[i - jacoStartIndex]), jointState.position[i]);
00180 }
00181
00182
00183 rail_manipulation_msgs::MoveToJointPoseResult result;
00184 armGroup->setPlannerId("arm[KPIECEkConfigDefault]");
00185 if (goal->planningTime == 0.0)
00186 armGroup->setPlanningTime(5.0);
00187 else
00188 armGroup->setPlanningTime(goal->planningTime);
00189 armGroup->setStartStateToCurrentState();
00190 armGroup->setJointValueTarget(jointGoal);
00191 ROS_INFO("Planning and moving...");
00192
00193 move_group_interface::MoveItErrorCode errorCode = armGroup->move();
00194 ROS_INFO("Finished plan and move");
00195 if (errorCode == moveit_msgs::MoveItErrorCodes::SUCCESS)
00196 {
00197 ROS_INFO("Succeeded");
00198 result.success = true;
00199 }
00200 else
00201 {
00202 ROS_INFO("Failed with MoveIt error code: %d", errorCode.val);
00203 result.success = false;
00204 }
00205
00206 moveToJointPoseServer.setSucceeded(result);
00207 }
00208
00209 bool CarlMoveIt::cartesianPathCallback(rail_manipulation_msgs::CartesianPath::Request &req, rail_manipulation_msgs::CartesianPath::Response &res)
00210 {
00211 double eefStep = .05;
00212 double jumpThreshold = 1.5;
00213 moveit_msgs::RobotTrajectory finalTraj;
00214
00215
00216 vector<geometry_msgs::Pose> convertedWaypoints;
00217 for (unsigned int i = 0; i < req.waypoints.size(); i ++)
00218 {
00219 geometry_msgs::PoseStamped tempPose;
00220 tempPose.header.frame_id = armGroup->getPoseReferenceFrame();
00221 tf.transformPose(armGroup->getPoseReferenceFrame(), req.waypoints[i], tempPose);
00222 convertedWaypoints.push_back(tempPose.pose);
00223 }
00224
00225
00226 moveit_msgs::RobotTrajectory tempTraj;
00227 double completion = armGroup->computeCartesianPath(convertedWaypoints, eefStep, jumpThreshold, tempTraj, req.avoidCollisions);
00228 if (completion == -1)
00229 {
00230 ROS_INFO("Could not calculate a path.");
00231 res.success = false;
00232 return true;
00233 }
00234
00235 if (completion == 1.0)
00236 {
00237 finalTraj = tempTraj;
00238 }
00239 else
00240 {
00241 ROS_INFO("Could not find a complete path, varying parameters and recalculating...");
00242
00243 for (unsigned int i = 0; i < 2; i ++)
00244 {
00245 double newCompletion;
00246 if (i != 0)
00247 jumpThreshold += 1.5;
00248 for (unsigned int j = 0; j < 3; j ++)
00249 {
00250 if (j == 0)
00251 eefStep /= 2.0;
00252 else
00253 eefStep *= 2.0;
00254 newCompletion = armGroup->computeCartesianPath(convertedWaypoints, eefStep, jumpThreshold, tempTraj, req.avoidCollisions);
00255 if (newCompletion > completion)
00256 {
00257 ROS_INFO("Found a better path.");
00258 finalTraj = tempTraj;
00259 completion = newCompletion;
00260 if (newCompletion == 1.0)
00261 {
00262 ROS_INFO("Found a complete path!");
00263 break;
00264 }
00265 }
00266 }
00267 if (newCompletion == 1.0)
00268 break;
00269 }
00270 }
00271
00272 if (completion == 0.0)
00273 {
00274 ROS_INFO("Could not calculate a path.");
00275 res.success = false;
00276 return true;
00277 }
00278 else
00279 {
00280 res.success = true;
00281 res.completion = completion;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 move_group_interface::MoveGroup::Plan plan;
00296 plan.trajectory_ = finalTraj;
00297 moveit::core::robotStateToRobotStateMsg(*(armGroup->getCurrentState()), plan.start_state_);
00298
00299 armGroup->execute(plan);
00300
00301 res.success = true;
00302 return true;
00303 }
00304
00305 bool CarlMoveIt::ikCallback(rail_manipulation_msgs::CallIK::Request &req, rail_manipulation_msgs::CallIK::Response &res)
00306 {
00307 moveit_msgs::GetPositionIK::Response ikRes = callIK(req.pose);
00308
00309 if (ikRes.error_code.val == ikRes.error_code.SUCCESS)
00310 {
00311 ROS_INFO("IK service call succeeded");
00312
00313
00314 int jacoStartIndex = 0;
00315 for (unsigned int i = 0; i < jointState.name.size(); i++)
00316 {
00317 if (jointState.name[i].compare("jaco_joint_1") == 0)
00318 {
00319 jacoStartIndex = i;
00320 break;
00321 }
00322 }
00323
00324 std::vector<double> joints;
00325 joints.resize(6);
00326
00327 for (unsigned int i = jacoStartIndex; i <= jacoStartIndex + NUM_JACO_JOINTS; i++)
00328 {
00329 joints[i - jacoStartIndex] = nearest_equivalent(simplify_angle(ikRes.solution.joint_state.position[i]), jointState.position[i]);
00330 }
00331
00332 res.jointPositions = joints;
00333 res.success = true;
00334 }
00335 else
00336 {
00337 ROS_INFO("IK service call failed with error code: %d", ikRes.error_code.val);
00338 res.success = false;
00339 }
00340
00341 return true;
00342 }
00343
00344 moveit_msgs::GetPositionIK::Response CarlMoveIt::callIK(geometry_msgs::PoseStamped pose)
00345 {
00346 moveit_msgs::GetPositionIK::Request ikReq;
00347 moveit_msgs::GetPositionIK::Response ikRes;
00348
00349
00350 robot_state::RobotStatePtr kinematicState = armGroup->getCurrentState();
00351 const robot_state::JointModelGroup *jointModelGroup = kinematicState->getRobotModel()->getJointModelGroup("arm");
00352
00353
00354 ikReq.ik_request.group_name = "arm";
00355 ikReq.ik_request.pose_stamped = pose;
00356 ikReq.ik_request.ik_link_name = "jaco_link_eef";
00357
00358 ikReq.ik_request.robot_state.joint_state.name = jointModelGroup->getJointModelNames();
00359 kinematicState->copyJointGroupPositions(jointModelGroup, ikReq.ik_request.robot_state.joint_state.position);
00360
00361
00362 ikReq.ik_request.timeout = ros::Duration(.1);
00363 ikReq.ik_request.attempts = 10;
00364
00365 ikClient.call(ikReq, ikRes);
00366
00367 return ikRes;
00368 }
00369
00370 void CarlMoveIt::cartesianControlCallback(const geometry_msgs::Twist &msg)
00371 {
00372
00373 robot_state::RobotStatePtr kinematicState = armGroup->getCurrentState();
00374 const moveit::core::JointModelGroup* jointModelGroup = kinematicState->getRobotModel()->getJointModelGroup("arm");
00375 Eigen::Vector3d referencePointPosition(0.0, 0.0, 0.0);
00376 Eigen::MatrixXd jacobian;
00377 kinematicState->getJacobian(jointModelGroup, kinematicState->getLinkModel(jointModelGroup->getLinkModelNames().back()), referencePointPosition, jacobian);
00378
00379
00380
00381
00382 Eigen::MatrixXd pInv = EIGEN_PINV::pinv(jacobian, 0.001);
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 Eigen::VectorXd twist(6);
00395 twist << msg.linear.x, msg.linear.y, msg.linear.z, msg.angular.x, msg.angular.y, msg.angular.z;
00396 Eigen::VectorXd jointVel(6);
00397 jointVel = pInv * twist;
00398
00399
00400 wpi_jaco_msgs::AngularCommand cmd;
00401 cmd.position = false;
00402 cmd.armCommand = true;
00403 cmd.fingerCommand = false;
00404 cmd.repeat = true;
00405 cmd.joints.resize(6);
00406 for(unsigned int i = 0; i < jointVel.size(); i ++)
00407 {
00408 cmd.joints[i] = jointVel[i];
00409 }
00410 angularCmdPublisher.publish(cmd);
00411 }
00412
00413 void CarlMoveIt::recognizedObjectsCallback(const rail_manipulation_msgs::SegmentedObjectList &msg)
00414 {
00415
00416 unattachedObjects.clear();
00417 vector<string> previousObjects = planningSceneInterface->getKnownObjectNames();
00418 if (!attachedObjects.empty())
00419 {
00420
00421 for (unsigned int i = 0; i < previousObjects.size(); i ++)
00422 {
00423 for (unsigned int j = 0; j < attachedObjects.size(); j ++)
00424 if (previousObjects[i] == attachedObjects[j])
00425 {
00426 previousObjects.erase(previousObjects.begin() + i);
00427 i --;
00428 break;
00429 }
00430 }
00431 }
00432 planningSceneInterface->removeCollisionObjects(previousObjects);
00433
00434 {
00435 boost::recursive_mutex::scoped_lock lock(api_mutex);
00436
00437
00438 objectList = msg;
00439
00440 if (!msg.objects.empty())
00441 {
00442
00443 vector<moveit_msgs::CollisionObject> collisionObjects;
00444 collisionObjects.resize(msg.objects.size());
00445 for (unsigned int i = 0; i < collisionObjects.size(); i++)
00446 {
00447
00448 collisionObjects[i].header.frame_id = msg.objects[i].point_cloud.header.frame_id;
00449 stringstream ss;
00450 if (msg.objects[i].recognized)
00451 ss << msg.objects[i].name << i;
00452 else
00453 ss << "object" << i;
00454
00455 for (unsigned int j = 0; j < attachedObjects.size(); j ++)
00456 {
00457 if (ss.str() == attachedObjects[j])
00458 ss << "(2)";
00459 }
00460 collisionObjects[i].id = ss.str();
00461 unattachedObjects.push_back(ss.str());
00462
00463
00464 pcl::PointCloud<pcl::PointXYZRGB>::Ptr objectCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00465 pcl::PCLPointCloud2 converter;
00466 pcl_conversions::toPCL(msg.objects[i].point_cloud, converter);
00467 pcl::fromPCLPointCloud2(converter, *objectCloud);
00468
00469
00470 Eigen::Matrix3f covariance;
00471 Eigen::Vector4f centroid;
00472 centroid[0] = msg.objects[i].centroid.x;
00473 centroid[1] = msg.objects[i].centroid.y;
00474 centroid[2] = msg.objects[i].centroid.z;
00475 pcl::computeCovarianceMatrixNormalized(*objectCloud, centroid, covariance);
00476 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);
00477 Eigen::Matrix3f eig_dx = eigen_solver.eigenvectors();
00478 eig_dx.col(2) = eig_dx.col(0).cross(eig_dx.col(1));
00479
00480
00481 Eigen::Matrix4f p2w(Eigen::Matrix4f::Identity());
00482 p2w.block(0, 0, 3, 3) = eig_dx.transpose();
00483 p2w.block(0, 3, 3, 1) = -1.f * (p2w.block(0, 0, 3, 3) * centroid.head(3));
00484 pcl::PointCloud<pcl::PointXYZRGB> c_points;
00485 pcl::transformPointCloud(*objectCloud, c_points, p2w);
00486
00487 pcl::PointXYZRGB min_pt, max_pt;
00488 pcl::getMinMax3D(c_points, min_pt, max_pt);
00489 const Eigen::Vector3f mean_diag = 0.5f * (max_pt.getVector3fMap() + min_pt.getVector3fMap());
00490
00491
00492 const Eigen::Quaternionf qfinal(eig_dx);
00493 const Eigen::Vector3f tfinal = eig_dx * mean_diag + centroid.head(3);
00494
00495
00496 shape_msgs::SolidPrimitive boundingVolume;
00497 boundingVolume.type = shape_msgs::SolidPrimitive::BOX;
00498 boundingVolume.dimensions.resize(3);
00499 boundingVolume.dimensions[shape_msgs::SolidPrimitive::BOX_X] = max_pt.x - min_pt.x;
00500 boundingVolume.dimensions[shape_msgs::SolidPrimitive::BOX_Y] = max_pt.y - min_pt.y;
00501 boundingVolume.dimensions[shape_msgs::SolidPrimitive::BOX_Z] = max_pt.z - min_pt.z;
00502 collisionObjects[i].primitives.push_back(boundingVolume);
00503 geometry_msgs::Pose pose;
00504 pose.position.x = tfinal[0];
00505 pose.position.y = tfinal[1];
00506 pose.position.z = tfinal[2];
00507 pose.orientation.w = qfinal.w();
00508 pose.orientation.x = qfinal.x();
00509 pose.orientation.y = qfinal.y();
00510 pose.orientation.z = qfinal.z();
00511 collisionObjects[i].primitive_poses.push_back(pose);
00512 collisionObjects[i].operation = moveit_msgs::CollisionObject::ADD;
00513 }
00514
00515 planningSceneInterface->addCollisionObjects(collisionObjects);
00516 }
00517 }
00518 }
00519
00520 bool CarlMoveIt::attachClosestSceneObject(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
00521 {
00522 boost::recursive_mutex::scoped_lock lock(api_mutex);
00523
00524
00525 int closest = 0;
00526 if (objectList.objects.size() == 0)
00527 {
00528 ROS_INFO("No scene objects to attach.");
00529 return true;
00530 } else if (objectList.objects.size() > 1)
00531 {
00532
00533 float min = numeric_limits<float>::infinity();
00534
00535
00536 for (size_t i = 0; i < objectList.objects.size(); i++)
00537 {
00538 geometry_msgs::TransformStamped eef_transform = tfBuffer.lookupTransform(
00539 objectList.objects[i].point_cloud.header.frame_id, armGroup->getEndEffectorLink(), ros::Time(0)
00540 );
00541 geometry_msgs::Vector3 &v = eef_transform.transform.translation;
00542
00543 sensor_msgs::PointCloud cloud;
00544 sensor_msgs::convertPointCloud2ToPointCloud(objectList.objects[i].point_cloud, cloud);
00545
00546 for (size_t j = 0; j < cloud.points.size(); j++)
00547 {
00548
00549 float dist = sqrt(
00550 pow(cloud.points[j].x - v.x, 2) + pow(cloud.points[j].y - v.y, 2) + pow(cloud.points[j].z - v.z, 2)
00551 );
00552 if (dist < min)
00553 {
00554 min = dist;
00555 closest = i;
00556 }
00557 }
00558 }
00559
00560 if (min > SCENE_OBJECT_DST_THRESHOLD)
00561 {
00562 ROS_INFO("No scene objects are close enough to the end effector to be attached.");
00563 return true;
00564 }
00565 }
00566
00567 vector<string> touchLinks;
00568 touchLinks.push_back("jaco_link_eef");
00569 touchLinks.push_back("jaco_link_finger_1");
00570 touchLinks.push_back("jaco_link_finger_2");
00571 touchLinks.push_back("jaco_link_finger_3");
00572 touchLinks.push_back("jaco_link_finger_tip_1");
00573 touchLinks.push_back("jaco_link_finger_tip_2");
00574 touchLinks.push_back("jaco_link_finger_tip_3");
00575 touchLinks.push_back("jaco_link_hand");
00576 armGroup->attachObject(unattachedObjects[closest], armGroup->getEndEffectorLink(), touchLinks);
00577 attachedObjects.push_back(unattachedObjects[closest]);
00578 unattachedObjects.erase(unattachedObjects.begin() + closest);
00579
00580 return true;
00581 }
00582
00583 bool CarlMoveIt::detachSceneObjects(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
00584 {
00585 for (int i = 0; i < attachedObjects.size(); i ++)
00586 {
00587 armGroup->detachObject(attachedObjects[i]);
00588 }
00589 planningSceneInterface->removeCollisionObjects(attachedObjects);
00590 attachedObjects.clear();
00591
00592 return true;
00593 }
00594
00595 int main(int argc, char **argv)
00596 {
00597 ros::init(argc, argv, "carl_moveit_wrapper");
00598
00599 CarlMoveIt c;
00600
00601 ros::spin();
00602 }