39 #include <sensor_msgs/Image.h> 41 #include <sensor_msgs/PointCloud2.h> 48 :device_(FX8_INVALID_HANDLE),
49 diagnostics_enable_(true),
50 device_running_(false),
51 target_frequency_(0.0)
189 NODELET_INFO(
"Succeeded in initializing Infinisoleil.");
215 std::string hostname(
"");
217 int measure_mode = 0;
218 int connect_timeout = 0;
219 int send_timeout = 0;
220 int receive_timeout = 0;
223 xy_data.surface_count = 0;
224 xy_data.surface = NULL;
226 int ret = FX8_ERROR_SUCCESS;
227 std::stringstream ss;
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)
236 NODELET_WARN(
"Failed to set connect timeout. %d is less than 0. Set default value (10000).",
238 connect_timeout = 10000;
241 param_nh.
param(
"send_timeout", send_timeout, 3000);
242 if (send_timeout < 0)
245 "Failed to set send timeout. %d is less than 0. Set default value (3000).", send_timeout);
248 param_nh.
param(
"receive_timeout", receive_timeout, 5000);
249 if (receive_timeout < 0)
252 "Failed to set receive timeout. %d is less than 0. Set default value (5000).", receive_timeout);
253 receive_timeout = 5000;
257 diagnostic_updater_->setHardwareIDf(
"Infinisoleil:[%s:%d]", hostname.c_str(), port_number);
260 ret = fx8_create_handle(&device);
261 if (!device || ret != FX8_ERROR_SUCCESS)
263 ss <<
"Failed to create Infinisoleil handle.";
268 ret = fx8_set_connect_timeout(device, connect_timeout);
269 if (ret != FX8_ERROR_SUCCESS)
271 ss <<
"Failed to set connect timeout.";
274 connect_timeout = fx8_get_connect_timeout(device);
276 ret = fx8_connect(device, hostname.c_str(),
static_cast<unsigned short>(port_number));
277 if (ret != FX8_ERROR_SUCCESS)
279 ss <<
"Failed to connect to Infinisoleil. [" << hostname << ':' << static_cast<unsigned short>(port_number) <<
']';
282 NODELET_INFO(
"Infinisoleil is connected. [%s:%d]", hostname.c_str(),
static_cast<unsigned short>(port_number));
285 if (!
setDeviceMeasureMode(device, static_cast<FX8MeasureMode>(measure_mode), &sensor_info, &xy_data))
291 ret = fx8_set_send_timeout(device, send_timeout);
292 if (ret != FX8_ERROR_SUCCESS)
294 ss <<
"Failed to set send timeout.";
297 send_timeout = fx8_get_send_timeout(device);
298 ret = fx8_set_receive_timeout(device, receive_timeout);
299 if (ret != FX8_ERROR_SUCCESS)
301 ss <<
"Failed to set receive timeout.";
304 receive_timeout = fx8_get_receive_timeout(device);
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]);
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);
334 if (ret != FX8_ERROR_SUCCESS)
336 ss <<
" [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
337 << std::setfill(
'0') << ret <<
']';
345 if (xy_data.surface != NULL)
346 fx8_free_xy_data(&xy_data);
369 current_xy_data.surface_count = 0;
370 current_xy_data.surface = NULL;
377 int ret = fx8_set_measure_mode(device, measure_mode);
378 if (ret != FX8_ERROR_SUCCESS)
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 <<
']';
390 if (current_xy_data.surface != NULL)
391 fx8_free_xy_data(¤t_xy_data);
395 if (current_xy_data.surface != NULL)
396 fx8_free_xy_data(¤t_xy_data);
408 int ret = fx8_get_sensor_property(device, NULL, sensor_info, xy_data);
409 if (ret != FX8_ERROR_SUCCESS)
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 <<
']';
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);
450 sprintf(buf,
"%u.%u.%u", logic_version[0], logic_version[1], logic_version[2]);
451 param_nh.
setParam(
"logic_version", buf);
453 sprintf(buf,
"%u.%u.%u", firm_version[0], firm_version[1], firm_version[2]);
454 param_nh.
setParam(
"firm_version", buf);
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);
465 int ret = FX8_ERROR_SUCCESS;
466 std::stringstream ss;
469 if (ret != FX8_ERROR_SUCCESS)
471 ss <<
"Failed to set receive range data event handler.";
475 if (ret != FX8_ERROR_SUCCESS)
477 ss <<
"Failed to set receive error info event handler.";
481 ret = fx8_start_ranging(
device_);
482 if (ret != FX8_ERROR_SUCCESS)
484 ss <<
"Failed to start ranging.";
491 if (ret != FX8_ERROR_SUCCESS)
493 ss <<
" [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
494 << std::setfill(
'0') << ret <<
']';
511 boost::this_thread::sleep(boost::posix_time::milliseconds(5));
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;
529 size_t scan_data_size_per_point = 3;
532 if (obtained_data_size != calculated_data_size)
534 NODELET_ERROR(
"Obtained data is not data of current measure mode.");
542 if (
scan_.
xy_data.surface_count <= static_cast<int>(surf))
544 NODELET_ERROR(
"Publish no message. Surface number is out of range.");
554 if (!range_msg && !ir_msg && !point_cloud_msg)
556 NODELET_DEBUG(
"Publish no messages. Subscribed topic is nothing.");
589 sensor_msgs::ImagePtr
msg;
593 msg.reset(
new sensor_msgs::Image());
599 msg->step =
sizeof(
unsigned short);
600 msg->data.resize(msg->height * msg->width * msg->step);
607 sensor_msgs::ImagePtr
msg;
611 msg.reset(
new sensor_msgs::Image());
617 msg->step =
sizeof(
unsigned short);
618 msg->data.resize(msg->height * msg->width * msg->step);
625 sensor_msgs::PointCloud2Ptr
msg;
629 msg.reset(
new sensor_msgs::PointCloud2());
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;
656 sensor_msgs::ImagePtr range_msg, sensor_msgs::ImagePtr ir_msg, sensor_msgs::PointCloud2Ptr point_cloud_msg,
657 unsigned char surface_number)
660 unsigned short* range_data = NULL;
662 range_data =
reinterpret_cast<unsigned short*
>(&range_msg->data[0]);
663 unsigned short* ir_data = NULL;
665 ir_data =
reinterpret_cast<unsigned short*
>(&ir_msg->data[0]);
666 float* point_cloud_data = NULL;
668 point_cloud_data =
reinterpret_cast<float*
>(&point_cloud_msg->data[0]);
671 unsigned short intensity;
672 unsigned short range;
674 for (
int i = 0; i < surface->element_count; ++i)
682 ir_data[index] = intensity;
685 range_data[index] = range;
687 if (point_cloud_data)
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;
698 unsigned short* range,
unsigned short* intensity)
701 unsigned int scan_data_offset = 9;
707 unsigned int scan_data_size = 3;
709 unsigned int target_index = index * scan_data_size + scan_data_offset;
712 unsigned int range_per_digit = 4;
715 *intensity = (scan_data[target_index] << 4) | ((scan_data[target_index + 1] & 0xF0) >> 4);
718 *range = ((scan_data[target_index + 1] & 0x0F) << 8) | (scan_data[target_index + 2]);
721 *range *= range_per_digit;
729 status.
summaryf(diagnostic_msgs::DiagnosticStatus::OK,
"No Infinisoleil Error Info");
735 status.
summaryf(diagnostic_msgs::DiagnosticStatus::ERROR,
"Infinisoleil Error Info");
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());
752 status.
summaryf(diagnostic_msgs::DiagnosticStatus::OK,
"No Infinisoleil Received Error Code");
762 std::vector<ReceivedErrorCodePackets>::iterator error_code_it =
error_code_.begin();
763 unsigned char*
data = &(error_code_it->second[0]);
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]);
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);
780 if (condition & 0xC000)
782 NODELET_WARN(
"Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
786 NODELET_ERROR(
"Received Infinisoleil Error Code.[%s:%s]", key_buf, value_buf);
794 status.
summaryf(diagnostic_msgs::DiagnosticStatus::WARN,
"Infinisoleil Received Error Code");
798 status.
summaryf(diagnostic_msgs::DiagnosticStatus::ERROR,
"Infinisoleil Received Error Code");
809 error_code_.back().second.assign(error_data, &error_data[size]);
814 int ret = FX8_ERROR_SUCCESS;
815 std::stringstream ss;
819 if (
device_ == FX8_INVALID_HANDLE)
823 if (!fx8_get_connected(
device_))
825 NODELET_WARN(
"Failed to reconfigure. Infinisoleil is disconnected.");
833 NODELET_INFO(
"No need reconfiguration. Current measure_mode is %d.", measure_mode);
837 ret = fx8_stop_ranging(
device_);
838 if (ret != FX8_ERROR_SUCCESS)
840 ss <<
"Failed to stop ranging.";
841 ss <<
" [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
842 << std::setfill(
'0') << ret <<
']';
853 xy_data.surface_count = 0;
854 xy_data.surface = NULL;
862 if (xy_data.surface != NULL)
863 fx8_free_xy_data(&xy_data);
880 ret = fx8_start_ranging(
device_);
881 if (ret != FX8_ERROR_SUCCESS)
883 ss <<
"Failed to restart ranging.";
884 ss <<
" [return code = " << std::showbase << std::hex << std::setw(10) << std::internal
885 << std::setfill(
'0') << ret <<
']';
boost::mutex mutex_scan_
Mutex for scan data.
fx8_xy_data_surface FX8XyDataSurface
Surface of device xy data.
Struct of fx8 information.
fx8_sensor_info FX8SensorInfo
Sensor information.
#define NODELET_ERROR(...)
std::vector< ErrorInfo > error_info_
Error information of FX8.
ScanDataPackets scan_data
Scan data.
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.
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.
FX8XyData xy_data
FX8 xy data.
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 ¶m_name, T ¶m_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.
const std::string TYPE_16UC1
std::string point_cloud_frame_id
Point cloud frame id.
FX8DriverNodelet()
Constructer.
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.
std::string ir_frame_id
IR frame id.
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.
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)
bool startScan()
Start FX8 scan.
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.