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 }