cart_state_estimator.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  * Copyright (c) 2008, Willow Garage, Inc.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
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  * Initialization
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   /* Uncomment to use local grasp_solver_ call rather than service call
00071   cart_init_pose_(readTransformParameter(string("cart_init_pose"))),
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         /* Uncomment to use local grasp_solver_ call rather than service call
00090         gripper_init_poses_.push_back(readTransformParameter(string("r_gripper_grasp")));
00091         gripper_init_poses_.push_back(readTransformParameter(string("l_gripper_grasp")));
00092         grasp_solver_ = ManipulationTransforms(cart_init_pose_, gripper_init_poses_);
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   //ROS_DEBUG_NAMED ("node", "Acquiring lock");
00150   Lock l(mutex_);
00151 
00152   /****************************************
00153    * Use gripper positions to get
00154    * proprioceptive estimate
00155    ****************************************/
00156 
00157   optional<btTransform> proprioceptive_estimate;
00158   tf::StampedTransform l_gripper_to_base, r_gripper_to_base;
00159   /* Uncomment to use local grasp_solver_ call rather than service call
00160   std::vector<tf::Transform> gripper_tfT_base; gripper_tfT_base.resize(2); // Can't be StampedTransform b/c vector clobbers type, and can't be passed
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       // Compute object pose using solver directly
00181       /* Uncomment to use local grasp_solver_ call rather than service call
00182       gripper_tfT_base[0] = btTransform(r_gripper_to_base);
00183       gripper_tfT_base[1] = btTransform(l_gripper_to_base);
00184       grasp_solver_.mapEffectorPosesToObject(gripper_to_base, estimate);
00185        */
00186 
00187       // convert poses to vector of PoseStamped for service call
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       //ROS_DEBUG_STREAM("obj pose resp = " << mapsrv.response.object_pose.pose << "(error: " << mapsrv.response.error << ")");
00200       // Provide a clean way to handle failures on the manipulation_transforms service call
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    * Use checkerboard pose to get sensory
00220    * estimate
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    * If we have both estimates, then reset
00252    * the grasp solver to make it match the
00253    * checkerboard estimate
00254    ****************************************/
00255   
00256   if (proprioceptive_estimate && cb_estimate) {
00257     ROS_DEBUG_STREAM_NAMED ("cart_pose_estimate", "Updating grasp solver");
00258     /* Uncomment to use local grasp_solver_ call rather than service call
00259     gripper_tfT_base[0] = btTransform(r_gripper_to_base);
00260     gripper_tfT_base[1] = btTransform(l_gripper_to_base);
00261     grasp_solver_.setInitialTransforms(*cb_estimate, gripper_tfT_base);
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 } // namespace cart_state_estimator
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); // Because the pub thread sometimes waits for the fake pub thread
00280   spinner.spin();
00281   return 0;
00282 }


cart_state_estimator
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:12:52