msg_conversion.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2016 The Cartographer Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
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"
30 #include "ros/ros.h"
31 #include "ros/serialization.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"
36 
37 namespace cartographer_ros {
38 
39 namespace {
40 
41 // The ros::sensor_msgs::PointCloud2 binary data contains 4 floats for each
42 // point. The last one must be this value or RViz is not showing the point cloud
43 // properly.
44 constexpr float kPointCloudComponentFourMagic = 1.;
45 
46 using ::cartographer::transform::Rigid3d;
47 using ::cartographer::kalman_filter::PoseCovariance;
48 using ::cartographer::sensor::PointCloudWithIntensities;
49 
50 sensor_msgs::PointCloud2 PreparePointCloud2Message(const int64 timestamp,
51  const string& frame_id,
52  const int num_points) {
53  sensor_msgs::PointCloud2 msg;
54  msg.header.stamp = ToRos(::cartographer::common::FromUniversal(timestamp));
55  msg.header.frame_id = frame_id;
56  msg.height = 1;
57  msg.width = num_points;
58  msg.fields.resize(3);
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;
72  msg.point_step = 16;
73  msg.row_step = 16 * msg.width;
74  msg.is_dense = true;
75  msg.data.resize(16 * num_points);
76  return msg;
77 }
78 
79 // For sensor_msgs::LaserScan.
80 bool HasEcho(float) { return true; }
81 
82 float GetFirstEcho(float range) { return range; }
83 
84 // For sensor_msgs::MultiEchoLaserScan.
85 bool HasEcho(const sensor_msgs::LaserEcho& echo) {
86  return !echo.echoes.empty();
87 }
88 
89 float GetFirstEcho(const sensor_msgs::LaserEcho& echo) {
90  return echo.echoes[0];
91 }
92 
93 // For sensor_msgs::LaserScan and sensor_msgs::MultiEchoLaserScan.
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);
101  } else {
102  CHECK_GT(msg.angle_min, msg.angle_max);
103  }
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));
119  } else {
120  point_cloud.intensities.push_back(0.f);
121  }
122  }
123  }
124  angle += msg.angle_increment;
125  }
126  return point_cloud;
127 }
128 
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) {
133  return true;
134  }
135  }
136  return false;
137 }
138 
139 } // namespace
140 
141 sensor_msgs::PointCloud2 ToPointCloud2Message(
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());
145  ::ros::serialization::OStream stream(msg.data.data(), msg.data.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);
151  }
152  return msg;
153 }
154 
155 PointCloudWithIntensities ToPointCloudWithIntensities(
156  const sensor_msgs::LaserScan& msg) {
157  return LaserScanToPointCloudWithIntensities(msg);
158 }
159 
160 PointCloudWithIntensities ToPointCloudWithIntensities(
161  const sensor_msgs::MultiEchoLaserScan& msg) {
162  return LaserScanToPointCloudWithIntensities(msg);
163 }
164 
165 PointCloudWithIntensities ToPointCloudWithIntensities(
166  const sensor_msgs::PointCloud2& message) {
167  PointCloudWithIntensities point_cloud;
168  // We check for intensity field here to avoid run-time warnings if we pass in
169  // a PointCloud2 without intensity.
170  if (PointCloud2HasField(message, "intensity")) {
171  pcl::PointCloud<pcl::PointXYZI> pcl_point_cloud;
172  pcl::fromROSMsg(message, 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);
176  }
177  } else {
178  pcl::PointCloud<pcl::PointXYZ> pcl_point_cloud;
179  pcl::fromROSMsg(message, pcl_point_cloud);
180 
181  // If we don't have an intensity field, just copy XYZ and fill in
182  // 1.0.
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);
186  }
187  }
188  return point_cloud;
189 }
190 
191 Rigid3d ToRigid3d(const geometry_msgs::TransformStamped& transform) {
192  return Rigid3d(ToEigen(transform.transform.translation),
193  ToEigen(transform.transform.rotation));
194 }
195 
196 Rigid3d ToRigid3d(const geometry_msgs::Pose& pose) {
197  return Rigid3d({pose.position.x, pose.position.y, pose.position.z},
198  ToEigen(pose.orientation));
199 }
200 
201 Eigen::Vector3d ToEigen(const geometry_msgs::Vector3& vector3) {
202  return Eigen::Vector3d(vector3.x, vector3.y, vector3.z);
203 }
204 
205 Eigen::Quaterniond ToEigen(const geometry_msgs::Quaternion& quaternion) {
206  return Eigen::Quaterniond(quaternion.w, quaternion.x, quaternion.y,
207  quaternion.z);
208 }
209 
210 PoseCovariance ToPoseCovariance(const boost::array<double, 36>& covariance) {
211  return Eigen::Map<const Eigen::Matrix<double, 6, 6>>(covariance.data());
212 }
213 
214 geometry_msgs::Transform ToGeometryMsgTransform(const Rigid3d& rigid3d) {
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();
223  return transform;
224 }
225 
226 geometry_msgs::Pose ToGeometryMsgPose(const Rigid3d& rigid3d) {
227  geometry_msgs::Pose pose;
228  pose.position = ToGeometryMsgPoint(rigid3d.translation());
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();
233  return pose;
234 }
235 
236 geometry_msgs::Point ToGeometryMsgPoint(const Eigen::Vector3d& vector3d) {
237  geometry_msgs::Point point;
238  point.x = vector3d.x();
239  point.y = vector3d.y();
240  point.z = vector3d.z();
241  return point;
242 }
243 
244 } // namespace cartographer_ros
PoseCovariance ToPoseCovariance(const boost::array< double, 36 > &covariance)
geometry_msgs::Pose ToGeometryMsgPose(const Rigid3d &rigid3d)
geometry_msgs::Point ToGeometryMsgPoint(const Eigen::Vector3d &vector3d)
Rigid3< double > Rigid3d
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)
transform::Rigid3d pose
float angle
Time FromUniversal(const int64 ticks)
sensor_msgs::PointCloud2 ToPointCloud2Message(const int64 timestamp, const string &frame_id, const ::cartographer::sensor::PointCloud &point_cloud)
int64_t int64
ROS_FORCE_INLINE void next(const T &t)
::ros::Time ToRos(::cartographer::common::Time time)


cartographer_ros
Author(s):
autogenerated on Wed Jun 5 2019 22:35:56