scanning.cpp
Go to the documentation of this file.
1 /************************************************
2 Scanner
3 This file which operate scanning represents
4 one node of the entire demonstrator
5 ************************************************/
6 
7 // ROS headers
8 #include <ros/ros.h>
9 #include <ros/service.h>
10 #include <tf/transform_listener.h>
13 #include <std_msgs/String.h>
15 #include <moveit_msgs/ExecuteKnownTrajectory.h>
16 #include <yaml-cpp/exceptions.h>
17 #include <yaml-cpp/mark.h>
18 #include "yaml_utils.h"
19 #include <fanuc_grinding_scanning/ScanningService.h> // Description of the Service we will use
20 #include <fanuc_grinding_publish_meshfile/PublishMeshfileService.h>
21 
22 // PCL headers
23 #include <pcl/point_cloud.h>
24 #include <pcl/common/colors.h>
25 #include <pcl/common/transforms.h>
26 #include <pcl/io/davidsdk_grabber.h>
27 #include <pcl/io/ply_io.h>
28 #include <pcl/filters/voxel_grid.h>
29 
30 // PCL davidSDK object pointer
31 pcl::DavidSDKGrabber::Ptr davidsdk_ptr;
32 
34 typedef pcl::PointCloud<PointXYZ> PointCloudXYZ;
35 
38 
41 
47 bool executeJointState(const std::vector<double> joint_states)
48 {
49  // Give the joint state to execute
50  group->setJointValueTarget(joint_states);
51  if (group->move() == false)
52  return false;
53  return true;
54 }
55 
62 bool moveRobotScan(fanuc_grinding_scanning::ScanningService::Request &req,
63  fanuc_grinding_scanning::ScanningService::Response &res)
64 {
65  std_msgs::String status;
66  status.data = "Parsing YAML trajectory file";
67  status_pub->publish(status);
68 
69  // Parse YAML File
70  const std::string filename= req.YamlFileName;
71  std::string reference_frame;
72  std::string tool_reference;
73  std::vector<double> joint;
74  std::vector<std::vector<double> > joint_list;
75  try
76  {
77  YAML::Node yamlFile;
78  yaml_parser::yamlNodeFromFileName(filename, yamlFile);
79 
80  // Parse "reference" node in YAML file
81  // Just say no node if no node -->exception
82  const YAML::Node & reference_node = yaml_parser::parseNode(yamlFile, "reference");
83  if(!yamlFile["reference"])
84  {
85  YAML::Mark mark;
86  YAML::Exception yaml_exception(mark, "Cannot parse 'reference' node");
87  throw yaml_exception;
88  }
89 
90  // Parse "reference_frame" tag in "reference" node in YAML file
91  yaml_parser::parseString(reference_node, "reference_frame", reference_frame);
92 
93  // Parse "tool" node in YAML file
94  const YAML::Node & tool_node = yaml_parser::parseNode(yamlFile, "tool");
95  if(!yamlFile["tool"])
96  {
97  YAML::Mark mark;
98  YAML::Exception yaml_exception(mark,"Cannot parse 'tool' node");
99  throw yaml_exception;
100  }
101 
102  // Parse "tool_reference" tag in "tool" node in YAML file
103  yaml_parser::parseString(tool_node, "tool_reference", tool_reference);
104 
105  // Parse "joint_values" node in YAML file
106  const YAML::Node & joint_node = yaml_parser::parseNode(yamlFile, "joint_values");
107  if(!yamlFile["joint_values"])
108  {
109  YAML::Mark mark;
110  YAML::Exception yaml_exception(mark,"Cannot parse 'joint_values' node");
111  throw yaml_exception;
112  }
113 
114  // Parse all "joint" tag in "joint_values" node in YAML file
115  for(unsigned j = 0; j < joint_node.size(); ++ j)
116  {
117  yaml_parser::parseVectorD(joint_node[j], "joint", joint);
118  joint_list.push_back(joint);
119  }
120  }
121  catch(const YAML::Exception &e)
122  {
123  res.ReturnStatus = false;
124  res.ReturnMessage = "Problem occurred during parsing yaml file for joint values, problem is: " + e.msg;
125  return true;
126  }
127 
128  // Parse YAML file in order to obtain sls_2_calibration matrix
129  status.data = "Parsing YAML calibration file";
130  status_pub->publish(status);
131  const std::string filenameCalibration= req.YamlCalibrationFileName;
132  std::vector<double> n_vector;
133  std::vector<double> o_vector;
134  std::vector<double> a_vector;
135  std::vector<double> p_vector;
136  try
137  {
138  YAML::Node yamlFileCalibration;
139  yaml_parser::yamlNodeFromFileName(filenameCalibration, yamlFileCalibration);
140 
141  // Parse all tags in "sls_2_calibration_values" node in YAML file
142  const YAML::Node& sls_2_node = yaml_parser::parseNode(yamlFileCalibration, "sls_2_calibration_values");
143  if(!yamlFileCalibration["sls_2_calibration_values"])
144  {
145  YAML::Mark mark;
146  YAML::Exception yaml_exception(mark,"Cannot parse 'sls_2_calibration_values'");
147  throw yaml_exception;
148  }
149  yaml_parser::parseVectorD(sls_2_node[0], "n", n_vector);
150  yaml_parser::parseVectorD(sls_2_node[1], "o", o_vector);
151  yaml_parser::parseVectorD(sls_2_node[2], "a", a_vector);
152  yaml_parser::parseVectorD(sls_2_node[3], "p", p_vector);
153  }
154  catch (const YAML::Exception &e)
155  {
156  res.ReturnStatus = false;
157  res.ReturnMessage = "Problem parsing YAML calibration file, error:\n" + e.msg;
158  return true;
159  }
160 
161  // We fill the calibration_sls2 transformation matrix with values contained in the YAML file
162  Eigen::Affine3d calib_sls_2;
163  calib_sls_2.matrix() <<
164  n_vector[0], o_vector[0], a_vector[0], p_vector[0],
165  n_vector[1], o_vector[1], a_vector[1], p_vector[1],
166  n_vector[2], o_vector[2], a_vector[2], p_vector[2],
167  n_vector[3], o_vector[3], a_vector[3], p_vector[3];
168 
169  // We have to invert this matrix in order to give point cloud in a correct frame
170  calib_sls_2 = calib_sls_2.inverse();
171 
172  // Declaration of ROS listener
173  tf::TransformListener listener;
174  // Grab transformation between /sls_2_frame and tool0
175  tf::StampedTransform transform_sls_2_tool0;
176  Eigen::Affine3d calibration;
177 
178  listener.waitForTransform("/base", "/sls_2_frame", ros::Time(0), ros::Duration(1.5));
179  listener.lookupTransform("/tool0", "/sls_2_frame", ros::Time(0), transform_sls_2_tool0);
180  tf::transformTFToEigen(transform_sls_2_tool0, calibration);
181 
182  // Connect SLS-2 Camera
183  status.data = "Connecting to SLS-2 server...";
184  status_pub->publish(status);
185  std::string davidSDK_ip = req.SLS2IpAddress;
186  std::string davidSDK_server_name = req.SLS2ServerName;
187 
188  // Connect to the SLS_2
189  davidsdk_ptr.reset(new pcl::DavidSDKGrabber);
190  ROS_INFO_STREAM("scanning: Trying to connect to DavidSDK IP \"" << davidSDK_ip << "\" and server name \"" << davidSDK_server_name << "\"");
191  davidsdk_ptr->connect(davidSDK_ip);
192  if (!davidsdk_ptr->isConnected())
193  {
194  ROS_ERROR_STREAM("scanning: Cannot connect to the David SLS-2 scanner (IP: " << davidSDK_ip << ")");
195  ROS_ERROR_STREAM("scanning: Server name: " << davidSDK_server_name);
196  res.ReturnStatus = false;
197  res.ReturnMessage = "Cannot connect to the David SLS-2 scanner";
198  return true;
199  }
200  davidsdk_ptr->setLocalAndRemotePaths("/var/tmp/davidsdk/", "\\\\" + davidSDK_server_name + "\\davidsdk\\");
201  davidsdk_ptr->setFileFormatToSTL(); // Best performance
202 
203  status.data = "SLS-2 connected";
204  status_pub->publish(status);
205 
206  // Create entire point cloud
207  PointCloudXYZ::Ptr stacked_point_cloud (new PointCloudXYZ());
208 
209  for(unsigned k = 0; k < joint_list.size(); ++k)
210  {
211  if(!executeJointState(joint_list[k]))
212  {
213  res.ReturnStatus = false;
214  res.ReturnMessage = "Could not move the robot for scanning pose " + boost::lexical_cast<std::string>(k);
215  return true;
216  }
217  else
218  {
219  // Grab robot transform
220  tf::StampedTransform transform;
221  sleep(1);
222  listener.waitForTransform("/base", "/sls_2_frame", ros::Time::now(), ros::Duration(1.5));
223  listener.lookupTransform("/base_link", "/tool0", ros::Time(0), transform);
224  Eigen::Affine3d matrix_transform;
225  tf::transformTFToEigen(transform, matrix_transform);
226 
227  // Grab point cloud
228  PointCloudXYZ::Ptr point_cloud (new PointCloudXYZ());
229  if (!davidsdk_ptr->grabSingleCloud(*point_cloud))
230  {
231  res.ReturnStatus = false;
232  res.ReturnMessage = "Could not capture point cloud";
233  return true;
234  }
235 
236  status.data = "Point cloud " + boost::lexical_cast<std::string>(k + 1) +
237  "/" + boost::lexical_cast<std::string>(joint_list.size()) + " captured";
238  status_pub->publish(status);
239 
240  // Resize point cloud in meters
241  Eigen::Affine3d resize_pc_meters(Eigen::Affine3d::Identity());
242  resize_pc_meters.matrix() *= 0.001;
243  // Transform point cloud in order into the robot frame
244  Eigen::Affine3d transformation_pc(Eigen::Affine3d::Identity());
245  transformation_pc = matrix_transform * calibration * calib_sls_2 * resize_pc_meters;
246  pcl::transformPointCloud(*point_cloud, *point_cloud, transformation_pc);
247 
248  // Store it into global point cloud
249  *stacked_point_cloud += *point_cloud;
250  }
251  }
252 
253  // Apply a voxel grid to make entire point cloud homogeneous
254  status.data = "Applying voxel grid on point clouds";
255  status_pub->publish(status);
256 
257  pcl::VoxelGrid<PointXYZ> sor;
258  sor.setLeafSize (req.VoxelGridLeafSize, req.VoxelGridLeafSize, req.VoxelGridLeafSize);
259  sor.setInputCloud (stacked_point_cloud);
260  sor.filter (*stacked_point_cloud);
261 
262  if(stacked_point_cloud->size() == 0)
263  {
264  res.ReturnStatus = false;
265  res.ReturnMessage = "Filtered point cloud is empty";
266  return true;
267  }
268 
269  // Save the point cloud with CAD meshname and a suffix
270  if (req.CADName.size() < 4)
271  {
272  res.ReturnStatus = false;
273  res.ReturnMessage = "CAD mesh name is too short!";
274  return true;
275  }
276 
277  res.ScanMeshName = req.CADName.substr(0, req.CADName.size() - 4) + "_scan.ply";
278  pcl::io::savePLYFileBinary(res.ScanMeshName, *stacked_point_cloud);
279 
280  // Call publish_meshfile service
281  fanuc_grinding_publish_meshfile::PublishMeshfileService srv_publish_meshfile;
282  ros::ServiceClient publish_meshfile_service =
283  node->serviceClient<fanuc_grinding_publish_meshfile::PublishMeshfileService>("publish_meshfile_service");
284 
285  // Publish final point cloud
286  status.data = "Publishing final point cloud";
287  status_pub->publish(status);
288  srv_publish_meshfile.request.MeshName = res.ScanMeshName;
289  srv_publish_meshfile.request.MarkerName = req.MarkerName;
290  srv_publish_meshfile.request.PosX =
291  srv_publish_meshfile.request.PosY =
292  srv_publish_meshfile.request.PosZ =
293  srv_publish_meshfile.request.RotX =
294  srv_publish_meshfile.request.RotY =
295  srv_publish_meshfile.request.RotZ = 0.0;
296  srv_publish_meshfile.request.RotW = 1.0;
297  srv_publish_meshfile.request.ColorR = 75 / 255.0;
298  srv_publish_meshfile.request.ColorG = 75 / 255.0;
299  srv_publish_meshfile.request.ColorB = 130 / 255.0;
300  srv_publish_meshfile.request.ColorA = 1.0;
301  publish_meshfile_service.call(srv_publish_meshfile);
302 
303  res.ReturnStatus = true;
304  boost::filesystem::path p(res.ScanMeshName);
305  res.ReturnMessage = "Scan succeeded, file:\n" + p.filename().string();
306  return true;
307 }
308 
309 int main(int argc, char **argv)
310 {
311  ros::init(argc, argv, "scanning");
312  node.reset(new ros::NodeHandle);
313 
314  // Initialize move group
315  group.reset(new moveit::planning_interface::MoveGroupInterface("manipulator"));
316  group->setPlannerId("RRTConnectkConfigDefault");
317  group->setPoseReferenceFrame("/base");
318  group->setPlanningTime(2);
319 
320  status_pub.reset(new ros::Publisher);
321  *status_pub = node->advertise<std_msgs::String>("scanning_status", 1);
322 
323  // Create service server and wait for incoming requests
324  ros::ServiceServer service = node->advertiseService("scanning_service", moveRobotScan);
326  spinner.start();
327 
328  while (node->ok())
329  {
330  sleep(1);
331  ros::spin();
332  }
333  spinner.stop();
334  return 0;
335 }
pcl::PointCloud< PointXYZ > PointCloudXYZ
Definition: scanning.cpp:34
filename
int main(int argc, char **argv)
Definition: scanning.cpp:309
pcl::PointXYZ PointXYZ
Definition: scanning.cpp:33
bool parseVectorD(const YAML::Node &node, char const *var_name, std::vector< double > &var_value)
Definition: yaml_utils.h:61
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
bool moveRobotScan(fanuc_grinding_scanning::ScanningService::Request &req, fanuc_grinding_scanning::ScanningService::Response &res)
Definition: scanning.cpp:62
pcl::DavidSDKGrabber::Ptr davidsdk_ptr
Definition: scanning.cpp:31
void spinner()
ROSCPP_DECL void spin(Spinner &spinner)
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
const YAML::Node parseNode(const YAML::Node &node, char const *var_name)
Definition: yaml_utils.h:78
boost::shared_ptr< ros::NodeHandle > node
Definition: scanning.cpp:36
bool parseString(const YAML::Node &node, char const *var_name, std::string &var_value)
Definition: yaml_utils.h:41
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
#define ROS_INFO_STREAM(args)
boost::shared_ptr< ros::Publisher > status_pub
Definition: scanning.cpp:40
static Time now()
void transformTFToEigen(const tf::Transform &t, Eigen::Isometry3d &e)
#define ROS_ERROR_STREAM(args)
bool executeJointState(const std::vector< double > joint_states)
Definition: scanning.cpp:47
bool yamlNodeFromFileName(std::string filename, YAML::Node &ynode)
Definition: yaml_utils.h:92
boost::shared_ptr< moveit::planning_interface::MoveGroupInterface > group
Definition: scanning.cpp:37


scanning
Author(s): Kévin Bolloré, Victor Lamoine - Institut Maupertuis
autogenerated on Thu Dec 19 2019 03:38:24