00001
00009 #include <karto_scan_matcher/karto_scan_matcher.h>
00010 #include <tf/transform_datatypes.h>
00011 #include <string>
00012 #include <vector>
00013 #include <boost/bind.hpp>
00014 #include <boost/foreach.hpp>
00015 #include <boost/lexical_cast.hpp>
00016 #include <boost/thread.hpp>
00017
00018 namespace karto_scan_matcher
00019 {
00020
00021 namespace sm=sensor_msgs;
00022 namespace gm=geometry_msgs;
00023 using std::string;
00024 using std::vector;
00025 using boost::bind;
00026 using boost::lexical_cast;
00027
00028
00029
00030 static boost::mutex static_name_mutex;
00031 static unsigned name_suffix;
00032
00033
00034
00035
00036
00037
00038 karto::LocalizedRangeScan* convertLaserScan (karto::LaserRangeFinder* laser, const sm::LaserScan& scan,
00039 const gm::Pose2D& pose)
00040 {
00041
00042 karto::Pose2 karto_pose(pose.x, pose.y, pose.theta);
00043 vector<kt_double> readings(scan.ranges.begin(), scan.ranges.end());
00044
00045 karto::LocalizedRangeScan* localized = new karto::LocalizedRangeScan(laser->GetName(), readings);
00046 localized->SetOdometricPose(karto_pose);
00047 localized->SetCorrectedPose(karto_pose);
00048 return localized;
00049 }
00050
00051 karto::LocalizedRangeScan* convertLaserScan(karto::LaserRangeFinder* laser, const ScanWithPose& scan)
00052 {
00053 return convertLaserScan(laser, scan.scan, scan.pose);
00054 }
00055
00056
00057
00058
00059
00060
00061 KartoScanMatcher::KartoScanMatcher (const sm::LaserScan& init_scan, const tf::TransformListener& tf,
00062 const double search_space_size, const double search_grid_resolution)
00063 {
00064
00065 tf::Stamped<tf::Pose> ident;
00066 tf::Stamped<btTransform> laser_to_base;
00067 ident.setIdentity();
00068 ident.frame_id_ = init_scan.header.frame_id;
00069 ident.stamp_ = ros::Time();
00070
00071 if (!tf.waitForTransform("base_link", ident.frame_id_, ros::Time::now(), ros::Duration(10.0))) {
00072 ROS_FATAL_STREAM ("Didn't get a transform between base_link and " << ident.frame_id_ <<
00073 " in time during KartoScanMatcher initialization");
00074 ROS_BREAK();
00075 }
00076
00077 tf.transformPose("base_link", ident, laser_to_base);
00078
00079 gm::Pose2D laser_pose;
00080 laser_pose.x = laser_to_base.getOrigin().x();
00081 laser_pose.y = laser_to_base.getOrigin().y();
00082 laser_pose.theta = tf::getYaw(laser_to_base.getRotation());
00083
00084 vector<double> search_sizes;
00085 search_sizes.push_back(search_space_size);
00086 vector<double> search_resolutions;
00087 search_resolutions.push_back(search_grid_resolution);
00088 initialize(init_scan, laser_pose, search_sizes, search_resolutions);
00089 }
00090
00091 KartoScanMatcher::KartoScanMatcher (const sm::LaserScan& init_scan, const gm::Pose2D& laser_pose,
00092 const double search_space_size, const double search_grid_resolution)
00093 {
00094 DoubleVector search_sizes;
00095 search_sizes.push_back(search_space_size);
00096 DoubleVector search_resolutions;
00097 search_resolutions.push_back(search_grid_resolution);
00098 initialize(init_scan, laser_pose, search_sizes, search_resolutions);
00099 }
00100
00101 KartoScanMatcher::KartoScanMatcher (const sensor_msgs::LaserScan& init_scan, const geometry_msgs::Pose2D& laser_pose,
00102 const DoubleVector& search_sizes, const DoubleVector& search_resolutions)
00103 {
00104 initialize(init_scan, laser_pose, search_sizes, search_resolutions);
00105 }
00106
00107 void KartoScanMatcher::initialize (const sm::LaserScan& init_scan, const gm::Pose2D& laser_pose,
00108 const DoubleVector& search_sizes, const DoubleVector& search_resolutions)
00109 {
00110 penalize_distance_ = true;
00111 string suffix;
00112 {
00113 boost::mutex::scoped_lock l(static_name_mutex);
00114 suffix = boost::lexical_cast<string>(name_suffix++);
00115 }
00116
00117 ROS_DEBUG_NAMED ("karto", "Initializing scan matcher(s) using scan %u", init_scan.header.seq);
00118 dataset_.reset(new karto::Dataset());
00119 const size_t num_matchers = search_sizes.size();
00120 if (num_matchers == 0)
00121 ROS_WARN_NAMED ("karto", "Zero sets of matcher parameters given to KartoScanMatcher: almost surely an error");
00122 ROS_ASSERT (search_resolutions.size() == num_matchers);
00123 matchers_.resize(num_matchers);
00124 mappers_.resize(num_matchers);
00125 for (size_t i=0; i<num_matchers; i++) {
00126 if (i>0) {
00127 if (search_sizes[i] >= search_sizes[i-1])
00128 ROS_WARN_NAMED ("karto", "Matcher %zu search size was %f and %zu was %f, which look out of order",
00129 i-1, search_sizes[i-1], i, search_sizes[i]);
00130 if (search_resolutions[i] >= search_resolutions[i-1])
00131 ROS_WARN_NAMED ("karto", "Matcher %zu search resolution was %f and %zu was %f, which look out of order",
00132 i-1, search_resolutions[i-1], i, search_sizes[i]);
00133 }
00134 mappers_[i].reset(new karto::Mapper());
00135 matchers_[i].reset(karto::ScanMatcher::Create(mappers_[i].get(), search_sizes[i], search_resolutions[i],
00136 DEFAULT_SMEAR_DEVIATION, DEFAULT_RANGE_THRESHOLD));
00137 ROS_DEBUG_NAMED ("karto", "Search space size for matcher %zu is %.2f and resolution is %.2f",
00138 i, search_sizes[i], search_resolutions[i]);
00139 }
00140
00141
00142
00143
00144
00145
00146 string name = init_scan.header.frame_id;
00147 laser_ = karto::LaserRangeFinder::CreateLaserRangeFinder(karto::LaserRangeFinder_Custom, karto::Name(name+suffix));
00148 laser_->SetOffsetPose(karto::Pose2(laser_pose.x, laser_pose.y, laser_pose.theta));
00149 laser_->SetMinimumRange(init_scan.range_min);
00150 laser_->SetMaximumRange(init_scan.range_max);
00151 laser_->SetMinimumAngle(init_scan.angle_min);
00152 laser_->SetMaximumAngle(init_scan.angle_max);
00153 laser_->SetAngularResolution(init_scan.angle_increment);
00154
00155
00156 dataset_->Add(laser_);
00157 }
00158
00159 void KartoScanMatcher::setPenalizeDistance (const bool penalize)
00160 {
00161 penalize_distance_ = penalize;
00162 }
00163
00164
00165
00166
00167
00168 gm::Pose2D subtractLaserOffset (const karto::Pose2& pose, const karto::Pose2& offset)
00169 {
00170 btTransform laser_to_base(tf::createQuaternionFromYaw(offset.GetHeading()),
00171 btVector3(offset.GetX(), offset.GetY(), 0.0));
00172 btTransform laser_to_map(tf::createQuaternionFromYaw(pose.GetHeading()),
00173 btVector3(pose.GetX(), pose.GetY(), 0.0));
00174 btTransform base_to_map = laser_to_map*laser_to_base.inverse();
00175 gm::Pose2D result;
00176 result.x = base_to_map.getOrigin().x();
00177 result.y = base_to_map.getOrigin().y();
00178 result.theta = tf::getYaw(base_to_map.getRotation());
00179 return result;
00180 }
00181
00182 typedef boost::shared_ptr<karto::LocalizedRangeScan> ScanPtr;
00183 ScanPtr wrapBareScanPtr (karto::LocalizedRangeScan* scan)
00184 {
00185 return ScanPtr(scan);
00186 }
00187
00188
00189 ScanMatchResult KartoScanMatcher::scanMatch (const sm::LaserScan& scan, const gm::Pose2D& pose,
00190 const vector<ScanWithPose>& reference_scans) const
00191 {
00192 ROS_DEBUG_NAMED ("karto", "Converting to Karto and matching");
00193
00194 karto::LocalizedRangeScanVector localized_reference_scans;
00195 transform(reference_scans.begin(), reference_scans.end(), back_inserter(localized_reference_scans),
00196 bind(convertLaserScan, laser_, _1));
00197
00198
00199 vector<ScanPtr> scan_ptrs(localized_reference_scans.size());
00200 transform(localized_reference_scans.begin(), localized_reference_scans.end(),
00201 scan_ptrs.begin(), wrapBareScanPtr);
00202
00203 gm::Pose2D current_estimate = pose;
00204 double last_response = -42.42;
00205 Eigen::Matrix3f covariance = Eigen::Matrix3f::Zero();
00206
00207
00208 BOOST_FOREACH (const MatcherPtr matcher, matchers_) {
00209
00210 karto::LocalizedRangeScan* localized_scan = convertLaserScan(laser_, scan, current_estimate);
00211
00212
00213
00214
00215
00216
00217
00218 ScanPtr scan_ptr(localized_scan);
00219 karto::Pose2 mean;
00220 karto::Matrix3 cov;
00221
00222 const bool refine_match = true;
00223 ROS_DEBUG_NAMED ("karto", " Current estimate is %.2f, %.2f, %.2f, Calling scan matcher",
00224 current_estimate.x, current_estimate.y, current_estimate.theta);
00225 last_response = matcher->MatchScan(localized_scan, localized_reference_scans, mean,
00226 cov, penalize_distance_, refine_match);
00227 current_estimate = subtractLaserOffset(mean, laser_->GetOffsetPose());
00228 for (unsigned i=0; i<3; i++) {
00229 for (unsigned j=0; j<3; j++) {
00230 covariance(i,j) = cov(i,j);
00231 }
00232 }
00233 ROS_DEBUG_NAMED ("karto", " Response was %.4f.", last_response);
00234 }
00235
00236 ROS_DEBUG_NAMED ("karto", "Returning result %.2f, %.2f, %.2f with covariances (x-x: %.2f, y-y: %.2f, x-y: %.2f, th-th: %.2f)",
00237 current_estimate.x, current_estimate.y, current_estimate.theta, covariance(0,0),
00238 covariance(1,1), covariance(0,1), covariance(2,2));
00239 return ScanMatchResult(current_estimate, covariance, last_response);
00240 }
00241
00242
00243
00244
00245 }