sick_tim3xx.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


sick_tim3xx
Author(s): Jochen Sprickerhof, Martin Günther
autogenerated on Tue May 28 2013 15:08:43