sick_tim551_2050001_parser.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013, Osnabrück University
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 Osnabrück University 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: 14.11.2013
00030  *
00031  *      Author: Martin Günther <mguenthe@uos.de>
00032  *
00033  */
00034 
00035 #include <sick_tim/sick_tim551_2050001_parser.h>
00036 
00037 #include <ros/ros.h>
00038 
00039 namespace sick_tim
00040 {
00041 
00042 SickTim5512050001Parser::SickTim5512050001Parser() :
00043     AbstractParser(),
00044     override_range_min_(0.05),
00045     override_range_max_(10.0),
00046     override_time_increment_(-1.0)
00047 {
00048 }
00049 
00050 SickTim5512050001Parser::~SickTim5512050001Parser()
00051 {
00052 }
00053 
00054 int SickTim5512050001Parser::parse_datagram(char* datagram, size_t datagram_length, SickTimConfig &config,
00055                                      sensor_msgs::LaserScan &msg)
00056 {
00057   static const size_t HEADER_FIELDS = 33;
00058   char* cur_field;
00059   size_t count;
00060 
00061   // Reserve sufficient space
00062   std::vector<char *> fields;
00063   fields.reserve(datagram_length / 2);
00064 
00065   // ----- only for debug output
00066   char datagram_copy[datagram_length + 1];
00067   strncpy(datagram_copy, datagram, datagram_length); // datagram will be changed by strtok
00068   datagram_copy[datagram_length] = 0;
00069 
00070   // ----- tokenize
00071   count = 0;
00072   cur_field = strtok(datagram, " ");
00073 
00074   while (cur_field != NULL)
00075   {
00076     fields.push_back(cur_field);
00077     cur_field = strtok(NULL, " ");
00078   }
00079 
00080   count = fields.size();
00081 
00082   // Validate header. Total number of tokens is highly unreliable as this may
00083   // change when you change the scanning range or the device name using SOPAS ET
00084   // tool. The header remains stable, however.
00085   if (count < HEADER_FIELDS)
00086   {
00087     ROS_WARN(
00088         "received less fields than minimum fields (actual: %zu, minimum: %zu), ignoring scan", count, HEADER_FIELDS);
00089     ROS_WARN("are you using the correct node? (124 --> sick_tim310_1130000m01, > 33 --> sick_tim551_2050001, 580 --> sick_tim310s01, 592 --> sick_tim310)");
00090     // ROS_DEBUG("received message was: %s", datagram_copy);
00091     return ExitError;
00092   }
00093   if (strcmp(fields[15], "0"))
00094   {
00095     ROS_WARN("Field 15 of received data is not equal to 0 (%s). Unexpected data, ignoring scan", fields[15]);
00096     return ExitError;
00097   }
00098   if (strcmp(fields[20], "DIST1"))
00099   {
00100     ROS_WARN("Field 20 of received data is not equal to DIST1i (%s). Unexpected data, ignoring scan", fields[20]);
00101     return ExitError;
00102   }
00103 
00104   // More in depth checks: check data length and RSSI availability
00105   // 25: Number of data (<= 10F)
00106   unsigned short int number_of_data = 0;
00107   sscanf(fields[25], "%hx", &number_of_data);
00108 
00109   if (number_of_data < 1 || number_of_data > 811)
00110   {
00111     ROS_WARN("Data length is outside acceptable range 1-811 (%d). Ignoring scan", number_of_data);
00112     return ExitError;
00113   }
00114   if (count < HEADER_FIELDS + number_of_data)
00115   {
00116     ROS_WARN("Less fields than expected for %d data points (%zu). Ignoring scan", number_of_data, count);
00117     return ExitError;
00118   }
00119   ROS_DEBUG("Number of data: %d", number_of_data);
00120 
00121   // Calculate offset of field that contains indicator of whether or not RSSI data is included
00122   size_t rssi_idx = 26 + number_of_data;
00123   int tmp;
00124   sscanf(fields[rssi_idx], "%d", &tmp);
00125   bool rssi = tmp > 0;
00126   unsigned short int number_of_rssi_data = 0;
00127   if (rssi)
00128   {
00129     sscanf(fields[rssi_idx + 6], "%hx", &number_of_rssi_data);
00130 
00131     // Number of RSSI data should be equal to number of data
00132     if (number_of_rssi_data != number_of_data)
00133     {
00134       ROS_WARN("Number of RSSI data is lower than number of range data (%d vs %d", number_of_data, number_of_rssi_data);
00135       return ExitError;
00136     }
00137 
00138     // Check if the total length is still appropriate.
00139     // RSSI data size = number of RSSI readings + 6 fields describing the data
00140     if (count < HEADER_FIELDS + number_of_data + number_of_rssi_data + 6)
00141     {
00142       ROS_WARN("Less fields than expected for %d data points (%zu). Ignoring scan", number_of_data, count);
00143       return ExitError;
00144     }
00145 
00146     if (strcmp(fields[rssi_idx + 1], "RSSI1"))
00147     {
00148       ROS_WARN("Field %zu of received data is not equal to RSSI1 (%s). Unexpected data, ignoring scan", rssi_idx + 1, fields[rssi_idx + 1]);
00149     }
00150   }
00151 
00152   // ----- read fields into msg
00153   msg.header.frame_id = config.frame_id;
00154   ROS_DEBUG("publishing with frame_id %s", config.frame_id.c_str());
00155 
00156   ros::Time start_time = ros::Time::now(); // will be adjusted in the end
00157 
00158   // <STX> (\x02)
00159   // 0: Type of command (SN)
00160   // 1: Command (LMDscandata)
00161   // 2: Firmware version number (1)
00162   // 3: Device number (1)
00163   // 4: Serial number (eg. B96518)
00164   // 5 + 6: Device Status (0 0 = ok, 0 1 = error)
00165   // 7: Telegram counter (eg. 99)
00166   // 8: Scan counter (eg. 9A)
00167   // 9: Time since startup (eg. 13C8E59)
00168   // 10: Time of transmission (eg. 13C9CBE)
00169   // 11 + 12: Input status (0 0)
00170   // 13 + 14: Output status (8 0)
00171   // 15: Reserved Byte A (0)
00172 
00173   // 16: Scanning Frequency (5DC)
00174   unsigned short scanning_freq = -1;
00175   sscanf(fields[16], "%hx", &scanning_freq);
00176   msg.scan_time = 1.0 / (scanning_freq / 100.0);
00177   // ROS_DEBUG("hex: %s, scanning_freq: %d, scan_time: %f", fields[16], scanning_freq, msg.scan_time);
00178 
00179   // 17: Measurement Frequency (36)
00180   unsigned short measurement_freq = -1;
00181   sscanf(fields[17], "%hx", &measurement_freq);
00182   msg.time_increment = 1.0 / (measurement_freq * 100.0);
00183   if (override_time_increment_ > 0.0)
00184   {
00185     // Some lasers may report incorrect measurement frequency
00186     msg.time_increment = override_time_increment_;
00187   }
00188   // ROS_DEBUG("measurement_freq: %d, time_increment: %f", measurement_freq, msg.time_increment);
00189 
00190   // 18: Number of encoders (0)
00191   // 19: Number of 16 bit channels (1)
00192   // 20: Measured data contents (DIST1)
00193 
00194   // 21: Scaling factor (3F800000)
00195   // ignored for now (is always 1.0):
00196 //      unsigned int scaling_factor_int = -1;
00197 //      sscanf(fields[21], "%x", &scaling_factor_int);
00198 //
00199 //      float scaling_factor = reinterpret_cast<float&>(scaling_factor_int);
00200 //      // ROS_DEBUG("hex: %s, scaling_factor_int: %d, scaling_factor: %f", fields[21], scaling_factor_int, scaling_factor);
00201 
00202   // 22: Scaling offset (00000000) -- always 0
00203   // 23: Starting angle (FFF92230)
00204   int starting_angle = -1;
00205   sscanf(fields[23], "%x", &starting_angle);
00206   msg.angle_min = (starting_angle / 10000.0) / 180.0 * M_PI - M_PI / 2;
00207   // ROS_DEBUG("starting_angle: %d, angle_min: %f", starting_angle, msg.angle_min);
00208 
00209   // 24: Angular step width (2710)
00210   unsigned short angular_step_width = -1;
00211   sscanf(fields[24], "%hx", &angular_step_width);
00212   msg.angle_increment = (angular_step_width / 10000.0) / 180.0 * M_PI;
00213   msg.angle_max = msg.angle_min + (number_of_data - 1) * msg.angle_increment;
00214 
00215   // 25: Number of data (<= 10F)
00216   // This is already determined above in number_of_data
00217 
00218   // adjust angle_min to min_ang config param
00219   int index_min = 0;
00220   while (msg.angle_min + msg.angle_increment < config.min_ang)
00221   {
00222     msg.angle_min += msg.angle_increment;
00223     index_min++;
00224   }
00225 
00226   // adjust angle_max to max_ang config param
00227   int index_max = number_of_data - 1;
00228   while (msg.angle_max - msg.angle_increment > config.max_ang)
00229   {
00230     msg.angle_max -= msg.angle_increment;
00231     index_max--;
00232   }
00233 
00234   ROS_DEBUG("index_min: %d, index_max: %d", index_min, index_max);
00235   // ROS_DEBUG("angular_step_width: %d, angle_increment: %f, angle_max: %f", angular_step_width, msg.angle_increment, msg.angle_max);
00236 
00237   // 26..26 + n - 1: Data_1 .. Data_n
00238   msg.ranges.resize(index_max - index_min + 1);
00239   for (int j = index_min; j <= index_max; ++j)
00240   {
00241     unsigned short range;
00242     sscanf(fields[j + 26], "%hx", &range);
00243     msg.ranges[j - index_min] = range / 1000.0;
00244   }
00245 
00246   if (config.intensity) {
00247     if (rssi)
00248     {
00249       // 26 + n: RSSI data included
00250 
00251       //   26 + n + 1 = RSSI Measured Data Contents (RSSI1)
00252       //   26 + n + 2 = RSSI scaling factor (3F80000)
00253       //   26 + n + 3 = RSSI Scaling offset (0000000)
00254       //   26 + n + 4 = RSSI starting angle (equal to Range starting angle)
00255       //   26 + n + 5 = RSSI angular step width (equal to Range angular step width)
00256       //   26 + n + 6 = RSSI number of data (equal to Range number of data)
00257       //   26 + n + 7 .. 26 + n + 7 + n - 1: RSSI_Data_1 .. RSSI_Data_n
00258       //   26 + n + 7 + n .. 26 + n + 7 + n + 2 = unknown (but seems to be [0, 1, B] always)
00259       //   26 + n + 7 + n + 2 .. count - 4 = device label
00260       //   count - 3 .. count - 1 = unknown (but seems to be 0 always)
00261       //   <ETX> (\x03)
00262       msg.intensities.resize(index_max - index_min + 1);
00263       size_t offset = 26 + number_of_data + 7;
00264       for (int j = index_min; j <= index_max; ++j)
00265       {
00266         unsigned short intensity;
00267         sscanf(fields[j + offset], "%hx", &intensity);
00268         msg.intensities[j - index_min] = intensity;
00269       }
00270     } else {
00271       ROS_WARN_ONCE("Intensity parameter is enabled, but the scanner is not configured to send RSSI values! "
00272        "Please read the section 'Enabling intensity (RSSI) output' here: http://wiki.ros.org/sick_tim.");
00273     }
00274   }
00275 
00276   // 26 + n: RSSI data included
00277   // IF RSSI not included:
00278   //   26 + n + 1 .. 26 + n + 3 = unknown (but seems to be [0, 1, B] always)
00279   //   26 + n + 4 .. count - 4 = device label
00280   //   count - 3 .. count - 1 = unknown (but seems to be 0 always)
00281   //   <ETX> (\x03)
00282 
00283   msg.range_min = override_range_min_;
00284   msg.range_max = override_range_max_;
00285 
00286   // ----- adjust start time
00287   // - last scan point = now  ==>  first scan point = now - number_of_data * time increment
00288   msg.header.stamp = start_time - ros::Duration().fromSec(number_of_data * msg.time_increment);
00289 
00290   // - shift forward to time of first published scan point
00291   msg.header.stamp += ros::Duration().fromSec((double)index_min * msg.time_increment);
00292 
00293   // - add time offset (to account for USB latency etc.)
00294   msg.header.stamp += ros::Duration().fromSec(config.time_offset);
00295 
00296   // ----- consistency check
00297  float expected_time_increment = msg.scan_time * msg.angle_increment / (2.0 * M_PI);
00298  if (fabs(expected_time_increment - msg.time_increment) > 0.00001)
00299  {
00300    ROS_WARN_THROTTLE(60, "The time_increment, scan_time and angle_increment values reported by the scanner are inconsistent! "
00301        "Expected time_increment: %.9f, reported time_increment: %.9f. "
00302        "Perhaps you should set the parameter time_increment to the expected value. This message will print every 60 seconds.",
00303        expected_time_increment, msg.time_increment);
00304  }
00305 
00306   return ExitSuccess;
00307 }
00308 
00309 void SickTim5512050001Parser::set_range_min(float min)
00310 {
00311   override_range_min_ = min;
00312 }
00313 
00314 void SickTim5512050001Parser::set_range_max(float max)
00315 {
00316   override_range_max_ = max;
00317 }
00318 
00319 void SickTim5512050001Parser::set_time_increment(float time)
00320 {
00321   override_time_increment_ = time;
00322 }
00323 
00324 } /* namespace sick_tim */


sick_tim
Author(s): Jochen Sprickerhof , Martin Günther
autogenerated on Mon Aug 14 2017 02:16:11