00001 #include <rosbag/bag.h>
00002 #include <rosbag/view.h>
00003 #include <rosbag/message_instance.h>
00004
00005 #include <tf/transform_listener.h>
00006 #include <geometry_msgs/WrenchStamped.h>
00007 #include <geometry_msgs/Wrench.h>
00008 #include <hrl_phri_2011/hsl_rgb_conversions.h>
00009 #include <hrl_phri_2011/ForceProcessed.h>
00010 #include <hrl_phri_2011/pcl_features.h>
00011 #include <hrl_phri_2011/utils.h>
00012 #include <hrl_phri_2011/ellipsoid_space.h>
00013
00014 typedef Eigen::Matrix<double, 6, 1> CartVec;
00015
00016 void wrenchMsgToEigen(const geometry_msgs::Wrench& wrench_msg, CartVec& wrench_eig)
00017 {
00018 wrench_eig(0, 0) = wrench_msg.force.x;
00019 wrench_eig(1, 0) = wrench_msg.force.y;
00020 wrench_eig(2, 0) = wrench_msg.force.z;
00021 wrench_eig(3, 0) = wrench_msg.torque.x;
00022 wrench_eig(4, 0) = wrench_msg.torque.y;
00023 wrench_eig(5, 0) = wrench_msg.torque.z;
00024 }
00025
00026 #define NORM(x, y, z) ( std::sqrt( (x) * (x) + (y) * (y) + (z) * (z) ) )
00027 #ifndef SQ
00028 #define SQ(x) ( (x) * (x) )
00029 #endif
00030 #define NORMAL(x, sig) ( std::exp( - (x) * (x) / (2.0 * (sig) * (sig))) / std::sqrt(2.0 * 3.14159 * (sig) * (sig)))
00031
00032 class DataExtractor
00033 {
00034 private:
00035 ros::Subscriber wrench_sub;
00036 tf::TransformListener tf_list;
00037 ros::NodeHandle nh;
00038 PCRGB::Ptr pc_head;
00039 KDTree::Ptr kd_tree;
00040 PCNormals::Ptr normals;
00041 int pub_ind;
00042 double start_time;
00043 vector<hrl_phri_2011::ForceProcessed> fp_list;
00044 bool compute_norms;
00045 tf::Transform registration_tf, ell_reg_tf;
00046 Ellipsoid ell;
00047
00048 void wrenchCallback(geometry_msgs::WrenchStamped::ConstPtr wrench_stamped)
00049 {
00050 double cur_time = wrench_stamped->header.stamp.toSec();
00051 if(start_time == -1)
00052 start_time = cur_time;
00053 CartVec w;
00054 wrenchMsgToEigen(wrench_stamped->wrench, w);
00055 double force_mag = NORM(w(0, 0), w(1, 0), w(2, 0));
00056 tf::StampedTransform tool_loc_tf;
00057 try {
00058 tf_list.waitForTransform("/head_center", "/wipe_finger", wrench_stamped->header.stamp, ros::Duration(0.1));
00059 tf_list.lookupTransform("/head_center", "/wipe_finger", wrench_stamped->header.stamp, tool_loc_tf);
00060 }
00061 catch (tf::TransformException ex) {
00062 ROS_ERROR("%s", ex.what());
00063 return;
00064 }
00065 tool_loc_tf.mult(registration_tf, tool_loc_tf);
00066 btVector3 tool_loc = tool_loc_tf.getOrigin();
00067 PRGB query_pt;
00068 query_pt.x = tool_loc.x(); query_pt.y = tool_loc.y(); query_pt.z = tool_loc.z();
00069 vector<int> nk_inds(1);
00070 vector<float> nk_dists(1);
00071 kd_tree->nearestKSearch(query_pt, 1, nk_inds, nk_dists);
00072 int closest_ind = nk_inds[0];
00073 float closest_dist = nk_dists[0];
00074
00075 hrl_phri_2011::ForceProcessed fp;
00076 fp.time_offset = cur_time - start_time;
00077 tf::transformStampedTFToMsg(tool_loc_tf, fp.tool_frame);
00078 fp.header = wrench_stamped->header;
00079 fp.header.frame_id = "/head_center";
00080 fp.wrench = wrench_stamped->wrench;
00081 fp.pc_ind = closest_ind;
00082 fp.pc_dist = closest_dist;
00083 fp.pc_pt.x = pc_head->points[closest_ind].x;
00084 fp.pc_pt.y = pc_head->points[closest_ind].y;
00085 fp.pc_pt.z = pc_head->points[closest_ind].z;
00086 fp.force_magnitude = force_mag;
00087 if(compute_norms) {
00088 fp.pc_normal.x = normals->points[closest_ind].normal[0];
00089 fp.pc_normal.y = normals->points[closest_ind].normal[1];
00090 fp.pc_normal.z = normals->points[closest_ind].normal[2];
00091 }
00092
00093
00094 tf::Transform tool_loc_ell = ell_reg_tf * tool_loc_tf;
00095 tf::transformTFToMsg(tool_loc_ell, fp.tool_ell_frame);
00096 btVector3 tloce_pos = tool_loc_ell.getOrigin();
00097 ell.cartToEllipsoidal(tloce_pos.x(), tloce_pos.y(), tloce_pos.z(),
00098 fp.ell_coords.x, fp.ell_coords.y, fp.ell_coords.z);
00099
00100 fp_list.push_back(fp);
00101 pub_ind++;
00102 if(pub_ind % 100 == 0)
00103 ROS_INFO("Recorded %d samples", pub_ind);
00104 }
00105
00106 public:
00107 void startVisualization(bool use_raw = false)
00108 {
00109 string topic;
00110 if(!use_raw)
00111 topic = "/tool_netft_zeroer/wrench_zeroed";
00112 else
00113 topic = "/tool_netft/wrench_raw";
00114 wrench_sub = nh.subscribe(topic, 100, &DataExtractor::wrenchCallback, this);
00115 }
00116
00117 DataExtractor(PCRGB::Ptr& pch, bool compute_normals, const geometry_msgs::Transform& registration,
00118 const hrl_phri_2011::EllipsoidParams& ep) :
00119 pc_head(pch),
00120 kd_tree(new pcl::KdTreeFLANN<PRGB> ()),
00121 normals(new PCNormals()),
00122 pub_ind(0),
00123 start_time(-1),
00124 compute_norms(compute_normals),
00125 ell(ep)
00126 {
00127 kd_tree->setInputCloud(pc_head);
00128 if(compute_norms)
00129 computeNormals(pc_head, kd_tree, normals);
00130 pc_head->header.frame_id = "/head_center";
00131 tf::transformMsgToTF(registration, registration_tf);
00132 if(ep.e_frame.transform.rotation.w != 0) {
00133 tf::transformMsgToTF(ep.e_frame.transform, ell_reg_tf);
00134 ell_reg_tf = ell_reg_tf.inverse();
00135 }
00136 }
00137
00138 void writeBag(const string& pbag_name)
00139 {
00140 rosbag::Bag processed_bag;
00141 processed_bag.open(pbag_name, rosbag::bagmode::Write);
00142 BOOST_FOREACH(const hrl_phri_2011::ForceProcessed& fp, fp_list) {
00143 processed_bag.write("/force_processed", fp.header.stamp, fp);
00144 }
00145 processed_bag.close();
00146 }
00147 };
00148
00149 int main(int argc, char **argv)
00150 {
00151 ros::init(argc, argv, "data_extractor");
00152
00153 if(argc < 3 || argc > 7) {
00154 printf("Usage: data_extractor head_pc forces_bag_output [compute_normals=1] [registration_bag] [use_raw=0] [ellipse_registration]\n");
00155 return 1;
00156 }
00157
00158 rosbag::Bag pc_bag, force_bag;
00159 PCRGB::Ptr pc_head(new PCRGB);
00160
00161 pc_bag.open(std::string(argv[1]), rosbag::bagmode::Read);
00162 rosbag::View pc_view(pc_bag, rosbag::TopicQuery("/stitched_head"));
00163 BOOST_FOREACH(rosbag::MessageInstance const m, pc_view) {
00164 sensor_msgs::PointCloud2::Ptr pc2 = m.instantiate<sensor_msgs::PointCloud2>();
00165 pcl::fromROSMsg(*pc2, *pc_head);
00166 }
00167
00168 bool compute_normals = true;
00169 if(argc >= 4)
00170 compute_normals = atoi(argv[3]);
00171 bool use_raw = false;
00172 if(argc >= 6)
00173 use_raw = atoi(argv[5]);
00174 geometry_msgs::Transform tf_msg;
00175 tf_msg.rotation.w = 1.0;
00176 if(argc >= 5) {
00177 vector<geometry_msgs::TransformStamped::Ptr> tf_msgs;
00178 readBagTopic<geometry_msgs::TransformStamped>(argv[4], tf_msgs, "/itf_transform");
00179 tf_msg = tf_msgs[0]->transform;
00180 }
00181 vector<hrl_phri_2011::EllipsoidParams::Ptr> e_params_msgs;
00182 e_params_msgs.push_back(boost::shared_ptr<hrl_phri_2011::EllipsoidParams>(new hrl_phri_2011::EllipsoidParams()));
00183 e_params_msgs[0]->e_frame.transform.rotation.w = 1.0;
00184 if(argc >= 7) {
00185 e_params_msgs.clear();
00186 readBagTopic<hrl_phri_2011::EllipsoidParams>(argv[6], e_params_msgs, "/ellipsoid_params");
00187 }
00188
00189
00190 DataExtractor de(pc_head, compute_normals, tf_msg, *e_params_msgs[0]);
00191 de.startVisualization(use_raw);
00192 ROS_INFO("Ready for collection");
00193 ros::spin();
00194 de.writeBag(argv[2]);
00195 ROS_INFO("Bag written to %s", argv[2]);
00196 }