LeicaStateMachine.cpp
Go to the documentation of this file.
1 
18 #include <LeicaStateMachine.h>
19 #include <Filter.h>
20 #include <InitialAlignment.h>
21 #include <GICPAlignment.h>
22 #include <FODDetector.h>
23 #include <Viewer.h>
24 
25 typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloudRGB;
26 
27 StateMachine::StateMachine(PointCloudRGB::Ptr source_cloud, PointCloudRGB::Ptr target_cloud, ros::NodeHandle nh)
28  : nh_(nh),
29  source_cloud_(source_cloud),
30  target_cloud_(target_cloud),
31  source_cloud_filtered_(new PointCloudRGB),
32  target_cloud_filtered_(new PointCloudRGB)
33 {
34  source_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/source/cloud_aligned", 1);
35  target_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/target/cloud_filtered", 1);
36  fods_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("/source/fods_detected", 1);
37  n_fods_pub_ = nh_.advertise<std_msgs::Int16>("/source/num_of_fods_detected", 1);
38  cloud_transform_ = Eigen::Matrix4f::Identity();
39 }
40 
41 FilterState::FilterState(my_context ctx) : my_base(ctx)
42 {
43  ROS_INFO("Into FilterState");
44 
45  PointCloudRGB::Ptr source_cloud = context<StateMachine>().getSourceCloud();
46  PointCloudRGB::Ptr target_cloud = context<StateMachine>().getTargetCloud();
47 
48  // set params
49  double part_max_size = 4; // Larger side of the part
50  ros::param::get("/part_max_size", part_max_size);
51 
52  double floor_height = 0.35; // Maximum height to search for floor
53  ros::param::get("/floor_height", floor_height);
54 
55  const double INF = std::numeric_limits<double>::infinity();
56  Eigen::Vector3f part_center(INF, INF, INF); // Coordinates for part center
57  ros::param::get("/part_center_x", part_center[0]);
58  ros::param::get("/part_center_y", part_center[1]);
59  ros::param::get("/part_center_z", part_center[2]);
60 
61  double leaf_size_factor = 10;
62  ros::param::get("/leaf_size_factor", leaf_size_factor);
63  double target_res = Utils::computeCloudResolution(target_cloud);
64  double source_res = Utils::computeCloudResolution(source_cloud);
65  double leaf_size = leaf_size_factor * std::max(target_res, source_res);
66 
67  bool using_cad = false;
68  ros::param::get("/using_CAD", using_cad);
69 
70  // filter
71  PointCloudRGB::Ptr source_cloud_filtered(new PointCloudRGB);
72  PointCloudRGB::Ptr target_cloud_filtered(new PointCloudRGB);
73  PointCloudRGB::Ptr source_cloud_downsampled(new PointCloudRGB);
74  PointCloudRGB::Ptr target_cloud_downsampled(new PointCloudRGB);
75 
76  Filter source_cloud_filter(leaf_size, part_max_size, floor_height);
77  if(part_center[0]!=INF && part_center[1]!=INF && part_center[2]!=INF)
78  source_cloud_filter.setCloudCenter(part_center);
79  source_cloud_filter.run(source_cloud, source_cloud_filtered);
80  source_cloud_filter.downsampleCloud(source_cloud_filtered, source_cloud_downsampled);
81 
82  if(!using_cad) // source and target are sources
83  {
84  source_cloud_filter.run(target_cloud, target_cloud_filtered);
85  source_cloud_filter.downsampleCloud(target_cloud_filtered, target_cloud_downsampled);
86  }
87  else // target is CAD
88  {
89  Filter target_cloud_filter(leaf_size);
90  target_cloud_filter.run(target_cloud, target_cloud_filtered);
91  target_cloud_filter.downsampleCloud(target_cloud, target_cloud_downsampled);
92  }
93 
94  // store on machine filtered and downsampled clouds
95  context<StateMachine>().setTargetCloudFiltered(target_cloud_filtered);
96  context<StateMachine>().setSourceCloudFiltered(source_cloud_filtered);
97 
98  if (Utils::isValidCloud(source_cloud_downsampled) && Utils::isValidCloud(target_cloud_downsampled))
99  post_event(ValidEvent(source_cloud_downsampled, target_cloud_downsampled));
100  else
101  post_event(NoValidEvent());
102 }
103 
104 AlignState::AlignState(my_context ctx) : my_base(ctx)
105 {
106  ROS_INFO("Into AlignState");
107 
108  PointCloudRGB::Ptr source_cloud = context<StateMachine>().getSourceCloud();
109  PointCloudRGB::Ptr target_cloud = context<StateMachine>().getTargetCloud();
110  PointCloudRGB::Ptr aligned_cloud(new PointCloudRGB);
111 
112  double radius_factor = 1.4;
113  ros::param::get("/radius_factor", radius_factor);
114 
115  int align_method = 1;
116  ros::param::get("/align_method", align_method);
117 
118  // Perform initial alignment
119  InitialAlignment initial_alignment(target_cloud, source_cloud);
120 
121  initial_alignment.setMethod((AlignmentMethod)align_method);
122  initial_alignment.setRadiusFactor(radius_factor);
123 
124  initial_alignment.run();
125  initial_alignment.getAlignedCloud(aligned_cloud);
126 
127  // store transform value on StateMachine
128  context<StateMachine>().setCloudTransform(initial_alignment.getRigidTransform());
129  ROS_INFO("Transform result from pre-alignment");
130  Utils::printTransform(initial_alignment.getRigidTransform());
131 
132  if (Utils::isValidCloud(aligned_cloud))
133  post_event(ValidEvent(aligned_cloud));
134  else
135  post_event(NoValidEvent());
136 }
137 
138 GICPState::GICPState(my_context ctx) : my_base(ctx)
139 {
140  ROS_INFO("Into GICPState");
141 
142  PointCloudRGB::Ptr source_cloud = context<StateMachine>().getSourceCloud();
143  PointCloudRGB::Ptr target_cloud = context<StateMachine>().getTargetCloud();
144  PointCloudRGB::Ptr aligned_cloud(new PointCloudRGB);
145 
146  bool compute_cov = false;
147  ros::param::get("/gicp_with_covariances", compute_cov);
148 
149  GICPAlignment gicp_alignment(target_cloud, source_cloud, compute_cov);
150  gicp_alignment.run();
151  gicp_alignment.getAlignedCloud(aligned_cloud);
152 
153  if (!Utils::isValidTransform(gicp_alignment.getFineTransform()))
154  {
155  ROS_ERROR("Nan on transform");
156  post_event(NoValidEvent());
157  }
158  else
159  {
160  // update and store transform value on StateMachine
161  ROS_INFO("Updated transform:");
162  Eigen::Matrix4f final_transform = gicp_alignment.getFineTransform() * context<StateMachine>().getCloudTransform();
163  Utils::printTransform(final_transform);
164  context<StateMachine>().setCloudTransform(final_transform);
165 
166  if (Utils::isValidCloud(aligned_cloud))
167  post_event(ValidEvent(aligned_cloud));
168  else
169  post_event(NoValidEvent());
170  }
171 }
172 
173 FODDetectionState::FODDetectionState(my_context ctx) : my_base(ctx)
174 {
175  PointCloudRGB::Ptr source_cloud = context<StateMachine>().getSourceCloudFiltered();
176  PointCloudRGB::Ptr target_cloud = context<StateMachine>().getTargetCloudFiltered();
177  PointCloudRGB::Ptr substracted_cloud(new PointCloudRGB);
178 
179  // apply tf to source orig cloud
180  Eigen::Matrix4f final_transform = context<StateMachine>().getCloudTransform();
181  Utils::printTransform(final_transform);
182  pcl::transformPointCloud(*source_cloud, *source_cloud, final_transform);
183 
184  double voxelize_factor = 3;
185  ros::param::get("/voxelize_factor", voxelize_factor);
186  ROS_INFO("Received from launch voxelize factor: %f", voxelize_factor);
187 
188  double th = 4e-3 * voxelize_factor;
189  Filter::removeFromCloud(source_cloud, target_cloud, th, substracted_cloud);
190 
191  double min_fod_points = 3;
192  ros::param::get("/min_fod_points", min_fod_points);
193 
194  int num_of_fods = 0;
195  std::vector<PointCloudRGB::Ptr> fods_cloud_array;
196 
197  if (Utils::isValidCloud(substracted_cloud))
198  {
199  // Viewer::visualizePointCloud<pcl::PointXYZRGB>(substracted_cloud);
200  double cluster_tolerance = th * 100;
201  FODDetector fod_detector(substracted_cloud, cluster_tolerance, min_fod_points);
202  fod_detector.clusterPossibleFODs();
203 
204  // create a pointcloud for each cluster
205  num_of_fods = fod_detector.fodIndicesToPointCloud(fods_cloud_array);
206  }
207  else
208  {
209  // an empty substracted cloud means no fods on piece
210  ROS_INFO("No difference between source and target cloud");
211  substracted_cloud = nullptr;
212  fods_cloud_array.push_back(substracted_cloud);
213  }
214  ROS_INFO("Detected %d fods", num_of_fods);
215  post_event(ValidFODEvent(num_of_fods, fods_cloud_array));
216 }
217 
218 
219 PublishState::PublishState(my_context ctx) : my_base(ctx)
220 {
221  sensor_msgs::PointCloud2 target_cloud_msg, source_cloud_msg;
222 
223  PointCloudRGB::Ptr source_cloud = context<StateMachine>().getSourceCloudFiltered();
224  PointCloudRGB::Ptr target_cloud = context<StateMachine>().getTargetCloudFiltered();
225 
226  // Convert target cloud and aligned cloud to ROS data type
227  Utils::cloudToROSMsg(source_cloud, source_cloud_msg);
228  Utils::cloudToROSMsg(target_cloud, target_cloud_msg);
229 
230  // Publish clouds
231  context<StateMachine>().target_pub_.publish(target_cloud_msg);
232  context<StateMachine>().source_pub_.publish(source_cloud_msg);
233 
234  // If detected fods on source cloud store them
235  int n_fods = context<StateMachine>().getNFODs();
236  if (n_fods>0)
237  {
238  std_msgs::Int16 n_fods_msg;
239  PointCloudRGB::Ptr fods_cloud(new PointCloudRGB);
240 
241  std::vector<PointCloudRGB::Ptr> fods_cloud_array = context<StateMachine>().getFODCloudArray();
242  for(int i=0; i<n_fods; i++)
243  {
244  /* sensor_msgs::PointCloud2 cloud_msg;
245  Utils::cloudToROSMsg(fods_cloud_array[i], cloud_msg);
246  context<StateMachine>().fods_pub_.publish(cloud_msg); */
247  *fods_cloud += *fods_cloud_array[i];
248  }
249  sensor_msgs::PointCloud2 cloud_msg;
250  Utils::cloudToROSMsg(fods_cloud, cloud_msg);
251  context<StateMachine>().fods_pub_.publish(cloud_msg);
252 
253  n_fods_msg.data = n_fods;
254  context<StateMachine>().n_fods_pub_.publish(n_fods_msg);
255  }
256 }
static void printTransform(const Eigen::Matrix4f &transform)
Print on console transform values with matrix format.
Definition: Utils.cpp:176
pcl::PointCloud< pcl::PointXYZRGB > PointCloudRGB
static bool isValidTransform(Eigen::Matrix4f transform)
Check whether transform contains valid data and is not NaN.
Definition: Utils.cpp:71
int fodIndicesToPointCloud(std::vector< PointCloudRGB::Ptr > &cloud_array)
Save each cluster (possible FOD) in a pcl::PointCloudRGB. Give back an array of all generated clouds...
Definition: FODDetector.cpp:60
PublishState(my_context ctx)
Definition: Filter.h:25
void run()
Perform GICP alignment.
AlignmentMethod
Define possible Alignment methods.
void getAlignedCloud(PointCloudRGB::Ptr aligned_cloud)
Get the aligned cloud object.
Perform a fine alignment from source to target cloud with Generalized Iterative Closest Point...
Definition: GICPAlignment.h:32
ros::Publisher target_pub_
pcl::PointCloud< pcl::PointXYZRGB > PointCloudRGB
AlignState(my_context ctx)
static bool isValidCloud(PointCloudXYZ::Ptr cloud)
Check whether cloud contains data and is not empty.
Definition: Utils.cpp:46
FODDetectionState(my_context ctx)
GICPState(my_context ctx)
ros::Publisher fods_pub_
ros::Publisher source_pub_
Eigen::Matrix4f cloud_transform_
void run()
Perform initial alignment.
ros::NodeHandle nh_
ROSCPP_DECL bool get(const std::string &key, std::string &s)
Eigen::Matrix4f getRigidTransform()
Get the rigid transform object.
static void cloudToROSMsg(PointCloudRGB::Ptr cloud, sensor_msgs::PointCloud2 &cloud_msg, const std::string &frameid="world")
Convert XYZRGB cloud to PointCloud2.
Definition: Utils.cpp:100
#define ROS_INFO(...)
void clusterPossibleFODs()
Extract cluster indices from input cloud with resolution set. Each cluster is a possible FOD...
Definition: FODDetector.cpp:45
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void getAlignedCloud(PointCloudRGB::Ptr aligned_cloud)
Get the aligned cloud object.
static double computeCloudResolution(PointCloudXYZ::Ptr cloud)
Obtain the resolution of the cloud.
Definition: Utils.cpp:114
ros::Publisher n_fods_pub_
Eigen::Matrix4f getFineTransform()
Get the fine transform object.
void setMethod(AlignmentMethod method)
Set the AlignmentMethod object.
void setRadiusFactor(double align_factor)
Set the Radius Factor object.
StateMachine(PointCloudRGB::Ptr source_cloud, PointCloudRGB::Ptr target_cloud, ros::NodeHandle nh)
FilterState(my_context ctx)
#define ROS_ERROR(...)


leica_point_cloud_processing
Author(s): Ines Lara Sicilia
autogenerated on Fri Feb 5 2021 03:20:30