00001
00017 #include <ros/ros.h>
00018
00019 #include "tf/message_filter.h"
00020 #include "message_filters/subscriber.h"
00021 #include "tf/transform_listener.h"
00022 #include <tf/transform_broadcaster.h>
00023
00024 #include "articulation_models/models/factory.h"
00025
00026 #include "articulation_msgs/ModelMsg.h"
00027 #include "articulation_msgs/TrackMsg.h"
00028 #include "articulation_msgs/ParamMsg.h"
00029 #include "geometry_msgs/PoseStamped.h"
00030
00031 #include <sstream>
00032 #include <cmath>
00033
00034 #include <visualization_msgs/Marker.h>
00035
00036 using namespace articulation_models;
00037 using namespace articulation_msgs;
00038
00039
00040 ModelMsg global_model_msg;
00041
00042
00043 visualization_msgs::Marker visualize_door_model(GenericModelPtr model);
00044 void print(tf::Matrix3x3 m);
00045 void print(tf::Quaternion q);
00046 void print(tf::Vector3 v);
00047 std::string stream(tf::Vector3 v);
00048 std::string stream(tf::Quaternion v);
00049 std::string stream(tf::StampedTransform tf);
00050 void publish_door_coordinate_frame(GenericModelPtr generic_model);
00051 tf::Transform compute_aligned_door_frame(GenericModelPtr generic_model);
00052
00053 void poseCallback(const tf::TransformListener* listener,
00054 std::string target_frame,
00055 geometry_msgs::PoseStamped::ConstPtr pose_stamped);
00056
00057 int main(int argc, char** argv)
00058 {
00059 ros::init(argc, argv, "articulated_door_model_fitting");
00060 ros::NodeHandle n;
00061 ros::Publisher model_pub = n.advertise<ModelMsg> ("door_model", 5);
00062 ros::Publisher model_visualization_pub = n.advertise<visualization_msgs::Marker> ("door_trajectory", 5);
00063
00064 message_filters::Subscriber<geometry_msgs::PoseStamped> pose_sub;
00065 pose_sub.subscribe(n, "pose0", 10);
00066 std::string fixed_frame;
00067 ros::NodeHandle nh("~");
00068 nh.param<std::string>("fixed_frame", fixed_frame, "/odom_combined");
00069 ROS_DEBUG("Using %s as fixed frame", fixed_frame.c_str());
00070 tf::TransformListener tf_listener;
00071 tf::MessageFilter<geometry_msgs::PoseStamped> tf_filter(pose_sub, tf_listener, fixed_frame, 10);
00072 tf_filter.registerCallback(boost::bind(&poseCallback, &tf_listener, fixed_frame, _1));
00073
00074 tf::TransformBroadcaster br;
00075 ros::Rate loop_rate(10);
00076
00077 MultiModelFactory factory;
00078 global_model_msg.name = "rotational";
00079 ParamMsg sigma_param;
00080 sigma_param.name = "sigma_position";
00081 sigma_param.value = 0.02;
00082 sigma_param.type = ParamMsg::PRIOR;
00083 global_model_msg.params.push_back(sigma_param);
00084 unsigned long int prev_size = 0;
00085 GenericModelPtr model_instance;
00086 while (ros::ok()) {
00087 if(global_model_msg.track.pose.size() < 4)
00088 ROS_INFO_THROTTLE(2, "Not enough samples: %lu", global_model_msg.track.pose.size());
00089 else {
00090
00091 if(prev_size < global_model_msg.track.pose.size())
00092 {
00093 model_instance = factory.restoreModel(global_model_msg);
00094 model_instance->fitModel();
00095 model_instance->evaluateModel();
00096 ROS_INFO_STREAM_THROTTLE(5,"log LH of rotational model: " << model_instance->getLogLikelihood(false));
00097 }
00098
00099
00100 ROS_FATAL_COND(model_instance.get() == NULL, "Used model_instance before restoring the model?");
00101 ModelMsg fitted_model_msg = model_instance->getModel();
00102 tf::Transform aligned_door_tf = compute_aligned_door_frame(model_instance);
00103 tf::StampedTransform door_stamped(aligned_door_tf, ros::Time::now(), fitted_model_msg.track.header.frame_id, "/door");
00104 br.sendTransform(door_stamped);
00105 ROS_INFO_STREAM_THROTTLE(1, "<node pkg=\"tf\" type=\"static_transform_publisher\" name=\"door_broadcaster\" args=\"" << stream(door_stamped)<<" 100\" />");
00106
00107 if(model_pub.getNumSubscribers() > 0)
00108 model_pub.publish(fitted_model_msg);
00109 if(model_visualization_pub.getNumSubscribers() > 0)
00110 model_visualization_pub.publish(visualize_door_model(model_instance));
00111
00112 }
00113 ros::spinOnce();
00114 loop_rate.sleep();
00115 }
00116 }
00117
00118 void poseCallback(const tf::TransformListener* listener,
00119 std::string target_frame,
00120 geometry_msgs::PoseStamped::ConstPtr pose_stamped)
00121 {
00122 try
00123 {
00124 geometry_msgs::PoseStamped pose_in_fixed_frame;
00125 listener->transformPose(target_frame, *pose_stamped, pose_in_fixed_frame);
00126
00127
00128 global_model_msg.track.pose.push_back(pose_in_fixed_frame.pose);
00129 global_model_msg.track.header = pose_in_fixed_frame.header;
00130
00131 ROS_INFO("Recorded %lu. pose", global_model_msg.track.pose.size());
00132 }
00133 catch (tf::TransformException &ex)
00134 {
00135 ROS_ERROR("Failure %s\n", ex.what());
00136 }
00137 }
00138
00139
00140 visualization_msgs::Marker visualize_door_model(GenericModelPtr generic_model)
00141 {
00142 ModelMsg model = generic_model->getModel();
00143 visualization_msgs::Marker trajectory;
00144 trajectory.header = model.track.header;
00145 trajectory.id = 1;
00146 trajectory.type = visualization_msgs::Marker::POINTS;
00147 trajectory.action = visualization_msgs::Marker::ADD;
00148 trajectory.pose.orientation.w = 1.0;
00149 trajectory.scale.x = 0.02;
00150 trajectory.scale.y = 0.02;
00151 trajectory.scale.z = 0.02;
00152 trajectory.color.a = 0.5;
00153 trajectory.color.r = 0.5;
00154 trajectory.color.g = 0.5;
00155
00156 for(unsigned int i = 0; i < model.track.pose.size(); i++){
00157 trajectory.points.push_back(model.track.pose[i].position);
00158 }
00159 geometry_msgs::Point center;
00160 center.x = generic_model->getParam("rot_center.x");
00161 center.y = generic_model->getParam("rot_center.y");
00162 center.z = generic_model->getParam("rot_center.z");
00163 trajectory.points.push_back(center);
00164 return trajectory;
00165 }
00166
00167
00168 tf::Transform compute_aligned_door_frame(GenericModelPtr generic_model)
00169 {
00170
00171 TrackMsg tm = global_model_msg.track;
00172
00173 double q_min = generic_model->getParam("q_min[0]");
00174 double q_max = generic_model->getParam("q_max[0]");
00175 double rot_radius = generic_model->getParam("rot_radius");
00176 tf::Vector3 rot_center(generic_model->getParam("rot_center.x"),
00177 generic_model->getParam("rot_center.y"),
00178 generic_model->getParam("rot_center.z"));
00179
00180 tf::Quaternion rot_axis(generic_model->getParam("rot_axis.x"),
00181 generic_model->getParam("rot_axis.y"),
00182 generic_model->getParam("rot_axis.z"),
00183 generic_model->getParam("rot_axis.w"));
00184
00185 tf::Quaternion rot_orientation(generic_model->getParam("rot_orientation.x"),
00186 generic_model->getParam("rot_orientation.y"),
00187 generic_model->getParam("rot_orientation.z"),
00188 generic_model->getParam("rot_orientation.w"));
00189
00190
00191 tf::Transform center(rot_axis,rot_center);
00192 tf::Transform rotZ_min(tf::Quaternion(tf::Vector3(0, 0, 1), -q_min), tf::Vector3(0, 0, 0));
00193 tf::Transform rotZ_max(tf::Quaternion(tf::Vector3(0, 0, 1), -q_max), tf::Vector3(0, 0, 0));
00194 tf::Transform r(tf::Quaternion(0,0,0,1), tf::Vector3(rot_radius, 0, 0));
00195 tf::Transform offset(rot_orientation, tf::Vector3(0, 0, 0));
00196 tf::Transform qmin_pose = rotZ_min * r * offset;
00197 tf::Transform qmax_pose = rotZ_max * r * offset;
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 tf::Pose q1st_pose_in_fixed_frame;
00219 tf::poseMsgToTF(tm.pose[0], q1st_pose_in_fixed_frame);
00220 tf::Transform q1st_pose = center.inverse() * q1st_pose_in_fixed_frame;
00221
00222
00223 tf::Vector3 q1st_position = q1st_pose.getOrigin();
00224 tf::Vector3 qmin_position = qmin_pose.getOrigin();
00225 tf::Vector3 qmax_position = qmax_pose.getOrigin();
00226 tf::Vector3 closed_door_handle_in_ff, open_door_handle_in_ff;
00227
00228
00229 ROS_ERROR_COND((abs(qmin_position.length2() - qmax_position.length2()) > 0.001), "Reprojected poses should have same length");
00230 if(q1st_position.dot(qmax_position) > q1st_position.dot(qmin_position))
00231 {
00232
00233 closed_door_handle_in_ff = center*qmax_position;
00234 open_door_handle_in_ff = center*qmin_position;
00235 } else {
00236 closed_door_handle_in_ff = center*qmin_position;
00237 open_door_handle_in_ff = center*qmax_position;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246 tf::Vector3 closed_axis = closed_door_handle_in_ff - center.getOrigin();
00247 tf::Vector3 open_axis = open_door_handle_in_ff - center.getOrigin();
00248
00249
00250
00251
00252
00253
00254
00255
00256 tf::Vector3 rotation_axis = closed_axis.cross(open_axis);
00257 open_axis = rotation_axis.cross(closed_axis);
00258 closed_axis = closed_axis.normalize();
00259 print(closed_axis);
00260 open_axis = open_axis.normalize();
00261 print(open_axis);
00262 rotation_axis = rotation_axis.normalize();
00263 print(rotation_axis);
00264
00265 tf::Matrix3x3 basis(closed_axis.x(), open_axis.x(), rotation_axis.x(),
00266 closed_axis.y(), open_axis.y(), rotation_axis.y(),
00267 closed_axis.z(), open_axis.z(), rotation_axis.z());
00268 print(basis);
00269 tf::Quaternion qbasis; basis.getRotation(qbasis);
00270 print(qbasis);
00271 return tf::Transform(basis, center.getOrigin());
00272
00273
00274
00275
00276
00277
00278
00279
00280 }
00281
00282 void print(tf::Matrix3x3 m){
00283 ROS_DEBUG("RotM:\n%.5f, %.5f, %.5f\n%.5f, %.5f, %.5f\n%.5f, %.5f, %.5f\n",
00284 m[0][0], m[0][1], m[0][2],
00285 m[1][0], m[1][1], m[1][2],
00286 m[2][0], m[2][1], m[2][2]);
00287 }
00288 void print(tf::Quaternion q){
00289 ROS_DEBUG("Quat: %.4f, %.4f, %.4f, %.4f", q.getX(), q.getY(), q.getZ(), q.w());
00290 }
00291 void print(tf::Vector3 v){
00292 ROS_DEBUG("Vec: %.4f, %.4f, %.4f, %.4f", v.getX(), v.getY(), v.getZ(), v.w());
00293 }
00294 std::string stream(tf::Vector3 v){
00295 std::stringstream ss;
00296 ss << v.x() << " " << v.y() << " " << v.z();
00297 return ss.str();
00298 }
00299 std::string stream(tf::Quaternion v){
00300 std::stringstream ss;
00301 ss << v.x() << " " << v.y() << " " << v.z()<< " " << v.w();
00302 return ss.str();
00303 }
00304 std::string stream(tf::StampedTransform tf){
00305 std::stringstream ss;
00306 ss << stream(tf.getOrigin()) << " " << stream(tf.getRotation()) << " " << tf.frame_id_ << " " << tf.child_frame_id_;
00307 return ss.str();
00308 }