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


sick_tim
Author(s): Jochen Sprickerhof , Martin Günther , Sebastian Pütz
autogenerated on Thu May 9 2019 02:32:02