00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <csignal>
00033 #include <cstdio>
00034 #include <math.h>
00035 #include <limits>
00036 #include <sicktoolbox/SickLMS2xx.hh>
00037 #include "ros/ros.h"
00038 #include "sensor_msgs/LaserScan.h"
00039 #include <diagnostic_updater/diagnostic_updater.h>
00040 #include <diagnostic_updater/publisher.h>
00041 using namespace SickToolbox;
00042 using namespace std;
00043
00044 void publish_scan(diagnostic_updater::DiagnosedPublisher<sensor_msgs::LaserScan> *pub, uint32_t *range_values,
00045 uint32_t n_range_values, uint32_t *intensity_values,
00046 uint32_t n_intensity_values, double scale, ros::Time start,
00047 double scan_time, bool inverted, float angle_min,
00048 float angle_max, std::string frame_id)
00049 {
00050 static int scan_count = 0;
00051 sensor_msgs::LaserScan scan_msg;
00052 scan_msg.header.frame_id = frame_id;
00053 scan_count++;
00054 if (inverted) {
00055 scan_msg.angle_min = angle_max;
00056 scan_msg.angle_max = angle_min;
00057 } else {
00058 scan_msg.angle_min = angle_min;
00059 scan_msg.angle_max = angle_max;
00060 }
00061 scan_msg.angle_increment = (scan_msg.angle_max - scan_msg.angle_min) / (double)(n_range_values-1);
00062 scan_msg.scan_time = scan_time;
00063 scan_msg.time_increment = scan_time / (2*M_PI) * scan_msg.angle_increment;
00064 scan_msg.range_min = 0;
00065 if (scale == 0.01) {
00066 scan_msg.range_max = 81;
00067 }
00068 else if (scale == 0.001) {
00069 scan_msg.range_max = 8.1;
00070 }
00071 scan_msg.ranges.resize(n_range_values);
00072 scan_msg.header.stamp = start;
00073 for (size_t i = 0; i < n_range_values; i++) {
00074
00075 switch (range_values[i])
00076 {
00077
00078 case 8191:
00079 scan_msg.ranges[i] = numeric_limits<float>::quiet_NaN();
00080 break;
00081 case 8190:
00082 scan_msg.ranges[i] = numeric_limits<float>::quiet_NaN();
00083 break;
00084 case 8189:
00085 scan_msg.ranges[i] = numeric_limits<float>::quiet_NaN();
00086 break;
00087 case 8187:
00088 scan_msg.ranges[i] = numeric_limits<float>::quiet_NaN();
00089 break;
00090 case 8186:
00091 scan_msg.ranges[i] = numeric_limits<float>::quiet_NaN();
00092 break;
00093 case 8183:
00094 scan_msg.ranges[i] = numeric_limits<float>::infinity();
00095 break;
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 default:
00136 scan_msg.ranges[i] = (float)range_values[i] * (float)scale;
00137 }
00138 }
00139 scan_msg.intensities.resize(n_intensity_values);
00140 for (size_t i = 0; i < n_intensity_values; i++) {
00141 scan_msg.intensities[i] = (float)intensity_values[i];
00142 }
00143
00144
00145 pub->publish(scan_msg);
00146 }
00147
00148 SickLMS2xx::sick_lms_2xx_measuring_units_t StringToLmsMeasuringUnits(string units)
00149 {
00150 if (units.compare("mm") == 0)
00151 return SickLMS2xx::SICK_MEASURING_UNITS_MM;
00152 else if (units.compare("cm") == 0)
00153 return SickLMS2xx::SICK_MEASURING_UNITS_CM;
00154
00155 return SickLMS2xx::SICK_MEASURING_UNITS_UNKNOWN;
00156 }
00157
00158
00159 int main(int argc, char **argv)
00160 {
00161 ros::init(argc, argv, "sicklms");
00162 ros::NodeHandle nh;
00163 ros::NodeHandle nh_ns("~");
00164 string port;
00165 int baud;
00166 int delay;
00167 bool inverted;
00168 int angle;
00169 double resolution;
00170 std::string measuring_units;
00171 std::string frame_id;
00172 double scan_time = 0;
00173 double angle_increment = 0;
00174 float angle_min = 0.0;
00175 float angle_max = 0.0;
00176
00177
00178 double desired_freq;
00179 nh_ns.param<double>("desired_frequency", desired_freq, 75.0);
00180 double min_freq;
00181 nh_ns.param<double>("min_frequency", min_freq, desired_freq);
00182 double max_freq;
00183 nh_ns.param<double>("max_frequency", max_freq, desired_freq);
00184 double freq_tolerance;
00185 nh_ns.param<double>("frequency_tolerance", freq_tolerance, 0.3);
00186 int window_size;
00187 nh_ns.param<int>("window_size", window_size, 30);
00188 double min_delay;
00189 nh_ns.param<double>("min_acceptable_delay", min_delay, 0.0);
00190 double max_delay;
00191 nh_ns.param<double>("max_acceptable_delay", max_delay, 0.2);
00192 std::string hardware_id;
00193 nh_ns.param<std::string>("hardware_id", hardware_id, "SICK LMS");
00194 double time_offset_sec;
00195 nh_ns.param<double>("time_offset", time_offset_sec, 0.0);
00196 ros::Duration time_offset(time_offset_sec);
00197
00198
00199 diagnostic_updater::Updater updater;
00200 updater.setHardwareID(hardware_id);
00201 diagnostic_updater::DiagnosedPublisher<sensor_msgs::LaserScan> scan_pub(nh.advertise<sensor_msgs::LaserScan>("scan", 10), updater,
00202 diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, freq_tolerance, window_size),
00203 diagnostic_updater::TimeStampStatusParam(min_delay, max_delay));
00204
00205 nh_ns.param("port", port, string("/dev/lms200"));
00206 nh_ns.param("baud", baud, 38400);
00207 nh_ns.param("connect_delay", delay, 0);
00208 nh_ns.param("inverted", inverted, false);
00209 nh_ns.param("angle", angle, 0);
00210 nh_ns.param("resolution", resolution, 0.0);
00211 nh_ns.param("units", measuring_units, string());
00212 nh_ns.param<std::string>("frame_id", frame_id, "laser");
00213
00214
00215 std::string key;
00216 if (nh.searchParam("use_rep_117", key))
00217 {
00218 ROS_ERROR("The use_rep_117 parameter has not been specified and is now ignored. This parameter was removed in Hydromedusa. Please see: http://ros.org/wiki/rep_117/migration");
00219 }
00220
00221 SickLMS2xx::sick_lms_2xx_baud_t desired_baud = SickLMS2xx::IntToSickBaud(baud);
00222 if (desired_baud == SickLMS2xx::SICK_BAUD_UNKNOWN)
00223 {
00224 ROS_ERROR("Baud rate must be in {9600, 19200, 38400, 500000}");
00225 return 1;
00226 }
00227 uint32_t range_values[SickLMS2xx::SICK_MAX_NUM_MEASUREMENTS] = {0};
00228 uint32_t intensity_values[SickLMS2xx::SICK_MAX_NUM_MEASUREMENTS] = {0};
00229 uint32_t n_range_values = 0;
00230 uint32_t n_intensity_values = 0;
00231 SickLMS2xx sick_lms(port);
00232 double scale = 0;
00233 double angle_offset;
00234 uint32_t partial_scan_index;
00235
00236 try
00237 {
00238 uint32_t on_delay = 0;
00239 if(delay > 0){
00240 on_delay = delay;
00241 }
00242 sick_lms.Initialize(desired_baud, on_delay);
00243
00244
00245
00246 int actual_angle = sick_lms.GetSickScanAngle();
00247 double actual_resolution = sick_lms.GetSickScanResolution();
00248 SickLMS2xx::sick_lms_2xx_measuring_units_t actual_units = sick_lms.GetSickMeasuringUnits();
00249
00250
00251 try {
00252 if ((angle && actual_angle != angle) || (resolution && actual_resolution != resolution)) {
00253 ROS_INFO("Setting variant to (%i, %f)", angle, resolution);
00254 sick_lms.SetSickVariant(sick_lms.IntToSickScanAngle(angle),
00255 sick_lms.DoubleToSickScanResolution(resolution));
00256 } else {
00257 ROS_INFO("Variant setup not requested or identical to actual (%i, %f)", actual_angle,
00258 actual_resolution);
00259 angle = actual_angle;
00260 resolution = actual_resolution;
00261 }
00262 } catch (SickConfigException e) {
00263 actual_angle = sick_lms.GetSickScanAngle();
00264 actual_resolution = sick_lms.GetSickScanResolution();
00265 if (angle != actual_angle) {
00266 ROS_WARN("Unable to set scan angle. Using %i instead of %i.", actual_angle, angle);
00267 angle = actual_angle;
00268 }
00269 if (resolution != actual_resolution) {
00270 ROS_WARN("Unable to set resolution. Using %e instead of %e.", actual_resolution, resolution);
00271 resolution = actual_resolution;
00272 }
00273 }
00274
00275
00276 try {
00277 if (!measuring_units.empty() && (actual_units != StringToLmsMeasuringUnits(measuring_units))) {
00278 ROS_INFO("Setting measuring units to '%s'", measuring_units.c_str());
00279 actual_units = StringToLmsMeasuringUnits(measuring_units);
00280 sick_lms.SetSickMeasuringUnits(actual_units);
00281 } else {
00282 ROS_INFO("Measuring units setup not requested or identical to actual ('%s')",
00283 sick_lms.SickMeasuringUnitsToString(actual_units).c_str());
00284 }
00285 } catch (SickConfigException e) {
00286 actual_units = sick_lms.GetSickMeasuringUnits();
00287 if (StringToLmsMeasuringUnits(measuring_units) != actual_units) {
00288 ROS_WARN("Unable to set measuring units. Using '%s' instead of '%s'.",
00289 sick_lms.SickMeasuringUnitsToString(actual_units).c_str(), measuring_units.c_str());
00290 measuring_units = sick_lms.SickMeasuringUnitsToString(actual_units);
00291 }
00292 }
00293
00294 if (actual_units == SickLMS2xx::SICK_MEASURING_UNITS_CM)
00295 scale = 0.01;
00296 else if (actual_units == SickLMS2xx::SICK_MEASURING_UNITS_MM)
00297 scale = 0.001;
00298 else
00299 {
00300 ROS_ERROR("Invalid measuring unit.");
00301 return 1;
00302 }
00303
00304
00305
00306
00307
00308 if (angle == 180 || sick_lms.IsSickLMS2xxFast()) {
00309 scan_time = 1.0 / 75;
00310 }
00311 else {
00312 SickLMS2xx::sick_lms_2xx_scan_resolution_t scan_resolution =
00313 SickLMS2xx::DoubleToSickScanResolution(resolution);
00314 if ( scan_resolution == SickLMS2xx::SICK_SCAN_RESOLUTION_25) {
00315
00316 scan_time = 4.0 / 75;
00317 }
00318 else if ( scan_resolution == SickLMS2xx::SICK_SCAN_RESOLUTION_50) {
00319
00320 scan_time = 2.0 / 75;
00321 }
00322 else if ( scan_resolution == SickLMS2xx::SICK_SCAN_RESOLUTION_100) {
00323
00324 scan_time = 1.0 / 75;
00325 }
00326 else {
00327 ROS_ERROR("Bogus scan resolution.");
00328 return 1;
00329 }
00330 if ( scan_resolution != SickLMS2xx::SICK_SCAN_RESOLUTION_100) {
00331 ROS_WARN("You are using an angle smaller than 180 degrees and a "
00332 "scan resolution less than 1 degree per scan. Thus, "
00333 "you are in inteleaved mode and the returns will not "
00334 "arrive sequentially how you read them. So, the "
00335 "time_increment field will be misleading. If you need to "
00336 "know when the measurement was made at a time resolution "
00337 "better than the scan_time, use the whole 180 degree "
00338 "field of view.");
00339 }
00340 }
00341
00342
00343
00344
00345
00346 angle_increment = sick_lms.IsSickLMS2xxFast() ? 0.5 : 1.0;
00347
00348 angle_offset = (180.0-angle)/2;
00349 }
00350 catch (...)
00351 {
00352 ROS_ERROR("Initialize failed! are you using the correct device path?");
00353 return 2;
00354 }
00355 try
00356 {
00357 while (ros::ok())
00358 {
00359 if (sick_lms.IsSickLMS2xxFast()) {
00360
00361
00362 sick_lms.GetSickScan(range_values, intensity_values,
00363 n_range_values, n_intensity_values);
00364 angle_min = -M_PI/4;
00365 angle_max = M_PI/4;
00366 }
00367 else if (angle != 180) {
00368
00369
00370
00371 sick_lms.GetSickScan(range_values, n_range_values);
00372 angle_min = (-90.0 + angle_offset) * M_PI / 180.0;
00373 angle_max = (90.0 - angle_offset) * M_PI / 180.0;
00374 }
00375 else {
00376
00377
00378
00379
00380 sick_lms.GetSickPartialScan(range_values, n_range_values,
00381 partial_scan_index);
00382 double partialScanOffset = 0.25 * partial_scan_index;
00383 angle_min = (-90.0 + angle_offset + partialScanOffset) * M_PI / 180.0;
00384 angle_max = (90.0 - angle_offset - fmod(1.0 - partialScanOffset, 1.0))
00385 * M_PI / 180.0;
00386 }
00387
00388
00389
00390
00391 ros::Time end_of_scan = ros::Time::now();
00392 ros::Time start = end_of_scan - ros::Duration(scan_time / 2.0) + time_offset;
00393
00394 publish_scan(&scan_pub, range_values, n_range_values, intensity_values,
00395 n_intensity_values, scale, start, scan_time, inverted,
00396 angle_min, angle_max, frame_id);
00397 ros::spinOnce();
00398
00399 updater.update();
00400 }
00401 }
00402 catch (...)
00403 {
00404 ROS_ERROR("Unknown error.");
00405 return 1;
00406 }
00407 try
00408 {
00409 sick_lms.Uninitialize();
00410 }
00411 catch (...)
00412 {
00413 ROS_ERROR("Error during uninitialize");
00414 return 1;
00415 }
00416 ROS_INFO("Success.\n");
00417
00418 return 0;
00419 }
00420