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 }