$search
00001 /* 00002 * Copyright (C) 2012, University of Osnabrück 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the University of Osnabrück nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 * 00029 * Created on: 24.05.2012 00030 * 00031 * Authors: 00032 * Jochen Sprickerhof <jochen@sprickerhof.de> 00033 * Martin Günther <mguenthe@uos.de> 00034 * 00035 * Based on the TiM communication example by SICK AG. 00036 * 00037 */ 00038 00039 #include <stdio.h> 00040 #include <stdlib.h> 00041 #include <string.h> 00042 #include <libusb-1.0/libusb.h> 00043 00044 #include "ros/ros.h" 00045 #include "sensor_msgs/LaserScan.h" 00046 00047 #include <dynamic_reconfigure/server.h> 00048 #include <sick_tim3xx/SickTim3xxConfig.h> 00049 00050 namespace sick_tim3xx 00051 { 00052 00053 class SickTim3xx 00054 { 00055 public: 00056 SickTim3xx(); 00057 virtual ~SickTim3xx(); 00058 int init_usb(); 00059 int loopOnce(); 00060 void check_angle_range(SickTim3xxConfig &conf); 00061 void update_config(sick_tim3xx::SickTim3xxConfig &new_config, uint32_t level = 0); 00062 00063 private: 00064 static const unsigned int USB_TIMEOUT = 500; // milliseconds 00065 00066 ssize_t getSOPASDeviceList(libusb_context *ctx, uint16_t vendorID, uint16_t productID, libusb_device ***list); 00067 void freeSOPASDeviceList(libusb_device **list); 00068 00069 void printUSBDeviceDetails(struct libusb_device_descriptor desc); 00070 void printUSBInterfaceDetails(libusb_device* device); 00071 void printSOPASDeviceInformation(ssize_t numberOfDevices, libusb_device** devices); 00072 00073 int sendSOPASCommand(libusb_device_handle* device_handle, const char* request, unsigned int timeout); 00074 00075 // ROS 00076 ros::NodeHandle nh_; 00077 ros::Publisher pub_; 00078 00079 // Dynamic Reconfigure 00080 SickTim3xxConfig config_; 00081 dynamic_reconfigure::Server<sick_tim3xx::SickTim3xxConfig> dynamic_reconfigure_server_; 00082 00083 // libusb 00084 libusb_context *ctx_; 00085 ssize_t numberOfDevices_; 00086 libusb_device **devices_; 00087 libusb_device_handle *device_handle_; 00088 }; 00089 00090 SickTim3xx::SickTim3xx() : 00091 ctx_(NULL), numberOfDevices_(0), devices_(NULL), device_handle_(NULL) 00092 { 00093 dynamic_reconfigure::Server<sick_tim3xx::SickTim3xxConfig>::CallbackType f; 00094 f = boost::bind(&sick_tim3xx::SickTim3xx::update_config, this, _1, _2); 00095 dynamic_reconfigure_server_.setCallback(f); 00096 00097 pub_ = nh_.advertise<sensor_msgs::LaserScan>("scan", 1000); 00098 } 00099 00100 SickTim3xx::~SickTim3xx() 00101 { 00102 if (device_handle_ != NULL) 00103 { 00104 /* 00105 * Stop streaming measurements 00106 */ 00107 const char requestScanData0[] = {"\x02sEN LMDscandata 0\x03\0"}; 00108 int result = sendSOPASCommand(device_handle_, requestScanData0, USB_TIMEOUT); 00109 if (result != 0) 00110 // use printf because we cannot use ROS_ERROR in the destructor 00111 printf("\nSOPAS - Error stopping streaming scan data!\n"); 00112 else 00113 printf("\nSOPAS - Stopped streaming scan data.\n"); 00114 00115 /* 00116 * Release the interface 00117 */ 00118 result = libusb_release_interface(device_handle_, 0); 00119 if (result != 0) 00120 printf("LIBUSB - Cannot Release Interface!\n"); 00121 else 00122 printf("LIBUSB - Released Interface.\n"); 00123 00124 /* 00125 * Close the device handle. 00126 */ 00127 libusb_close(device_handle_); 00128 } 00129 00130 /* 00131 * Free the list of the USB devices. 00132 */ 00133 freeSOPASDeviceList(devices_); 00134 00135 /* 00136 * Close the LIBUSB session. 00137 */ 00138 libusb_exit(ctx_); 00139 00140 printf("sick_tim3xx driver exiting.\n"); 00141 } 00142 00146 ssize_t SickTim3xx::getSOPASDeviceList(libusb_context *ctx, uint16_t vendorID, uint16_t productID, 00147 libusb_device ***list) 00148 { 00149 libusb_device **resultDevices = NULL; 00150 ssize_t numberOfResultDevices = 0; 00151 libusb_device **devices; 00152 00153 /* 00154 * Get a list of all USB devices connected. 00155 */ 00156 ssize_t numberOfDevices = libusb_get_device_list(ctx, &devices); 00157 00158 /* 00159 * Iterate through the list of the connected USB devices and search for devices with the given vendorID and productID. 00160 */ 00161 for (ssize_t i = 0; i < numberOfDevices; i++) 00162 { 00163 struct libusb_device_descriptor desc; 00164 int result = libusb_get_device_descriptor(devices[i], &desc); 00165 if (result < 0) 00166 { 00167 ROS_ERROR("LIBUSB - Failed to get device descriptor"); 00168 continue; 00169 } 00170 00171 if (desc.idVendor == vendorID && desc.idProduct == 0x5001) 00172 { 00173 /* 00174 * Add the matching device to the function result list and increase the device reference count. 00175 */ 00176 resultDevices = (libusb_device **)realloc(resultDevices, sizeof(libusb_device *) * (numberOfResultDevices + 2)); 00177 if (resultDevices == NULL) 00178 { 00179 ROS_ERROR("LIBUSB - Failed to allocate memory for the device result list."); 00180 } 00181 else 00182 { 00183 resultDevices[numberOfResultDevices] = devices[i]; 00184 resultDevices[numberOfResultDevices + 1] = NULL; 00185 libusb_ref_device(devices[i]); 00186 numberOfResultDevices++; 00187 } 00188 } 00189 } 00190 00191 /* 00192 * Free the list of the connected USB devices and decrease the device reference count. 00193 */ 00194 libusb_free_device_list(devices, 1); 00195 00196 /* 00197 * Prepare the return values of the function. 00198 */ 00199 *list = resultDevices; 00200 return numberOfResultDevices; 00201 } 00202 00203 /* 00204 * Free the list of devices obtained from the function 'getSOPASDeviceList'. 00205 */ 00206 void SickTim3xx::freeSOPASDeviceList(libusb_device **list) 00207 { 00208 if (!list) 00209 return; 00210 00211 int i = 0; 00212 struct libusb_device *dev; 00213 while ((dev = list[i++]) != NULL) 00214 libusb_unref_device(dev); 00215 00216 free(list); 00217 } 00218 00219 /* 00220 * Print the device details such as USB device class, vendor id and product id to the console. 00221 */ 00222 void SickTim3xx::printUSBDeviceDetails(struct libusb_device_descriptor desc) 00223 { 00224 ROS_INFO("Device Class: 0x%x", desc.bDeviceClass); 00225 ROS_INFO("VendorID: 0x%x", desc.idVendor); 00226 ROS_INFO("ProductID: 0x%x", desc.idProduct); 00227 } 00228 00229 /* 00230 * Iterate through the the interfaces of the USB device and print out the interface details to the console. 00231 */ 00232 void SickTim3xx::printUSBInterfaceDetails(libusb_device* device) 00233 { 00234 struct libusb_config_descriptor *config; 00235 00236 /* 00237 * Get a USB configuration descriptor based on its index. 00238 */ 00239 libusb_get_config_descriptor(device, 0, &config); 00240 00241 ROS_INFO("Interfaces: %i", (int)config->bNumInterfaces); 00242 ROS_INFO("----------------------------------------"); 00243 00244 const struct libusb_interface *interface; 00245 const struct libusb_interface_descriptor *interface_descriptor; 00246 const struct libusb_endpoint_descriptor *endpoint_descriptor; 00247 00248 int i, j, k; 00249 for (i = 0; i < config->bNumInterfaces; i++) 00250 { 00251 interface = &config->interface[i]; 00252 ROS_INFO("Number of alternate settings: %i", interface->num_altsetting); 00253 00254 for (j = 0; j < interface->num_altsetting; j++) 00255 { 00256 interface_descriptor = &interface->altsetting[j]; 00257 00258 ROS_INFO("Interface number: %i", (int)interface_descriptor->bInterfaceNumber); 00259 ROS_INFO("Number of endpoints: %i", (int)interface_descriptor->bNumEndpoints); 00260 00261 for (k = 0; k < interface_descriptor->bNumEndpoints; k++) 00262 { 00263 endpoint_descriptor = &interface_descriptor->endpoint[k]; 00264 ROS_INFO("Descriptor Type: %i", endpoint_descriptor->bDescriptorType); 00265 ROS_INFO("EP Address: %i", endpoint_descriptor->bEndpointAddress); 00266 } 00267 } 00268 00269 if (i < config->bNumInterfaces - 1) 00270 { 00271 ROS_INFO("----------------------------------------"); 00272 } 00273 } 00274 00275 /* 00276 * Free the configuration descriptor obtained from 'libusb_get_config_descriptor' 00277 */ 00278 libusb_free_config_descriptor(config); 00279 } 00280 00284 void SickTim3xx::printSOPASDeviceInformation(ssize_t numberOfDevices, libusb_device** devices) 00285 { 00286 ssize_t i; 00287 for (i = 0; i < numberOfDevices; i++) 00288 { 00289 struct libusb_device_descriptor desc; 00290 int result = libusb_get_device_descriptor(devices[i], &desc); 00291 if (result < 0) 00292 { 00293 ROS_ERROR("LIBUSB - Failed to get device descriptor"); 00294 continue; 00295 } 00296 if (result == 0) 00297 { 00298 ROS_INFO("SICK AG - TIM3XX - [%zu]", (i + 1)); 00299 ROS_INFO("----------------------------------------"); 00300 printUSBDeviceDetails(desc); 00301 ROS_INFO("----------------------------------------"); 00302 printUSBInterfaceDetails(devices[i]); 00303 ROS_INFO("----------------------------------------"); 00304 } 00305 } 00306 00307 if (numberOfDevices == 0) 00308 { 00309 ROS_INFO("LIBUSB - No SICK TIM3xx device connected."); 00310 } 00311 } 00312 00316 int SickTim3xx::sendSOPASCommand(libusb_device_handle* device_handle, const char* request, unsigned int timeout) 00317 { 00318 int result = 0; 00319 unsigned char receiveBuffer[65536]; 00320 00321 /* 00322 * Write a SOPAS variable read request to the device. 00323 */ 00324 ROS_DEBUG("LIBUSB - Write data... %s", request); 00325 00326 int actual_length = 0; 00327 int requestLength = strlen(request); 00328 result = libusb_bulk_transfer(device_handle, (2 | LIBUSB_ENDPOINT_OUT), (unsigned char*)request, requestLength, 00329 &actual_length, 0); 00330 if (result != 0 || actual_length != requestLength) 00331 { 00332 ROS_ERROR("LIBUSB - Write Error: %i.", result); 00333 return result; 00334 } 00335 00336 /* 00337 * Read the SOPAS device response with the given timeout. 00338 */ 00339 result = libusb_bulk_transfer(device_handle, (1 | LIBUSB_ENDPOINT_IN), receiveBuffer, 65535, &actual_length, timeout); 00340 if (result != 0) 00341 { 00342 ROS_ERROR("LIBUSB - Read Error: %i.", result); 00343 return result; 00344 } 00345 00346 receiveBuffer[actual_length] = 0; 00347 ROS_DEBUG("LIBUSB - Read data... %s", receiveBuffer); 00348 00349 return result; 00350 } 00351 00352 /* 00353 * provided as a separate method (not inside constructor) so we can return error codes 00354 */ 00355 int SickTim3xx::init_usb() 00356 { 00357 /* 00358 * Create and initialize a new LIBUSB session. 00359 */ 00360 int result = libusb_init(&ctx_); 00361 if (result != 0) 00362 { 00363 ROS_ERROR("LIBUSB - Initialization failed with the following error code: %i.", result); 00364 return EXIT_FAILURE; 00365 } 00366 00367 /* 00368 * Set the verbosity level to 3 as suggested in the documentation. 00369 */ 00370 libusb_set_debug(ctx_, 3); 00371 00372 /* 00373 * Get a list of all SICK TIM3xx devices connected to the USB bus. 00374 * 00375 * As a shortcut, you can also use the LIBUSB function: 00376 * libusb_open_device_with_vid_pid(ctx, 0x19A2, 0x5001). 00377 */ 00378 int vendorID = 0x19A2; // SICK AG 00379 int deviceID = 0x5001; // TIM3XX 00380 numberOfDevices_ = getSOPASDeviceList(ctx_, vendorID, deviceID, &devices_); 00381 00382 /* 00383 * If available, open the first SICK TIM3xx device. 00384 */ 00385 if (numberOfDevices_ == 0) 00386 { 00387 ROS_ERROR("No SICK TiM3xx devices connected!"); 00388 return EXIT_FAILURE; 00389 } 00390 else if (numberOfDevices_ > 1) 00391 { 00392 ROS_WARN("%zu TiM3xx scanners connected, using the first one", numberOfDevices_); 00393 } 00394 00395 /* 00396 * Print out the SOPAS device information to the console. 00397 */ 00398 printSOPASDeviceInformation(numberOfDevices_, devices_); 00399 00400 /* 00401 * Open the device handle and detach all kernel drivers. 00402 */ 00403 libusb_open(devices_[0], &device_handle_); 00404 if (device_handle_ == NULL) 00405 { 00406 ROS_ERROR("LIBUSB - Cannot open device; please read sick_tim3xx/udev/README"); 00407 return EXIT_FAILURE; 00408 } 00409 else 00410 { 00411 ROS_DEBUG("LIBUSB - Device opened"); 00412 } 00413 00414 if (libusb_kernel_driver_active(device_handle_, 0) == 1) 00415 { 00416 ROS_DEBUG("LIBUSB - Kernel driver active"); 00417 if (libusb_detach_kernel_driver(device_handle_, 0) == 0) 00418 { 00419 ROS_DEBUG("LIBUSB - Kernel driver detached!"); 00420 } 00421 } 00422 00423 /* 00424 * Claim the interface 0 00425 */ 00426 result = libusb_claim_interface(device_handle_, 0); 00427 if (result < 0) 00428 { 00429 ROS_ERROR("LIBUSB - Cannot claim interface"); 00430 return EXIT_FAILURE; 00431 } 00432 else 00433 { 00434 ROS_INFO("LIBUSB - Claimed interface"); 00435 } 00436 00437 /* 00438 * Read the SOPAS variable 'DeviceIdent' by index. 00439 */ 00440 const char requestDeviceIdent[] = "\x02sRI0\x03\0"; 00441 result = sendSOPASCommand(device_handle_, requestDeviceIdent, USB_TIMEOUT); 00442 if (result != 0) 00443 { 00444 ROS_ERROR("SOPAS - Error reading variable 'DeviceIdent'."); 00445 } 00446 00447 /* 00448 * Read the SOPAS variable 'SerialNumber' by name. 00449 */ 00450 const char requestSerialNumber[] = "\x02sRN SerialNumber\x03\0"; 00451 result = sendSOPASCommand(device_handle_, requestSerialNumber, USB_TIMEOUT); 00452 if (result != 0) 00453 { 00454 ROS_ERROR("SOPAS - Error reading variable 'SerialNumber'."); 00455 } 00456 00457 /* 00458 * Read the SOPAS variable 'FirmwareVersion' by name. 00459 */ 00460 const char requestFirmwareVersion[] = {"\x02sRN FirmwareVersion\x03\0"}; 00461 result = sendSOPASCommand(device_handle_, requestFirmwareVersion, USB_TIMEOUT); 00462 if (result != 0) 00463 { 00464 ROS_ERROR("SOPAS - Error reading variable 'FirmwareVersion'."); 00465 } 00466 00467 /* 00468 * Start streaming 'LMDscandata'. 00469 */ 00470 const char requestScanData[] = {"\x02sEN LMDscandata 1\x03\0"}; 00471 result = sendSOPASCommand(device_handle_, requestScanData, USB_TIMEOUT); 00472 if (result != 0) 00473 { 00474 ROS_ERROR("SOPAS - Error starting to stream 'LMDscandata'."); 00475 return EXIT_FAILURE; 00476 } 00477 00478 return EXIT_SUCCESS; 00479 } 00480 00481 int SickTim3xx::loopOnce() 00482 { 00483 int result = 0; 00484 unsigned char receiveBuffer[65536]; 00485 unsigned char receiveBufferCopy[65536]; // only for debugging 00486 int actual_length = 0; 00487 static const size_t NUM_FIELDS = 580; 00488 char* fields[NUM_FIELDS]; 00489 size_t count; 00490 static unsigned int iteration_count = 0; 00491 00492 result = libusb_bulk_transfer(device_handle_, (1 | LIBUSB_ENDPOINT_IN), receiveBuffer, 65535, &actual_length, 00493 USB_TIMEOUT); 00494 if (result != 0) 00495 { 00496 if (result == LIBUSB_ERROR_TIMEOUT) 00497 { 00498 ROS_WARN("LIBUSB - Read Error: LIBUSB_ERROR_TIMEOUT."); 00499 return EXIT_SUCCESS; // return success to continue looping 00500 } 00501 else 00502 { 00503 ROS_ERROR("LIBUSB - Read Error: %i.", result); 00504 return EXIT_FAILURE; 00505 } 00506 } 00507 00508 // ----- if requested, skip frames 00509 if (iteration_count++ % (config_.skip + 1) != 0) 00510 return EXIT_SUCCESS; 00511 00512 receiveBuffer[actual_length] = 0; 00513 // ROS_DEBUG("LIBUSB - Read data... %s", receiveBuffer); 00514 00515 // ----- tokenize 00516 strncpy((char*)receiveBufferCopy, (char*)receiveBuffer, 65535); // receiveBuffer will be changed by strtok 00517 receiveBufferCopy[65535] = 0; 00518 00519 count = 0; 00520 fields[count] = strtok((char *)receiveBuffer, " "); 00521 // ROS_DEBUG("%d: %s ", count, fields[count]); 00522 00523 while (fields[count] != NULL) 00524 { 00525 count++; 00526 if (count > NUM_FIELDS) 00527 break; 00528 00529 fields[count] = strtok(NULL, " "); 00530 // ROS_DEBUG("%d: %s ", count, fields[count]); 00531 } 00532 00533 if (count < NUM_FIELDS) 00534 { 00535 ROS_WARN( 00536 "received less fields than expected fields (actual: %zu, expected: %zu), ignoring scan", count, NUM_FIELDS); 00537 // ROS_DEBUG("received message was: %s", receiveBufferCopy); 00538 return EXIT_SUCCESS; // return success to continue looping 00539 } 00540 else if (count > NUM_FIELDS) 00541 { 00542 ROS_WARN("received more fields than expected (expected: %zu), ignoring scan", NUM_FIELDS); 00543 // ROS_DEBUG("received message was: %s", receiveBufferCopy); 00544 return EXIT_SUCCESS; // return success to continue looping 00545 } 00546 00547 // ----- read fields into msg 00548 sensor_msgs::LaserScan msg; 00549 00550 msg.header.frame_id = config_.frame_id; 00551 ROS_DEBUG("publishing with frame_id %s", config_.frame_id.c_str()); 00552 00553 ros::Time start_time = ros::Time::now(); // will be adjusted in the end 00554 00555 // <STX> (\x02) 00556 // 0: Type of command (SN) 00557 // 1: Command (LMDscandata) 00558 // 2: Firmware version number (1) 00559 // 3: Device number (1) 00560 // 4: Serial number (B96518) 00561 // 5 + 6: Device Status (0 0 = ok, 0 1 = error) 00562 // 7: Telegram counter (99) 00563 // 8: Scan counter (9A) 00564 // 9: Time since startup (13C8E59) 00565 // 10: Time of transmission (13C9CBE) 00566 // 11 + 12: Input status (0 0) 00567 // 13 + 14: Output status (8 0) 00568 // 15: Reserved Byte A (0) 00569 00570 // 16: Scanning Frequency (5DC) 00571 unsigned short scanning_freq = -1; 00572 sscanf(fields[16], "%hx", &scanning_freq); 00573 msg.scan_time = 1.0 / (scanning_freq / 100.0); 00574 // ROS_DEBUG("hex: %s, scanning_freq: %d, scan_time: %f", fields[16], scanning_freq, msg.scan_time); 00575 00576 // 17: Measurement Frequency (36) 00577 unsigned short measurement_freq = -1; 00578 sscanf(fields[17], "%hx", &measurement_freq); 00579 msg.time_increment = 1.0 / (measurement_freq * 100.0); 00580 // ROS_DEBUG("measurement_freq: %d, time_increment: %f", measurement_freq, msg.time_increment); 00581 00582 // 18: Number of encoders (0) 00583 // 19: Number of 16 bit channels (1) 00584 // 20: Measured data contents (DIST1) 00585 00586 // 21: Scaling factor (3F800000) 00587 // ignored for now (is always 1.0): 00588 // unsigned int scaling_factor_int = -1; 00589 // sscanf(fields[21], "%x", &scaling_factor_int); 00590 // 00591 // float scaling_factor = reinterpret_cast<float&>(scaling_factor_int); 00592 // // ROS_DEBUG("hex: %s, scaling_factor_int: %d, scaling_factor: %f", fields[21], scaling_factor_int, scaling_factor); 00593 00594 // 22: Scaling offset (00000000) -- always 0 00595 // 23: Starting angle (FFF92230) 00596 int starting_angle = -1; 00597 sscanf(fields[23], "%x", &starting_angle); 00598 msg.angle_min = (starting_angle / 10000.0) / 180.0 * M_PI - M_PI / 2; 00599 // ROS_DEBUG("starting_angle: %d, angle_min: %f", starting_angle, msg.angle_min); 00600 00601 // 24: Angular step width (2710) 00602 unsigned short angular_step_width = -1; 00603 sscanf(fields[24], "%hx", &angular_step_width); 00604 msg.angle_increment = (angular_step_width / 10000.0) / 180.0 * M_PI; 00605 msg.angle_max = msg.angle_min + 270.0 * msg.angle_increment; 00606 00607 // adjust angle_min to min_ang config param 00608 int index_min = 0; 00609 while (msg.angle_min + msg.angle_increment < config_.min_ang) 00610 { 00611 msg.angle_min += msg.angle_increment; 00612 index_min++; 00613 } 00614 00615 // adjust angle_max to max_ang config param 00616 int index_max = 270; 00617 while (msg.angle_max - msg.angle_increment > config_.max_ang) 00618 { 00619 msg.angle_max -= msg.angle_increment; 00620 index_max--; 00621 } 00622 00623 ROS_DEBUG("index_min: %d, index_max: %d", index_min, index_max); 00624 // ROS_DEBUG("angular_step_width: %d, angle_increment: %f, angle_max: %f", angular_step_width, msg.angle_increment, msg.angle_max); 00625 00626 // 25: Number of data (10F) 00627 00628 // 26..296: Data_1 .. Data_n 00629 msg.ranges.resize(index_max - index_min + 1); 00630 for (int j = index_min; j <= index_max; ++j) 00631 { 00632 unsigned short range; 00633 sscanf(fields[j + 26], "%hx", &range); 00634 msg.ranges[j - index_min] = range / 1000.0; 00635 } 00636 00637 // 297: Number of 8 bit channels (1) 00638 // 298: Measured data contents (RSSI1) 00639 // 299: Scaling factor (3F800000) 00640 // 300: Scaling offset (00000000) 00641 // 301: Starting angle (FFF92230) 00642 // 302: Angular step width (2710) 00643 // 303: Number of data (10F) 00644 // 304..574: Data_1 .. Data_n 00645 if (config_.intensity) 00646 { 00647 msg.intensities.resize(index_max - index_min + 1); 00648 for (int j = index_min; j <= index_max; ++j) 00649 { 00650 unsigned short intensity; 00651 sscanf(fields[j + 304], "%hx", &intensity); 00652 msg.intensities[j - index_min] = intensity; 00653 } 00654 } 00655 00656 // 575: Position (0) 00657 // 576: Name (0) 00658 // 577: Comment (0) 00659 // 578: Time information (0) 00660 // 579: Event information (0) 00661 // <ETX> (\x03) 00662 00663 msg.range_min = 0.05; 00664 msg.range_max = 4.0; 00665 00666 // ----- adjust start time 00667 // - last scan point = now ==> first scan point = now - 271 * time increment 00668 msg.header.stamp = start_time - ros::Duration().fromSec(271 * msg.time_increment); 00669 00670 // - shift forward to time of first published scan point 00671 msg.header.stamp += ros::Duration().fromSec((double)index_min * msg.time_increment); 00672 00673 // - add time offset (to account for USB latency etc.) 00674 msg.header.stamp += ros::Duration().fromSec(config_.time_offset); 00675 00676 pub_.publish(msg); 00677 return EXIT_SUCCESS; 00678 } 00679 00680 void SickTim3xx::check_angle_range(SickTim3xxConfig &conf) 00681 { 00682 if (conf.min_ang > conf.max_ang) 00683 { 00684 ROS_WARN("Minimum angle must be greater than maximum angle. Adjusting min_ang."); 00685 conf.min_ang = conf.max_ang; 00686 } 00687 } 00688 00689 void SickTim3xx::update_config(sick_tim3xx::SickTim3xxConfig &new_config, uint32_t level) 00690 { 00691 check_angle_range(new_config); 00692 config_ = new_config; 00693 } 00694 00695 } // end namespace sick_tim3xx 00696 00697 int main(int argc, char **argv) 00698 { 00699 ros::init(argc, argv, "sick_tim3xx"); 00700 00701 sick_tim3xx::SickTim3xx s; 00702 s.init_usb(); 00703 00704 int result = EXIT_SUCCESS; 00705 while (ros::ok() && (result == EXIT_SUCCESS)) 00706 { 00707 ros::spinOnce(); 00708 result = s.loopOnce(); 00709 } 00710 00711 return result; 00712 }