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 <sicklms-1.0/SickLMS.hh>
00036 #include "ros/ros.h"
00037 #include "sensor_msgs/LaserScan.h"
00038 using namespace SickToolbox;
00039 using namespace std;
00040
00041 void publish_scan(ros::Publisher *pub, uint32_t *range_values,
00042 uint32_t n_range_values, uint32_t *intensity_values,
00043 uint32_t n_intensity_values, double scale, ros::Time start,
00044 double scan_time, bool inverted, float angle_min,
00045 float angle_max, std::string frame_id)
00046 {
00047 static int scan_count = 0;
00048 sensor_msgs::LaserScan scan_msg;
00049 scan_msg.header.frame_id = frame_id;
00050 scan_count++;
00051 if (inverted) {
00052 scan_msg.angle_min = angle_max;
00053 scan_msg.angle_max = angle_min;
00054 } else {
00055 scan_msg.angle_min = angle_min;
00056 scan_msg.angle_max = angle_max;
00057 }
00058 scan_msg.angle_increment = (scan_msg.angle_max - scan_msg.angle_min) / (double)(n_range_values-1);
00059 scan_msg.scan_time = scan_time;
00060 scan_msg.time_increment = scan_time / (2*M_PI) * scan_msg.angle_increment;
00061 scan_msg.range_min = 0;
00062 if (scale == 0.01) {
00063 scan_msg.range_max = 81;
00064 }
00065 else if (scale == 0.001) {
00066 scan_msg.range_max = 8.1;
00067 }
00068 scan_msg.ranges.resize(n_range_values);
00069 scan_msg.header.stamp = start;
00070 for (size_t i = 0; i < n_range_values; i++) {
00071 scan_msg.ranges[i] = (float)range_values[i] * (float)scale;
00072 }
00073 scan_msg.intensities.resize(n_intensity_values);
00074 for (size_t i = 0; i < n_intensity_values; i++) {
00075 scan_msg.intensities[i] = (float)intensity_values[i];
00076 }
00077
00078
00079 pub->publish(scan_msg);
00080 }
00081
00082 int main(int argc, char **argv)
00083 {
00084 ros::init(argc, argv, "sicklms");
00085 string port;
00086 int baud;
00087 bool inverted;
00088 int angle;
00089 double resolution;
00090 std::string frame_id;
00091 double scan_time = 0;
00092 double angle_increment = 0;
00093 float angle_min = 0.0;
00094 float angle_max = 0.0;
00095
00096 ros::NodeHandle nh;
00097 ros::NodeHandle nh_ns("~");
00098 ros::Publisher scan_pub = nh.advertise<sensor_msgs::LaserScan>("scan", 1);
00099 nh_ns.param("port", port, string("/dev/lms200"));
00100 nh_ns.param("baud", baud, 38400);
00101 nh_ns.param("inverted", inverted, false);
00102 nh_ns.param("angle", angle, 0);
00103 nh_ns.param("resolution", resolution, 0.0);
00104 nh_ns.param<std::string>("frame_id", frame_id, "laser");
00105
00106 SickLMS::sick_lms_baud_t desired_baud = SickLMS::IntToSickBaud(baud);
00107 if (desired_baud == SickLMS::SICK_BAUD_UNKNOWN)
00108 {
00109 ROS_ERROR("Baud rate must be in {9600, 19200, 38400, 500000}");
00110 return 1;
00111 }
00112 uint32_t range_values[SickLMS::SICK_MAX_NUM_MEASUREMENTS] = {0};
00113 uint32_t intensity_values[SickLMS::SICK_MAX_NUM_MEASUREMENTS] = {0};
00114 uint32_t n_range_values = 0;
00115 uint32_t n_intensity_values = 0;
00116 SickLMS sick_lms(port);
00117 double scale = 0;
00118 double angle_offset;
00119 uint32_t partial_scan_index;
00120
00121 try
00122 {
00123 sick_lms.Initialize(desired_baud);
00124
00125
00126
00127 if (angle == 0)
00128 angle = sick_lms.GetSickScanAngle();
00129 if (resolution == 0.0)
00130 resolution = sick_lms.GetSickScanResolution();
00131 try {
00132 ROS_INFO("Setting variant to (%i, %f)", angle, resolution);
00133 sick_lms.SetSickVariant(sick_lms.IntToSickScanAngle(angle),
00134 sick_lms.DoubleToSickScanResolution(resolution));
00135 } catch (SickConfigException e) {
00136 int actual_angle = sick_lms.GetSickScanAngle();
00137 double actual_resolution = sick_lms.GetSickScanResolution();
00138 if (angle != actual_angle) {
00139 ROS_WARN("Unable to set scan angle. Using %i instead of %i.", actual_angle, angle);
00140 angle = actual_angle;
00141 }
00142 if (resolution != actual_resolution) {
00143 ROS_WARN("Unable to set resolution. Using %e instead of %e.", actual_resolution, resolution);
00144 resolution = actual_resolution;
00145 }
00146 }
00147
00148 SickLMS::sick_lms_measuring_units_t u = sick_lms.GetSickMeasuringUnits();
00149 if (u == SickLMS::SICK_MEASURING_UNITS_CM)
00150 scale = 0.01;
00151 else if (u == SickLMS::SICK_MEASURING_UNITS_MM)
00152 scale = 0.001;
00153 else
00154 {
00155 ROS_ERROR("Bogus measuring unit.");
00156 return 1;
00157 }
00158
00159
00160
00161
00162
00163 if (angle == 180 || sick_lms.IsSickLMSFast()) {
00164 scan_time = 1.0 / 75;
00165 }
00166 else {
00167 SickLMS::sick_lms_scan_resolution_t scan_resolution =
00168 SickLMS::DoubleToSickScanResolution(resolution);
00169 if ( scan_resolution == SickLMS::SICK_SCAN_RESOLUTION_25) {
00170
00171 scan_time = 4.0 / 75;
00172 }
00173 else if ( scan_resolution == SickLMS::SICK_SCAN_RESOLUTION_50) {
00174
00175 scan_time = 2.0 / 75;
00176 }
00177 else if ( scan_resolution == SickLMS::SICK_SCAN_RESOLUTION_100) {
00178
00179 scan_time = 1.0 / 75;
00180 }
00181 else {
00182 ROS_ERROR("Bogus scan resolution.");
00183 return 1;
00184 }
00185 if ( scan_resolution != SickLMS::SICK_SCAN_RESOLUTION_100) {
00186 ROS_WARN("You are using an angle smaller than 180 degrees and a "
00187 "scan resolution less than 1 degree per scan. Thus, "
00188 "you are in inteleaved mode and the returns will not "
00189 "arrive sequentially how you read them. So, the "
00190 "time_increment field will be misleading. If you need to "
00191 "know when the measurement was made at a time resolution "
00192 "better than the scan_time, use the whole 180 degree "
00193 "field of view.");
00194 }
00195 }
00196
00197
00198
00199
00200
00201 angle_increment = sick_lms.IsSickLMSFast() ? 0.5 : 1.0;
00202
00203 angle_offset = (180.0-angle)/2;
00204 }
00205 catch (...)
00206 {
00207 ROS_ERROR("Initialize failed! are you using the correct device path?");
00208 return 2;
00209 }
00210 try
00211 {
00212 ros::Time last_scan_time = ros::Time::now();
00213 while (ros::ok())
00214 {
00215 if (sick_lms.IsSickLMSFast()) {
00216
00217
00218 sick_lms.GetSickScan(range_values, intensity_values,
00219 n_range_values, n_intensity_values);
00220 angle_min = -M_PI/4;
00221 angle_max = M_PI/4;
00222 }
00223 else if (angle != 180) {
00224
00225
00226
00227 sick_lms.GetSickScan(range_values, n_range_values);
00228 angle_min = (-90.0 + angle_offset) * M_PI / 180.0;
00229 angle_max = (90.0 - angle_offset) * M_PI / 180.0;
00230 }
00231 else {
00232
00233
00234
00235
00236 sick_lms.GetSickPartialScan(range_values, n_range_values,
00237 partial_scan_index);
00238 double partialScanOffset = 0.25 * partial_scan_index;
00239 angle_min = (-90.0 + angle_offset + partialScanOffset) * M_PI / 180.0;
00240 angle_max = (90.0 - angle_offset - fmod(1.0 - partialScanOffset, 1.0))
00241 * M_PI / 180.0;
00242 }
00243
00244
00245
00246
00247 ros::Time end_of_scan = ros::Time::now();
00248 ros::Time start = end_of_scan - ros::Duration(scan_time / 2.0);
00249
00250 ros::Duration diff = start - last_scan_time;
00251 if (diff > ros::Duration(scan_time * 1.5)) {
00252 ROS_WARN_STREAM("A scan was probably missed. The last scan was "
00253 << diff.toSec() << " seconds ago.");
00254 }
00255 last_scan_time = start;
00256
00257 publish_scan(&scan_pub, range_values, n_range_values, intensity_values,
00258 n_intensity_values, scale, start, scan_time, inverted,
00259 angle_min, angle_max, frame_id);
00260 ros::spinOnce();
00261 }
00262 }
00263 catch (...)
00264 {
00265 ROS_ERROR("woah! error!");
00266 return 1;
00267 }
00268 try
00269 {
00270 sick_lms.Uninitialize();
00271 }
00272 catch (...)
00273 {
00274 ROS_ERROR("error during uninitialize");
00275 return 1;
00276 }
00277 ROS_INFO("success.\n");
00278
00279 return 0;
00280 }
00281