diff --git a/apps/scan_matching_odometry_nodelet.cpp b/apps/scan_matching_odometry_nodelet.cpp index fb69a7e1..0bb42d5c 100644 --- a/apps/scan_matching_odometry_nodelet.cpp +++ b/apps/scan_matching_odometry_nodelet.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { auto& pnh = private_nh; points_topic = pnh.param("points_topic", "/velodyne_points"); odom_frame_id = pnh.param("odom_frame_id", "odom"); + robot_odom_frame_id = pnh.param("robot_odom_frame_id", "robot_odom"); // The minimum tranlational distance and rotation angle between keyframes. // If this value is zero, frames are always compared with the previous frame @@ -161,6 +163,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { */ Eigen::Matrix4f matching(const ros::Time& stamp, const pcl::PointCloud::ConstPtr& cloud) { if(!keyframe) { + prev_time = ros::Time(); prev_trans.setIdentity(); keyframe_pose.setIdentity(); keyframe_stamp = stamp; @@ -172,6 +175,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { auto filtered = downsample(cloud); registration->setInputSource(filtered); + std::string msf_source; Eigen::Isometry3f msf_delta = Eigen::Isometry3f::Identity(); if(private_nh.param("enable_imu_frontend", false)) { @@ -180,16 +184,31 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { Eigen::Isometry3d pose1 = pose2isometry(msf_pose->pose.pose); Eigen::Isometry3d delta = pose0.inverse() * pose1; + msf_source = "imu"; msf_delta = delta.cast(); } else { std::cerr << "msf data is too old" << std::endl; } + } else if(private_nh.param("enable_robot_odometry_init_guess", false) && !prev_time.isZero()) { + tf::StampedTransform transform; + if(tf_listener.waitForTransform(cloud->header.frame_id, stamp, cloud->header.frame_id, prev_time, robot_odom_frame_id, ros::Duration(0))) { + tf_listener.lookupTransform(cloud->header.frame_id, stamp, cloud->header.frame_id, prev_time, robot_odom_frame_id, transform); + } else if(tf_listener.waitForTransform(cloud->header.frame_id, ros::Time(0), cloud->header.frame_id, prev_time, robot_odom_frame_id, ros::Duration(0))) { + tf_listener.lookupTransform(cloud->header.frame_id, ros::Time(0), cloud->header.frame_id, prev_time, robot_odom_frame_id, transform); + } + + if(transform.stamp_.isZero()) { + NODELET_WARN_STREAM("failed to look up transform between " << cloud->header.frame_id << " and " << robot_odom_frame_id); + } else { + msf_source = "odometry"; + msf_delta = tf2isometry(transform).cast(); + } } pcl::PointCloud::Ptr aligned(new pcl::PointCloud()); registration->align(*aligned, prev_trans * msf_delta.matrix()); - publish_scan_matching_status(stamp, cloud->header.frame_id, *registration); + publish_scan_matching_status(stamp, cloud->header.frame_id, msf_source, msf_delta); if(!registration->hasConverged()) { NODELET_INFO_STREAM("scan matching has not converged!!"); @@ -212,6 +231,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { } } + prev_time = stamp; prev_trans = trans; auto keyframe_trans = matrix2transform(stamp, keyframe_pose, odom_frame_id, "keyframe"); @@ -226,6 +246,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { keyframe_pose = odom; keyframe_stamp = stamp; + prev_time = stamp; prev_trans.setIdentity(); } @@ -273,7 +294,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { /** * @brief publish scan matching status */ - void publish_scan_matching_status(const ros::Time& stamp, const std::string& frame_id, const pcl::Registration& reg) { + void publish_scan_matching_status(const ros::Time& stamp, const std::string& frame_id, const std::string& msf_source, const Eigen::Isometry3f& msf_delta) { if(!status_pub.getNumSubscribers()) { return; } @@ -289,24 +310,24 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { int num_inliers = 0; std::vector k_indices; std::vector k_sq_dists; - for(const auto& pt: *reg.getInputCloud()) { - reg.getSearchMethodTarget()->nearestKSearch(pt, 1, k_indices, k_sq_dists); + for(const auto& pt: *registration->getInputCloud()) { + registration->getSearchMethodTarget()->nearestKSearch(pt, 1, k_indices, k_sq_dists); if(k_sq_dists[0] < max_correspondence_dist * max_correspondence_dist) { num_inliers++; } } - status.inlier_fraction = static_cast(num_inliers) / reg.getInputCloud()->size(); + status.inlier_fraction = static_cast(num_inliers) / registration->getInputCloud()->size(); + + status.relative_pose = isometry2pose(Eigen::Isometry3f(registration->getFinalTransformation()).cast()); - Eigen::Quaternionf quat(registration->getFinalTransformation().block<3, 3>(0, 0)); - Eigen::Vector3f trans = registration->getFinalTransformation().block<3, 1>(0, 3); + if(!msf_source.empty()) { + status.prediction_labels.resize(1); + status.prediction_labels[0].data = msf_source; - status.relative_pose.position.x = trans.x(); - status.relative_pose.position.y = trans.y(); - status.relative_pose.position.z = trans.z(); - status.relative_pose.orientation.x = quat.x(); - status.relative_pose.orientation.y = quat.y(); - status.relative_pose.orientation.z = quat.z(); - status.relative_pose.orientation.w = quat.w(); + status.prediction_errors.resize(1); + Eigen::Isometry3f error = Eigen::Isometry3f(registration->getFinalTransformation()).inverse() * msf_delta; + status.prediction_errors[0] = isometry2pose(error.cast()); + } status_pub.publish(status); } @@ -324,11 +345,13 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { ros::Publisher trans_pub; ros::Publisher aligned_points_pub; ros::Publisher status_pub; + tf::TransformListener tf_listener; tf::TransformBroadcaster odom_broadcaster; tf::TransformBroadcaster keyframe_broadcaster; std::string points_topic; std::string odom_frame_id; + std::string robot_odom_frame_id; ros::Publisher read_until_pub; // keyframe parameters @@ -345,6 +368,7 @@ class ScanMatchingOdometryNodelet : public nodelet::Nodelet { geometry_msgs::PoseWithCovarianceStampedConstPtr msf_pose; geometry_msgs::PoseWithCovarianceStampedConstPtr msf_pose_after_update; + ros::Time prev_time; Eigen::Matrix4f prev_trans; // previous estimated transform from keyframe Eigen::Matrix4f keyframe_pose; // keyframe pose ros::Time keyframe_stamp; // keyframe time diff --git a/include/hdl_graph_slam/ros_utils.hpp b/include/hdl_graph_slam/ros_utils.hpp index b7da6f49..0a53617f 100644 --- a/include/hdl_graph_slam/ros_utils.hpp +++ b/include/hdl_graph_slam/ros_utils.hpp @@ -49,6 +49,29 @@ static Eigen::Isometry3d pose2isometry(const geometry_msgs::Pose& pose) { return mat; } +static Eigen::Isometry3d tf2isometry(const tf::StampedTransform& trans) { + Eigen::Isometry3d mat = Eigen::Isometry3d::Identity(); + mat.translation() = Eigen::Vector3d(trans.getOrigin().x(), trans.getOrigin().y(), trans.getOrigin().z()); + mat.linear() = Eigen::Quaterniond(trans.getRotation().w(), trans.getRotation().x(), trans.getRotation().y(), trans.getRotation().z()).toRotationMatrix(); + return mat; +} + +static geometry_msgs::Pose isometry2pose(const Eigen::Isometry3d& mat) { + Eigen::Quaterniond quat(mat.linear()); + Eigen::Vector3d trans = mat.translation(); + + geometry_msgs::Pose pose; + pose.position.x = trans.x(); + pose.position.y = trans.y(); + pose.position.z = trans.z(); + pose.orientation.w = quat.w(); + pose.orientation.x = quat.x(); + pose.orientation.y = quat.y(); + pose.orientation.z = quat.z(); + + return pose; +} + static Eigen::Isometry3d odom2isometry(const nav_msgs::OdometryConstPtr& odom_msg) { const auto& orientation = odom_msg->pose.pose.orientation; const auto& position = odom_msg->pose.pose.position; diff --git a/launch/hdl_graph_slam.launch b/launch/hdl_graph_slam.launch index 80591ad4..b5e7868b 100644 --- a/launch/hdl_graph_slam.launch +++ b/launch/hdl_graph_slam.launch @@ -6,7 +6,14 @@ + + + + + + + @@ -36,27 +43,29 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -74,8 +83,8 @@ - - + + @@ -143,5 +152,5 @@ - + diff --git a/launch/hdl_graph_slam_400.launch b/launch/hdl_graph_slam_400.launch index ef047822..1b4b4f27 100644 --- a/launch/hdl_graph_slam_400.launch +++ b/launch/hdl_graph_slam_400.launch @@ -6,7 +6,14 @@ + + + + + + + @@ -37,11 +44,13 @@ - + + + @@ -74,8 +83,8 @@ - - + + diff --git a/launch/hdl_graph_slam_501.launch b/launch/hdl_graph_slam_501.launch index 0ac1f5b9..8f009c06 100644 --- a/launch/hdl_graph_slam_501.launch +++ b/launch/hdl_graph_slam_501.launch @@ -6,7 +6,14 @@ + + + + + + + @@ -37,11 +44,13 @@ - + + + @@ -74,8 +83,8 @@ - - + + diff --git a/launch/hdl_graph_slam_centrair.launch b/launch/hdl_graph_slam_centrair.launch deleted file mode 100644 index 477bc819..00000000 --- a/launch/hdl_graph_slam_centrair.launch +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/hdl_graph_slam_ford.launch b/launch/hdl_graph_slam_ford.launch deleted file mode 100644 index da5740c1..00000000 --- a/launch/hdl_graph_slam_ford.launch +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/hdl_graph_slam_imu.launch b/launch/hdl_graph_slam_imu.launch index 57b2caca..b7c41192 100644 --- a/launch/hdl_graph_slam_imu.launch +++ b/launch/hdl_graph_slam_imu.launch @@ -33,7 +33,7 @@ - + diff --git a/launch/hdl_graph_slam_kit.launch b/launch/hdl_graph_slam_kit.launch deleted file mode 100644 index 152df526..00000000 --- a/launch/hdl_graph_slam_kit.launch +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/hdl_graph_slam_pasco.launch b/launch/hdl_graph_slam_pasco.launch deleted file mode 100644 index 6575f6ef..00000000 --- a/launch/hdl_graph_slam_pasco.launch +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msg/ScanMatchingStatus.msg b/msg/ScanMatchingStatus.msg index 8dde80f1..58d8b525 100644 --- a/msg/ScanMatchingStatus.msg +++ b/msg/ScanMatchingStatus.msg @@ -4,3 +4,6 @@ bool has_converged float32 matching_error float32 inlier_fraction geometry_msgs/Pose relative_pose + +std_msgs/String[] prediction_labels +geometry_msgs/Pose[] prediction_errors \ No newline at end of file