camera_external_calibration.cpp
Go to the documentation of this file.
00001 
00008 #include <carl_tools/camera_external_calibration.h>
00009 
00010 using namespace std;
00011 
00012 CameraExternalCalibration::CameraExternalCalibration()
00013 {
00014   // private node handle
00015   ros::NodeHandle private_nh("~");
00016 
00017   // get the id of the calibration marker
00018   private_nh.param("calibration_marker_id", markerID, 200);
00019 
00020   calibrated = false;
00021   calibrationEnabled = false;
00022   calibrationWritten = false;
00023   transformSamples.clear();
00024 
00025   asusCommandPublisher = n.advertise<std_msgs::Float64>("asus_controller/command", 1);
00026 
00027   markerSubscriber = n.subscribe("asus_marker_tracker/ar_pose_marker", 1, &CameraExternalCalibration::markerCallback, this);
00028 
00029   //set camera position for calibration
00030   this->setCameraPos();
00031 }
00032 
00033 void CameraExternalCalibration::setCameraPos()
00034 {
00035   ROS_INFO("Setting camera position and waiting for autofocus/autoexposure...");
00036   std_msgs::Float64 asusCmd;
00037   asusCmd.data = 0.5;
00038   asusCommandPublisher.publish(asusCmd);
00039   ros::Duration(5.0).sleep(); //give time for servo to move and camera to focus
00040   calibrationEnabled = true;
00041   ROS_INFO("Ready to calibrate.");
00042 }
00043 
00044 void CameraExternalCalibration::markerCallback(const ar_track_alvar_msgs::AlvarMarkers::ConstPtr& msg)
00045 {
00046   if (calibrationEnabled)
00047   {
00048     for (unsigned int i = 0; i < msg->markers.size(); i++)
00049     {
00050       //check if the marker detected is the calibration marker
00051       if (msg->markers[i].id == markerID)
00052       {
00053         geometry_msgs::PoseStamped sample = msg->markers[i].pose;
00054         sample.header.frame_id = msg->markers[i].header.frame_id;
00055 
00056         // construct transform from camera to marker
00057         tf::Transform tfSample;
00058         tfSample.setOrigin(tf::Vector3(sample.pose.position.x, sample.pose.position.y, sample.pose.position.z));
00059         tfSample.setRotation(tf::Quaternion(sample.pose.orientation.x, sample.pose.orientation.y, sample.pose.orientation.z, sample.pose.orientation.w).normalize());
00060         // invert it
00061         tf::Transform tfSampleInverse = tfSample.inverse();
00062         ros::Time time = ros::Time::now();
00063         tf::StampedTransform tfSampleStamped(tfSampleInverse, time, "calibration_link", "calibrated_asus_camera_link");
00064         br.sendTransform(tfSampleStamped);
00065 
00066         transformSamples.push_back(tfSampleStamped);
00067         if (transformSamples.size() >= REQUIRED_SAMPLES)
00068         {
00069           ROS_INFO("Finished calibration for asus.");
00070           calibrationEnabled = false;
00071         }
00072       }
00073     }
00074   }
00075 }
00076 
00077 void CameraExternalCalibration::publishTransforms()
00078 {
00079   // go through each marker
00080   bool finished = true;
00081 
00082   // publish the average pose from the camera if it's received enough samples
00083   if (transformSamples.size() >= REQUIRED_SAMPLES)
00084   {
00085     if (!calibrated)
00086     {
00087       //calculate average pose
00088       tf::StampedTransform avgTransform;
00089       avgTransform.frame_id_ = transformSamples[0].frame_id_;
00090       avgTransform.child_frame_id_ = transformSamples[0].child_frame_id_;
00091       avgTransform.stamp_ = ros::Time::now();
00092       float x = 0.0, y = 0.0, z = 0.0;
00093       tf::Quaternion avgQuat;
00094       int failedSamples = 0;
00095       for (unsigned int i = 0; i < transformSamples.size(); i++)
00096       {
00097         //check if a transform is empty, this can happen rarely from lookuptransform errors; these should be ignored
00098         if (transformSamples[i].getOrigin().x() == 0 && transformSamples[i].getOrigin().y() == 0 && transformSamples[i].getOrigin().z() == 0)
00099         {
00100           failedSamples ++;
00101         }
00102         else
00103         {
00104           x += transformSamples[i].getOrigin().x();
00105           y += transformSamples[i].getOrigin().y();
00106           z += transformSamples[i].getOrigin().z();
00107           if (i == 0)
00108           {
00109             avgQuat = transformSamples[i].getRotation().normalize();
00110           }
00111           else
00112           {
00113             avgQuat.slerp(transformSamples[i].getRotation().normalize(), 1.0 / ((float) (i + 1 - failedSamples))).normalize();
00114           }
00115         }
00116       }
00117 
00118       int numSamples = transformSamples.size() - failedSamples;
00119       avgTransform.setOrigin(tf::Vector3(x/numSamples, y/numSamples, z/numSamples));
00120       avgTransform.setRotation(avgQuat);
00121 
00122       finalTransform = avgTransform;
00123       calibrated = true;
00124     }
00125 
00126     finalTransform.stamp_ = ros::Time::now();
00127     br.sendTransform(finalTransform);
00128   }
00129   else
00130   {
00131     finished = false;
00132   }
00133 
00134   if (finished && !calibrationWritten)
00135   {
00136     //calculate the corrected transform
00137     tf::StampedTransform correctedTransform;
00138     tfListener.waitForTransform("asus_mount_link", "calibrated_asus_camera_link", ros::Time::now(), ros::Duration(5.0));
00139     tfListener.lookupTransform("asus_mount_link", "calibrated_asus_camera_link", ros::Time(0), correctedTransform);
00140     double roll, pitch, yaw;
00141     tf::Matrix3x3(correctedTransform.getRotation()).getRPY(roll, pitch, yaw);
00142 
00143     //write calibration file
00144     ROS_INFO("The new calibrated transform between asus_mount_link and camera_link is:\n\n"
00145         "<origin xyz=\"%f %f %f\" rpy=\"%f %f %f\" />\n",
00146         correctedTransform.getOrigin().x(), correctedTransform.getOrigin().y(), correctedTransform.getOrigin().z(),
00147         roll, pitch, yaw);
00148     ROS_INFO("If this accurate, copy the above line into the carl_asus_camera.urdf.xacro file in the carl_bot package in place of the origin line\n"
00149         "<xacro:sensor_asus_xtion_pro parent=\"asus_mount_link\">\n"
00150         "  <origin ... />\n"
00151         "</xacro:sensor_asus_xtion_pro>");
00152 
00153     calibrationWritten = true;
00154   }
00155 }
00156 
00157 int main(int argc, char **argv)
00158 {
00159   ros::init(argc, argv, "camera_external_calibration");
00160 
00161   CameraExternalCalibration c;
00162 
00163   ros::Rate loop_rate(30);
00164   while (ros::ok())
00165   {
00166     c.publishTransforms();
00167     ros::spinOnce();
00168     loop_rate.sleep();
00169   }
00170 }


carl_tools
Author(s): Russell Toris , David Kent
autogenerated on Thu Jun 6 2019 21:10:06