21 #include "cartographer/transform/proto/transform.pb.h" 24 #include "geometry_msgs/Pose.h" 25 #include "geometry_msgs/Quaternion.h" 26 #include "geometry_msgs/Transform.h" 27 #include "geometry_msgs/TransformStamped.h" 28 #include "geometry_msgs/Vector3.h" 29 #include "glog/logging.h" 32 #include "sensor_msgs/Imu.h" 33 #include "sensor_msgs/LaserScan.h" 34 #include "sensor_msgs/MultiEchoLaserScan.h" 35 #include "sensor_msgs/PointCloud2.h" 44 constexpr
float kPointCloudComponentFourMagic = 1.;
46 using ::cartographer::transform::Rigid3d;
47 using ::cartographer::kalman_filter::PoseCovariance;
48 using ::cartographer::sensor::PointCloudWithIntensities;
50 sensor_msgs::PointCloud2 PreparePointCloud2Message(
const int64 timestamp,
51 const string& frame_id,
52 const int num_points) {
53 sensor_msgs::PointCloud2 msg;
55 msg.header.frame_id = frame_id;
57 msg.width = num_points;
59 msg.fields[0].name =
"x";
60 msg.fields[0].offset = 0;
61 msg.fields[0].datatype = sensor_msgs::PointField::FLOAT32;
62 msg.fields[0].count = 1;
63 msg.fields[1].name =
"y";
64 msg.fields[1].offset = 4;
65 msg.fields[1].datatype = sensor_msgs::PointField::FLOAT32;
66 msg.fields[1].count = 1;
67 msg.fields[2].name =
"z";
68 msg.fields[2].offset = 8;
69 msg.fields[2].datatype = sensor_msgs::PointField::FLOAT32;
70 msg.fields[2].count = 1;
71 msg.is_bigendian =
false;
73 msg.row_step = 16 * msg.width;
75 msg.data.resize(16 * num_points);
80 bool HasEcho(
float) {
return true; }
82 float GetFirstEcho(
float range) {
return range; }
85 bool HasEcho(
const sensor_msgs::LaserEcho& echo) {
86 return !echo.echoes.empty();
89 float GetFirstEcho(
const sensor_msgs::LaserEcho& echo) {
90 return echo.echoes[0];
94 template <
typename LaserMessageType>
95 PointCloudWithIntensities LaserScanToPointCloudWithIntensities(
96 const LaserMessageType& msg) {
97 CHECK_GE(msg.range_min, 0.f);
98 CHECK_GE(msg.range_max, msg.range_min);
99 if (msg.angle_increment > 0.f) {
100 CHECK_GT(msg.angle_max, msg.angle_min);
102 CHECK_GT(msg.angle_min, msg.angle_max);
104 PointCloudWithIntensities point_cloud;
105 float angle = msg.angle_min;
106 for (
size_t i = 0; i < msg.ranges.size(); ++i) {
107 const auto& echoes = msg.ranges[i];
108 if (HasEcho(echoes)) {
109 const float first_echo = GetFirstEcho(echoes);
110 if (msg.range_min <= first_echo && first_echo <= msg.range_max) {
111 const Eigen::AngleAxisf rotation(angle, Eigen::Vector3f::UnitZ());
112 point_cloud.points.push_back(rotation *
113 (first_echo * Eigen::Vector3f::UnitX()));
114 if (msg.intensities.size() > 0) {
115 CHECK_EQ(msg.intensities.size(), msg.ranges.size());
116 const auto& echo_intensities = msg.intensities[i];
117 CHECK(HasEcho(echo_intensities));
118 point_cloud.intensities.push_back(GetFirstEcho(echo_intensities));
120 point_cloud.intensities.push_back(0.f);
124 angle += msg.angle_increment;
129 bool PointCloud2HasField(
const sensor_msgs::PointCloud2& pc2,
130 const std::string& field_name) {
131 for (
const auto& field : pc2.fields) {
132 if (field.name == field_name) {
142 const int64 timestamp,
const string& frame_id,
143 const ::cartographer::sensor::PointCloud& point_cloud) {
144 auto msg = PreparePointCloud2Message(timestamp, frame_id, point_cloud.size());
146 for (
const auto& point : point_cloud) {
147 stream.
next(point.x());
148 stream.next(point.y());
149 stream.next(point.z());
150 stream.next(kPointCloudComponentFourMagic);
156 const sensor_msgs::LaserScan& msg) {
157 return LaserScanToPointCloudWithIntensities(msg);
161 const sensor_msgs::MultiEchoLaserScan& msg) {
162 return LaserScanToPointCloudWithIntensities(msg);
166 const sensor_msgs::PointCloud2& message) {
167 PointCloudWithIntensities point_cloud;
170 if (PointCloud2HasField(message,
"intensity")) {
171 pcl::PointCloud<pcl::PointXYZI> pcl_point_cloud;
173 for (
const auto& point : pcl_point_cloud) {
174 point_cloud.points.emplace_back(point.x, point.y, point.z);
175 point_cloud.intensities.push_back(point.intensity);
178 pcl::PointCloud<pcl::PointXYZ> pcl_point_cloud;
183 for (
const auto& point : pcl_point_cloud) {
184 point_cloud.points.emplace_back(point.x, point.y, point.z);
185 point_cloud.intensities.push_back(1.0);
193 ToEigen(transform.transform.rotation));
197 return Rigid3d({pose.position.x, pose.position.y, pose.position.z},
201 Eigen::Vector3d
ToEigen(
const geometry_msgs::Vector3& vector3) {
202 return Eigen::Vector3d(vector3.x, vector3.y, vector3.z);
205 Eigen::Quaterniond
ToEigen(
const geometry_msgs::Quaternion& quaternion) {
206 return Eigen::Quaterniond(quaternion.w, quaternion.x, quaternion.y,
211 return Eigen::Map<const Eigen::Matrix<double, 6, 6>>(covariance.data());
215 geometry_msgs::Transform transform;
216 transform.translation.x = rigid3d.translation().x();
217 transform.translation.y = rigid3d.translation().y();
218 transform.translation.z = rigid3d.translation().z();
219 transform.rotation.w = rigid3d.rotation().w();
220 transform.rotation.x = rigid3d.rotation().x();
221 transform.rotation.y = rigid3d.rotation().y();
222 transform.rotation.z = rigid3d.rotation().z();
227 geometry_msgs::Pose
pose;
229 pose.orientation.w = rigid3d.rotation().w();
230 pose.orientation.x = rigid3d.rotation().x();
231 pose.orientation.y = rigid3d.rotation().y();
232 pose.orientation.z = rigid3d.rotation().z();
237 geometry_msgs::Point point;
238 point.x = vector3d.x();
239 point.y = vector3d.y();
240 point.z = vector3d.z();
PoseCovariance ToPoseCovariance(const boost::array< double, 36 > &covariance)
geometry_msgs::Pose ToGeometryMsgPose(const Rigid3d &rigid3d)
geometry_msgs::Point ToGeometryMsgPoint(const Eigen::Vector3d &vector3d)
Rigid3d ToRigid3d(const geometry_msgs::TransformStamped &transform)
PointCloudWithIntensities ToPointCloudWithIntensities(const sensor_msgs::LaserScan &msg)
geometry_msgs::Transform ToGeometryMsgTransform(const Rigid3d &rigid3d)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
Eigen::Matrix< double, 6, 6 > PoseCovariance
Eigen::Vector3d ToEigen(const geometry_msgs::Vector3 &vector3)
Time FromUniversal(const int64 ticks)
sensor_msgs::PointCloud2 ToPointCloud2Message(const int64 timestamp, const string &frame_id, const ::cartographer::sensor::PointCloud &point_cloud)
ROS_FORCE_INLINE void next(const T &t)
::ros::Time ToRos(::cartographer::common::Time time)