fx8_driver_nodelet.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2013, NIPPON CONTROL SYSTEM Corporation
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  *
18  * * Neither the name of the NIPPON CONTROL SYSTEM Corporation nor
19  * the names of its contributors may be used to endorse or promote
20  * products derived from this software without specific prior
21  * written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  *****************************************************************************/
37 
39 #include <sensor_msgs/Image.h>
41 #include <sensor_msgs/PointCloud2.h>
42 #include "fx8_driver_nodelet.h"
43 #include <signal.h>
44 
45 namespace infinisoleil
46 {
48  :device_(FX8_INVALID_HANDLE),
49  diagnostics_enable_(true),
50  device_running_(false),
51  target_frequency_(0.0)
52 {
53  scan_.xy_data.surface_count = 0 ;
54  scan_.xy_data.surface = NULL;
55  memset(&config_, 0, sizeof(Config));
56 }
57 
59 {
61 
62  driver_thread_ = boost::thread(boost::bind(&FX8DriverNodelet::driverThreadFunc, this));
63 }
64 
66 {
67  device_running_ = false;
68 
69  /*
70  * First, shut down reconfigure server. It prevents destructor of
71  * reconfigure server from stopping. It occurs often at killing
72  * nodelet manager and FX8DriverNodelet by SIGINT when these are
73  * launched by same launch file. And, this problem seems to occur
74  * at unloading FX8DriverNodelet by request of unloading it before
75  * shutting down nodelet manager.
76  */
78 
79  driver_thread_.join();
80 
82 }
83 
85 {
88 
89  // Initialize publisher.
90  range_publisher_ = nh.advertise<sensor_msgs::Image>("range_image", 1000);
91  ir_publisher_ = nh.advertise<sensor_msgs::Image>("ir_image", 1000);
92  point_cloud_publisher_ = nh.advertise<sensor_msgs::PointCloud2>("point_cloud", 1000);
93 
94  // Get frame id of topics.
95  param_nh.param("range_frame_id", scan_.range_frame_id, std::string("range_image"));
96  param_nh.param("ir_frame_id", scan_.ir_frame_id, std::string("ir_image"));
97  param_nh.param("point_cloud_frame_id", scan_.point_cloud_frame_id, std::string("point_cloud"));
98 
99  // Setup dynamic reconfigure server.
100  initializeReconfigureServer(param_nh);
101 
102  // Read flag of diagnostics_enable.
103  param_nh.param("diagnostics_enable", diagnostics_enable_, true);
106 }
107 
109 {
111 
112  // Shut down publisher.
116 
117  // Shut down diagnostic updater.
118  diagnostic_updater_.reset();
119 
120  // Remove parameter form parameter server.
121  param_nh.deleteParam("diagnostics_enable");
122  param_nh.deleteParam("hostname");
123  param_nh.deleteParam("port_number");
124  param_nh.deleteParam("connect_timeout");
125  param_nh.deleteParam("send_timeout");
126  param_nh.deleteParam("receive_timeout");
127  param_nh.deleteParam("measure_point_x");
128  param_nh.deleteParam("measure_point_y");
129  param_nh.deleteParam("swing_fs");
130  param_nh.deleteParam("swing_ss");
131  param_nh.deleteParam("xy_surface_count");
132  param_nh.deleteParam("frame_cycle");
133  param_nh.deleteParam("measure_mode");
134  param_nh.deleteParam("max_measure_mode");
135  param_nh.deleteParam("xy_serial_number");
136  param_nh.deleteParam("logic_version");
137  param_nh.deleteParam("firm_version");
138  param_nh.deleteParam("product_number");
139  param_nh.deleteParam("range_frame_id");
140  param_nh.deleteParam("ir_frame_id");
141  param_nh.deleteParam("point_cloud_frame_id");
142 }
143 
145 {
146  reconfigure_server_.reset(new ReconfigureServer(param_nh));
147  reconfigure_server_->setCallback(boost::bind(&FX8DriverNodelet::reconfigureFX8Callback, this, _1, _2));
148 }
149 
151 {
152  reconfigure_server_.reset();
153 }
154 
156 {
157  boost::mutex::scoped_lock lock(mutex_diagnostics_);
159  diagnostic_updater_->add("Received Error Code from Infinisoleil",
161  diagnostic_updater_->add("Infinisoleil Error Info",
162  boost::bind(&FX8DriverNodelet::fillDiagnosticStatusByErrorInfo, this, _1));
163 
165  new TopicDiagnostic("range_image", *diagnostic_updater_,
167 
169  new TopicDiagnostic("ir_image", *diagnostic_updater_,
171 
173  new TopicDiagnostic("point_cloud", *diagnostic_updater_,
175 }
176 
178 {
179  bool result = false;
180  // Initialize device.
181  if (!initializeDevice())
182  {
183  NODELET_ERROR("Failed to initialize Infinisoleil.");
184  // Wait for publishing diagnostics.
185  sleep(1);
186  goto Exit;
187  }
188 
189  NODELET_INFO("Succeeded in initializing Infinisoleil.");
190 
191  // Start fx8 ranging.
192  if (!startScan())
193  goto Exit;
194 
195  device_running_ = true;
196  NODELET_INFO("Start scan.");
197 
198  spin();
199 
200  result = true;
201 Exit:
202  if (diagnostic_updater_ && diagnostics_enable_ && !result)
203  {
204  diagnostic_updater_->force_update();
205  }
206 
207  shutdownDevice();
208  return;
209 }
210 
212 {
214  FX8Handle device = FX8_INVALID_HANDLE;
215  std::string hostname("");
216  int port_number = 0;
217  int measure_mode = 0;
218  int connect_timeout = 0;
219  int send_timeout = 0;
220  int receive_timeout = 0;
221  FX8SensorInfo sensor_info;
222  FX8XyData xy_data;
223  xy_data.surface_count = 0;
224  xy_data.surface = NULL;
225 
226  int ret = FX8_ERROR_SUCCESS;
227  std::stringstream ss;
228 
229  // Get initial parameters.
230  param_nh.param("hostname", hostname, std::string("192.168.0.80"));
231  param_nh.param("port_number", port_number, 50000);
232  param_nh.param("measure_mode", measure_mode, 0);
233  param_nh.param("connect_timeout", connect_timeout, 10000);
234  if (connect_timeout < 0)
235  {
236  NODELET_WARN("Failed to set connect timeout. %d is less than 0. Set default value (10000).",
237  connect_timeout);
238  connect_timeout = 10000;
239  }
240 
241  param_nh.param("send_timeout", send_timeout, 3000);
242  if (send_timeout < 0)
243  {
244  NODELET_WARN(
245  "Failed to set send timeout. %d is less than 0. Set default value (3000).", send_timeout);
246  send_timeout = 3000;
247  }
248  param_nh.param("receive_timeout", receive_timeout, 5000);
249  if (receive_timeout < 0)
250  {
251  NODELET_WARN(
252  "Failed to set receive timeout. %d is less than 0. Set default value (5000).", receive_timeout);
253  receive_timeout = 5000;
254  }
255 
257  diagnostic_updater_->setHardwareIDf("Infinisoleil:[%s:%d]", hostname.c_str(), port_number);
258 
259  // Create instance.
260  ret = fx8_create_handle(&device);
261  if (!device || ret != FX8_ERROR_SUCCESS)
262  {
263  ss << "Failed to create Infinisoleil handle.";
264  goto Exit;
265  }
266 
267  // Connect to device.
268  ret = fx8_set_connect_timeout(device, connect_timeout);
269  if (ret != FX8_ERROR_SUCCESS)
270  {
271  ss << "Failed to set connect timeout.";
272  goto Exit;
273  }
274  connect_timeout = fx8_get_connect_timeout(device);
275 
276  ret = fx8_connect(device, hostname.c_str(), static_cast<unsigned short>(port_number));
277  if (ret != FX8_ERROR_SUCCESS)
278  {
279  ss << "Failed to connect to Infinisoleil. [" << hostname << ':' << static_cast<unsigned short>(port_number) << ']';
280  goto Exit;
281  }
282  NODELET_INFO("Infinisoleil is connected. [%s:%d]", hostname.c_str(), static_cast<unsigned short>(port_number));
283 
284  // Set measure mode.
285  if (!setDeviceMeasureMode(device, static_cast<FX8MeasureMode>(measure_mode), &sensor_info, &xy_data))
286  {
287  goto Exit;
288  }
289 
290  // Set timeout.
291  ret = fx8_set_send_timeout(device, send_timeout);
292  if (ret != FX8_ERROR_SUCCESS)
293  {
294  ss << "Failed to set send timeout.";
295  goto Exit;
296  }
297  send_timeout = fx8_get_send_timeout(device);
298  ret = fx8_set_receive_timeout(device, receive_timeout);
299  if (ret != FX8_ERROR_SUCCESS)
300  {
301  ss << "Failed to set receive timeout.";
302  goto Exit;
303  }
304  receive_timeout = fx8_get_receive_timeout(device);
305 
306  // Set device data.
307  device_ = device;
308  memcpy(&config_.sensor_info, &sensor_info, sizeof(FX8SensorInfo));
309  scan_.xy_data.surface_count = xy_data.surface_count;
310  scan_.xy_data.surface = xy_data.surface;
311  target_frequency_ = 1 / (config_.sensor_info.frame_cycle / 1000.0);
313  {
314  unsigned char* product_number = config_.sensor_info.product_number;
315  diagnostic_updater_->setHardwareIDf("%c%c%c%c%c%c%c%c", product_number[0], product_number[1], product_number[2],
316  product_number[3], product_number[4], product_number[5], product_number[6], product_number[7]);
317  }
318 
319  // Write parameters to parameter server.
320  param_nh.setParam("hostname", hostname);
321  param_nh.setParam("port_number", port_number);
322  param_nh.setParam("connect_timeout", connect_timeout);
323  param_nh.setParam("send_timeout", send_timeout);
324  param_nh.setParam("receive_timeout", receive_timeout);
325  param_nh.setParam("diagnostics_enable", diagnostics_enable_);
326  param_nh.setParam("range_frame_id", scan_.range_frame_id);
327  param_nh.setParam("ir_frame_id", scan_.ir_frame_id);
328  param_nh.setParam("point_cloud_frame_id", scan_.point_cloud_frame_id);
330 
331  return true;
332 
333 Exit:
334  if (ret != FX8_ERROR_SUCCESS)
335  {
336  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
337  << std::setfill('0') << ret << ']';
338  NODELET_ERROR("%s", ss.str().c_str());
339  }
340  {
341  boost::mutex::scoped_lock lock(mutex_diagnostics_);
342  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
343  }
344 
345  if (xy_data.surface != NULL)
346  fx8_free_xy_data(&xy_data);
347 
348  return false;
349 }
350 
352 {
353  if (device_)
354  {
355  fx8_stop_ranging(device_);
356  fx8_disconnect(device_);
357  fx8_close_handle(device_);
358  device_ = FX8_INVALID_HANDLE;
359  if (scan_.xy_data.surface != NULL)
360  fx8_free_xy_data(&scan_.xy_data);
361  NODELET_DEBUG("Infinisoleil closed.");
362  }
363 }
364 
366  FX8SensorInfo* sensor_info, FX8XyData* xy_data)
367 {
368  FX8XyData current_xy_data;
369  current_xy_data.surface_count = 0;
370  current_xy_data.surface = NULL;
371  FX8SensorInfo current_sensor_info;
372 
373  // Get current FX8SensorInfo.
374  if (!getDeviceSensorInfo(device, &current_sensor_info, &current_xy_data))
375  return false;
376 
377  int ret = fx8_set_measure_mode(device, measure_mode);
378  if (ret != FX8_ERROR_SUCCESS)
379  {
380  std::stringstream ss;
381  ss << "Failed to set measure mode. (Measure mode[0 - "
382  << static_cast<unsigned int>(current_sensor_info.max_measure_mode) << "])";
383  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
384  << std::setfill('0') << ret << ']';
385  NODELET_ERROR("%s", ss.str().c_str());
386  {
387  boost::mutex::scoped_lock lock(mutex_diagnostics_);
388  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
389  }
390  if (current_xy_data.surface != NULL)
391  fx8_free_xy_data(&current_xy_data);
392  return false;
393  }
394 
395  if (current_xy_data.surface != NULL)
396  fx8_free_xy_data(&current_xy_data);
397 
398  // Get new FX8SensorInfo.
399  if (!getDeviceSensorInfo(device, sensor_info, xy_data))
400  return false;
401 
402  return true;
403 }
404 
405 bool FX8DriverNodelet::getDeviceSensorInfo(const FX8Handle device, FX8SensorInfo* sensor_info, FX8XyData* xy_data)
406 {
407  // Set FX8 properties.
408  int ret = fx8_get_sensor_property(device, NULL, sensor_info, xy_data);
409  if (ret != FX8_ERROR_SUCCESS)
410  {
411  std::stringstream ss;
412  ss << "Failed to get current sensor info.";
413  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
414  << std::setfill('0') << ret << ']';
415  NODELET_ERROR("%s", ss.str().c_str());
416  {
417  boost::mutex::scoped_lock lock(mutex_diagnostics_);
418  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
419  }
420  return false;
421  }
422 
423  return true;
424 }
425 
427 {
428  char buf[128];
429  unsigned char* xy_serial_number = config_.sensor_info.xy_serial_number;
430  unsigned char* firm_version = config_.sensor_info.firm_version;
431  unsigned char* logic_version = config_.sensor_info.logic_version;
432  unsigned char* product_number = config_.sensor_info.product_number;
433 
435 
436  // Update parameter server.
437  param_nh.setParam("measure_point_x", config_.sensor_info.measure_point.x);
438  param_nh.setParam("measure_point_y", config_.sensor_info.measure_point.y);
439  param_nh.setParam("swing_fs", config_.sensor_info.swing_fs);
440  param_nh.setParam("swing_ss", config_.sensor_info.swing_ss);
441  param_nh.setParam("xy_surface_count", config_.sensor_info.xy_surface_count);
442  param_nh.setParam("frame_cycle", config_.sensor_info.frame_cycle);
443  param_nh.setParam("measure_mode", config_.sensor_info.measure_mode);
444  param_nh.setParam("max_measure_mode", config_.sensor_info.max_measure_mode);
445 
446  sprintf(buf, "%02X.%02X.%02X.%02X", xy_serial_number[0], xy_serial_number[1], xy_serial_number[2],
447  xy_serial_number[3]);
448  param_nh.setParam("xy_serial_number", buf);
449 
450  sprintf(buf, "%u.%u.%u", logic_version[0], logic_version[1], logic_version[2]);
451  param_nh.setParam("logic_version", buf);
452 
453  sprintf(buf, "%u.%u.%u", firm_version[0], firm_version[1], firm_version[2]);
454  param_nh.setParam("firm_version", buf);
455 
456  sprintf(buf, "%c%c%c%c%c%c%c%c", product_number[0], product_number[1], product_number[2], product_number[3],
457  product_number[4], product_number[5], product_number[6], product_number[7]);
458  param_nh.setParam("product_number", buf);
459 
460  return;
461 }
462 
464 {
465  int ret = FX8_ERROR_SUCCESS;
466  std::stringstream ss;
467  // Start waiting for scan data of FX8.
468  ret = fx8_set_receive_range_data_event_handler(device_, receiveScanDataCallback, reinterpret_cast<void*>(this));
469  if (ret != FX8_ERROR_SUCCESS)
470  {
471  ss << "Failed to set receive range data event handler.";
472  goto Exit;
473  }
474  ret = fx8_set_receive_error_info_event_handler(device_, receiveErrorCodeCallback, reinterpret_cast<void*>(this));
475  if (ret != FX8_ERROR_SUCCESS)
476  {
477  ss << "Failed to set receive error info event handler.";
478  goto Exit;
479  }
480 
481  ret = fx8_start_ranging(device_);
482  if (ret != FX8_ERROR_SUCCESS)
483  {
484  ss << "Failed to start ranging.";
485  goto Exit;
486  }
487 
488  return true;
489 
490 Exit:
491  if (ret != FX8_ERROR_SUCCESS)
492  {
493  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
494  << std::setfill('0') << ret << ']';
495  NODELET_ERROR("%s", ss.str().c_str());
496  {
497  boost::mutex::scoped_lock lock(mutex_diagnostics_);
498  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
499  }
500  }
501  return false;
502 }
503 
505 {
506  while (device_running_ && ros::ok())
507  {
509  diagnostic_updater_->update();
510 
511  boost::this_thread::sleep(boost::posix_time::milliseconds(5));
512  }
513 }
514 
515 void FX8DriverNodelet::publishScanData(const unsigned char* scan_data, size_t size)
516 {
517  if (!device_running_)
518  return;
519 
520  // Lock scan.
521  boost::mutex::scoped_lock lock(mutex_scan_);
522 
523  // Obtained scan data size.
524  size_t header_size = 11;
525  size_t internal_data_size = 64;
526  size_t obtained_data_size = size - header_size - internal_data_size;
527 
528  // Calculated scan data size by FX8SensorInfo.
529  size_t scan_data_size_per_point = 3; // bytes
530  size_t calculated_data_size = config_.sensor_info.measure_point.x
531  * config_.sensor_info.measure_point.y * scan_data_size_per_point;
532  if (obtained_data_size != calculated_data_size)
533  {
534  NODELET_ERROR("Obtained data is not data of current measure mode.");
535  return;
536  }
537 
538  scan_.scan_data.assign(scan_data, &scan_data[size]);
539 
540  // Compare scan data
541  unsigned char surf = scan_.scan_data[6];
542  if (scan_.xy_data.surface_count <= static_cast<int>(surf))
543  {
544  NODELET_ERROR("Publish no message. Surface number is out of range.");
545  return;
546  }
547 
548  // Create subscribed messages.
549  sensor_msgs::ImagePtr range_msg = createRangeImageMessage();
550  sensor_msgs::ImagePtr ir_msg = createIRImageMessage();
551  sensor_msgs::PointCloud2Ptr point_cloud_msg = createPointCloudMessage();
552 
553  // Return, if subscribed message is nothing.
554  if (!range_msg && !ir_msg && !point_cloud_msg)
555  {
556  NODELET_DEBUG("Publish no messages. Subscribed topic is nothing.");
557  return;
558  }
559 
560  // Set publish data.
561  setMessageData(range_msg, ir_msg, point_cloud_msg, surf);
562 
563  // Publish message.
564  if (range_msg)
565  {
566  range_publisher_.publish(range_msg);
569  NODELET_DEBUG("Publish range_image.");
570  }
571  if (ir_msg)
572  {
573  ir_publisher_.publish(ir_msg);
576  NODELET_DEBUG("Publish ir_image.");
577  }
578  if (point_cloud_msg)
579  {
580  point_cloud_publisher_.publish(point_cloud_msg);
583  NODELET_DEBUG("Publish point_cloud.");
584  }
585 }
586 
588 {
589  sensor_msgs::ImagePtr msg;
591  return msg;
592 
593  msg.reset(new sensor_msgs::Image());
594  msg->header.stamp = latest_update_time_;
595  msg->header.frame_id = scan_.range_frame_id;
596  msg->height = config_.sensor_info.measure_point.y;
597  msg->width = config_.sensor_info.measure_point.x;
599  msg->step = sizeof(unsigned short);
600  msg->data.resize(msg->height * msg->width * msg->step);
601 
602  return msg;
603 }
604 
606 {
607  sensor_msgs::ImagePtr msg;
608  if (ir_publisher_.getNumSubscribers() <= 0)
609  return msg;
610 
611  msg.reset(new sensor_msgs::Image());
612  msg->header.stamp = latest_update_time_;
613  msg->header.frame_id = scan_.ir_frame_id;
614  msg->height = config_.sensor_info.measure_point.y;
615  msg->width = config_.sensor_info.measure_point.x;
617  msg->step = sizeof(unsigned short);
618  msg->data.resize(msg->height * msg->width * msg->step);
619 
620  return msg;
621 }
622 
623 sensor_msgs::PointCloud2Ptr FX8DriverNodelet::createPointCloudMessage()
624 {
625  sensor_msgs::PointCloud2Ptr msg;
627  return msg;
628 
629  msg.reset(new sensor_msgs::PointCloud2());
630  msg->header.stamp = latest_update_time_;
631  msg->header.frame_id = scan_.point_cloud_frame_id;
632  msg->height = config_.sensor_info.measure_point.y;
633  msg->width = config_.sensor_info.measure_point.x;
634  msg->fields.resize(3);
635  msg->fields[0].name = "x";
636  msg->fields[0].offset = 0;
637  msg->fields[0].datatype = 7;
638  msg->fields[0].count = 1;
639  msg->fields[1].name = "y";
640  msg->fields[1].offset = 4;
641  msg->fields[1].datatype = 7;
642  msg->fields[1].count = 1;
643  msg->fields[2].name = "z";
644  msg->fields[2].offset = 8;
645  msg->fields[2].datatype = 7;
646  msg->fields[2].count = 1;
647  msg->point_step = sizeof(float) * msg->fields.size();
648  msg->row_step = msg->width * msg->point_step;
649  msg->data.resize(msg->height * msg->row_step);
650  msg->is_dense = false;
651 
652  return msg;
653 }
654 
656  sensor_msgs::ImagePtr range_msg, sensor_msgs::ImagePtr ir_msg, sensor_msgs::PointCloud2Ptr point_cloud_msg,
657  unsigned char surface_number)
658 {
659  //Extract publish image and create point cloud from scan data.
660  unsigned short* range_data = NULL;
661  if (range_msg)
662  range_data = reinterpret_cast<unsigned short*>(&range_msg->data[0]);
663  unsigned short* ir_data = NULL;
664  if (ir_msg)
665  ir_data = reinterpret_cast<unsigned short*>(&ir_msg->data[0]);
666  float* point_cloud_data = NULL;
667  if (point_cloud_msg)
668  point_cloud_data = reinterpret_cast<float*>(&point_cloud_msg->data[0]);
669 
670  FX8XyDataSurface* surface = &scan_.xy_data.surface[surface_number];
671  unsigned short intensity;
672  unsigned short range;
673 
674  for (int i = 0; i < surface->element_count; ++i)
675  {
676  FX8XyDataElement* element = &surface->element[i];
677  int index = element->y * config_.sensor_info.measure_point.x + element->x;
678 
679  extractRangeAndIntensityFromScanData(i, &scan_.scan_data[0], &range, &intensity);
680 
681  if (ir_data)
682  ir_data[index] = intensity;
683 
684  if (range_data)
685  range_data[index] = range;
686 
687  if (point_cloud_data)
688  {
689  int point_cloud_index = index * 3;
690  point_cloud_data[point_cloud_index] = static_cast<float>(range * element->bx) / 1000;
691  point_cloud_data[point_cloud_index + 1] = static_cast<float>(range * element->by) / 1000;
692  point_cloud_data[point_cloud_index + 2] = static_cast<float>(range * element->bz) / 1000;
693  }
694  }
695 }
696 
697 void FX8DriverNodelet::extractRangeAndIntensityFromScanData(int index, const unsigned char* scan_data,
698  unsigned short* range, unsigned short* intensity)
699 {
700  // 9 bytes are offset to skip header of scan data packets.
701  unsigned int scan_data_offset = 9;
702 
703  /*
704  * A scan data is a set of range and intensity data and each data is 12 bit
705  * aligned data. A scan data is 3 bytes (24 bit) aligned data.
706  */
707  unsigned int scan_data_size = 3;
708 
709  unsigned int target_index = index * scan_data_size + scan_data_offset;
710 
711  // Range data is output in digit. A digit is equal to 4 millimeter.
712  unsigned int range_per_digit = 4;
713 
714  // Extract intensity data from scan data.
715  *intensity = (scan_data[target_index] << 4) | ((scan_data[target_index + 1] & 0xF0) >> 4);
716 
717  // Extract range data from scan data.
718  *range = ((scan_data[target_index + 1] & 0x0F) << 8) | (scan_data[target_index + 2]);
719 
720  // Convert from digit to millimeter.
721  *range *= range_per_digit;
722 }
723 
725 {
726  boost::mutex::scoped_lock lock(mutex_diagnostics_);
727  if (error_info_.empty())
728  {
729  status.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "No Infinisoleil Error Info");
730  return;
731  }
732 
733  char key_buf[256];
734 
735  status.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Infinisoleil Error Info");
736  while(!error_info_.empty())
737  {
738  std::vector<ErrorInfo>::iterator error_info_it = error_info_.begin();
739  sprintf(key_buf, "%.lf", error_info_it->first.toSec());
740  status.add(key_buf, error_info_it->second.c_str());
741  NODELET_DEBUG("Infinisoleil Error Information.[%s:%s]", key_buf, error_info_it->second.c_str());
742  error_info_.erase(error_info_it);
743  }
744 }
745 
748 {
749  boost::mutex::scoped_lock lock(mutex_diagnostics_);
750  if (error_code_.empty())
751  {
752  status.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "No Infinisoleil Received Error Code");
753  return;
754  }
755 
756  char key_buf[256];
757  char value_buf[256];
758  bool is_warn = true;
759 
760  while (!error_code_.empty())
761  {
762  std::vector<ReceivedErrorCodePackets>::iterator error_code_it = error_code_.begin();
763  unsigned char* data = &(error_code_it->second[0]);
764 
765  // Set error code.
766  unsigned int condition = (data[6] << 8) | data[7];
767  unsigned int error_code[6];
768  error_code[0] = static_cast<unsigned int>(data[8]);
769  error_code[1] = static_cast<unsigned int>(data[9]);
770  error_code[2] = static_cast<unsigned int>(data[10]);
771  error_code[3] = static_cast<unsigned int>(data[11]);
772  error_code[4] = static_cast<unsigned int>(data[12]);
773  error_code[5] = static_cast<unsigned int>(data[13]);
774  sprintf(value_buf,
775  "Error:0x%04X, Code(0):0x%02X, Code(1):0x%02X, Code(2):0x%02X, Code(3):0x%02X, Code(4):0x%02X, Code(5):0x%02X",
776  condition, error_code[0], error_code[1], error_code[2], error_code[3], error_code[4], error_code[5]);
777  sprintf(key_buf, "%.6lf", error_code_it->first.toSec());
778  status.add(key_buf, value_buf);
779 
780  if (condition & 0xC000)
781  {
782  NODELET_WARN("Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
783  }
784  else
785  {
786  NODELET_ERROR("Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
787  is_warn = false;
788  }
789  error_code_.erase(error_code_it);
790  }
791 
792  if (is_warn)
793  {
794  status.summaryf(diagnostic_msgs::DiagnosticStatus::WARN, "Infinisoleil Received Error Code");
795  }
796  else
797  {
798  status.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Infinisoleil Received Error Code");
799  }
800 }
801 
802 void FX8DriverNodelet::addDiagnostics(const unsigned char* error_data, size_t size)
803 {
804  // Lock diagnostics.
805  boost::mutex::scoped_lock lock(mutex_diagnostics_);
806 
807  // Copy error data.
808  error_code_.push_back(ReceivedErrorCodePackets(ros::Time::now(), std::vector<unsigned char>()));
809  error_code_.back().second.assign(error_data, &error_data[size]);
810 }
811 
812 void FX8DriverNodelet::reconfigureFX8Callback(FX8Config config, uint32_t level)
813 {
814  int ret = FX8_ERROR_SUCCESS;
815  std::stringstream ss;
817 
818  // Check initialization of FX8.
819  if (device_ == FX8_INVALID_HANDLE)
820  return;
821 
822  // Check connection to FX8.
823  if (!fx8_get_connected(device_))
824  {
825  NODELET_WARN("Failed to reconfigure. Infinisoleil is disconnected.");
826  return;
827  }
828 
829  // Reconfigure measure mode of FX8.
830  FX8MeasureMode measure_mode = static_cast<FX8MeasureMode>(config.measure_mode);
831  if (measure_mode == config_.sensor_info.measure_mode)
832  {
833  NODELET_INFO("No need reconfiguration. Current measure_mode is %d.", measure_mode);
834  return;
835  }
836 
837  ret = fx8_stop_ranging(device_);
838  if (ret != FX8_ERROR_SUCCESS)
839  {
840  ss << "Failed to stop ranging.";
841  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
842  << std::setfill('0') << ret << ']';
843  NODELET_ERROR("%s", ss.str().c_str());
844  {
845  boost::mutex::scoped_lock lock(mutex_diagnostics_);
846  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
847  }
848  return;
849  }
850 
851  FX8SensorInfo sensor_info;
852  FX8XyData xy_data;
853  xy_data.surface_count = 0;
854  xy_data.surface = NULL;
855  // Lock scan.
856  {
857  boost::mutex::scoped_lock lock(mutex_scan_);
858 
859  // Set FX8 measure mode.
860  if (!setDeviceMeasureMode(device_, measure_mode, &sensor_info, &xy_data))
861  {
862  if (xy_data.surface != NULL)
863  fx8_free_xy_data(&xy_data);
864  return;
865  }
866 
867  if (scan_.xy_data.surface != NULL)
868  fx8_free_xy_data(&scan_.xy_data);
869  scan_.xy_data.surface = xy_data.surface;
870  scan_.xy_data.surface_count = xy_data.surface_count;
871  memcpy(&config_.sensor_info, &sensor_info, sizeof(FX8SensorInfo));
872  }
873  {
874  boost::mutex::scoped_lock lock(mutex_diagnostics_);
875  target_frequency_ = 1 / (config_.sensor_info.frame_cycle / 1000.0);
876  }
878 
879  // Restart ranging.
880  ret = fx8_start_ranging(device_);
881  if (ret != FX8_ERROR_SUCCESS)
882  {
883  ss << "Failed to restart ranging.";
884  ss << " [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
885  << std::setfill('0') << ret << ']';
886  NODELET_ERROR("%s", ss.str().c_str());
887  {
888  boost::mutex::scoped_lock lock(mutex_diagnostics_);
889  error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
890  }
891  return;
892  }
893  return;
894 }
895 
897 {
899 }
900 
901 void FX8DriverNodelet::receiveScanDataCallback(const unsigned char* scan_data, size_t size, void* user_data)
902 {
903  FX8DriverNodelet* driver = reinterpret_cast<FX8DriverNodelet*>(user_data);
904  driver->updateTime();
905  driver->publishScanData(scan_data, size);
906 }
907 
908 void FX8DriverNodelet::receiveErrorCodeCallback(const unsigned char* error_data, size_t size, void* user_data)
909 {
910  FX8DriverNodelet* driver = reinterpret_cast<FX8DriverNodelet*>(user_data);
911  driver->addDiagnostics(error_data, size);
912 }
913 } // namespace infinisoleil_fx8
914 
boost::mutex mutex_scan_
Mutex for scan data.
msg
fx8_xy_data_surface FX8XyDataSurface
Surface of device xy data.
fx8_sensor_info FX8SensorInfo
Sensor information.
#define NODELET_ERROR(...)
std::vector< ErrorInfo > error_info_
Error information of FX8.
sensor_msgs::ImagePtr createRangeImageMessage()
Create message for range_image topic.
#define NODELET_WARN(...)
void publish(const boost::shared_ptr< M > &message) const
dynamic_reconfigure::Server< infinisoleil::FX8Config > ReconfigureServer
Dynamic reconfigure server.
fx8_handle FX8Handle
Device handle.
void shutdownDevice()
Shut down device.
virtual ~FX8DriverNodelet()
Destructor.
void extractRangeAndIntensityFromScanData(int index, const unsigned char *scan_data, unsigned short *range, unsigned short *intensity)
Extract range and intensity data from scan data packets.
bool deleteParam(const std::string &key) const
sensor_msgs::ImagePtr createIRImageMessage()
Create message for ir_image topic.
void shutdownReconfigureServer()
Shut down reconfigure server.
std::vector< ReceivedErrorCodePackets > error_code_
Received error code from FX8.
data
void addDiagnostics(const unsigned char *error_data, size_t size)
Add obtained error data.
TopicDiagnosticPtr point_cloud_diagnostic_frequency_
Topic diagnostic for point cloud.
static void receiveScanDataCallback(const unsigned char *scan_data, size_t size, void *user_data)
Receive FX8 scan data.
ros::NodeHandle & getPrivateNodeHandle() const
fx8_xy_data_element FX8XyDataElement
Element of device xy data.
void summaryf(unsigned char lvl, const char *format,...)
ros::Publisher ir_publisher_
Publisher of IR image.
std::string range_frame_id
Range frame id.
Config config_
Configurations of FX8.
boost::shared_ptr< diagnostic_updater::Updater > diagnostic_updater_
Diagnostic updater.
diagnostic_updater::HeaderlessTopicDiagnostic TopicDiagnostic
Topic diagnostic.
ros::Publisher point_cloud_publisher_
Publisher of point cloud.
FX8Handle device_
Handle of FX8.
void reconfigureFX8Callback(FX8Config config, uint32_t level)
Reconfigure FX8.
std::pair< ros::Time, std::vector< unsigned char > > ReceivedErrorCodePackets
Received FX8 error code.
bool setDeviceMeasureMode(const FX8Handle device, const FX8MeasureMode measure_mode, FX8SensorInfo *sensor_info, FX8XyData *xy_data)
Set measure mode of FX8.
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void spin()
Spin driver thread.
void fillDiagnosticStatusByErrorInfo(diagnostic_updater::DiagnosticStatusWrapper &status)
Fill diagnostic status by error information of FX8.
ROSCPP_DECL bool ok()
const std::string TYPE_16UC1
std::string point_cloud_frame_id
Point cloud frame id.
boost::mutex mutex_diagnostics_
Mutex for diagnostics.
FX8SensorInfo sensor_info
Sensor information.
ros::Time latest_update_time_
Timestamp for topics.
static void receiveErrorCodeCallback(const unsigned char *error_data, size_t size, void *user_data)
Receive FX8 Error code.
virtual void onInit()
Initialize FX8 driver.
sensor_msgs::PointCloud2Ptr createPointCloudMessage()
Create message for point_cloud topic.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
fx8_measure_mode FX8MeasureMode
Device measure mode.
Scan scan_
Scan data from FX8.
ros::NodeHandle & getNodeHandle() const
void driverThreadFunc()
FX8 driver thread.
boost::thread driver_thread_
FX8 driver thread.
bool device_running_
Flag of running device.
bool initializeDevice()
Initialize and connect to FX8.
void publishScanData(const unsigned char *scan_data, size_t size)
Publish scan data.
void fillDiagnosticStatusByReceivedErrorCode(diagnostic_updater::DiagnosticStatusWrapper &status)
Fill diagnostic status by received error code of FX8.
TopicDiagnosticPtr ir_image_diagnostic_frequency_
Topic diagnostic for IR image.
#define NODELET_INFO(...)
uint32_t getNumSubscribers() const
void setMessageData(sensor_msgs::ImagePtr range_msg, sensor_msgs::ImagePtr ir_msg, sensor_msgs::PointCloud2Ptr point_cloud_msg, unsigned char surface_number)
Set data of range image, IR image and point cloud.
Namespace containing driver.
void initializeReconfigureServer(ros::NodeHandle param_nh)
Initialize reconfigure server.
void updateTime()
Update timestamp.
static Time now()
std::pair< ros::Time, std::string > ErrorInfo
Error information.
void initializeNodelet()
Initialize nodelet.
boost::shared_ptr< ReconfigureServer > reconfigure_server_
Server for reconfiguration.
void outputDeviceParameters()
Output FX8 parameters to parameter server.
double target_frequency_
Target frame rate of topics.
void add(const std::string &key, const T &val)
void setupDiagnostics()
Setup diagnostics.
TopicDiagnosticPtr range_image_diagnostic_frequency_
Topic diagnostic for range image.
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void shutdownNodelet()
Shut down nodelet.
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
#define NODELET_DEBUG(...)
bool diagnostics_enable_
Flag to enable diagnostics.
ros::Publisher range_publisher_
Publisher of range image.
fx8_xy_data FX8XyData
Device xy data.
FX8 driver nodelet class.
bool getDeviceSensorInfo(const FX8Handle device, FX8SensorInfo *sensor_info, FX8XyData *xy_data)
Get FX8SensorInfo and set these.


infinisoleil
Author(s): NCS 3D Sensing Team <3d-sensing@nippon-control-system.co.jp>
autogenerated on Mon Jun 10 2019 13:34:27