fx8_driver_nodelet.cpp
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  *  Copyright (C) 2013, NIPPON CONTROL SYSTEM Corporation
00004  *  All rights reserved.
00005  *  
00006  *  Redistribution and use in source and binary forms, with or without
00007  *  modification, are permitted provided that the following conditions
00008  *  are met:
00009  *  
00010  *    * Redistributions of source code must retain the above copyright
00011  *      notice, this list of conditions and the following disclaimer.
00012  *   
00013  *    * Redistributions in binary form must reproduce the above
00014  *      copyright notice, this list of conditions and the following
00015  *      disclaimer in the documentation and/or other materials provided
00016  *      with the distribution.
00017  *   
00018  *    * Neither the name of the NIPPON CONTROL SYSTEM Corporation nor
00019  *      the names of its contributors may be used to endorse or promote
00020  *      products derived from this software without specific prior
00021  *      written permission.
00022  *  
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  *****************************************************************************/
00037 
00038 #include <pluginlib/class_list_macros.h>
00039 #include <sensor_msgs/Image.h>
00040 #include <sensor_msgs/image_encodings.h>
00041 #include <sensor_msgs/PointCloud2.h>
00042 #include "fx8_driver_nodelet.h"
00043 #include <signal.h>
00044 
00045 namespace infinisoleil
00046 {
00047 FX8DriverNodelet::FX8DriverNodelet()
00048   :device_(FX8_INVALID_HANDLE),
00049    diagnostics_enable_(true),
00050    device_running_(false),
00051    target_frequency_(0.0)
00052 {
00053   scan_.xy_data.surface_count = 0 ;
00054   scan_.xy_data.surface = NULL;
00055   memset(&config_, 0, sizeof(Config));
00056 }
00057 
00058 void FX8DriverNodelet::onInit()
00059 {
00060   initializeNodelet();
00061 
00062   driver_thread_ = boost::thread(boost::bind(&FX8DriverNodelet::driverThreadFunc, this));
00063 }
00064 
00065 FX8DriverNodelet::~FX8DriverNodelet()
00066 {
00067   device_running_ = false;
00068 
00069   /*
00070    *  First, shut down reconfigure server. It prevents destructor of
00071    *  reconfigure server from stopping. It occurs often at killing
00072    *  nodelet manager and FX8DriverNodelet by SIGINT when these are
00073    *  launched by same launch file. And, this problem seems to occur
00074    *  at unloading FX8DriverNodelet by request of unloading it before
00075    *  shutting down nodelet manager.
00076    */
00077   shutdownReconfigureServer();
00078 
00079   driver_thread_.join();
00080 
00081   shutdownNodelet();
00082 }
00083 
00084 void FX8DriverNodelet::initializeNodelet()
00085 {
00086   ros::NodeHandle nh = getNodeHandle();
00087   ros::NodeHandle param_nh = getPrivateNodeHandle();
00088  
00089   // Initialize publisher.
00090   range_publisher_ = nh.advertise<sensor_msgs::Image>("range_image", 1000);
00091   ir_publisher_ = nh.advertise<sensor_msgs::Image>("ir_image", 1000);
00092   point_cloud_publisher_ = nh.advertise<sensor_msgs::PointCloud2>("point_cloud", 1000);
00093 
00094   // Get frame id of topics.
00095   param_nh.param("range_frame_id", scan_.range_frame_id, std::string("range_image"));
00096   param_nh.param("ir_frame_id", scan_.ir_frame_id, std::string("ir_image"));
00097   param_nh.param("point_cloud_frame_id", scan_.point_cloud_frame_id, std::string("point_cloud"));
00098 
00099   // Setup dynamic reconfigure server.
00100   initializeReconfigureServer(param_nh);
00101 
00102   // Read flag of diagnostics_enable.
00103   param_nh.param("diagnostics_enable", diagnostics_enable_, true);
00104   if (diagnostics_enable_)
00105     setupDiagnostics();
00106 }
00107 
00108 void FX8DriverNodelet::shutdownNodelet()
00109 {
00110   ros::NodeHandle param_nh = getPrivateNodeHandle();
00111 
00112   // Shut down publisher.
00113   range_publisher_.shutdown();
00114   ir_publisher_.shutdown();
00115   point_cloud_publisher_.shutdown();
00116 
00117   // Shut down diagnostic updater.
00118   diagnostic_updater_.reset();
00119 
00120   // Remove parameter form parameter server. 
00121   param_nh.deleteParam("diagnostics_enable");
00122   param_nh.deleteParam("hostname");
00123   param_nh.deleteParam("port_number");
00124   param_nh.deleteParam("connect_timeout");
00125   param_nh.deleteParam("send_timeout");
00126   param_nh.deleteParam("receive_timeout");
00127   param_nh.deleteParam("measure_point_x");
00128   param_nh.deleteParam("measure_point_y");
00129   param_nh.deleteParam("swing_fs");
00130   param_nh.deleteParam("swing_ss");
00131   param_nh.deleteParam("xy_surface_count");
00132   param_nh.deleteParam("frame_cycle");
00133   param_nh.deleteParam("measure_mode");
00134   param_nh.deleteParam("max_measure_mode");
00135   param_nh.deleteParam("xy_serial_number");
00136   param_nh.deleteParam("logic_version");
00137   param_nh.deleteParam("firm_version");
00138   param_nh.deleteParam("product_number");
00139   param_nh.deleteParam("range_frame_id");
00140   param_nh.deleteParam("ir_frame_id");
00141   param_nh.deleteParam("point_cloud_frame_id");
00142 }
00143 
00144 void FX8DriverNodelet::initializeReconfigureServer(ros::NodeHandle param_nh)
00145 {
00146   reconfigure_server_.reset(new ReconfigureServer(param_nh));
00147   reconfigure_server_->setCallback(boost::bind(&FX8DriverNodelet::reconfigureFX8Callback, this, _1, _2));
00148 }
00149 
00150 void FX8DriverNodelet::shutdownReconfigureServer()
00151 {
00152   reconfigure_server_.reset();
00153 }
00154 
00155 void FX8DriverNodelet::setupDiagnostics()
00156 {
00157   boost::mutex::scoped_lock lock(mutex_diagnostics_);
00158   diagnostic_updater_.reset(new diagnostic_updater::Updater());
00159   diagnostic_updater_->add("Received Error Code from Infinisoleil",
00160     boost::bind(&FX8DriverNodelet::fillDiagnosticStatusByReceivedErrorCode, this, _1));
00161   diagnostic_updater_->add("Infinisoleil Error Info",
00162     boost::bind(&FX8DriverNodelet::fillDiagnosticStatusByErrorInfo, this, _1));
00163 
00164   range_image_diagnostic_frequency_.reset(
00165     new TopicDiagnostic("range_image", *diagnostic_updater_,
00166       diagnostic_updater::FrequencyStatusParam(&target_frequency_, &target_frequency_, 0.25)));
00167 
00168   ir_image_diagnostic_frequency_.reset(
00169     new TopicDiagnostic("ir_image", *diagnostic_updater_,
00170       diagnostic_updater::FrequencyStatusParam(&target_frequency_, &target_frequency_, 0.25)));
00171 
00172   point_cloud_diagnostic_frequency_.reset(
00173     new TopicDiagnostic("point_cloud", *diagnostic_updater_,
00174       diagnostic_updater::FrequencyStatusParam(&target_frequency_, &target_frequency_, 0.25)));
00175 }
00176 
00177 void FX8DriverNodelet::driverThreadFunc()
00178 { 
00179   bool result = false;
00180   // Initialize device.
00181   if (!initializeDevice())
00182   {
00183     NODELET_ERROR("Failed to initialize Infinisoleil.");
00184     // Wait for publishing diagnostics.
00185     sleep(1);
00186     goto Exit;
00187   }
00188 
00189   NODELET_INFO("Succeeded in initializing Infinisoleil.");
00190 
00191   // Start fx8 ranging.
00192   if (!startScan())
00193     goto Exit;
00194 
00195   device_running_ = true;
00196   NODELET_INFO("Start scan.");
00197 
00198   spin();
00199 
00200   result = true;
00201 Exit:
00202   if (diagnostic_updater_ && diagnostics_enable_ && !result)
00203   {
00204     diagnostic_updater_->force_update();
00205   }
00206 
00207   shutdownDevice();
00208   return;
00209 }
00210 
00211 bool FX8DriverNodelet::initializeDevice()
00212 {
00213   ros::NodeHandle param_nh = getPrivateNodeHandle();
00214   FX8Handle device = FX8_INVALID_HANDLE;
00215   std::string hostname("");
00216   int port_number = 0;
00217   int measure_mode = 0;
00218   int connect_timeout = 0;
00219   int send_timeout = 0;
00220   int receive_timeout = 0;
00221   FX8SensorInfo sensor_info;
00222   FX8XyData xy_data;
00223   xy_data.surface_count = 0;
00224   xy_data.surface = NULL;
00225 
00226   int ret = FX8_ERROR_SUCCESS;
00227   std::stringstream ss;
00228 
00229   // Get initial parameters.
00230   param_nh.param("hostname", hostname, std::string("192.168.0.80"));
00231   param_nh.param("port_number", port_number, 50000);
00232   param_nh.param("measure_mode", measure_mode, 0);
00233   param_nh.param("connect_timeout", connect_timeout, 10000);
00234   if (connect_timeout < 0)
00235   {
00236     NODELET_WARN("Failed to set connect timeout. %d is less than 0. Set default value (10000).",
00237       connect_timeout);
00238       connect_timeout = 10000;
00239   }
00240 
00241   param_nh.param("send_timeout", send_timeout, 3000);
00242   if (send_timeout < 0)
00243   {
00244     NODELET_WARN(
00245       "Failed to set send timeout. %d is less than 0. Set default value (3000).", send_timeout);
00246       send_timeout = 3000;
00247   }
00248   param_nh.param("receive_timeout", receive_timeout, 5000);
00249   if (receive_timeout < 0)
00250   {
00251     NODELET_WARN(
00252       "Failed to set receive timeout. %d is less than 0. Set default value (5000).", receive_timeout);
00253       receive_timeout = 5000;
00254   }
00255 
00256   if (diagnostics_enable_ && diagnostic_updater_)
00257     diagnostic_updater_->setHardwareIDf("Infinisoleil:[%s:%d]", hostname.c_str(), port_number);
00258 
00259   // Create instance.
00260   ret = fx8_create_handle(&device);
00261   if (!device || ret != FX8_ERROR_SUCCESS)
00262   {
00263     ss << "Failed to create Infinisoleil handle.";
00264     goto Exit;
00265   }
00266 
00267   // Connect to device.
00268   ret = fx8_set_connect_timeout(device, connect_timeout);
00269   if (ret != FX8_ERROR_SUCCESS)
00270   {
00271     ss << "Failed to set connect timeout.";
00272     goto Exit;
00273   }
00274   connect_timeout = fx8_get_connect_timeout(device);
00275 
00276   ret = fx8_connect(device, hostname.c_str(), static_cast<unsigned short>(port_number));
00277   if (ret != FX8_ERROR_SUCCESS)
00278   {
00279     ss << "Failed to connect to Infinisoleil. [" << hostname << ':' << static_cast<unsigned short>(port_number) << ']';
00280     goto Exit;
00281   }
00282   NODELET_INFO("Infinisoleil is connected. [%s:%d]", hostname.c_str(), static_cast<unsigned short>(port_number));
00283 
00284   // Set measure mode.
00285   if (!setDeviceMeasureMode(device, static_cast<FX8MeasureMode>(measure_mode), &sensor_info, &xy_data))
00286   {
00287     goto Exit;
00288   }
00289 
00290   // Set timeout.
00291   ret = fx8_set_send_timeout(device, send_timeout);
00292   if (ret != FX8_ERROR_SUCCESS)
00293   {
00294     ss << "Failed to set send timeout.";
00295     goto Exit;
00296   }
00297   send_timeout = fx8_get_send_timeout(device);
00298   ret = fx8_set_receive_timeout(device, receive_timeout);
00299   if (ret != FX8_ERROR_SUCCESS)
00300   {
00301     ss << "Failed to set receive timeout.";
00302     goto Exit;
00303   }
00304   receive_timeout = fx8_get_receive_timeout(device);
00305 
00306   // Set device data.
00307   device_ = device;
00308   memcpy(&config_.sensor_info, &sensor_info, sizeof(FX8SensorInfo));
00309   scan_.xy_data.surface_count = xy_data.surface_count;
00310   scan_.xy_data.surface = xy_data.surface;
00311   target_frequency_ = 1 / (config_.sensor_info.frame_cycle / 1000.0);
00312   if (diagnostics_enable_ && diagnostic_updater_)
00313   {
00314     unsigned char* product_number = config_.sensor_info.product_number;
00315     diagnostic_updater_->setHardwareIDf("%c%c%c%c%c%c%c%c", product_number[0], product_number[1], product_number[2],
00316       product_number[3], product_number[4], product_number[5], product_number[6], product_number[7]);
00317    }
00318 
00319   // Write parameters to parameter server.
00320   param_nh.setParam("hostname", hostname);
00321   param_nh.setParam("port_number", port_number);
00322   param_nh.setParam("connect_timeout", connect_timeout);
00323   param_nh.setParam("send_timeout", send_timeout);
00324   param_nh.setParam("receive_timeout", receive_timeout);
00325   param_nh.setParam("diagnostics_enable", diagnostics_enable_);
00326   param_nh.setParam("range_frame_id", scan_.range_frame_id);
00327   param_nh.setParam("ir_frame_id", scan_.ir_frame_id);
00328   param_nh.setParam("point_cloud_frame_id", scan_.point_cloud_frame_id);
00329   outputDeviceParameters();
00330 
00331   return true;
00332 
00333 Exit:
00334   if (ret != FX8_ERROR_SUCCESS)
00335   {
00336     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00337       << std::setfill('0') << ret << ']';
00338     NODELET_ERROR("%s", ss.str().c_str());
00339   }
00340   {
00341     boost::mutex::scoped_lock lock(mutex_diagnostics_);
00342     error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00343   }
00344 
00345   if (xy_data.surface != NULL)
00346     fx8_free_xy_data(&xy_data);
00347 
00348   return false;
00349 }
00350 
00351 void FX8DriverNodelet::shutdownDevice()
00352 {
00353   if (device_)
00354   {
00355     fx8_stop_ranging(device_);
00356     fx8_disconnect(device_);
00357     fx8_close_handle(device_);
00358     device_ = FX8_INVALID_HANDLE;
00359     if (scan_.xy_data.surface != NULL)
00360       fx8_free_xy_data(&scan_.xy_data);
00361     NODELET_DEBUG("Infinisoleil closed.");
00362   }
00363 }
00364 
00365 bool FX8DriverNodelet::setDeviceMeasureMode(const FX8Handle device, const FX8MeasureMode measure_mode,
00366   FX8SensorInfo* sensor_info, FX8XyData* xy_data)
00367 {
00368   FX8XyData current_xy_data;
00369   current_xy_data.surface_count = 0;
00370   current_xy_data.surface = NULL;
00371   FX8SensorInfo current_sensor_info;
00372 
00373   // Get current FX8SensorInfo.
00374   if (!getDeviceSensorInfo(device, &current_sensor_info, &current_xy_data))
00375     return false;
00376 
00377   int ret = fx8_set_measure_mode(device, measure_mode);
00378   if (ret != FX8_ERROR_SUCCESS)
00379   {
00380     std::stringstream ss;
00381     ss << "Failed to set measure mode. (Measure mode[0 - "
00382        << static_cast<unsigned int>(current_sensor_info.max_measure_mode) << "])";
00383     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00384      << std::setfill('0') << ret << ']';
00385     NODELET_ERROR("%s", ss.str().c_str());
00386     {
00387       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00388       error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00389     }
00390     if (current_xy_data.surface != NULL)
00391       fx8_free_xy_data(&current_xy_data);
00392     return false;
00393   }
00394 
00395   if (current_xy_data.surface != NULL)
00396     fx8_free_xy_data(&current_xy_data);
00397 
00398   // Get new FX8SensorInfo.
00399   if (!getDeviceSensorInfo(device, sensor_info, xy_data))
00400     return false;
00401 
00402   return true;
00403 }
00404 
00405 bool FX8DriverNodelet::getDeviceSensorInfo(const FX8Handle device, FX8SensorInfo* sensor_info, FX8XyData* xy_data)
00406 {
00407   // Set FX8 properties.
00408   int ret = fx8_get_sensor_property(device, NULL, sensor_info, xy_data);
00409   if (ret != FX8_ERROR_SUCCESS)
00410   {
00411     std::stringstream ss;
00412     ss << "Failed to get current sensor info.";
00413     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00414      << std::setfill('0') << ret << ']';
00415     NODELET_ERROR("%s", ss.str().c_str());
00416     {
00417       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00418       error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00419     }
00420     return false;
00421   }
00422 
00423   return true;
00424 }
00425 
00426 void FX8DriverNodelet::outputDeviceParameters()
00427 {
00428   char buf[128];
00429   unsigned char* xy_serial_number = config_.sensor_info.xy_serial_number;
00430   unsigned char* firm_version = config_.sensor_info.firm_version;
00431   unsigned char* logic_version = config_.sensor_info.logic_version;
00432   unsigned char* product_number = config_.sensor_info.product_number;
00433 
00434   ros::NodeHandle param_nh = getPrivateNodeHandle();
00435 
00436   // Update parameter server.
00437   param_nh.setParam("measure_point_x", config_.sensor_info.measure_point.x);
00438   param_nh.setParam("measure_point_y", config_.sensor_info.measure_point.y);
00439   param_nh.setParam("swing_fs", config_.sensor_info.swing_fs);
00440   param_nh.setParam("swing_ss", config_.sensor_info.swing_ss);
00441   param_nh.setParam("xy_surface_count", config_.sensor_info.xy_surface_count);
00442   param_nh.setParam("frame_cycle", config_.sensor_info.frame_cycle);
00443   param_nh.setParam("measure_mode", config_.sensor_info.measure_mode);
00444   param_nh.setParam("max_measure_mode", config_.sensor_info.max_measure_mode);
00445 
00446   sprintf(buf, "%02X.%02X.%02X.%02X", xy_serial_number[0], xy_serial_number[1], xy_serial_number[2],
00447      xy_serial_number[3]);
00448   param_nh.setParam("xy_serial_number", buf);
00449 
00450   sprintf(buf, "%u.%u.%u", logic_version[0], logic_version[1], logic_version[2]);
00451   param_nh.setParam("logic_version", buf);
00452 
00453   sprintf(buf, "%u.%u.%u", firm_version[0], firm_version[1], firm_version[2]);
00454   param_nh.setParam("firm_version", buf);
00455 
00456   sprintf(buf, "%c%c%c%c%c%c%c%c", product_number[0], product_number[1], product_number[2], product_number[3],
00457     product_number[4], product_number[5], product_number[6], product_number[7]);
00458   param_nh.setParam("product_number", buf);
00459   
00460   return;
00461 }
00462 
00463 bool FX8DriverNodelet::startScan()
00464 {
00465   int ret = FX8_ERROR_SUCCESS;
00466   std::stringstream ss;
00467   // Start waiting for scan data of FX8.
00468   ret = fx8_set_receive_range_data_event_handler(device_, receiveScanDataCallback, reinterpret_cast<void*>(this));
00469   if (ret != FX8_ERROR_SUCCESS)
00470   {
00471     ss << "Failed to set receive range data event handler.";
00472     goto Exit;
00473   }
00474   ret = fx8_set_receive_error_info_event_handler(device_, receiveErrorCodeCallback, reinterpret_cast<void*>(this));
00475   if (ret != FX8_ERROR_SUCCESS)
00476   {
00477     ss << "Failed to set receive error info event handler.";
00478     goto Exit;
00479   }
00480 
00481   ret = fx8_start_ranging(device_);
00482   if (ret != FX8_ERROR_SUCCESS)
00483   {
00484     ss << "Failed to start ranging.";
00485     goto Exit;
00486   }
00487   
00488   return true;
00489 
00490 Exit:
00491   if (ret != FX8_ERROR_SUCCESS)
00492   {
00493     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00494       << std::setfill('0') << ret << ']';
00495     NODELET_ERROR("%s", ss.str().c_str());
00496     {
00497       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00498       error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00499     }
00500   }
00501   return false;
00502 }
00503 
00504 void FX8DriverNodelet::spin()
00505 {
00506   while (device_running_ && ros::ok())
00507   {
00508     if (diagnostics_enable_ && diagnostic_updater_)
00509       diagnostic_updater_->update();
00510 
00511     boost::this_thread::sleep(boost::posix_time::milliseconds(5));
00512   }
00513 }
00514 
00515 void FX8DriverNodelet::publishScanData(const unsigned char* scan_data, size_t size)
00516 {
00517   if (!device_running_)
00518     return;
00519 
00520   // Lock scan.
00521   boost::mutex::scoped_lock lock(mutex_scan_);
00522   
00523   // Obtained scan data size.
00524   size_t header_size = 11;
00525   size_t internal_data_size = 64;
00526   size_t obtained_data_size = size - header_size - internal_data_size;
00527 
00528   // Calculated scan data size by FX8SensorInfo.
00529   size_t scan_data_size_per_point = 3; // bytes
00530   size_t calculated_data_size = config_.sensor_info.measure_point.x
00531     * config_.sensor_info.measure_point.y * scan_data_size_per_point;
00532   if (obtained_data_size != calculated_data_size)
00533   {
00534     NODELET_ERROR("Obtained data is not data of current measure mode.");
00535     return;
00536   }
00537  
00538   scan_.scan_data.assign(scan_data, &scan_data[size]);
00539 
00540   // Compare scan data
00541   unsigned char surf = scan_.scan_data[6];
00542   if (scan_.xy_data.surface_count <= static_cast<int>(surf))
00543   {
00544     NODELET_ERROR("Publish no message. Surface number is out of range.");
00545     return;
00546   }
00547 
00548   // Create subscribed messages.
00549   sensor_msgs::ImagePtr range_msg = createRangeImageMessage();
00550   sensor_msgs::ImagePtr ir_msg = createIRImageMessage();
00551   sensor_msgs::PointCloud2Ptr point_cloud_msg = createPointCloudMessage();
00552 
00553   // Return, if subscribed message is nothing.
00554   if (!range_msg && !ir_msg && !point_cloud_msg)
00555   {
00556     NODELET_DEBUG("Publish no messages. Subscribed topic is nothing.");
00557     return;
00558   }
00559 
00560   // Set publish data.
00561   setMessageData(range_msg, ir_msg, point_cloud_msg, surf);
00562 
00563   // Publish message.
00564   if (range_msg)
00565   {
00566     range_publisher_.publish(range_msg);
00567     if (diagnostics_enable_)
00568       range_image_diagnostic_frequency_->tick();
00569     NODELET_DEBUG("Publish range_image.");
00570   }
00571   if (ir_msg)
00572   {
00573     ir_publisher_.publish(ir_msg);
00574     if (diagnostics_enable_)
00575       ir_image_diagnostic_frequency_->tick();
00576     NODELET_DEBUG("Publish ir_image.");
00577   }
00578   if (point_cloud_msg)
00579   {
00580     point_cloud_publisher_.publish(point_cloud_msg);
00581     if (diagnostics_enable_)
00582       point_cloud_diagnostic_frequency_->tick();
00583     NODELET_DEBUG("Publish point_cloud.");
00584   }
00585 }
00586 
00587 sensor_msgs::ImagePtr FX8DriverNodelet::createRangeImageMessage()
00588 {
00589   sensor_msgs::ImagePtr msg;
00590   if (range_publisher_.getNumSubscribers() <= 0)
00591     return msg;
00592 
00593   msg.reset(new sensor_msgs::Image());
00594   msg->header.stamp = latest_update_time_;
00595   msg->header.frame_id = scan_.range_frame_id;
00596   msg->height = config_.sensor_info.measure_point.y;
00597   msg->width = config_.sensor_info.measure_point.x;
00598   msg->encoding = sensor_msgs::image_encodings::TYPE_16UC1;
00599   msg->step = sizeof(unsigned short);
00600   msg->data.resize(msg->height * msg->width * msg->step);
00601 
00602   return msg;
00603 }
00604 
00605 sensor_msgs::ImagePtr FX8DriverNodelet::createIRImageMessage()
00606 {
00607   sensor_msgs::ImagePtr msg;
00608   if (ir_publisher_.getNumSubscribers() <= 0)
00609     return msg;
00610 
00611   msg.reset(new sensor_msgs::Image());
00612   msg->header.stamp = latest_update_time_;
00613   msg->header.frame_id = scan_.ir_frame_id;
00614   msg->height = config_.sensor_info.measure_point.y;
00615   msg->width = config_.sensor_info.measure_point.x;
00616   msg->encoding = sensor_msgs::image_encodings::TYPE_16UC1;
00617   msg->step = sizeof(unsigned short);
00618   msg->data.resize(msg->height * msg->width * msg->step);
00619 
00620   return msg;
00621 }
00622 
00623 sensor_msgs::PointCloud2Ptr FX8DriverNodelet::createPointCloudMessage()
00624 {
00625   sensor_msgs::PointCloud2Ptr msg;
00626   if (point_cloud_publisher_.getNumSubscribers() <= 0)
00627     return msg;
00628 
00629   msg.reset(new sensor_msgs::PointCloud2());
00630   msg->header.stamp = latest_update_time_;
00631   msg->header.frame_id = scan_.point_cloud_frame_id;
00632   msg->height = config_.sensor_info.measure_point.y;
00633   msg->width = config_.sensor_info.measure_point.x;
00634   msg->fields.resize(3);
00635   msg->fields[0].name = "x";
00636   msg->fields[0].offset = 0;
00637   msg->fields[0].datatype = 7;
00638   msg->fields[0].count = 1;
00639   msg->fields[1].name = "y";
00640   msg->fields[1].offset = 4;
00641   msg->fields[1].datatype = 7;
00642   msg->fields[1].count = 1;
00643   msg->fields[2].name = "z";
00644   msg->fields[2].offset = 8;
00645   msg->fields[2].datatype = 7;
00646   msg->fields[2].count = 1;
00647   msg->point_step = sizeof(float) * msg->fields.size();
00648   msg->row_step = msg->width * msg->point_step;
00649   msg->data.resize(msg->height * msg->row_step);
00650   msg->is_dense = false;
00651 
00652   return msg;
00653 }
00654 
00655 void FX8DriverNodelet::setMessageData(
00656   sensor_msgs::ImagePtr range_msg, sensor_msgs::ImagePtr ir_msg, sensor_msgs::PointCloud2Ptr point_cloud_msg,
00657   unsigned char surface_number)
00658 {
00659   //Extract publish image and create point cloud from scan data.
00660   unsigned short* range_data = NULL;
00661   if (range_msg)
00662     range_data = reinterpret_cast<unsigned short*>(&range_msg->data[0]);
00663   unsigned short* ir_data = NULL;
00664   if (ir_msg)
00665     ir_data  = reinterpret_cast<unsigned short*>(&ir_msg->data[0]);
00666   float* point_cloud_data = NULL;
00667   if (point_cloud_msg)
00668     point_cloud_data = reinterpret_cast<float*>(&point_cloud_msg->data[0]);
00669 
00670   FX8XyDataSurface* surface = &scan_.xy_data.surface[surface_number];
00671   unsigned short intensity;
00672   unsigned short range;
00673 
00674   for (int i = 0; i < surface->element_count; ++i)
00675   {
00676     FX8XyDataElement* element = &surface->element[i];
00677     int index = element->y * config_.sensor_info.measure_point.x + element->x;
00678     
00679     extractRangeAndIntensityFromScanData(i, &scan_.scan_data[0], &range, &intensity);
00680 
00681     if (ir_data)
00682       ir_data[index] = intensity;
00683      
00684     if (range_data)
00685       range_data[index] = range;
00686 
00687     if (point_cloud_data)
00688     {
00689       int point_cloud_index = index * 3;
00690       point_cloud_data[point_cloud_index] = static_cast<float>(range * element->bx) / 1000;
00691       point_cloud_data[point_cloud_index + 1] = static_cast<float>(range * element->by) / 1000;
00692       point_cloud_data[point_cloud_index + 2] = static_cast<float>(range * element->bz) / 1000;
00693     }
00694   }
00695 }
00696 
00697 void FX8DriverNodelet::extractRangeAndIntensityFromScanData(int index, const unsigned char* scan_data,
00698  unsigned short* range, unsigned short* intensity)
00699 {
00700   // 9 bytes are offset to skip header of scan data packets.
00701   unsigned int scan_data_offset = 9;
00702 
00703   /*
00704    *  A scan data is a set of range and intensity data and each data is 12 bit
00705    *  aligned data. A scan data is 3 bytes (24 bit) aligned data.
00706   */ 
00707   unsigned int scan_data_size = 3;
00708 
00709   unsigned int target_index = index * scan_data_size + scan_data_offset;
00710 
00711   // Range data is output in digit. A digit is equal to 4 millimeter.
00712   unsigned int range_per_digit = 4;
00713 
00714   // Extract intensity data from scan data.
00715   *intensity = (scan_data[target_index] << 4) | ((scan_data[target_index + 1] & 0xF0) >> 4);
00716 
00717   // Extract range data from scan data.
00718   *range = ((scan_data[target_index + 1] & 0x0F) << 8) | (scan_data[target_index + 2]);
00719 
00720   // Convert from digit to millimeter.
00721   *range *= range_per_digit;
00722 }
00723 
00724 void FX8DriverNodelet::fillDiagnosticStatusByErrorInfo(diagnostic_updater::DiagnosticStatusWrapper &status)
00725 {
00726   boost::mutex::scoped_lock lock(mutex_diagnostics_);
00727   if (error_info_.empty())
00728   {
00729     status.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "No Infinisoleil Error Info");
00730     return;
00731   }
00732 
00733   char key_buf[256];
00734 
00735   status.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Infinisoleil Error Info");
00736   while(!error_info_.empty())
00737   {
00738     std::vector<ErrorInfo>::iterator error_info_it = error_info_.begin();
00739     sprintf(key_buf, "%.lf", error_info_it->first.toSec());
00740     status.add(key_buf, error_info_it->second.c_str()); 
00741     NODELET_DEBUG("Infinisoleil Error Information.[%s:%s]", key_buf, error_info_it->second.c_str());
00742     error_info_.erase(error_info_it);
00743   }
00744 }
00745 
00746 void FX8DriverNodelet::fillDiagnosticStatusByReceivedErrorCode(
00747   diagnostic_updater::DiagnosticStatusWrapper &status)
00748 {
00749   boost::mutex::scoped_lock lock(mutex_diagnostics_);
00750   if (error_code_.empty())
00751   {
00752     status.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "No Infinisoleil Received Error Code");
00753     return;
00754   }
00755 
00756   char key_buf[256];
00757   char value_buf[256];
00758   bool is_warn = true;
00759 
00760   while (!error_code_.empty())
00761   {
00762     std::vector<ReceivedErrorCodePackets>::iterator error_code_it = error_code_.begin();
00763     unsigned char* data = &(error_code_it->second[0]);
00764 
00765     // Set error code.
00766     unsigned int condition = (data[6] << 8) | data[7];
00767     unsigned int error_code[6];
00768     error_code[0] = static_cast<unsigned int>(data[8]);
00769     error_code[1] = static_cast<unsigned int>(data[9]);
00770     error_code[2] = static_cast<unsigned int>(data[10]);
00771     error_code[3] = static_cast<unsigned int>(data[11]);
00772     error_code[4] = static_cast<unsigned int>(data[12]);
00773     error_code[5] = static_cast<unsigned int>(data[13]);
00774     sprintf(value_buf,
00775       "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",
00776       condition, error_code[0], error_code[1], error_code[2], error_code[3], error_code[4], error_code[5]);
00777     sprintf(key_buf, "%.6lf", error_code_it->first.toSec());
00778     status.add(key_buf, value_buf);
00779 
00780     if (condition & 0xC000)
00781     {
00782       NODELET_WARN("Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
00783     }
00784     else
00785     {
00786       NODELET_ERROR("Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
00787       is_warn = false;
00788     }
00789     error_code_.erase(error_code_it);
00790   }
00791 
00792   if (is_warn)
00793   {
00794     status.summaryf(diagnostic_msgs::DiagnosticStatus::WARN, "Infinisoleil Received Error Code");
00795   }
00796   else
00797   {
00798     status.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Infinisoleil Received Error Code");
00799   }
00800 }
00801 
00802 void FX8DriverNodelet::addDiagnostics(const unsigned char* error_data, size_t size)
00803 {
00804   // Lock diagnostics.
00805   boost::mutex::scoped_lock lock(mutex_diagnostics_);
00806 
00807   // Copy error data.
00808   error_code_.push_back(ReceivedErrorCodePackets(ros::Time::now(), std::vector<unsigned char>()));
00809   error_code_.back().second.assign(error_data, &error_data[size]);
00810 }
00811 
00812 void FX8DriverNodelet::reconfigureFX8Callback(FX8Config config, uint32_t level)
00813 { 
00814   int ret = FX8_ERROR_SUCCESS;
00815   std::stringstream ss;
00816   ros::NodeHandle param_nh = getPrivateNodeHandle();
00817 
00818   // Check initialization of FX8.
00819   if (device_ == FX8_INVALID_HANDLE)
00820     return;
00821 
00822   // Check connection to FX8.
00823   if (!fx8_get_connected(device_))
00824   {
00825     NODELET_WARN("Failed to reconfigure. Infinisoleil is disconnected.");
00826     return;
00827   }
00828 
00829   // Reconfigure measure mode of FX8.
00830   FX8MeasureMode measure_mode = static_cast<FX8MeasureMode>(config.measure_mode);
00831   if (measure_mode == config_.sensor_info.measure_mode)
00832   {
00833     NODELET_INFO("No need reconfiguration. Current measure_mode is %d.", measure_mode);
00834     return;
00835   }
00836 
00837   ret = fx8_stop_ranging(device_);
00838   if (ret != FX8_ERROR_SUCCESS)
00839   {
00840     ss << "Failed to stop ranging.";
00841     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00842      << std::setfill('0') << ret << ']';    
00843     NODELET_ERROR("%s", ss.str().c_str());
00844     {
00845       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00846       error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00847     }
00848     return;
00849   }
00850 
00851   FX8SensorInfo sensor_info;
00852   FX8XyData xy_data;
00853   xy_data.surface_count = 0;
00854   xy_data.surface = NULL;
00855   // Lock scan.
00856   {
00857     boost::mutex::scoped_lock lock(mutex_scan_);
00858 
00859     // Set FX8 measure mode.
00860     if (!setDeviceMeasureMode(device_, measure_mode, &sensor_info, &xy_data))
00861     {
00862       if (xy_data.surface != NULL)
00863         fx8_free_xy_data(&xy_data);
00864       return;
00865     } 
00866    
00867     if (scan_.xy_data.surface != NULL)
00868       fx8_free_xy_data(&scan_.xy_data);
00869     scan_.xy_data.surface = xy_data.surface;
00870     scan_.xy_data.surface_count = xy_data.surface_count;
00871     memcpy(&config_.sensor_info, &sensor_info, sizeof(FX8SensorInfo));
00872   }
00873   {
00874       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00875       target_frequency_ = 1 / (config_.sensor_info.frame_cycle / 1000.0);
00876   }
00877   outputDeviceParameters();
00878 
00879   // Restart ranging.
00880   ret = fx8_start_ranging(device_);
00881   if (ret != FX8_ERROR_SUCCESS)
00882   {
00883     ss << "Failed to restart ranging.";
00884     ss << " [return code = " << std::showbase <<  std::hex << std::setw(10) << std::internal 
00885      << std::setfill('0') << ret << ']';
00886     NODELET_ERROR("%s", ss.str().c_str());
00887     {
00888       boost::mutex::scoped_lock lock(mutex_diagnostics_);
00889       error_info_.push_back(ErrorInfo(ros::Time::now(), ss.str()));
00890     }
00891     return; 
00892   }
00893   return;
00894 }
00895 
00896 void FX8DriverNodelet::updateTime()
00897 {
00898   latest_update_time_ = ros::Time::now();
00899 }
00900 
00901 void FX8DriverNodelet::receiveScanDataCallback(const unsigned char* scan_data, size_t size, void* user_data)
00902 {
00903   FX8DriverNodelet* driver = reinterpret_cast<FX8DriverNodelet*>(user_data);
00904   driver->updateTime();
00905   driver->publishScanData(scan_data, size);
00906 }
00907 
00908 void FX8DriverNodelet::receiveErrorCodeCallback(const unsigned char* error_data, size_t size, void* user_data)
00909 {
00910   FX8DriverNodelet* driver = reinterpret_cast<FX8DriverNodelet*>(user_data);
00911   driver->addDiagnostics(error_data, size);
00912 }
00913 } // namespace infinisoleil_fx8
00914 
00915 PLUGINLIB_EXPORT_CLASS(infinisoleil::FX8DriverNodelet, nodelet::Nodelet)


infinisoleil
Author(s): NCS 3D Sensing Team <3d-sensing@nippon-control-system.co.jp>
autogenerated on Thu Jun 6 2019 22:05:50