25 #define PCL_NO_PRECOMPILE 27 #include "velo2cam_calibration/ClusterCentroids.h" 32 #include <sensor_msgs/PointCloud2.h> 33 #include <pcl/point_cloud.h> 35 #include <pcl/common/transforms.h> 36 #include <pcl/registration/icp.h> 46 #include <tf2_sensor_msgs/tf2_sensor_msgs.h> 47 #include <geometry_msgs/TransformStamped.h> 70 std::vector<pcl::PointXYZ>
lv(4),
cv(4);
79 std::vector< std::tuple<int,int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> > >
laser_buffer;
80 std::vector< std::tuple<int,int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> > >
cam_buffer;
94 tstruct = *localtime(&now);
97 strftime(buf,
sizeof(buf),
"%Y-%m-%d.%X", &tstruct);
105 std::vector<pcl::PointXYZ> local_lv, local_cv;
106 pcl::PointCloud<pcl::PointXYZ>::Ptr local_laser_cloud, local_camera_cloud;
107 pcl::PointCloud<pcl::PointXYZ> local_l_cloud, local_c_cloud;
109 int used_stereo, used_laser;
114 auto it = std::find_if(
cam_buffer.begin(),
cam_buffer.end(), [&seek_iter](
const std::tuple<int,int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> >& e) {
return std::get<0>(e) == seek_iter;});
120 auto it2 = std::find_if(
laser_buffer.begin(),
laser_buffer.end(), [&seek_iter](
const std::tuple<int,int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> >& e) {
return std::get<0>(e) == seek_iter;});
126 used_stereo = std::get<1>(*it);
127 used_laser = std::get<1>(*it2);
129 local_cv = std::get<3>(*it);
130 local_c_cloud = std::get<2>(*it);
131 local_camera_cloud = local_c_cloud.makeShared();
133 local_lv = std::get<3>(*it2);
134 local_l_cloud = std::get<2>(*it2);
135 local_laser_cloud = local_l_cloud.makeShared();
136 ROS_INFO(
"Synchronizing cluster centroids");
144 sensor_msgs::PointCloud2 ros_cloud;
146 ros_cloud.header.frame_id =
"stereo";
150 ros_cloud.header.frame_id =
"velodyne";
154 las_12 << local_lv[0].x,
168 cam_12 << local_cv[0].x,
182 diff_12 = las_12-cam_12;
184 Eigen::MatrixXd matrix_transl(12,3);
185 matrix_transl << 1, 0, 0, 0, 1, 0, 0, 0, 1,
186 1, 0, 0, 0, 1, 0, 0, 0, 1,
187 1, 0, 0, 0, 1, 0, 0, 0, 1,
188 1, 0, 0, 0, 1, 0, 0, 0, 1;
191 x = matrix_transl.colPivHouseholderQr().solve(diff_12);
203 if(
DEBUG) cout << Tm << endl;
205 pcl::PointCloud<pcl::PointXYZ>::Ptr translated_pc (
new pcl::PointCloud<pcl::PointXYZ> ());
206 pcl::transformPointCloud(*local_camera_cloud, *translated_pc, Tm);
209 ros_cloud.header.frame_id =
"velodyne";
212 pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
213 icp.setInputSource(translated_pc);
214 icp.setInputTarget(local_laser_cloud);
215 pcl::PointCloud<pcl::PointXYZ> Final;
217 icp.setMaxCorrespondenceDistance(0.2);
218 icp.setMaximumIterations(1000);
219 if (icp.hasConverged()){
220 if(
DEBUG)
ROS_INFO(
"ICP Converged. Score: %lf", icp.getFitnessScore());
226 if(
DEBUG) cout << icp.getFinalTransformation() << std::endl;
228 Eigen::Matrix4f transformation = icp.getFinalTransformation ();
229 Eigen::Matrix4f final_trans = transformation * Tm;
232 tf3d.
setValue(final_trans(0,0), final_trans(0,1), final_trans(0,2),
233 final_trans(1,0), final_trans(1,1), final_trans(1,2),
234 final_trans(2,0), final_trans(2,1), final_trans(2,2));
237 if(
DEBUG) cout << final_trans << endl;
245 geometry_msgs::TransformStamped transformStamped;
248 transformStamped.header.frame_id =
"velodyne";
249 transformStamped.child_frame_id =
"stereo";
250 transformStamped.transform.translation.x = final_trans(0,3);
251 transformStamped.transform.translation.y = final_trans(1,3);
252 transformStamped.transform.translation.z = final_trans(2,3);
253 transformStamped.transform.rotation.x = tfqt.x();
254 transformStamped.transform.rotation.y = tfqt.y();
255 transformStamped.transform.rotation.z = tfqt.z();
256 transformStamped.transform.rotation.w = tfqt.w();
263 origin.
setValue(final_trans(0,3),final_trans(1,3),final_trans(2,3));
275 double roll, pitch, yaw;
280 savefile << seek_iter <<
", " << xt <<
", " << yt <<
", " << zt <<
", " << roll <<
", " << pitch <<
", " << yaw <<
", " << used_laser <<
", " << used_stereo << endl;
283 ROS_INFO(
"[V2C] Calibration result:");
284 ROS_INFO(
"x=%.4f y=%.4f z=%.4f",xt,yt,zt);
285 ROS_INFO(
"roll=%.4f, pitch=%.4f, yaw=%.4f",roll,pitch,yaw);
295 void laser_callback(
const velo2cam_calibration::ClusterCentroids::ConstPtr velo_centroids){
304 laser_buffer.push_back(std::tuple<
int,
int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> >(velo_centroids->total_iterations, velo_centroids->cluster_iterations, *
laser_cloud,
lv));
309 for(vector<pcl::PointXYZ>::iterator it=
lv.begin(); it<
lv.end(); ++it){
310 if (
DEBUG) cout <<
"l" << it -
lv.begin() <<
"="<<
"[" << (*it).x <<
" " << (*it).y <<
" " << (*it).z <<
"]" << endl;
336 void stereo_callback(velo2cam_calibration::ClusterCentroids::ConstPtr image_centroids){
343 PointCloud2 xy_image_cloud;
347 geometry_msgs::TransformStamped transformStamped;
362 pcl::PointCloud<pcl::PointXYZ>::Ptr xy_camera_cloud (
new pcl::PointCloud<pcl::PointXYZ> ());
364 fromROSMsg(image_centroids->cloud, *xy_camera_cloud);
372 ROS_WARN(
"TF exception:\n%s", ex.what());
377 double roll, pitch, yaw;
389 cam_buffer.push_back(std::tuple<
int,
int,pcl::PointCloud<pcl::PointXYZ>, std::vector<pcl::PointXYZ> >(image_centroids->total_iterations,image_centroids->cluster_iterations,*
camera_cloud,
cv));
390 cam_count = image_centroids->total_iterations;
394 for(vector<pcl::PointXYZ>::iterator it=
cv.begin(); it<
cv.end(); ++it){
395 if (
DEBUG) cout <<
"c" << it -
cv.begin() <<
"="<<
"[" << (*it).x <<
" " << (*it).y <<
" " << (*it).z <<
"]"<<endl;
422 int main(
int argc,
char **argv){
423 ros::init(argc, argv,
"velo2cam_calibration");
432 if (publish_tf_) br.sendTransform(tf_velodyne_camera);
435 laser_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(
new pcl::PointCloud<pcl::PointXYZ>);
436 ilaser_cloud = pcl::PointCloud<pcl::PointXYZI>::Ptr(
new pcl::PointCloud<pcl::PointXYZI>);
438 camera_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(
new pcl::PointCloud<pcl::PointXYZ>);
439 icamera_cloud = pcl::PointCloud<pcl::PointXYZI>::Ptr(
new pcl::PointCloud<pcl::PointXYZI>);
444 t_pub = nh_.
advertise<sensor_msgs::PointCloud2>(
"translated_cloud", 1);
445 clusters_c = nh_.
advertise<sensor_msgs::PointCloud2>(
"clusters_camera", 1);
446 clusters_l = nh_.
advertise<sensor_msgs::PointCloud2>(
"clusters_laser", 1);
454 savefile <<
"it, x, y, z, r, p, y, used_l, used_c" << endl;
463 if (save_to_file_)
savefile.close();
469 struct tm * timeinfo;
473 timeinfo = localtime(&rawtime);
475 strftime(buffer,80,
"%Y-%m-%d-%H-%M-%S", timeinfo);
476 std::string str(buffer);
480 double roll, pitch, yaw;
484 ROS_INFO(
"Calibration finished succesfully...");
485 ROS_INFO(
"x=%.4f y=%.4f z=%.4f",xt,yt,zt);
486 ROS_INFO(
"roll=%.4f, pitch=%.4f, yaw=%.4f", roll, pitch, yaw);
489 string backuppath = path +
"/launch/calibrated_tf_"+ str +
".launch";
490 path = path +
"/launch/calibrated_tf.launch";
492 cout << endl <<
"Creating .launch file with calibrated TF in: "<< endl << path.c_str() << endl;
495 TiXmlDeclaration * decl =
new TiXmlDeclaration(
"1.0",
"utf-8",
"");
496 doc.LinkEndChild( decl );
497 TiXmlElement * root =
new TiXmlElement(
"launch" );
498 doc.LinkEndChild( root );
500 TiXmlElement * arg =
new TiXmlElement(
"arg" );
501 arg->SetAttribute(
"name",
"stdout");
502 arg->SetAttribute(
"default",
"screen");
503 root->LinkEndChild( arg );
505 string stereo_rotation =
"0 0 0 -1.57079632679 0 -1.57079632679 stereo stereo_camera 10";
507 TiXmlElement * stereo_rotation_node =
new TiXmlElement(
"node" );
508 stereo_rotation_node->SetAttribute(
"pkg",
"tf");
509 stereo_rotation_node->SetAttribute(
"type",
"static_transform_publisher");
510 stereo_rotation_node->SetAttribute(
"name",
"stereo_ros_tf");
511 stereo_rotation_node->SetAttribute(
"args", stereo_rotation);
512 root->LinkEndChild( stereo_rotation_node );
514 std::ostringstream sstream;
515 sstream << xt <<
" " << yt <<
" " << zt <<
" " << yaw <<
" " <<pitch<<
" " << roll <<
" stereo velodyne 100";
516 string tf_args = sstream.str();
517 cout << tf_args << endl;
519 TiXmlElement * node =
new TiXmlElement(
"node" );
520 node->SetAttribute(
"pkg",
"tf");
521 node->SetAttribute(
"type",
"static_transform_publisher");
522 node->SetAttribute(
"name",
"l2c_tf");
523 node->SetAttribute(
"args", tf_args);
524 root->LinkEndChild( node );
528 doc.SaveFile(backuppath);
530 if(
DEBUG) cout <<
"Calibration process finished." << endl;
std::vector< std::tuple< int, int, pcl::PointCloud< pcl::PointXYZ >, std::vector< pcl::PointXYZ > > > cam_buffer
ros::Publisher clusters_l
pcl::PointCloud< pcl::PointXYZ >::Ptr camera_cloud
void publish(const boost::shared_ptr< M > &message) const
std::vector< std::tuple< int, int, pcl::PointCloud< pcl::PointXYZ >, std::vector< pcl::PointXYZ > > > laser_buffer
void sortPatternCentersYZ(pcl::PointCloud< pcl::PointXYZ >::Ptr pc, vector< pcl::PointXYZ > &v)
tf::StampedTransform tf_velodyne_camera
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ros::Publisher clusters_c
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
TFSIMD_FORCE_INLINE const tfScalar & getY() const
std::vector< pcl::PointXYZ > cv(4)
void setValue(const tfScalar &xx, const tfScalar &xy, const tfScalar &xz, const tfScalar &yx, const tfScalar &yy, const tfScalar &yz, const tfScalar &zx, const tfScalar &zy, const tfScalar &zz)
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
TFSIMD_FORCE_INLINE const tfScalar & getZ() const
TFSIMD_FORCE_INLINE void setValue(const tfScalar &x, const tfScalar &y, const tfScalar &z)
void laser_callback(const velo2cam_calibration::ClusterCentroids::ConstPtr velo_centroids)
void getRotation(Quaternion &q) const
void calibrateExtrinsics(int seek_iter=-1)
pcl::PointCloud< pcl::PointXYZ >::Ptr laser_cloud
Eigen::Matrix< double, 12, 12 > Matrix12d
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
TFSIMD_FORCE_INLINE Quaternion inverse(const Quaternion &q)
const std::string currentDateTime()
TFSIMD_FORCE_INLINE const tfScalar & x() const
void stereo_callback(velo2cam_calibration::ClusterCentroids::ConstPtr image_centroids)
std::vector< pcl::PointXYZ > lv(4)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
pcl::PointCloud< pcl::PointXYZI >::Ptr icamera_cloud
ROSLIB_DECL std::string getPath(const std::string &package_name)
pcl::PointCloud< pcl::PointXYZI >::Ptr ilaser_cloud
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
void colourCenters(const pcl::PointCloud< pcl::PointXYZ >::Ptr pc, pcl::PointCloud< pcl::PointXYZI >::Ptr coloured)
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
TFSIMD_FORCE_INLINE const tfScalar & getX() const
int main(int argc, char **argv)
ROSCPP_DECL void spinOnce()
Eigen::Matrix< double, 12, 1 > Vector12d