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
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include <ros/ros.h>
00062
00063
00064 #include <std_msgs/Bool.h>
00065 #include <sensor_msgs/LaserScan.h>
00066 #include <diagnostic_msgs/DiagnosticArray.h>
00067
00068
00069
00070
00071
00072 #include <cob_sick_s300/ScannerSickS300.h>
00073
00074 #include <boost/date_time/posix_time/posix_time.hpp>
00075 #include <boost/thread/thread.hpp>
00076 #include <boost/lexical_cast.hpp>
00077
00078 #define ROS_LOG_FOUND
00079
00080
00081
00082 class NodeClass
00083 {
00084
00085 public:
00086
00087 ros::NodeHandle nh;
00088
00089 ros::Publisher topicPub_LaserScan;
00090 ros::Publisher topicPub_InStandby;
00091 ros::Publisher topicPub_Diagnostic_;
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 std::string port;
00104 std::string node_name;
00105 int baud, scan_id, publish_frequency;
00106 bool inverted;
00107 double scan_duration, scan_cycle_time;
00108 std::string frame_id;
00109 ros::Time syncedROSTime;
00110 unsigned int syncedSICKStamp;
00111 bool syncedTimeReady;
00112 bool debug_;
00113 ScannerSickS300 scanner_;
00114 ros::Time loop_rate_;
00115 std_msgs::Bool inStandby_;
00116
00117
00118 NodeClass()
00119 {
00120
00121 nh = ros::NodeHandle("~");
00122
00123 if(!nh.hasParam("port")) ROS_WARN("Used default parameter for port");
00124 nh.param("port", port, std::string("/dev/ttyUSB0"));
00125
00126 if(!nh.hasParam("baud")) ROS_WARN("Used default parameter for baud");
00127 nh.param("baud", baud, 500000);
00128
00129 if(!nh.hasParam("scan_id")) ROS_WARN("Used default parameter for scan_id");
00130 nh.param("scan_id", scan_id, 7);
00131
00132 if(!nh.hasParam("inverted")) ROS_WARN("Used default parameter for inverted");
00133 nh.param("inverted", inverted, false);
00134
00135 if(!nh.hasParam("frame_id")) ROS_WARN("Used default parameter for frame_id");
00136 nh.param("frame_id", frame_id, std::string("/base_laser_link"));
00137
00138 if(!nh.hasParam("scan_duration")) ROS_WARN("Used default parameter for scan_duration");
00139 nh.param("scan_duration", scan_duration, 0.025);
00140
00141 if(!nh.hasParam("scan_cycle_time")) ROS_WARN("Used default parameter for scan_cycle_time");
00142 nh.param("scan_cycle_time", scan_cycle_time, 0.040);
00143
00144 if (!nh.hasParam("publish_frequency")) ROS_WARN("Used default parameter for publish_frequency");
00145 nh.param("publish_frequency", publish_frequency, 12);
00146
00147 if(nh.hasParam("debug")) nh.param("debug", debug_, false);
00148
00149
00150 XmlRpc::XmlRpcValue field_params;
00151 if(nh.getParam("fields",field_params) && field_params.getType() == XmlRpc::XmlRpcValue::TypeStruct)
00152 {
00153 for(XmlRpc::XmlRpcValue::iterator field=field_params.begin(); field!=field_params.end(); field++)
00154 {
00155 int field_number = boost::lexical_cast<int>(field->first);
00156 ROS_DEBUG("Found field %d in params", field_number);
00157
00158 if(!field->second.hasMember("scale"))
00159 {
00160 ROS_ERROR("Missing parameter scale");
00161 continue;
00162 }
00163 if(!field->second.hasMember("start_angle"))
00164 {
00165 ROS_ERROR("Missing parameter start_angle");
00166 continue;
00167 }
00168 if(!field->second.hasMember("stop_angle"))
00169 {
00170 ROS_ERROR("Missing parameter stop_angle");
00171 continue;
00172 }
00173
00174 ScannerSickS300::ParamType param;
00175 param.dScale = field->second["scale"];
00176 param.dStartAngle = field->second["start_angle"];
00177 param.dStopAngle = field->second["stop_angle"];
00178 scanner_.setRangeField(field_number, param);
00179
00180 ROS_DEBUG("params %f %f %f", param.dScale, param.dStartAngle, param.dStopAngle);
00181 }
00182 }
00183 else
00184 {
00185 ROS_WARN("No params for the Sick S300 fieldset were specified --> will using default, but it's deprecated now, please adjust parameters!!!");
00186
00187
00188 ScannerSickS300::ParamType param;
00189 param.dScale = 0.01;
00190 param.dStartAngle = -135.0/180.0*M_PI;
00191 param.dStopAngle = 135.0/180.0*M_PI;
00192 scanner_.setRangeField(1, param);
00193 }
00194
00195 syncedSICKStamp = 0;
00196 syncedROSTime = ros::Time::now();
00197 syncedTimeReady = false;
00198
00199 node_name = ros::this_node::getName();
00200
00201
00202 topicPub_LaserScan = nh.advertise<sensor_msgs::LaserScan>("scan", 1);
00203 topicPub_InStandby = nh.advertise<std_msgs::Bool>("scan_standby", 1);
00204 topicPub_Diagnostic_ = nh.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 1);
00205
00206 loop_rate_ = ros::Time::now();
00207 }
00208
00209 bool open() {
00210 return scanner_.open(port.c_str(), baud, scan_id);
00211 }
00212
00213 void receiveScan() {
00214 std::vector< double > ranges, rangeAngles, intensities;
00215 unsigned int iSickTimeStamp, iSickNow;
00216
00217 if(scanner_.getScan(ranges, rangeAngles, intensities, iSickTimeStamp, iSickNow, debug_))
00218 {
00219 if(scanner_.isInStandby())
00220 {
00221 publishWarn("scanner in standby");
00222 ROS_WARN_THROTTLE(30, "scanner %s on port %s in standby", node_name.c_str(), port.c_str());
00223 publishStandby(true);
00224 }
00225 else
00226 {
00227 publishStandby(false);
00228 publishLaserScan(ranges, rangeAngles, intensities, iSickTimeStamp, iSickNow);
00229 }
00230 }
00231 }
00232
00233
00234 ~NodeClass()
00235 {
00236 }
00237
00238 void publishStandby(bool inStandby)
00239 {
00240 this->inStandby_.data = inStandby;
00241 topicPub_InStandby.publish(this->inStandby_);
00242 }
00243
00244
00245 void publishLaserScan(std::vector<double> vdDistM, std::vector<double> vdAngRAD, std::vector<double> vdIntensAU, unsigned int iSickTimeStamp, unsigned int iSickNow)
00246 {
00247 if(ros::Time::now()-loop_rate_.now()>=ros::Duration(1./publish_frequency))
00248 return;
00249 loop_rate_ = ros::Time::now();
00250
00251
00252 int start_scan, stop_scan;
00253 int num_readings = vdDistM.size();
00254 start_scan = 0;
00255 stop_scan = vdDistM.size();
00256
00257
00258
00259 if(iSickNow != 0) {
00260 syncedROSTime = ros::Time::now() - ros::Duration(scan_cycle_time);
00261 syncedSICKStamp = iSickNow;
00262 syncedTimeReady = true;
00263
00264 ROS_DEBUG("Got iSickNow, store sync-stamp: %d", syncedSICKStamp);
00265 } else syncedTimeReady = false;
00266
00267
00268 sensor_msgs::LaserScan laserScan;
00269 if(syncedTimeReady) {
00270 double timeDiff = (int)(iSickTimeStamp - syncedSICKStamp) * scan_cycle_time;
00271 laserScan.header.stamp = syncedROSTime + ros::Duration(timeDiff);
00272
00273 ROS_DEBUG("Time::now() - calculated sick time stamp = %f",(ros::Time::now() - laserScan.header.stamp).toSec());
00274 } else {
00275 laserScan.header.stamp = ros::Time::now();
00276 }
00277
00278
00279 laserScan.header.frame_id = frame_id;
00280 laserScan.angle_increment = vdAngRAD[start_scan + 1] - vdAngRAD[start_scan];
00281 laserScan.range_min = 0.001;
00282 laserScan.range_max = 30.0;
00283 laserScan.time_increment = (scan_duration) / (vdDistM.size());
00284
00285
00286 num_readings = vdDistM.size();
00287 laserScan.angle_min = vdAngRAD[start_scan];
00288 laserScan.angle_max = vdAngRAD[stop_scan - 1];
00289 laserScan.ranges.resize(num_readings);
00290 laserScan.intensities.resize(num_readings);
00291
00292
00293
00294 if(inverted) {
00295
00296
00297 laserScan.time_increment = - laserScan.time_increment;
00298 } else {
00299 laserScan.header.stamp = laserScan.header.stamp - ros::Duration(scan_duration);
00300 }
00301
00302 for(int i = 0; i < (stop_scan - start_scan); i++)
00303 {
00304 if(inverted)
00305 {
00306 laserScan.ranges[i] = vdDistM[stop_scan-1-i];
00307 laserScan.intensities[i] = vdIntensAU[stop_scan-1-i];
00308 }
00309 else
00310 {
00311 laserScan.ranges[i] = vdDistM[start_scan + i];
00312 laserScan.intensities[i] = vdIntensAU[start_scan + i];
00313 }
00314 }
00315
00316
00317 topicPub_LaserScan.publish(laserScan);
00318
00319
00320 diagnostic_msgs::DiagnosticArray diagnostics;
00321 diagnostics.status.resize(1);
00322 diagnostics.status[0].level = 0;
00323 diagnostics.status[0].name = nh.getNamespace();
00324 diagnostics.status[0].message = "sick scanner running";
00325 topicPub_Diagnostic_.publish(diagnostics);
00326 }
00327
00328 void publishError(std::string error_str) {
00329 diagnostic_msgs::DiagnosticArray diagnostics;
00330 diagnostics.status.resize(1);
00331 diagnostics.status[0].level = 2;
00332 diagnostics.status[0].name = nh.getNamespace();
00333 diagnostics.status[0].message = error_str;
00334 topicPub_Diagnostic_.publish(diagnostics);
00335 }
00336
00337 void publishWarn(std::string warn_str) {
00338 diagnostic_msgs::DiagnosticArray diagnostics;
00339 diagnostics.status.resize(1);
00340 diagnostics.status[0].level = 1;
00341 diagnostics.status[0].name = nh.getNamespace();
00342 diagnostics.status[0].message = warn_str;
00343 topicPub_Diagnostic_.publish(diagnostics);
00344 }
00345 };
00346
00347
00348
00349 int main(int argc, char** argv)
00350 {
00351
00352 ros::init(argc, argv, "sick_s300");
00353
00354 NodeClass nodeClass;
00355
00356 bool bOpenScan = false;
00357 while (!bOpenScan && ros::ok()) {
00358 ROS_INFO("Opening scanner... (port:%s)", nodeClass.port.c_str());
00359
00360 bOpenScan = nodeClass.open();
00361
00362
00363
00364 if (!bOpenScan) {
00365 ROS_ERROR("...scanner not available on port %s. Will retry every second.", nodeClass.port.c_str());
00366 nodeClass.publishError("...scanner not available on port");
00367 }
00368 sleep(1);
00369 }
00370 ROS_INFO("...scanner opened successfully on port %s", nodeClass.port.c_str());
00371
00372
00373 while (ros::ok()) {
00374
00375 nodeClass.receiveScan();
00376 ros::spinOnce();
00377 }
00378 return 0;
00379 }