00001
00013 #include <rail_ceiling/calibration.hpp>
00014 #include <tf/transform_listener.h>
00015 #include <sstream>
00016 #include <fstream>
00017
00018 using namespace std;
00019
00020 calibration::calibration() :
00021 pnh_("~")
00022 {
00023 this->calibrated_ = false;
00024
00025
00026 pnh_.param("fixed_frame", this->fixed_frame_, string("map"));
00027 pnh_.param("camera_frame_id_prefix", this->camera_frame_id_prefix_, string("ceiling_cam_"));
00028 pnh_.param("num_cameras", this->num_cameras_, 1);
00029 pnh_.param("num_samples", this->num_samples_, 10);
00030
00031
00032 for (int i = 0; i < this->num_cameras_; i++)
00033 {
00034
00035 stringstream topic_ss, x_pos_ss, y_pos_ss, z_pos_ss, x_rot_ss, y_rot_ss, z_rot_ss, w_rot_ss;
00036 topic_ss << "ceiling_cam_tracker_" << i << "/ar_pose_marker";
00037 x_pos_ss << "ceiling_cam_" << i << "_pos_x";
00038 y_pos_ss << "ceiling_cam_" << i << "_pos_y";
00039 z_pos_ss << "ceiling_cam_" << i << "_pos_z";
00040 x_rot_ss << "ceiling_cam_" << i << "_rot_x";
00041 y_rot_ss << "ceiling_cam_" << i << "_rot_y";
00042 z_rot_ss << "ceiling_cam_" << i << "_rot_z";
00043 w_rot_ss << "ceiling_cam_" << i << "_rot_w";
00044
00045
00046 ros::Subscriber sub = this->nh_.subscribe<ar_track_alvar_msgs::AlvarMarkers>(
00047 topic_ss.str(), 1, boost::bind(&calibration::marker_cback, this, _1, i));
00048
00049 this->marker_subs_.push_back(sub);
00050
00051 vector<geometry_msgs::Pose> samples;
00052 this->samples_.push_back(samples);
00053
00054
00055 geometry_msgs::Pose pose;
00056 pnh_.param(x_pos_ss.str(), pose.position.x, 0.0);
00057 pnh_.param(y_pos_ss.str(), pose.position.y, 0.0);
00058 pnh_.param(z_pos_ss.str(), pose.position.z, 0.0);
00059 pnh_.param(x_rot_ss.str(), pose.orientation.x, 0.0);
00060 pnh_.param(y_rot_ss.str(), pose.orientation.y, 0.0);
00061 pnh_.param(z_rot_ss.str(), pose.orientation.z, 0.0);
00062 pnh_.param(w_rot_ss.str(), pose.orientation.w, 1.0);
00063 this->fixed_poses_.push_back(pose);
00064 }
00065
00066 ROS_INFO("Waiting to find %i samples of the calibration markers for each camera...", this->num_samples_);
00067 }
00068
00069 void calibration::marker_cback(const ar_track_alvar_msgs::AlvarMarkers::ConstPtr& msg, int camera)
00070 {
00071
00072 vector<geometry_msgs::Pose> &samples = this->samples_.at(camera);
00073 if (samples.size() < this->num_samples_)
00074 {
00075
00076 int dest_marker = camera + 100;
00077 for (int i = 0; i < msg->markers.size(); i++)
00078 {
00079 ar_track_alvar_msgs::AlvarMarker marker = msg->markers.at(i);
00080 if (marker.id == dest_marker)
00081
00082 samples.push_back(marker.pose.pose);
00083 }
00084 }
00085 }
00086
00087 void calibration::publish_tf()
00088 {
00089
00090 for (int i = 0; i < this->num_cameras_; i++)
00091 {
00092
00093 geometry_msgs::Pose &fixed_pose = this->fixed_poses_.at(i);
00094
00095 tf::Transform tf_fixed;
00096 tf_fixed.setOrigin(tf::Vector3(fixed_pose.position.x, fixed_pose.position.y, fixed_pose.position.z));
00097 tf_fixed.setRotation(
00098 tf::Quaternion(fixed_pose.orientation.x, fixed_pose.orientation.y, fixed_pose.orientation.z,
00099 fixed_pose.orientation.w));
00100
00101 stringstream ss_fixed;
00102 ss_fixed << FIXED_LINK_NAME << i;
00103 br.sendTransform(tf::StampedTransform(tf_fixed, ros::Time::now(), this->fixed_frame_, ss_fixed.str()));
00104
00105
00106 if (this->average_poses_.size() > i)
00107 {
00108
00109 geometry_msgs::Pose &average_pose = this->average_poses_.at(i);
00110
00111 tf::Transform tf_average;
00112 tf_average.setRotation(tf::Quaternion(0, 0, 0, 1));
00113 tf_average.setOrigin(tf::Vector3(average_pose.position.x, average_pose.position.y, average_pose.position.z));
00114 tf_average.setRotation(
00115 tf::Quaternion(average_pose.orientation.x, average_pose.orientation.y, average_pose.orientation.z,
00116 average_pose.orientation.w).normalize());
00117
00118 tf::Transform tf_average_inverse = tf_average.inverse();
00119 stringstream ss_camera;
00120 ss_camera << CAMERA_LINK_NAME << i;
00121 br.sendTransform(tf::StampedTransform(tf_average_inverse, ros::Time::now(), ss_fixed.str(), ss_camera.str()));
00122 }
00123 }
00124 }
00125
00126 void calibration::attempt_calibration()
00127 {
00128
00129 if (!this->calibrated_)
00130 {
00131
00132 bool ready = true;
00133 for (int i = 0; i < this->num_cameras_; i++)
00134 ready &= this->samples_.at(i).size() >= this->num_samples_;
00135
00136 if (ready)
00137 {
00138 ROS_INFO("Sample collection complete.");
00139
00140
00141 for (int i = 0; i < this->num_cameras_; i++)
00142 this->marker_subs_.at(i).shutdown();
00143
00144
00145 for (int i = 0; i < this->num_cameras_; i++)
00146 {
00147 geometry_msgs::Pose pose;
00148 vector<geometry_msgs::Pose> &samples = this->samples_.at(i);
00149 for (int j = 0; j < this->num_samples_; j++)
00150 {
00151
00152 geometry_msgs::Pose &sample = samples.at(j);
00153 int n = j + 1;
00154 pose.position.x = (((n - 1) * pose.position.x + sample.position.x) / (float)n);
00155 pose.position.y = (((n - 1) * pose.position.y + sample.position.y) / (float)n);
00156 pose.position.z = (((n - 1) * pose.position.z + sample.position.z) / (float)n);
00157 pose.orientation.w = (((n - 1) * pose.orientation.w + sample.orientation.w) / (float)n);
00158 pose.orientation.x = (((n - 1) * pose.orientation.x + sample.orientation.x) / (float)n);
00159 pose.orientation.y = (((n - 1) * pose.orientation.y + sample.orientation.y) / (float)n);
00160 pose.orientation.z = (((n - 1) * pose.orientation.z + sample.orientation.z) / (float)n);
00161 }
00162
00163 this->average_poses_.push_back(pose);
00164 }
00165
00166
00167 this->publish_tf();
00168
00169
00170 this->write_calibration();
00171
00172 this->calibrated_ = true;
00173 ROS_INFO("Calibration complete!");
00174 }
00175 }
00176 }
00177
00178 void calibration::write_calibration()
00179 {
00180
00181 tf::TransformListener listener;
00182 vector<tf::StampedTransform> tfs;
00183
00184 for (int i = 0; i < this->num_cameras_; i++)
00185 {
00186 stringstream ss_frame;
00187 ss_frame << CAMERA_LINK_NAME << i;
00188
00189
00190 bool found = false;
00191 while (!found)
00192 {
00193 try
00194 {
00195
00196 tf::StampedTransform tf;
00197 listener.lookupTransform(this->fixed_frame_, ss_frame.str(), ros::Time(0), tf);
00198 tfs.push_back(tf);
00199 found = true;
00200 }
00201 catch (tf::TransformException &ex)
00202 {
00203
00204 this->publish_tf();
00205
00206 ros::Duration(1.0).sleep();
00207 }
00208 }
00209 }
00210
00211 stringstream ss;
00212 ss << getenv("HOME") << "/" << URDF;
00213 string file_name = ss.str();
00214
00215
00216 ofstream urdf;
00217 urdf.open(file_name.c_str());
00218 if (!urdf.is_open())
00219 ROS_ERROR("Failed to open '~/%s' for writing.", file_name.c_str());
00220 else
00221 {
00222 urdf << "<?xml version=\"1.0\"?>\n";
00223 urdf << "<robot xmlns:xacro=\"http://www.ros.org/wiki/xacro\" name=\"ceiling\">\n\n";
00224
00225 urdf << " <!-- Auto-Generated from rail_ceiling/calibration Node -->\n\n";
00226
00227 urdf << " <xacro:include filename=\"$(find rail_ceiling)/urdf/camera.urdf.xacro\" />\n\n";
00228
00229 urdf << " <xacro:property name=\"PARENT\" value=\"" << this->fixed_frame_ << "\" />\n\n";
00230
00231 urdf << " <!-- fixed frame -->\n";
00232 urdf << " <link name=\"${PARENT}\" />\n\n";
00233
00234 urdf << " <!-- " << this->num_cameras_ << " Camera(s) -->\n";
00235 for (int i = 0; i < this->num_cameras_; i++)
00236 {
00237
00238 tf::StampedTransform &tf = tfs.at(i);
00239 tf::Vector3 &pos = tf.getOrigin();
00240 double roll, pitch, yaw;
00241 tf.getBasis().getRPY(roll, pitch, yaw);
00242 urdf << " <xacro:ceiling_cam parent=\"${PARENT}\" link=\"" << this->camera_frame_id_prefix_ << i << "\">\n";
00243 urdf << " <origin xyz=\"" << pos.getX() << " " << pos.getY() << " " << pos.getZ() << "\" rpy=\"" << roll << " "
00244 << pitch << " " << yaw << "\" />\n";
00245 urdf << " </xacro:ceiling_cam>\n";
00246 }
00247 urdf << "</robot>\n\n";
00248
00249 urdf.close();
00250 ROS_INFO("Calibration written to '%s'.", file_name.c_str());
00251 }
00252 }
00253
00254 int main(int argc, char **argv)
00255 {
00256
00257 ros::init(argc, argv, "calibration");
00258
00259
00260 calibration calib;
00261
00262
00263 ros::Rate r(60);
00264 while (ros::ok())
00265 {
00266 calib.publish_tf();
00267 calib.attempt_calibration();
00268 ros::spinOnce();
00269 r.sleep();
00270 }
00271
00272 return EXIT_SUCCESS;
00273 }