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 #include <urg_node/urg_c_wrapper.h>
00035 
00036 using namespace urg_node;
00037 
00038 URGCWrapper::URGCWrapper(const std::string& ip_address, const int ip_port, bool& using_intensity, bool& using_multiecho){
00039   
00040   ip_address_ = ip_address;
00041   ip_port_ = ip_port;
00042   serial_port_ = "";
00043   serial_baud_ = 0;
00044 
00045 
00046   long baudrate_or_port = (long)ip_port;
00047   const char *device = ip_address.c_str();
00048 
00049   int result = urg_open(&urg_, URG_ETHERNET, device, baudrate_or_port);
00050   if (result < 0) {
00051     std::stringstream ss;
00052     ss << "Could not open network Hokuyo:\n";
00053     ss << ip_address << ":" << ip_port << "\n";
00054     ss << urg_error(&urg_);
00055     throw std::runtime_error(ss.str());
00056   }
00057 
00058   initialize(using_intensity, using_multiecho);
00059 }
00060 
00061 URGCWrapper::URGCWrapper(const int serial_baud, const std::string& serial_port, bool& using_intensity, bool& using_multiecho){
00062   
00063   serial_baud_ = serial_baud;
00064   serial_port_ = serial_port;
00065   ip_address_ = "";
00066   ip_port_ = 0;
00067 
00068   long baudrate_or_port = (long)serial_baud;
00069   const char *device = serial_port.c_str();
00070 
00071   int result = urg_open(&urg_, URG_SERIAL, device, baudrate_or_port);
00072   if (result < 0) {
00073     std::stringstream ss;
00074     ss << "Could not open serial Hokuyo:\n";
00075     ss << serial_port << " @ " << serial_baud << "\n";
00076     ss << urg_error(&urg_);
00077     throw std::runtime_error(ss.str());
00078   }
00079 
00080   initialize(using_intensity, using_multiecho);
00081 }
00082 
00083 void URGCWrapper::initialize(bool& using_intensity, bool& using_multiecho){
00084   int urg_data_size = urg_max_data_size(&urg_);
00085   if(urg_data_size  > 5000){  
00086     urg_data_size = 5000;
00087   }
00088   data_.resize(urg_data_size * URG_MAX_ECHO);
00089   intensity_.resize(urg_data_size * URG_MAX_ECHO);
00090 
00091   started_ = false;
00092   frame_id_ = "";
00093   first_step_ = 0;
00094   last_step_ = 0;
00095   cluster_ = 1;
00096   skip_ = 0;
00097 
00098   if(using_intensity){
00099         using_intensity = isIntensitySupported();
00100   }
00101 
00102   if(using_multiecho){
00103         using_multiecho = isMultiEchoSupported();
00104   }
00105 
00106   use_intensity_ = using_intensity;
00107         use_multiecho_ = using_multiecho;
00108 
00109         measurement_type_ = URG_DISTANCE;
00110         if(use_intensity_ && use_multiecho_){
00111                 measurement_type_ = URG_MULTIECHO_INTENSITY;
00112         } else if(use_intensity_){
00113             measurement_type_ = URG_DISTANCE_INTENSITY;
00114         } else if(use_multiecho_){
00115                 measurement_type_ = URG_MULTIECHO;
00116         }
00117 }
00118 
00119 void URGCWrapper::start(){
00120         if(!started_){
00121                 int result = urg_start_measurement(&urg_, measurement_type_, 0, skip_);
00122                 if (result < 0) {
00123               std::stringstream ss;
00124               ss << "Could not start Hokuyo measurement:\n";
00125               if(use_intensity_){
00126                 ss << "With Intensity" << "\n";
00127               }
00128               if(use_multiecho_){
00129                 ss << "With MultiEcho" << "\n";
00130               }
00131               ss << urg_error(&urg_);
00132               throw std::runtime_error(ss.str());
00133             }
00134     }
00135     started_ = true;
00136 }
00137 
00138 void URGCWrapper::stop(){
00139         urg_stop_measurement(&urg_);
00140         started_ = false;
00141 }
00142 
00143 URGCWrapper::~URGCWrapper(){
00144         stop();
00145         urg_close(&urg_);
00146 }
00147 
00148 bool URGCWrapper::grabScan(const sensor_msgs::LaserScanPtr& msg){
00149   msg->header.frame_id = frame_id_;
00150   msg->angle_min = getAngleMin();
00151   msg->angle_max = getAngleMax();
00152   msg->angle_increment = getAngleIncrement();
00153   msg->scan_time = getScanPeriod();
00154   msg->time_increment = getTimeIncrement();
00155   msg->range_min = getRangeMin();
00156   msg->range_max = getRangeMax();
00157   
00158   
00159   int num_beams = 0;
00160   long time_stamp = 0;
00161   unsigned long long system_time_stamp = 0;
00162 
00163   if(use_intensity_){
00164         num_beams = urg_get_distance_intensity(&urg_, &data_[0], &intensity_[0], &time_stamp, &system_time_stamp);
00165   } else {
00166         num_beams = urg_get_distance(&urg_, &data_[0], &time_stamp, &system_time_stamp);
00167   } 
00168   if (num_beams <= 0) {
00169     return false;
00170   }
00171 
00172   
00173   msg->header.stamp.fromNSec((uint64_t)system_time_stamp);
00174   msg->header.stamp = msg->header.stamp + system_latency_ + user_latency_ + getAngularTimeOffset();
00175   msg->ranges.resize(num_beams);
00176   if(use_intensity_){
00177         msg->intensities.resize(num_beams);
00178   }
00179   
00180   for (int i = 0; i < num_beams; i++) {
00181     if(data_[(i) + 0] != 0){
00182       msg->ranges[i] = (float)data_[i]/1000.0;
00183       if(use_intensity_){
00184         msg->intensities[i] = intensity_[i];
00185           }
00186     } else {
00187       msg->ranges[i] = std::numeric_limits<float>::quiet_NaN();
00188       continue;
00189     }  
00190   }
00191   return true;
00192 }
00193 
00194 bool URGCWrapper::grabScan(const sensor_msgs::MultiEchoLaserScanPtr& msg){
00195   msg->header.frame_id = frame_id_;
00196   msg->angle_min = getAngleMin();
00197   msg->angle_max = getAngleMax();
00198   msg->angle_increment = getAngleIncrement();
00199   msg->scan_time = getScanPeriod();
00200   msg->time_increment = getTimeIncrement();
00201   msg->range_min = getRangeMin();
00202   msg->range_max = getRangeMax();
00203   
00204   
00205   int num_beams = 0;
00206   long time_stamp = 0;
00207   unsigned long long system_time_stamp;
00208 
00209   if(use_intensity_){
00210         num_beams = urg_get_multiecho_intensity(&urg_, &data_[0], &intensity_[0], &time_stamp, &system_time_stamp);
00211   } else {
00212         num_beams = urg_get_multiecho(&urg_, &data_[0], &time_stamp, &system_time_stamp);
00213   } 
00214   if (num_beams <= 0) {
00215     return false;
00216   }
00217 
00218   
00219   msg->header.stamp.fromNSec((uint64_t)system_time_stamp);
00220   msg->header.stamp = msg->header.stamp + system_latency_ + user_latency_ + getAngularTimeOffset();
00221   msg->ranges.reserve(num_beams);
00222   if(use_intensity_){
00223         msg->intensities.reserve(num_beams);
00224   } 
00225 
00226   for (size_t i = 0; i < num_beams; i++) {
00227     sensor_msgs::LaserEcho range_echo;
00228     range_echo.echoes.reserve(URG_MAX_ECHO);
00229     sensor_msgs::LaserEcho intensity_echo;
00230     if(use_intensity_){
00231       intensity_echo.echoes.reserve(URG_MAX_ECHO);
00232     }
00233     for(size_t j = 0; j < URG_MAX_ECHO; j++){
00234       if(data_[(URG_MAX_ECHO * i) + j] != 0){
00235         range_echo.echoes.push_back((float)data_[(URG_MAX_ECHO * i) + j]/1000.0f);
00236         if(use_intensity_){
00237                 intensity_echo.echoes.push_back(intensity_[(URG_MAX_ECHO * i) + j]);
00238           }
00239       } else {
00240         break;
00241       }
00242     }
00243     msg->ranges.push_back(range_echo);
00244     if(use_intensity_){
00245       msg->intensities.push_back(intensity_echo);
00246     }
00247   }
00248 
00249   return true;
00250 }
00251 
00252 bool URGCWrapper::isStarted() const{
00253   return started_;
00254 }
00255 
00256 double URGCWrapper::getRangeMin() const{
00257   long minr;
00258   long maxr;
00259   urg_distance_min_max(&urg_, &minr, &maxr);
00260   return (double)minr/1000.0;
00261 }
00262 
00263 double URGCWrapper::getRangeMax() const{
00264   long minr;
00265   long maxr;
00266   urg_distance_min_max(&urg_, &minr, &maxr);
00267   return (double)maxr/1000.0;
00268 }
00269 
00270 double URGCWrapper::getAngleMin() const{
00271   return urg_step2rad(&urg_, first_step_);
00272 }
00273 
00274 double URGCWrapper::getAngleMax() const{
00275   return urg_step2rad(&urg_, last_step_);
00276 }
00277 
00278 double URGCWrapper::getAngleMinLimit() const{
00279   int min_step;
00280   int max_step;
00281   urg_step_min_max(&urg_, &min_step, &max_step);
00282   return urg_step2rad(&urg_, min_step);
00283 }
00284 
00285 double URGCWrapper::getAngleMaxLimit() const{
00286   int min_step;
00287   int max_step;
00288   urg_step_min_max(&urg_, &min_step, &max_step);
00289   return urg_step2rad(&urg_, max_step);
00290 }
00291 
00292 double URGCWrapper::getAngleIncrement() const{
00293   double angle_min = getAngleMin();
00294   double angle_max = getAngleMax();
00295   return cluster_*(angle_max-angle_min)/(double)(last_step_-first_step_);
00296 }
00297 
00298 double URGCWrapper::getScanPeriod() const{
00299   long scan_usec = urg_scan_usec(&urg_);
00300   return 1.e-6*(double)(scan_usec);
00301 }
00302 
00303 double URGCWrapper::getTimeIncrement() const{
00304   int min_step;
00305   int max_step;
00306   urg_step_min_max(&urg_, &min_step, &max_step);
00307   double scan_period = getScanPeriod();
00308   double circle_fraction = (getAngleMaxLimit()-getAngleMinLimit())/(2.0*3.141592);
00309   return cluster_*circle_fraction*scan_period/(double)(max_step-min_step);
00310 }
00311 
00312 
00313 std::string URGCWrapper::getIPAddress() const{
00314   return ip_address_;
00315 }
00316 
00317 int URGCWrapper::getIPPort() const{
00318   return ip_port_;
00319 }
00320 
00321 std::string URGCWrapper::getSerialPort() const{
00322   return serial_port_;
00323 }
00324 
00325 int URGCWrapper::getSerialBaud() const{
00326   return serial_baud_;
00327 }
00328 
00329 std::string URGCWrapper::getVendorName(){
00330   return std::string(urg_sensor_vendor(&urg_));
00331 }
00332 
00333 std::string URGCWrapper::getProductName(){
00334   return std::string(urg_sensor_product_type(&urg_));
00335 }
00336 
00337 std::string URGCWrapper::getFirmwareVersion(){
00338   return std::string(urg_sensor_firmware_version(&urg_));
00339 }
00340 
00341 std::string URGCWrapper::getFirmwareDate(){
00342   return std::string(urg_sensor_firmware_date(&urg_));
00343 }
00344 
00345 std::string URGCWrapper::getProtocolVersion(){
00346   return std::string(urg_sensor_protocol_version(&urg_));
00347 }
00348 
00349 std::string URGCWrapper::getDeviceID(){
00350   return std::string(urg_sensor_serial_id(&urg_));
00351 }
00352 
00353 ros::Duration URGCWrapper::getComputedLatency() const{
00354   return system_latency_;
00355 }
00356 
00357 ros::Duration URGCWrapper::getUserTimeOffset() const{
00358   return user_latency_;
00359 }
00360 
00361 std::string URGCWrapper::getSensorStatus(){
00362   return std::string(urg_sensor_status(&urg_));
00363 }
00364 
00365 std::string URGCWrapper::getSensorState(){
00366   return std::string(urg_sensor_state(&urg_));
00367 }
00368 
00369 void URGCWrapper::setFrameId(const std::string& frame_id){
00370   frame_id_ = frame_id;
00371 }
00372 
00373 void URGCWrapper::setUserLatency(const double latency){
00374   user_latency_.fromSec(latency);
00375 }
00376 
00377 
00378 bool URGCWrapper::setAngleLimitsAndCluster(double& angle_min, double& angle_max, int cluster){
00379   if(started_){
00380         return false; 
00381   }
00382 
00383   
00384   first_step_ = urg_rad2step(&urg_, angle_min);
00385   last_step_ = urg_rad2step(&urg_, angle_max);
00386   cluster_ = cluster;
00387 
00388   
00389   if(first_step_ == last_step_){
00390         
00391         int min_step;
00392         int max_step;
00393         urg_step_min_max(&urg_, &min_step, &max_step);
00394         if(first_step_ == min_step){ 
00395                 last_step_ = first_step_ + 1;
00396         } else { 
00397                 first_step_ = last_step_ - 1;
00398         } 
00399   }
00400 
00401   
00402   if(last_step_ < first_step_){
00403         double temp = first_step_;
00404         first_step_ = last_step_;
00405         last_step_ = temp;
00406   }
00407 
00408   angle_min = urg_step2rad(&urg_, first_step_);
00409   angle_max = urg_step2rad(&urg_, last_step_);
00410   int result = urg_set_scanning_parameter(&urg_, first_step_, last_step_, cluster);
00411   if(result < 0){
00412     return false;
00413   }
00414   return true;
00415 }
00416 
00417 bool URGCWrapper::setSkip(int skip){
00418         skip_ = skip;
00419 }
00420 
00421 bool URGCWrapper::isIntensitySupported(){
00422   if(started_){
00423         return false; 
00424   }
00425 
00426   urg_start_measurement(&urg_, URG_DISTANCE_INTENSITY, 0, 0);
00427   int ret = urg_get_distance_intensity(&urg_, &data_[0], &intensity_[0], NULL, NULL);
00428   if(ret <= 0){
00429         return false; 
00430   }
00431   urg_stop_measurement(&urg_);
00432   return true;
00433 }
00434 
00435 bool URGCWrapper::isMultiEchoSupported(){
00436   if(started_){
00437         return false; 
00438   }
00439 
00440   urg_start_measurement(&urg_, URG_MULTIECHO, 0, 0);
00441   int ret = urg_get_multiecho(&urg_, &data_[0], NULL, NULL);
00442   if(ret <= 0){
00443         return false; 
00444   }
00445   urg_stop_measurement(&urg_);
00446   return true;
00447 }
00448 
00449 ros::Duration URGCWrapper::getAngularTimeOffset() const{
00450   
00451   
00452   double circle_fraction = 0.0;
00453   if(first_step_ == 0 && last_step_ == 0){
00454     circle_fraction = (getAngleMinLimit()+3.141592)/(2.0*3.141592);
00455   } else {
00456     circle_fraction = (getAngleMin()+3.141592)/(2.0*3.141592);
00457   }
00458   return ros::Duration(circle_fraction * getScanPeriod());
00459 }
00460 
00461 ros::Duration URGCWrapper::computeLatency(size_t num_measurements){
00462   system_latency_.fromNSec(0);
00463 
00464         ros::Duration start_offset = getNativeClockOffset(1);
00465         ros::Duration previous_offset;
00466 
00467         std::vector<ros::Duration> time_offsets(num_measurements);
00468         for (size_t i = 0; i < num_measurements; i++){
00469                 ros::Duration scan_offset = getTimeStampOffset(1);
00470                 ros::Duration post_offset = getNativeClockOffset(1);
00471                 ros::Duration adjusted_scan_offset = scan_offset - start_offset;
00472                 ros::Duration adjusted_post_offset = post_offset - start_offset;
00473                 ros::Duration average_offset;
00474                 average_offset.fromSec((adjusted_post_offset.toSec() + previous_offset.toSec())/2.0);
00475 
00476                 time_offsets[i] = adjusted_scan_offset - average_offset;
00477 
00478                 previous_offset = adjusted_post_offset;
00479         }
00480 
00481   
00482   
00483   std::nth_element(time_offsets.begin(), time_offsets.begin() + time_offsets.size()/2, time_offsets.end());
00484   system_latency_ = time_offsets[time_offsets.size()/2];
00485   return system_latency_ + getAngularTimeOffset(); 
00486 }
00487 
00488 ros::Duration URGCWrapper::getNativeClockOffset(size_t num_measurements){
00489   if(started_){
00490     std::stringstream ss;
00491     ss << "Cannot get native clock offset while started.";
00492     throw std::runtime_error(ss.str());
00493   }
00494 
00495   if(urg_start_time_stamp_mode(&urg_) < 0){
00496     std::stringstream ss;
00497     ss << "Cannot start time stamp mode.";
00498     throw std::runtime_error(ss.str());
00499   }
00500 
00501   std::vector<ros::Duration> time_offsets(num_measurements);
00502   for (size_t i = 0; i < num_measurements; i++)
00503   {
00504         ros::Time request_time = ros::Time::now();
00505         ros::Time laser_time;
00506         laser_time.fromNSec(1e6*(uint64_t)urg_time_stamp(&urg_)); 
00507         ros::Time response_time = ros::Time::now();
00508         ros::Time average_time;
00509         average_time.fromSec((response_time.toSec()+request_time.toSec())/2.0);
00510         time_offsets[i] = laser_time - average_time;
00511   }
00512 
00513   if(urg_stop_time_stamp_mode(&urg_) < 0){
00514     std::stringstream ss;
00515     ss << "Cannot stop time stamp mode.";
00516     throw std::runtime_error(ss.str());
00517   };
00518 
00519   
00520   
00521   std::nth_element(time_offsets.begin(), time_offsets.begin() + time_offsets.size()/2, time_offsets.end());
00522   return time_offsets[time_offsets.size()/2];
00523 }
00524 
00525 ros::Duration URGCWrapper::getTimeStampOffset(size_t num_measurements){
00526   if(started_){
00527     std::stringstream ss;
00528     ss << "Cannot get time stamp offset while started.";
00529     throw std::runtime_error(ss.str());
00530   }
00531 
00532   start();
00533 
00534   std::vector<ros::Duration> time_offsets(num_measurements);
00535   for(size_t i = 0; i < num_measurements; i++){
00536         long time_stamp;
00537     unsigned long long system_time_stamp;
00538         int ret = 0;
00539 
00540         if(measurement_type_ == URG_DISTANCE){
00541                 ret = urg_get_distance(&urg_, &data_[0], &time_stamp, &system_time_stamp);
00542         } else if(measurement_type_ == URG_DISTANCE_INTENSITY){
00543                 ret = urg_get_distance_intensity(&urg_, &data_[0], &intensity_[0], &time_stamp, &system_time_stamp);
00544         } else if(measurement_type_ == URG_MULTIECHO){
00545                 ret = urg_get_multiecho(&urg_, &data_[0], &time_stamp, &system_time_stamp);
00546         } else if(measurement_type_ == URG_MULTIECHO_INTENSITY){
00547                 ret = urg_get_multiecho_intensity(&urg_, &data_[0], &intensity_[0], &time_stamp, &system_time_stamp);
00548         }
00549 
00550         if(ret <= 0){
00551                 std::stringstream ss;
00552           ss << "Cannot get scan to measure time stamp offset.";
00553           throw std::runtime_error(ss.str());
00554         }
00555 
00556         ros::Time laser_timestamp;
00557         laser_timestamp.fromNSec(1e6*(uint64_t)time_stamp);
00558     ros::Time system_time;
00559     system_time.fromNSec((uint64_t)system_time_stamp);
00560 
00561         time_offsets[i] = laser_timestamp - system_time;
00562   }
00563 
00564   stop();
00565 
00566   
00567   
00568   std::nth_element(time_offsets.begin(), time_offsets.begin() + time_offsets.size()/2, time_offsets.end());
00569   return time_offsets[time_offsets.size()/2];
00570 }