|
1 | 1 | /* |
2 | | - ********************************************************* |
3 | | - * ******************************************************* |
4 | | - * *********** Iterative Closest Point (ICP) ************ |
5 | | - * ******************************************************* |
6 | | - * ************ written by Avinash on 04-02-2019 ********* |
7 | | - ********************************************************* |
8 | | - */ |
9 | | - |
| 2 | +Author: Avinash |
| 3 | +Version: 1.0.1 |
| 4 | +Date: Apr 03, 2019 |
| 5 | +*/ |
10 | 6 |
|
11 | 7 | #include <iostream> |
12 | 8 | #include <ros/ros.h> |
| 9 | +#include <tf/tf.h> |
| 10 | +#include <tf/transform_broadcaster.h> |
13 | 11 | #include <pcl_ros/point_cloud.h> |
14 | 12 | #include <pcl_conversions/pcl_conversions.h> |
15 | 13 | #include <pcl/io/pcd_io.h> |
16 | 14 | #include <pcl/point_types.h> |
17 | 15 | #include <pcl/registration/icp.h> |
18 | | -#include <sensor_msgs/point_cloud_conversion.h> |
19 | | -#include <sensor_msgs/PointCloud.h> |
| 16 | +#include <pcl_ros/transforms.h> |
20 | 17 | #include <sensor_msgs/PointCloud2.h> |
21 | 18 |
|
| 19 | +using namespace std; |
| 20 | + |
| 21 | +// Globals |
| 22 | +ros::Publisher pcl_pub; |
| 23 | +ros::Publisher template_pub; |
| 24 | +Eigen::Matrix4d icp_transform; |
| 25 | +string template_cuboid_filename; |
| 26 | +tf::TransformListener *tf_listener; |
| 27 | +sensor_msgs::PointCloud2 output_msg; |
| 28 | +sensor_msgs::PointCloud2 template_msg; |
| 29 | + |
| 30 | +// Flags |
| 31 | +bool DEBUG = false; |
| 32 | +bool ICP_SUCCESS = false; |
22 | 33 |
|
23 | | -typedef pcl::PointCloud<pcl::PointXYZ> PointCloud; |
24 | | -static ros::Publisher icp_PCL_pub; |
| 34 | +void convert_icp_eigen_to_tf(Eigen::Matrix4d Tm) |
| 35 | +{ |
| 36 | + // Set translation |
| 37 | + tf::Vector3 origin; |
| 38 | + origin.setValue(Tm(0, 3), Tm(1, 3), Tm(2, 3)); |
| 39 | + |
| 40 | + // Set rotation |
| 41 | + tf::Quaternion quaternion; |
| 42 | + tf::Matrix3x3 rotation_matrix; |
| 43 | + rotation_matrix.setValue(Tm(0, 0), Tm(0, 1), Tm(0, 2), |
| 44 | + Tm(1, 0), Tm(1, 1), Tm(1, 2), |
| 45 | + Tm(2, 0), Tm(2, 1), Tm(2, 2)); |
| 46 | + rotation_matrix.getRotation(quaternion); |
| 47 | + |
| 48 | + // Make tf transform message |
| 49 | + tf::Transform transform; |
| 50 | + transform.setOrigin(origin); |
| 51 | + transform.setRotation(quaternion); |
25 | 52 |
|
26 | | -pcl::PointCloud<pcl::PointXYZ>::Ptr template_cuboid(new pcl::PointCloud<pcl::PointXYZ>); |
27 | | -pcl::PointCloud<pcl::PointXYZ>::Ptr input_cuboid(new pcl::PointCloud<pcl::PointXYZ>); |
| 53 | + // Broadcast the transforms |
| 54 | + static tf::TransformBroadcaster br; |
| 55 | + // br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "cuboid_frame", "camera_depth_frame")); |
| 56 | +} |
28 | 57 |
|
29 | | -int performICP() |
| 58 | +void icp_callback(const sensor_msgs::PointCloud2::ConstPtr& msg) |
30 | 59 | { |
31 | | - pcl::IterativeClosestPoint <pcl::PointXYZ, pcl::PointXYZ> icp; |
| 60 | + // Compute ICP only once |
| 61 | + if (ICP_SUCCESS) |
| 62 | + { |
| 63 | + convert_icp_eigen_to_tf(icp_transform); |
| 64 | + pcl_pub.publish(output_msg); |
| 65 | + template_msg.header.frame_id = "camera_depth_optical_frame"; |
| 66 | + template_pub.publish(template_msg); |
| 67 | + return; |
| 68 | + } |
| 69 | + |
| 70 | + // Point cloud containers |
| 71 | + pcl::PointCloud<pcl::PointXYZ>::Ptr template_cuboid(new pcl::PointCloud<pcl::PointXYZ>); |
| 72 | + pcl::PointCloud<pcl::PointXYZ>::Ptr input_cuboid(new pcl::PointCloud<pcl::PointXYZ>); |
| 73 | + pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud(new pcl::PointCloud<pcl::PointXYZ>); |
| 74 | + |
| 75 | + // Read input point cloud |
| 76 | + pcl::fromROSMsg(*msg, *input_cuboid); |
| 77 | + |
| 78 | + // Read template point cloud |
| 79 | + if (pcl::io::loadPCDFile<pcl::PointXYZ>(template_cuboid_filename, *template_cuboid) == -1) |
| 80 | + { |
| 81 | + PCL_ERROR("Couldn't read the template PCL file"); |
| 82 | + return; |
| 83 | + } |
| 84 | + |
| 85 | + // Run ICP |
| 86 | + pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp; |
32 | 87 | icp.setInputSource(input_cuboid); |
33 | 88 | icp.setInputTarget(template_cuboid); |
34 | | - pcl::PointCloud <pcl::PointXYZ> Final; |
35 | | - icp.align(Final); |
36 | | - std::cout << "has converged:" << icp.hasConverged() << " score: " << |
37 | | - icp.getFitnessScore() << std::endl; |
38 | | - std::cout << icp.getFinalTransformation() << std::endl; |
| 89 | + icp.setMaximumIterations(2000); |
| 90 | + icp.setTransformationEpsilon(1e-9); |
| 91 | + // icp.setMaxCorrespondenceDistance(0.05); |
| 92 | + // icp.setEuclideanFitnessEpsilon(1); |
| 93 | + // icp.setRANSACOutlierRejectionThreshold(1.5); |
| 94 | + icp.align(*output_cloud); |
| 95 | + icp_transform = icp.getFinalTransformation().cast<double>().inverse(); |
| 96 | + |
| 97 | + // Convert ICP results and broadcast TF |
| 98 | + if (icp.hasConverged()) |
| 99 | + { |
| 100 | + cerr << "\nICP Score: " << icp.getFitnessScore() << endl; |
| 101 | + cerr << "ICP Transform:\n" << icp_transform << endl; |
39 | 102 |
|
40 | | - //icp_PCL_pub.publish(icp.getFinalTransformation()); |
| 103 | + ICP_SUCCESS = true; |
| 104 | + convert_icp_eigen_to_tf(icp_transform); |
41 | 105 |
|
42 | | - return (0); |
43 | | -} |
| 106 | + // Publish template point cloud |
| 107 | + template_msg.header.frame_id = "camera_depth_optical_frame"; |
| 108 | + pcl_pub.publish(output_msg); |
| 109 | + template_pub.publish(template_msg); |
44 | 110 |
|
45 | | -void rawPCL_cb(const sensor_msgs::PointCloud2::ConstPtr& msg) |
46 | | -{ |
47 | | - pcl::PCLPointCloud2 pcl_pc2; |
48 | | - pcl_conversions::toPCL(*msg,pcl_pc2); |
49 | | - pcl::fromPCLPointCloud2(pcl_pc2,*input_cuboid); |
50 | | - performICP(); |
| 111 | + // Convert to ROS data type |
| 112 | + pcl::toROSMsg(*output_cloud, output_msg); |
| 113 | + pcl::toROSMsg(*template_cuboid, template_msg); |
| 114 | + } |
51 | 115 | } |
52 | 116 |
|
53 | 117 | int main(int argc, char **argv) |
54 | 118 | { |
55 | | - ros::init(argc,argv,"iterative_closest_point"); |
| 119 | + // Init node |
| 120 | + ros::init(argc, argv, "iterative_closest_point"); |
56 | 121 | ros::NodeHandle nh; |
57 | | - //icp_PCL_pub = nh.advertise<geometry_msgs::>("iterative_closest_point", 1000); |
58 | | - ros::Subscriber raw_PCL_sub = nh.subscribe<sensor_msgs::PointCloud2>("/ground_plane_segmentation/points", 1000, rawPCL_cb); |
59 | 122 |
|
60 | | - if (pcl::io::loadPCDFile<pcl::PointXYZ> ("$/{workspaceFolder}/src/perception/cuboid_detection/templates/template_cuboid_L200_W100_H75.pcd", *template_cuboid) == -1) //* load the file |
61 | | - { |
62 | | - PCL_ERROR ("Couldn't read file test_pcd.pcd \n"); |
63 | | - return (-1); |
64 | | - } |
| 123 | + // Handle params |
| 124 | + nh.getParam("template_cuboid_path", template_cuboid_filename); |
| 125 | + cerr << "\nTemplate filename: " << template_cuboid_filename; |
65 | 126 |
|
66 | | - ros::spinOnce(); |
67 | | - return 0; |
| 127 | + // Subscribers |
| 128 | + ros::Subscriber pcl_sub = nh.subscribe<sensor_msgs::PointCloud2>("/ground_plane_segmentation/points", 1, icp_callback); |
| 129 | + |
| 130 | + // Publishers |
| 131 | + pcl_pub = nh.advertise<sensor_msgs::PointCloud2>("/icp/aligned_points", 1); |
| 132 | + template_pub = nh.advertise<sensor_msgs::PointCloud2>("/icp/template", 1); |
| 133 | + |
| 134 | + ros::spin(); |
68 | 135 | } |
0 commit comments