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 #include "cart_state_estimator/cart_state_estimator.h"
00033 #include "cart_state_estimator/util.h"
00034 
00035 namespace cart_state_estimator
00036 {
00037 const string CART_FRAME("cart");
00038 const string BASE_FRAME("base_footprint");
00039 const string CHECKERBOARD_FRAME("CRT");
00040 
00041 
00042 
00043 
00044 
00045 gm::PolygonStamped computeFootprint (const double w, const double l)
00046 {
00047   gm::PolygonStamped footprint;
00048   footprint.header.frame_id = CART_FRAME;
00049   footprint.polygon.points.resize(4);
00050   footprint.polygon.points[1].x = l;
00051   footprint.polygon.points[2].x = l;
00052   footprint.polygon.points[2].y = w;
00053   footprint.polygon.points[3].y = w;
00054   return footprint;
00055 }
00056 
00057 string toString (const btTransform& tr)
00058 {
00059   btVector3 t = tr.getOrigin();
00060   btQuaternion r = tr.getRotation();
00061   return (format("((%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f))") %
00062           t.x() % t.y() % t.z() % r.x() % r.y() % r.z() % r.w()).str();
00063 }
00064 
00065 CartStateEstimator::CartStateEstimator () :
00066   cart_width_(getParam<double>("width", "cart_pushing")),
00067   cart_length_(getParam<double>("length", "cart_pushing")),
00068   l_gripper_frame_(getParam<string>("l_gripper_frame")),
00069   r_gripper_frame_(getParam<string>("r_gripper_frame")),
00070   
00071 
00072 
00073   publish_fake_transforms_(getPrivateParam<bool>("publish_fake_gripper_transforms", false)),
00074   footprint_(computeFootprint(cart_width_, cart_length_)),
00075   footprint_x_offset_(getParam<double>("footprint_x_offset", "cart_pushing")),
00076   footprint_y_offset_(getParam<double>("footprint_y_offset", "cart_pushing")),
00077   publication_interval_(getPrivateParam<double>("publication_interval", 0.1)),
00078   transform_recency_threshold_(getPrivateParam<double>("transform_recency_threshold", 0.4)),
00079   cart_to_board_(readTransformParameter(string("cart_pushing/checkerboard_pose")).inverse()),
00080   pub_timer_(nh_.createWallTimer(WallDuration(publication_interval_), &CartStateEstimator::publishState, this)),
00081   footprint_pub_(nh_.advertise<gm::PolygonStamped> ("cart_footprint", 10)),
00082   effector_to_cart_client_(nh_.serviceClient<manipulation_transforms::MapEffectorPosesToObject>("manipulation_transforms_server/MapEffectorPosesToObject")),
00083   set_solver_transforms_client_(nh_.serviceClient<manipulation_transforms::SetInitialTransforms>("manipulation_transforms_server/SetInitialTransforms"))
00084 {
00085         ROS_INFO("Waiting for manipulation_transforms services");
00086         effector_to_cart_client_.waitForExistence(ros::Duration(-1));
00087         set_solver_transforms_client_.waitForExistence(ros::Duration(-1));
00088         ROS_INFO("Services connected!");
00089         
00090 
00091 
00092 
00093 
00094         ROS_ASSERT (cart_width_ > 0.0 && cart_length_ > 0.0);
00095 }
00096 
00097 StampedTransform CartStateEstimator::computeCartFrame (const StampedPose& left, const StampedPose& right) const
00098 {
00099   const double x0 = left.getOrigin().x();
00100   const double y0 = left.getOrigin().y();
00101   const double x1 = right.getOrigin().x();
00102   const double y1 = right.getOrigin().y();
00103   
00104   tf::Transform trans(btQuaternion::getIdentity(), btVector3((x0+x1)/2, (y0+y1)/2, 0));
00105   return tf::StampedTransform(trans, ros::Time::now(), BASE_FRAME, CART_FRAME);
00106 }
00107 
00108 gm::PolygonStamped CartStateEstimator::getProjectedFootprint () const 
00109 {
00110   gm::PolygonStamped footprint = footprint_;
00111   tf::StampedTransform cart_to_base;
00112   tf_listener_.lookupTransform (BASE_FRAME, CART_FRAME, Time(), cart_to_base);
00113   for (unsigned i = 0; i < 4; i++) {
00114                 btVector3 p(footprint.polygon.points[i].x - footprint_x_offset_,
00115                                 footprint.polygon.points[i].y - footprint_y_offset_,
00116                                 footprint.polygon.points[i].z);
00117                 btVector3 trans = cart_to_base * p;
00118                 footprint.polygon.points[i].x = trans.x();
00119                 footprint.polygon.points[i].y = trans.y();
00120                 footprint.polygon.points[i].z = 0.0;
00121         }
00122   footprint.header.stamp = Time::now();
00123   footprint.header.frame_id = BASE_FRAME;
00124   return footprint;
00125 }
00126 
00127 btTransform CartStateEstimator::cartPoseFromCheckerboard (const btTransform& cb_to_base) const
00128 {
00129   return cb_to_base*cart_to_board_;
00130 }
00131 
00132 
00133 void CartStateEstimator::broadcastCartPose(const string& frame, const btTransform& trans)
00134 {
00135   tf::StampedTransform stamped(trans, ros::Time::now(), BASE_FRAME, frame);
00136   ROS_DEBUG_STREAM_NAMED("cart_state_estimator", "broadcasting cart pose: " << toString(trans));
00137   tf_broadcaster_.sendTransform(stamped);
00138 }
00139 
00140 void CartStateEstimator::publishState (const WallTimerEvent& e) 
00141 {
00142   try {
00143     footprint_pub_.publish(getProjectedFootprint());
00144   }
00145   catch (tf::TransformException &ex) {
00146     ROS_DEBUG_STREAM_NAMED ("transforms", "Not publishing footprint due to transform exception " << ex.what());
00147   }
00148 
00149   
00150   Lock l(mutex_);
00151 
00152   
00153 
00154 
00155 
00156 
00157   optional<btTransform> proprioceptive_estimate;
00158   tf::StampedTransform l_gripper_to_base, r_gripper_to_base;
00159   
00160 
00161 
00162   std::vector<gm::PoseStamped> gripper_psT_base; gripper_psT_base.resize(2);
00163   const Time most_recent;
00164 
00165   Time cutoff;
00166   try {
00167     cutoff = Time::now() - Duration(transform_recency_threshold_);
00168   } catch (std::runtime_error &e){
00169     cutoff = Time::now();
00170   }
00171 
00172   try {
00173     tf_listener_.lookupTransform (BASE_FRAME, l_gripper_frame_, most_recent, l_gripper_to_base);
00174     tf_listener_.lookupTransform (BASE_FRAME, r_gripper_frame_, most_recent, r_gripper_to_base);
00175     if (l_gripper_to_base.stamp_ > cutoff && r_gripper_to_base.stamp_ > cutoff) {
00176       btTransform estimate;
00177       ROS_DEBUG_STREAM ("R gripper pose is " << toString(r_gripper_to_base) <<
00178                        " l gripper is " << toString(l_gripper_to_base));
00179 
00180       
00181       
00182 
00183 
00184 
00185 
00186 
00187       
00188       gm::PoseStamped l_gripper_msg, r_gripper_msg;
00189       gm::Pose lg, rg;
00190       tf::poseTFToMsg(l_gripper_to_base, lg);
00191       tf::poseTFToMsg(r_gripper_to_base, rg);
00192       r_gripper_msg.pose = rg; r_gripper_msg.header.stamp = ros::Time::now(); r_gripper_msg.header.frame_id = r_gripper_to_base.frame_id_;
00193       l_gripper_msg.pose = lg; l_gripper_msg.header.stamp = ros::Time::now(); l_gripper_msg.header.frame_id = l_gripper_to_base.frame_id_;
00194       gripper_psT_base[0] = r_gripper_msg; gripper_psT_base[1] = l_gripper_msg;
00195       manipulation_transforms::MapEffectorPosesToObject mapsrv;
00196       mapsrv.request.effector_poses = gripper_psT_base;
00197       effector_to_cart_client_.call(mapsrv);
00198 
00199       
00200       
00201       if (mapsrv.response.object_pose.pose.orientation.w == 0){
00202           tf::TransformException ex("Failed to receive valid pose from manipulation_transforms server");
00203           throw ex;
00204       }
00205 
00206       tf::poseMsgToTF(mapsrv.response.object_pose.pose, estimate);
00207       proprioceptive_estimate = estimate;
00208       broadcastCartPose("cart_proprioceptive", *proprioceptive_estimate);
00209     }
00210     else
00211       ROS_DEBUG_STREAM_NAMED ("transforms", "Transforms at " << l_gripper_to_base.stamp_ <<
00212                               " and " << r_gripper_to_base.stamp_ << " are not within cutoff " << cutoff);
00213   }
00214   catch (tf::TransformException &ex) {
00215     ROS_DEBUG_STREAM_NAMED ("transforms", "Skipping proprioceptive estimate due to transform error " << ex.what());
00216   }
00217 
00218   
00219 
00220 
00221 
00222 
00223   optional<btTransform> cb_estimate;
00224   tf::StampedTransform cb_to_base;
00225   try {
00226     tf_listener_.lookupTransform (BASE_FRAME, CHECKERBOARD_FRAME, most_recent, cb_to_base);
00227     if (cb_to_base.stamp_ > cutoff) {
00228       cb_estimate = cartPoseFromCheckerboard(cb_to_base);
00229       broadcastCartPose("cart_checkerboard", *cb_estimate);
00230     }
00231     else
00232       ROS_DEBUG_STREAM_NAMED ("transforms", "Most recent checkerboard transform at " << cb_to_base.stamp_
00233                               << " was not within cutoff " << cutoff);
00234   }
00235   catch (tf::TransformException &ex) {
00236     ROS_DEBUG_STREAM_NAMED ("transforms", "Skipping checkerboard estimate due to transform error " << ex.what());
00237   }
00238 
00239   if (cb_estimate) {
00240     ROS_DEBUG_NAMED ("cart_pose_estimate", "Using checkerboard estimate");
00241     broadcastCartPose(CART_FRAME, *cb_estimate);
00242   }
00243   else if (proprioceptive_estimate) {
00244     ROS_DEBUG_NAMED ("cart_pose_estimate", "Using proprioceptive estimate");
00245     broadcastCartPose(CART_FRAME, *proprioceptive_estimate);
00246   }
00247   else
00248     ROS_DEBUG_NAMED ("transforms", "Not publishing cart pose as neither estimate was available");
00249 
00250   
00251 
00252 
00253 
00254 
00255   
00256   if (proprioceptive_estimate && cb_estimate) {
00257     ROS_DEBUG_STREAM_NAMED ("cart_pose_estimate", "Updating grasp solver");
00258     
00259 
00260 
00261 
00262 
00263 
00264     manipulation_transforms::SetInitialTransforms setsrv;
00265     setsrv.request.effector_poses = gripper_psT_base;
00266     tf::poseTFToMsg(*cb_estimate, setsrv.request.object_pose.pose);
00267     setsrv.request.object_pose.header.stamp = ros::Time::now(); setsrv.request.object_pose.header.frame_id = cb_to_base.frame_id_;
00268     set_solver_transforms_client_.call(setsrv);
00269   }
00270 
00271 }
00272 
00273 } 
00274 
00275 int main (int argc, char** argv)
00276 {
00277   ros::init(argc, argv, "cart_state_estimator");
00278   cart_state_estimator::CartStateEstimator node;
00279   ros::MultiThreadedSpinner spinner(2); 
00280   spinner.spin();
00281   return 0;
00282 }