00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
00071
00072
00073
00074
00075
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
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
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
00100 initializeReconfigureServer(param_nh);
00101
00102
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
00113 range_publisher_.shutdown();
00114 ir_publisher_.shutdown();
00115 point_cloud_publisher_.shutdown();
00116
00117
00118 diagnostic_updater_.reset();
00119
00120
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
00181 if (!initializeDevice())
00182 {
00183 NODELET_ERROR("Failed to initialize Infinisoleil.");
00184
00185 sleep(1);
00186 goto Exit;
00187 }
00188
00189 NODELET_INFO("Succeeded in initializing Infinisoleil.");
00190
00191
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
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
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
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
00285 if (!setDeviceMeasureMode(device, static_cast<FX8MeasureMode>(measure_mode), &sensor_info, &xy_data))
00286 {
00287 goto Exit;
00288 }
00289
00290
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
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
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
00374 if (!getDeviceSensorInfo(device, ¤t_sensor_info, ¤t_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(¤t_xy_data);
00392 return false;
00393 }
00394
00395 if (current_xy_data.surface != NULL)
00396 fx8_free_xy_data(¤t_xy_data);
00397
00398
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
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
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
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
00521 boost::mutex::scoped_lock lock(mutex_scan_);
00522
00523
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
00529 size_t scan_data_size_per_point = 3;
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
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
00549 sensor_msgs::ImagePtr range_msg = createRangeImageMessage();
00550 sensor_msgs::ImagePtr ir_msg = createIRImageMessage();
00551 sensor_msgs::PointCloud2Ptr point_cloud_msg = createPointCloudMessage();
00552
00553
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
00561 setMessageData(range_msg, ir_msg, point_cloud_msg, surf);
00562
00563
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
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
00701 unsigned int scan_data_offset = 9;
00702
00703
00704
00705
00706
00707 unsigned int scan_data_size = 3;
00708
00709 unsigned int target_index = index * scan_data_size + scan_data_offset;
00710
00711
00712 unsigned int range_per_digit = 4;
00713
00714
00715 *intensity = (scan_data[target_index] << 4) | ((scan_data[target_index + 1] & 0xF0) >> 4);
00716
00717
00718 *range = ((scan_data[target_index + 1] & 0x0F) << 8) | (scan_data[target_index + 2]);
00719
00720
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
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
00805 boost::mutex::scoped_lock lock(mutex_diagnostics_);
00806
00807
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
00819 if (device_ == FX8_INVALID_HANDLE)
00820 return;
00821
00822
00823 if (!fx8_get_connected(device_))
00824 {
00825 NODELET_WARN("Failed to reconfigure. Infinisoleil is disconnected.");
00826 return;
00827 }
00828
00829
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
00856 {
00857 boost::mutex::scoped_lock lock(mutex_scan_);
00858
00859
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
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 }
00914
00915 PLUGINLIB_EXPORT_CLASS(infinisoleil::FX8DriverNodelet, nodelet::Nodelet)