00001 #include "scans_2_odom_alg_node.h"
00002
00003 Scans2OdomAlgNode::Scans2OdomAlgNode(void) :
00004 algorithm_base::IriBaseAlgorithm<Scans2OdomAlgorithm>()
00005 {
00006
00007
00008
00009
00010
00011
00012 this->scan_subscriber_ = this->public_node_handle_.subscribe("scan", 10, &Scans2OdomAlgNode::scan_callback, this);
00013
00014
00015 this->get_link_server_ = this->public_node_handle_.advertiseService("get_link", &Scans2OdomAlgNode::get_linkCallback, this);
00016
00017
00018 get_relative_pose_client_ = this->public_node_handle_.serviceClient<iri_laser_icp::GetRelativePose>("get_relative_pose");
00019
00020
00021
00022
00023 }
00024
00025 Scans2OdomAlgNode::~Scans2OdomAlgNode(void)
00026 {
00027
00028 }
00029
00030 void Scans2OdomAlgNode::mainNodeThread(void)
00031 {
00032
00033
00034
00035
00036
00037
00038
00039 }
00040
00041
00042 void Scans2OdomAlgNode::scan_callback(const sensor_msgs::LaserScan::ConstPtr& msg)
00043 {
00044 ROS_DEBUG("SCANS 2 ODOM New LaserScan Message Received");
00045
00046
00047
00048
00049 if (discarded_laser_scan_buffer_.size() == discarded_laser_scan_buffer_.capacity())
00050 discarded_laser_scan_buffer_.reserve(int(discarded_laser_scan_buffer_.size()) + 1000);
00051
00052 discarded_laser_scan_buffer_.push_back(*msg);
00053
00054 ROS_DEBUG("SCANS 2 ODOM New Laser Scan buffered");
00055
00056 }
00057
00058
00059 bool Scans2OdomAlgNode::get_linkCallback(iri_poseslam::GetLink::Request &req, iri_poseslam::GetLink::Response &res)
00060 {
00061
00062 if (laser_scan_buffer_.size() == laser_scan_buffer_.capacity())
00063 laser_scan_buffer_.reserve(int(laser_scan_buffer_.size()) + 1000);
00064
00065 res.success = false;
00066 res.end = false;
00067
00068
00069 if (req.current_step == 0 && req.with_step == 0)
00070 {
00071 if (discarded_laser_scan_buffer_.size() > 0)
00072 {
00073
00074 res.odom.header = discarded_laser_scan_buffer_.front().header;
00075 res.success = true;
00076
00077
00078 laser_scan_buffer_.push_back(discarded_laser_scan_buffer_.front());
00079
00080
00081 discarded_laser_scan_buffer_.erase(discarded_laser_scan_buffer_.begin(), discarded_laser_scan_buffer_.begin() + 1);
00082
00083 ROS_INFO("SCANS 2 ODOM first laser scan header given");
00084 }
00085 }
00086
00087
00088 else
00089 {
00090
00091
00092 if (discarded_laser_scan_buffer_.size() == 0)
00093 {
00094 if (laser_scan_buffer_.size() > 0)
00095 ROS_DEBUG("SCANS 2 ODOM there is no more laser scans for now...");
00096
00097 res.end = true;
00098 }
00099 else
00100 {
00101
00102 if (req.current_step < req.with_step)
00103 {
00104 if (online_mode)
00105 get_relative_pose_srv_.request.scan_sens = discarded_laser_scan_buffer_.back();
00106 else
00107 get_relative_pose_srv_.request.scan_sens = discarded_laser_scan_buffer_.front();
00108
00109 get_relative_pose_srv_.request.scan_ref = laser_scan_buffer_.at(req.current_step);
00110 get_relative_pose_srv_.request.prior_d.position.x = 0;
00111 get_relative_pose_srv_.request.prior_d.position.y = 0;
00112 get_relative_pose_srv_.request.prior_d.position.z = 0;
00113 get_relative_pose_srv_.request.prior_d.orientation.x = 0;
00114 get_relative_pose_srv_.request.prior_d.orientation.y = 0;
00115 get_relative_pose_srv_.request.prior_d.orientation.z = 0;
00116
00117
00118 if (get_relative_pose_client_.call(get_relative_pose_srv_))
00119 {
00120 ROS_DEBUG("SCANS 2 ODOM ICP in odometry success!");
00121 geometry_msgs::PoseWithCovarianceStamped d = get_relative_pose_srv_.response.pose_rel;
00122
00123
00124 if (!online_mode)
00125 {
00126
00127 discarded_laser_scan_buffer_.erase(discarded_laser_scan_buffer_.begin(), discarded_laser_scan_buffer_.begin() + 1);
00128 }
00129
00130
00131 else
00132 {
00133
00134 if ((d.pose.covariance.at(0) > bad_cov_thres ||
00135 d.pose.covariance.at(7) > bad_cov_thres ||
00136 d.pose.covariance.at(17) > bad_cov_thres))
00137 {
00138
00139 uint idx_LS = uint(discarded_laser_scan_buffer_.size() - 1);
00140
00141 ROS_WARN("SCANS 2 ODOM ICP given a too much covariance odometry, trying to reconstruct with the %i discarded poses", idx_LS + 1);
00142 bool good_cov = false;
00143
00144 while (!good_cov && idx_LS != 0)
00145 {
00146
00147 idx_LS = int(idx_LS / 2);
00148 get_relative_pose_srv_.request.scan_sens = discarded_laser_scan_buffer_.at(idx_LS);
00149
00150 if (get_relative_pose_client_.call(get_relative_pose_srv_))
00151 {
00152 d = get_relative_pose_srv_.response.pose_rel;
00153
00154 if (idx_LS > 0 && (d.pose.covariance.at(0) > bad_cov_thres
00155 || d.pose.covariance.at(7) > bad_cov_thres
00156 || d.pose.covariance.at(17) > bad_cov_thres))
00157 {
00158 ROS_INFO("SCANS 2 ODOM LaserScan %i still too much covariance - try with number %i", idx_LS + 1, int(idx_LS / 2) + 1);
00159 }
00160 else
00161 {
00162 if (idx_LS == 0)
00163 ROS_WARN("SCANS 2 ODOM ICP given too much covariance even in consecutive laser scans. Consecutive scans computed.");
00164 else
00165 ROS_INFO("SCANS 2 ODOM LaserScan %i works! adding it into the laser scan buffer", idx_LS + 1);
00166
00167 good_cov = true;
00168
00169
00170 discarded_laser_scan_buffer_.erase(discarded_laser_scan_buffer_.begin(), discarded_laser_scan_buffer_.begin() + idx_LS + 1);
00171
00172 ROS_INFO("SCANS 2 ODOM Removed discarded laser scans until %i. New discarded bufer size: %u", idx_LS + 1, uint(discarded_laser_scan_buffer_.size()));
00173 }
00174 }
00175 }
00176 }
00177 else
00178
00179 discarded_laser_scan_buffer_.clear();
00180 }
00181
00182
00183 Vector3d link_ICP = pose_2_vector(d.pose.pose);
00184 Matrix3d link_ICP_cov = covariance_2_matrix(d.pose);
00185
00186
00187 change_2_base_footprint_frame(link_ICP, link_ICP_cov);
00188
00189
00190 link_ICP_cov = link_ICP_cov * ICP_covariance_correction_factor;
00191
00192 res.odom.header = get_relative_pose_srv_.request.scan_sens.header;
00193 res.odom.pose = eigen_2_posewithcovariance(link_ICP, link_ICP_cov);
00194 res.success = true;
00195
00196
00197 laser_scan_buffer_.push_back(get_relative_pose_srv_.request.scan_sens);
00198 }
00199 else
00200 {
00201 ROS_WARN("SCANS 2 ODOM ICP failed in a odometry");
00202 res.success = false;
00203 }
00204 }
00205
00206
00207 else
00208 {
00209 get_relative_pose_srv_.request.scan_ref = laser_scan_buffer_.at(req.with_step);
00210 get_relative_pose_srv_.request.scan_sens = laser_scan_buffer_.at(req.current_step);
00211 get_relative_pose_srv_.request.prior_d = req.prior_d;
00212
00213
00214 if (get_relative_pose_client_.call(get_relative_pose_srv_))
00215 {
00216 Vector3d link_ICP = pose_2_vector(get_relative_pose_srv_.response.pose_rel.pose.pose);
00217 Matrix3d link_ICP_cov = covariance_2_matrix(get_relative_pose_srv_.response.pose_rel.pose);
00218
00219
00220 change_2_base_footprint_frame(link_ICP, link_ICP_cov);
00221
00222
00223 link_ICP_cov = link_ICP_cov * ICP_covariance_correction_factor;
00224
00225 res.odom.header = get_relative_pose_srv_.request.scan_sens.header;
00226 res.odom.pose = eigen_2_posewithcovariance(link_ICP, link_ICP_cov);
00227 res.success = true;
00228 ROS_DEBUG("SCANS 2 ODOM ICP in LC result = = %f, %f, %f", res.odom.pose.pose.position.x, res.odom.pose.pose.position.y, tf::getYaw(res.odom.pose.pose.orientation));
00229
00230 }
00231 else
00232 {
00233 ROS_WARN("SCANS 2 ODOM ICP failed in loop closure");
00234 res.success = false;
00235 }
00236 }
00237 }
00238 }
00239
00240 return true;
00241 }
00242
00243 Matrix3d Scans2OdomAlgNode::rotation_matrix(const double &alpha) const
00244 {
00245 Matrix3d rot = MatrixXd::Identity(3,3);
00246
00247 rot(0,0) = cos(alpha);
00248 rot(0,1) = -sin(alpha);
00249 rot(1,0) = sin(alpha);
00250 rot(1,1) = cos(alpha);
00251
00252 return rot;
00253 }
00254
00255 Matrix3d Scans2OdomAlgNode::covariance_2_matrix(const geometry_msgs::PoseWithCovariance &pose) const
00256 {
00257 Matrix3d cov;
00258
00259 cov(0,0) = pose.covariance[0];
00260 cov(0,1) = pose.covariance[1];
00261 cov(0,2) = pose.covariance[5];
00262 cov(1,0) = pose.covariance[6];
00263 cov(1,1) = pose.covariance[7];
00264 cov(1,2) = pose.covariance[11];
00265 cov(2,0) = pose.covariance[30];
00266 cov(2,1) = pose.covariance[31];
00267 cov(2,2) = pose.covariance[35];
00268
00269 return cov;
00270 }
00271
00272 Vector3d Scans2OdomAlgNode::pose_2_vector(const geometry_msgs::Pose &pose) const
00273 {
00274 Vector3d p;
00275
00276 p(0) = pose.position.x;
00277 p(1) = pose.position.y;
00278 p(2) = tf::getYaw(pose.orientation);
00279
00280 return p;
00281 }
00282
00283 geometry_msgs::PoseWithCovariance Scans2OdomAlgNode::eigen_2_posewithcovariance(const Vector3d &p, const Matrix3d &cov) const
00284 {
00285 geometry_msgs::PoseWithCovariance pose;
00286
00287 pose.pose.position.x = p(0);
00288 pose.pose.position.y = p(1);
00289 pose.pose.position.z = 0;
00290 pose.pose.orientation = tf::createQuaternionMsgFromYaw(p(2));
00291
00292 pose.covariance[0] = cov(0,0);
00293 pose.covariance[1] = cov(0,1);
00294 pose.covariance[5] = cov(0,2);
00295 pose.covariance[6] = cov(1,0);
00296 pose.covariance[7] = cov(1,1);
00297 pose.covariance[11] = cov(1,2);
00298 pose.covariance[30] = cov(2,0);
00299 pose.covariance[31] = cov(2,1);
00300 pose.covariance[35] = cov(2,2);
00301
00302 return pose;
00303 }
00304
00305 void Scans2OdomAlgNode::change_2_base_footprint_frame(Vector3d &odom_ICP, Matrix3d &odom_ICP_cov)
00306 {
00307 Matrix3d rot_frame = rotation_matrix(d_base_2_laser(2));
00308 Matrix3d rot_d = rotation_matrix(odom_ICP(2));
00309 odom_ICP = d_base_2_laser + rot_frame * odom_ICP - rot_d * d_base_2_laser;
00310
00311 Matrix3d J = rotation_matrix(d_base_2_laser(2));
00312 odom_ICP_cov = J * odom_ICP_cov * J.transpose();
00313 }
00314
00315
00316
00317
00318
00319 void Scans2OdomAlgNode::node_config_update(Config &config, uint32_t level)
00320 {
00321 this->alg_.lock();
00322
00323 online_mode = config.online_mode;
00324 bad_cov_thres = config.bad_cov_thres;
00325 d_base_2_laser(0) = config.dx_base_2_laser;
00326 d_base_2_laser(1) = config.dy_base_2_laser;
00327 d_base_2_laser(2) = config.dth_base_2_laser;
00328 ICP_covariance_correction_factor = config.ICP_covariance_correction_factor;
00329
00330 ROS_WARN("SCANS 2 ODOM: Config updated");
00331
00332 this->alg_.unlock();
00333 }
00334
00335 void Scans2OdomAlgNode::addNodeDiagnostics(void)
00336 {
00337 }
00338
00339
00340 int main(int argc,char *argv[])
00341 {
00342 return algorithm_base::main<Scans2OdomAlgNode>(argc, argv, "scans_2_odom_alg_node");
00343 }