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 #include <sick_tim/sick_tim_common.h>
00040
00041 #include <cstdio>
00042 #include <cstring>
00043
00044 namespace sick_tim
00045 {
00046
00047 SickTimCommon::SickTimCommon(AbstractParser* parser) :
00048 diagnosticPub_(NULL), expectedFrequency_(15.0), parser_(parser)
00049
00050 {
00051 dynamic_reconfigure::Server<sick_tim::SickTimConfig>::CallbackType f;
00052 f = boost::bind(&sick_tim::SickTimCommon::update_config, this, _1, _2);
00053 dynamic_reconfigure_server_.setCallback(f);
00054
00055
00056 ros::NodeHandle pn("~");
00057 pn.param<bool>("publish_datagram", publish_datagram_, false);
00058 if (publish_datagram_)
00059 datagram_pub_ = nh_.advertise<std_msgs::String>("datagram", 1000);
00060
00061
00062 pub_ = nh_.advertise<sensor_msgs::LaserScan>("scan", 1000);
00063
00064 diagnostics_.setHardwareID("none");
00065 diagnosticPub_ = new diagnostic_updater::DiagnosedPublisher<sensor_msgs::LaserScan>(pub_, diagnostics_,
00066
00067 diagnostic_updater::FrequencyStatusParam(&expectedFrequency_, &expectedFrequency_, 0.1, 10),
00068
00069 diagnostic_updater::TimeStampStatusParam(-1, 1.3 * 1.0/expectedFrequency_ - config_.time_offset));
00070 ROS_ASSERT(diagnosticPub_ != NULL);
00071 }
00072
00073 int SickTimCommon::stop_scanner()
00074 {
00075
00076
00077
00078 const char requestScanData0[] = {"\x02sEN LMDscandata 0\x03\0"};
00079 int result = sendSOPASCommand(requestScanData0, NULL);
00080 if (result != 0)
00081
00082 printf("\nSOPAS - Error stopping streaming scan data!\n");
00083 else
00084 printf("\nSOPAS - Stopped streaming scan data.\n");
00085
00086 return result;
00087 }
00088
00089 bool SickTimCommon::rebootScanner()
00090 {
00091
00092
00093
00094 std::vector<unsigned char> access_reply;
00095 int result = sendSOPASCommand("\x02sMN SetAccessMode 03 F4724744\x03\0", &access_reply);
00096 if (result != 0)
00097 {
00098 ROS_ERROR("SOPAS - Error setting access mode");
00099 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error setting access mode.");
00100 return false;
00101 }
00102 std::string access_reply_str = replyToString(access_reply);
00103 if (access_reply_str != "sAN SetAccessMode 1")
00104 {
00105 ROS_ERROR_STREAM("SOPAS - Error setting access mode, unexpected response : " << access_reply_str);
00106 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error setting access mode.");
00107 return false;
00108 }
00109
00110
00111
00112
00113 std::vector<unsigned char> reboot_reply;
00114 result = sendSOPASCommand("\x02sMN mSCreboot\x03\0", &reboot_reply);
00115 if (result != 0)
00116 {
00117 ROS_ERROR("SOPAS - Error rebooting scanner");
00118 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error rebooting device.");
00119 return false;
00120 }
00121 std::string reboot_reply_str = replyToString(reboot_reply);
00122 if (reboot_reply_str != "sAN mSCreboot")
00123 {
00124 ROS_ERROR_STREAM("SOPAS - Error rebooting scanner, unexpected response : " << reboot_reply_str);
00125 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error setting access mode.");
00126 return false;
00127 }
00128
00129 ROS_INFO("SOPAS - Rebooted scanner");
00130
00131
00132 ros::Duration(15.0).sleep();
00133
00134 return true;
00135 }
00136
00137 SickTimCommon::~SickTimCommon()
00138 {
00139 delete diagnosticPub_;
00140
00141 printf("sick_tim driver exiting.\n");
00142 }
00143
00144
00145 int SickTimCommon::init()
00146 {
00147 int result = init_device();
00148 if(result != 0) {
00149 ROS_FATAL("Failed to init device: %d", result);
00150 return result;
00151 }
00152 result = init_scanner();
00153 if(result != 0) {
00154 ROS_FATAL("Failed to init scanner: %d", result);
00155 }
00156 return result;
00157 }
00158
00159 int SickTimCommon::init_scanner()
00160 {
00161
00162
00163
00164 const char requestDeviceIdent[] = "\x02sRI0\x03\0";
00165 std::vector<unsigned char> identReply;
00166 int result = sendSOPASCommand(requestDeviceIdent, &identReply);
00167 if (result != 0)
00168 {
00169 ROS_ERROR("SOPAS - Error reading variable 'DeviceIdent'.");
00170 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'DeviceIdent'.");
00171 }
00172
00173
00174
00175
00176 const char requestSerialNumber[] = "\x02sRN SerialNumber\x03\0";
00177 std::vector<unsigned char> serialReply;
00178 result = sendSOPASCommand(requestSerialNumber, &serialReply);
00179 if (result != 0)
00180 {
00181 ROS_ERROR("SOPAS - Error reading variable 'SerialNumber'.");
00182 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'SerialNumber'.");
00183 }
00184
00185
00186 std::string identStr = replyToString(identReply);
00187 std::string serialStr = replyToString(serialReply);
00188 diagnostics_.setHardwareID(identStr + " " + serialStr);
00189
00190 if (!isCompatibleDevice(identStr))
00191 return ExitFatal;
00192
00193
00194
00195
00196 const char requestFirmwareVersion[] = {"\x02sRN FirmwareVersion\x03\0"};
00197 result = sendSOPASCommand(requestFirmwareVersion, NULL);
00198 if (result != 0)
00199 {
00200 ROS_ERROR("SOPAS - Error reading variable 'FirmwareVersion'.");
00201 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'FirmwareVersion'.");
00202 }
00203
00204
00205
00206
00207 const char requestDeviceState[] = {"\x02sRN SCdevicestate\x03\0"};
00208 std::vector<unsigned char> deviceStateReply;
00209 result = sendSOPASCommand(requestDeviceState, &deviceStateReply);
00210 if (result != 0)
00211 {
00212 ROS_ERROR("SOPAS - Error reading variable 'devicestate'.");
00213 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'devicestate'.");
00214 }
00215 std::string deviceStateReplyStr = replyToString(deviceStateReply);
00216
00217
00218
00219
00220
00221 if (deviceStateReplyStr == "sRA SCdevicestate 0")
00222 {
00223 ROS_WARN("Laser is busy");
00224 }
00225 else if (deviceStateReplyStr == "sRA SCdevicestate 1")
00226 {
00227 ROS_DEBUG("Laser is ready");
00228 }
00229 else if (deviceStateReplyStr == "sRA SCdevicestate 2")
00230 {
00231 ROS_ERROR_STREAM("Laser reports error state : " << deviceStateReplyStr);
00232 if (config_.auto_reboot)
00233 {
00234 rebootScanner();
00235 }
00236 }
00237 else
00238 {
00239 ROS_WARN_STREAM("Laser reports unknown devicestate : " << deviceStateReplyStr);
00240 }
00241
00242
00243
00244
00245 const char requestScanData[] = {"\x02sEN LMDscandata 1\x03\0"};
00246 result = sendSOPASCommand(requestScanData, NULL);
00247 if (result != 0)
00248 {
00249 ROS_ERROR("SOPAS - Error starting to stream 'LMDscandata'.");
00250 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error starting to stream 'LMDscandata'.");
00251 return ExitError;
00252 }
00253
00254 return ExitSuccess;
00255 }
00256
00257 std::string sick_tim::SickTimCommon::replyToString(const std::vector<unsigned char> &reply)
00258 {
00259 std::string reply_str;
00260 for (std::vector<unsigned char>::const_iterator it = reply.begin(); it != reply.end(); it++)
00261 {
00262 if (*it > 13)
00263 {
00264 reply_str.push_back(*it);
00265 }
00266 }
00267 return reply_str;
00268 }
00269
00270 bool sick_tim::SickTimCommon::isCompatibleDevice(const std::string identStr) const
00271 {
00272 char device_string[7];
00273 int version_major = -1;
00274 int version_minor = -1;
00275
00276 if (sscanf(identStr.c_str(), "sRA 0 6 %6s E V%d.%d", device_string,
00277 &version_major, &version_minor) == 3
00278 && strncmp("TiM3", device_string, 4) == 0
00279 && version_major >= 2 && version_minor >= 50)
00280 {
00281 ROS_ERROR("This scanner model/firmware combination does not support ranging output!");
00282 ROS_ERROR("Supported scanners: TiM5xx: all firmware versions; TiM3xx: firmware versions < V2.50.");
00283 ROS_ERROR("This is a %s, firmware version %d.%d", device_string, version_major, version_minor);
00284
00285 return false;
00286 }
00287 return true;
00288 }
00289
00290 int SickTimCommon::loopOnce()
00291 {
00292 diagnostics_.update();
00293
00294 unsigned char receiveBuffer[65536];
00295 int actual_length = 0;
00296 static unsigned int iteration_count = 0;
00297
00298 int result = get_datagram(receiveBuffer, 65536, &actual_length);
00299 if (result != 0)
00300 {
00301 ROS_ERROR("Read Error when getting datagram: %i.", result);
00302 diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "Read Error when getting datagram.");
00303 return ExitError;
00304 }
00305 if(actual_length <= 0)
00306 return ExitSuccess;
00307
00308
00309 if (iteration_count++ % (config_.skip + 1) != 0)
00310 return ExitSuccess;
00311
00312 if (publish_datagram_)
00313 {
00314 std_msgs::String datagram_msg;
00315 datagram_msg.data = std::string(reinterpret_cast<char*>(receiveBuffer));
00316 datagram_pub_.publish(datagram_msg);
00317 }
00318
00319 sensor_msgs::LaserScan msg;
00320
00321
00322
00323
00324 char* buffer_pos = (char*)receiveBuffer;
00325 char *dstart, *dend;
00326 while( (dstart = strchr(buffer_pos, 0x02)) && (dend = strchr(dstart + 1, 0x03)) )
00327 {
00328 size_t dlength = dend - dstart;
00329 *dend = '\0';
00330 dstart++;
00331 int success = parser_->parse_datagram(dstart, dlength, config_, msg);
00332 if (success == ExitSuccess)
00333 diagnosticPub_->publish(msg);
00334 buffer_pos = dend + 1;
00335 }
00336
00337 return ExitSuccess;
00338 }
00339
00340 void SickTimCommon::check_angle_range(SickTimConfig &conf)
00341 {
00342 if (conf.min_ang > conf.max_ang)
00343 {
00344 ROS_WARN("Minimum angle must be greater than maximum angle. Adjusting min_ang.");
00345 conf.min_ang = conf.max_ang;
00346 }
00347 }
00348
00349 void SickTimCommon::update_config(sick_tim::SickTimConfig &new_config, uint32_t level)
00350 {
00351 check_angle_range(new_config);
00352 config_ = new_config;
00353 }
00354
00355 }