sensor_bridge.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 
22 
23 namespace cartographer_ros {
24 
25 namespace carto = ::cartographer;
26 
27 using carto::transform::Rigid3d;
28 
29 namespace {
30 
31 const std::string& CheckNoLeadingSlash(const std::string& frame_id) {
32  if (frame_id.size() > 0) {
33  CHECK_NE(frame_id[0], '/') << "The frame_id " << frame_id
34  << " should not start with a /. See 1.7 in "
35  "http://wiki.ros.org/tf2/Migration.";
36  }
37  return frame_id;
38 }
39 
40 } // namespace
41 
43  const int num_subdivisions_per_laser_scan,
44  const std::string& tracking_frame,
45  const double lookup_transform_timeout_sec, tf2_ros::Buffer* const tf_buffer,
46  carto::mapping::TrajectoryBuilderInterface* const trajectory_builder)
47  : num_subdivisions_per_laser_scan_(num_subdivisions_per_laser_scan),
48  tf_bridge_(tracking_frame, lookup_transform_timeout_sec, tf_buffer),
49  trajectory_builder_(trajectory_builder) {}
50 
51 std::unique_ptr<carto::sensor::OdometryData> SensorBridge::ToOdometryData(
52  const nav_msgs::Odometry::ConstPtr& msg) {
53  const carto::common::Time time = FromRos(msg->header.stamp);
54  const auto sensor_to_tracking = tf_bridge_.LookupToTracking(
55  time, CheckNoLeadingSlash(msg->child_frame_id));
56  if (sensor_to_tracking == nullptr) {
57  return nullptr;
58  }
59  return carto::common::make_unique<carto::sensor::OdometryData>(
60  carto::sensor::OdometryData{
61  time, ToRigid3d(msg->pose.pose) * sensor_to_tracking->inverse()});
62 }
63 
64 void SensorBridge::HandleOdometryMessage(
65  const std::string& sensor_id, const nav_msgs::Odometry::ConstPtr& msg) {
66  std::unique_ptr<carto::sensor::OdometryData> odometry_data =
67  ToOdometryData(msg);
68  if (odometry_data != nullptr) {
69  trajectory_builder_->AddSensorData(
70  sensor_id,
71  carto::sensor::OdometryData{odometry_data->time, odometry_data->pose});
72  }
73 }
74 
75 void SensorBridge::HandleNavSatFixMessage(
76  const std::string& sensor_id, const sensor_msgs::NavSatFix::ConstPtr& msg) {
77  const carto::common::Time time = FromRos(msg->header.stamp);
78  if (msg->status.status == sensor_msgs::NavSatStatus::STATUS_NO_FIX) {
79  trajectory_builder_->AddSensorData(
80  sensor_id, carto::sensor::FixedFramePoseData{
81  time, carto::common::optional<Rigid3d>()});
82  return;
83  }
84 
85  if (!ecef_to_local_frame_.has_value()) {
86  ecef_to_local_frame_ =
87  ComputeLocalFrameFromLatLong(msg->latitude, msg->longitude);
88  LOG(INFO) << "Using NavSatFix. Setting ecef_to_local_frame with lat = "
89  << msg->latitude << ", long = " << msg->longitude << ".";
90  }
91 
92  trajectory_builder_->AddSensorData(
93  sensor_id,
94  carto::sensor::FixedFramePoseData{
95  time, carto::common::optional<Rigid3d>(Rigid3d::Translation(
96  ecef_to_local_frame_.value() *
97  LatLongAltToEcef(msg->latitude, msg->longitude,
98  msg->altitude)))});
99 }
100 
101 void SensorBridge::HandleLandmarkMessage(
102  const std::string& sensor_id,
103  const cartographer_ros_msgs::LandmarkList::ConstPtr& msg) {
104  trajectory_builder_->AddSensorData(sensor_id, ToLandmarkData(*msg));
105 }
106 
107 std::unique_ptr<carto::sensor::ImuData> SensorBridge::ToImuData(
108  const sensor_msgs::Imu::ConstPtr& msg) {
109  CHECK_NE(msg->linear_acceleration_covariance[0], -1)
110  << "Your IMU data claims to not contain linear acceleration measurements "
111  "by setting linear_acceleration_covariance[0] to -1. Cartographer "
112  "requires this data to work. See "
113  "http://docs.ros.org/api/sensor_msgs/html/msg/Imu.html.";
114  CHECK_NE(msg->angular_velocity_covariance[0], -1)
115  << "Your IMU data claims to not contain angular velocity measurements "
116  "by setting angular_velocity_covariance[0] to -1. Cartographer "
117  "requires this data to work. See "
118  "http://docs.ros.org/api/sensor_msgs/html/msg/Imu.html.";
119 
120  const carto::common::Time time = FromRos(msg->header.stamp);
121  const auto sensor_to_tracking = tf_bridge_.LookupToTracking(
122  time, CheckNoLeadingSlash(msg->header.frame_id));
123  if (sensor_to_tracking == nullptr) {
124  return nullptr;
125  }
126  CHECK(sensor_to_tracking->translation().norm() < 1e-5)
127  << "The IMU frame must be colocated with the tracking frame. "
128  "Transforming linear acceleration into the tracking frame will "
129  "otherwise be imprecise.";
130  return carto::common::make_unique<carto::sensor::ImuData>(
131  carto::sensor::ImuData{
132  time,
133  sensor_to_tracking->rotation() * ToEigen(msg->linear_acceleration),
134  sensor_to_tracking->rotation() * ToEigen(msg->angular_velocity)});
135 }
136 
137 void SensorBridge::HandleImuMessage(const std::string& sensor_id,
138  const sensor_msgs::Imu::ConstPtr& msg) {
139  std::unique_ptr<carto::sensor::ImuData> imu_data = ToImuData(msg);
140  if (imu_data != nullptr) {
141  trajectory_builder_->AddSensorData(
142  sensor_id,
143  carto::sensor::ImuData{imu_data->time, imu_data->linear_acceleration,
144  imu_data->angular_velocity});
145  }
146 }
147 
148 void SensorBridge::HandleLaserScanMessage(
149  const std::string& sensor_id, const sensor_msgs::LaserScan::ConstPtr& msg) {
150  carto::sensor::PointCloudWithIntensities point_cloud;
151  carto::common::Time time;
152  std::tie(point_cloud, time) = ToPointCloudWithIntensities(*msg);
153  HandleLaserScan(sensor_id, time, msg->header.frame_id, point_cloud);
154 }
155 
156 void SensorBridge::HandleMultiEchoLaserScanMessage(
157  const std::string& sensor_id,
158  const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg) {
159  carto::sensor::PointCloudWithIntensities point_cloud;
160  carto::common::Time time;
161  std::tie(point_cloud, time) = ToPointCloudWithIntensities(*msg);
162  HandleLaserScan(sensor_id, time, msg->header.frame_id, point_cloud);
163 }
164 
165 void SensorBridge::HandlePointCloud2Message(
166  const std::string& sensor_id,
167  const sensor_msgs::PointCloud2::ConstPtr& msg) {
168  pcl::PointCloud<pcl::PointXYZ> pcl_point_cloud;
169  pcl::fromROSMsg(*msg, pcl_point_cloud);
170  carto::sensor::TimedPointCloud point_cloud;
171  for (const auto& point : pcl_point_cloud) {
172  point_cloud.emplace_back(point.x, point.y, point.z, 0.f);
173  }
174  HandleRangefinder(sensor_id, FromRos(msg->header.stamp), msg->header.frame_id,
175  point_cloud);
176 }
177 
178 const TfBridge& SensorBridge::tf_bridge() const { return tf_bridge_; }
179 
180 void SensorBridge::HandleLaserScan(
181  const std::string& sensor_id, const carto::common::Time time,
182  const std::string& frame_id,
183  const carto::sensor::PointCloudWithIntensities& points) {
184  if (points.points.empty()) {
185  return;
186  }
187  CHECK_LE(points.points.back()[3], 0);
188  // TODO(gaschler): Use per-point time instead of subdivisions.
189  for (int i = 0; i != num_subdivisions_per_laser_scan_; ++i) {
190  const size_t start_index =
191  points.points.size() * i / num_subdivisions_per_laser_scan_;
192  const size_t end_index =
193  points.points.size() * (i + 1) / num_subdivisions_per_laser_scan_;
194  carto::sensor::TimedPointCloud subdivision(
195  points.points.begin() + start_index, points.points.begin() + end_index);
196  if (start_index == end_index) {
197  continue;
198  }
199  const double time_to_subdivision_end = subdivision.back()[3];
200  // `subdivision_time` is the end of the measurement so sensor::Collator will
201  // send all other sensor data first.
202  const carto::common::Time subdivision_time =
203  time + carto::common::FromSeconds(time_to_subdivision_end);
204  auto it = sensor_to_previous_subdivision_time_.find(sensor_id);
205  if (it != sensor_to_previous_subdivision_time_.end() &&
206  it->second >= subdivision_time) {
207  LOG(WARNING) << "Ignored subdivision of a LaserScan message from sensor "
208  << sensor_id << " because previous subdivision time "
209  << it->second << " is not before current subdivision time "
210  << subdivision_time;
211  continue;
212  }
213  sensor_to_previous_subdivision_time_[sensor_id] = subdivision_time;
214  for (Eigen::Vector4f& point : subdivision) {
215  point[3] -= time_to_subdivision_end;
216  }
217  CHECK_EQ(subdivision.back()[3], 0);
218  HandleRangefinder(sensor_id, subdivision_time, frame_id, subdivision);
219  }
220 }
221 
222 void SensorBridge::HandleRangefinder(
223  const std::string& sensor_id, const carto::common::Time time,
224  const std::string& frame_id, const carto::sensor::TimedPointCloud& ranges) {
225  const auto sensor_to_tracking =
226  tf_bridge_.LookupToTracking(time, CheckNoLeadingSlash(frame_id));
227  if (sensor_to_tracking != nullptr) {
228  trajectory_builder_->AddSensorData(
229  sensor_id, carto::sensor::TimedPointCloudData{
230  time, sensor_to_tracking->translation().cast<float>(),
231  carto::sensor::TransformTimedPointCloud(
232  ranges, sensor_to_tracking->cast<float>())});
233  }
234 }
235 
236 } // namespace cartographer_ros
int start_index
Rigid3d ToRigid3d(const geometry_msgs::TransformStamped &transform)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
const common::Time time
SensorBridge(int num_subdivisions_per_laser_scan, const std::string &tracking_frame, double lookup_transform_timeout_sec, tf2_ros::Buffer *tf_buffer, ::cartographer::mapping::TrajectoryBuilderInterface *trajectory_builder)
Eigen::Vector3d ToEigen(const geometry_msgs::Vector3 &vector3)
LandmarkData ToLandmarkData(const LandmarkList &landmark_list)
cartographer::transform::Rigid3d ComputeLocalFrameFromLatLong(const double latitude, const double longitude)
Eigen::Vector3d LatLongAltToEcef(const double latitude, const double longitude, const double altitude)
::cartographer::common::Time FromRos(const ::ros::Time &time)
std::tuple<::cartographer::sensor::PointCloudWithIntensities, ::cartographer::common::Time > ToPointCloudWithIntensities(const sensor_msgs::LaserScan &msg)
static Rigid3 Translation(const Vector &vector)
int end_index


cartographer_ros
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:06:05