calibration_from_carl.cpp
Go to the documentation of this file.
00001 
00008 #include <rail_ceiling/calibration_from_carl.h>
00009 
00010 using namespace std;
00011 
00012 CalibrationFromCarl::CalibrationFromCarl()
00013 {
00014   // private node handle
00015   ros::NodeHandle private_nh("~");
00016 
00017   // get number of marker topics (i.e. number of overhead cameras), and the id of the calibration marker
00018   int numCameras;
00019   private_nh.param("num_cameras", numCameras, 5);
00020   private_nh.param("calibration_marker_id", markerID, 200);
00021 
00022   calibrationEnabled.resize(numCameras);
00023   transformSamples.resize(numCameras);
00024   finalTransforms.resize(numCameras);
00025   calibrated.resize(numCameras);
00026   markerSubscribers.resize(numCameras);
00027   for (unsigned int i = 0; i < numCameras; i ++)
00028   {
00029     transformSamples[i].clear();
00030     calibrationEnabled[i] = false;
00031     calibrated[i] = false;
00032     stringstream topicStream;
00033     topicStream << "ceiling_cam_tracker_" << i << "/ar_pose_marker";
00034     markerSubscribers[i] = n.subscribe(topicStream.str(), 1, &CalibrationFromCarl::markerCallback, this);
00035   }
00036 
00037   startCalibrationSubscriber = n.subscribe("start_calibration", 1, &CalibrationFromCarl::startCalibrationCallback, this);
00038   calibrationComplete = false;
00039 }
00040 
00041 void CalibrationFromCarl::startCalibrationCallback(const std_msgs::Int16::ConstPtr& msg)
00042 {
00043   //enable calibration for the specified camera and clear out any previous samples
00044   calibrationEnabled[msg->data] = true;
00045   calibrated[msg->data] = false;
00046   transformSamples[msg->data].clear();
00047   calibrationComplete = false;
00048 }
00049 
00050 void CalibrationFromCarl::markerCallback(const ar_track_alvar_msgs::AlvarMarkers::ConstPtr& msg)
00051 {
00052   for (unsigned int i = 0; i < msg->markers.size(); i ++)
00053   {
00054     //check if the marker detected is the calibration marker
00055     if (msg->markers[i].id == markerID)
00056     {
00057       //get the marker index, this assumes the camera coordinate frames contain the string "cam_n", where n is an
00058       //integer denoting the camera number
00059       size_t pos = msg->markers[i].header.frame_id.find("cam_");
00060       int cameraid = atoi((msg->markers[i].header.frame_id.substr(pos + 4)).c_str());
00061       if (calibrationEnabled[cameraid])
00062       {
00063         geometry_msgs::PoseStamped sample = msg->markers[i].pose;
00064         sample.header.frame_id=msg->markers[i].header.frame_id;
00065 
00066         // transform pose to map frame
00067         tf::Transform tfSample;
00068         tf::StampedTransform finalTransform;
00069         tfSample.setOrigin(tf::Vector3(sample.pose.position.x, sample.pose.position.y, sample.pose.position.z));
00070         tfSample.setRotation(tf::Quaternion(sample.pose.orientation.x, sample.pose.orientation.y, sample.pose.orientation.z, sample.pose.orientation.w).normalize());
00071         // invert it
00072         tf::Transform tfSampleInverse = tfSample.inverse();
00073         ros::Time time = ros::Time::now();
00074         br.sendTransform(tf::StampedTransform(tfSampleInverse, time, "calibration_link", sample.header.frame_id.c_str()));
00075         tfListener.waitForTransform("map", "calibration_link", time, ros::Duration(1.0));
00076         tfListener.lookupTransform("map", sample.header.frame_id, time, finalTransform);
00077 
00078         transformSamples[cameraid].push_back(finalTransform);
00079         if (transformSamples[cameraid].size() >= REQUIRED_SAMPLES)
00080         {
00081           ROS_INFO("Finished calibration for camera %d", cameraid);
00082           calibrationEnabled[cameraid] = false;
00083         }
00084       }
00085     }
00086   }
00087 }
00088 
00089 void CalibrationFromCarl::publishTransforms()
00090 {
00091   // go through each marker
00092   bool finished = true;
00093   for (unsigned int i = 0; i < transformSamples.size(); i ++)
00094   {
00095     // publish the average pose from the camera if it's received enough samples
00096     if (transformSamples[i].size() >= REQUIRED_SAMPLES)
00097     {
00098       if (!calibrated[i])
00099       {
00100         //calculate average pose
00101         //TODO: find a better way to approximate average rotation in 3D
00102         tf::StampedTransform avgTransform;
00103         avgTransform.frame_id_ = transformSamples[i][0].frame_id_;
00104         avgTransform.child_frame_id_ = transformSamples[i][0].child_frame_id_;
00105         avgTransform.stamp_ = ros::Time::now();
00106         float x = 0.0, y = 0.0, z = 0.0;
00107         //float qx = 0.0, qy = 0.0, qz = 0.0, qw = 0.0;
00108         tf::Quaternion avgQuat;
00109         for (unsigned int j = 0; j < transformSamples[i].size(); j++)
00110         {
00111           x += transformSamples[i][j].getOrigin().x();
00112           y += transformSamples[i][j].getOrigin().y();
00113           z += transformSamples[i][j].getOrigin().z();
00114           if (j == 0)
00115           {
00116             avgQuat = transformSamples[i][j].getRotation();
00117           }
00118           else
00119           {
00120             avgQuat.slerp(transformSamples[i][j].getRotation(), 1.0/((float)(j + 1)));
00121           }
00122           /*
00123           qx += transformSamples[i][j].getRotation().getX();
00124           qy += transformSamples[i][j].getRotation().getY();
00125           qz += transformSamples[i][j].getRotation().getZ();
00126           qw += transformSamples[i][j].getRotation().getW();
00127           */
00128         }
00129 
00130         int numSamples = transformSamples[i].size();
00131         avgTransform.setOrigin(tf::Vector3(x/numSamples, y/numSamples, z/numSamples));
00132         //avgTransform.setRotation(tf::Quaternion(qx/numSamples, qy/numSamples, qz/numSamples, qw/numSamples).normalize());
00133         avgTransform.setRotation(avgQuat);
00134 
00135         finalTransforms[i] = avgTransform;
00136         calibrated[i] = true;
00137       }
00138 
00139       br.sendTransform(finalTransforms[i]);
00140     }
00141     else
00142     {
00143       finished = false;
00144     }
00145   }
00146 
00147   if (finished && !calibrationComplete)
00148   {
00149     //write calibration file
00150     ROS_INFO("Writing calibration...");
00151 
00152     stringstream ss;
00153     //TODO: update
00154     ss << getenv("HOME") << "/testCalibrationFile.urdf";
00155     string file_name = ss.str();
00156 
00157     // open the file for writing
00158     ofstream urdf;
00159     urdf.open(file_name.c_str());
00160     if (!urdf.is_open())
00161       ROS_ERROR("Failed to open '~/%s' for writing.", file_name.c_str());
00162     else
00163     {
00164       urdf << "<?xml version=\"1.0\"?>\n";
00165       urdf << "<robot xmlns:xacro=\"http://www.ros.org/wiki/xacro\" name=\"ceiling\">\n\n";
00166 
00167       urdf << "  <!-- Auto-Generated from rail_ceiling/calibration Node -->\n\n";
00168 
00169       urdf << "  <xacro:include filename=\"$(find rail_ceiling)/urdf/camera.urdf.xacro\" />\n\n";
00170 
00171       urdf << "  <xacro:property name=\"PARENT\" value=\"" << "map" << "\" />\n\n";
00172 
00173       urdf << "  <!-- fixed frame -->\n";
00174       urdf << "  <link name=\"${PARENT}\" />\n\n";
00175 
00176       urdf << "  <!-- " << finalTransforms.size() << " Camera(s) -->\n";
00177       for (int i = 0; i < finalTransforms.size(); i++)
00178       {
00179         // grab the TF info
00180         tf::StampedTransform &tf = finalTransforms.at(i);
00181         tf::Vector3 &pos = tf.getOrigin();
00182         double roll, pitch, yaw;
00183         tf.getBasis().getRPY(roll, pitch, yaw);
00184         urdf << "  <xacro:ceiling_cam parent=\"${PARENT}\" link=\"" << tf.child_frame_id_ << i << "\">\n";
00185         urdf << "    <origin xyz=\"" << pos.getX() << " " << pos.getY() << " " << pos.getZ() << "\" rpy=\"" << roll << " "
00186             << pitch << " " << yaw << "\" />\n";
00187         urdf << "  </xacro:ceiling_cam>\n";
00188       }
00189       urdf << "</robot>\n\n";
00190 
00191       urdf.close();
00192       ROS_INFO("Calibration written to '%s'.", file_name.c_str());
00193     }
00194 
00195     calibrationComplete = true;
00196   }
00197 }
00198 
00199 int main(int argc, char **argv)
00200 {
00201   ros::init(argc, argv, "calibration_from_carl");
00202 
00203   CalibrationFromCarl c;
00204 
00205   ros::Rate loop_rate(30);
00206   while (ros::ok())
00207   {
00208     c.publishTransforms();
00209     ros::spinOnce();
00210     loop_rate.sleep();
00211   }
00212 }


rail_ceiling
Author(s): Russell Toris , David Kent
autogenerated on Sat Jun 8 2019 20:39:22