Apollo 10.0
自动驾驶开放平台
compensator.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
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
19#include <limits>
20#include <memory>
21#include <string>
22
23namespace apollo {
24namespace drivers {
25namespace compensator {
26
27bool Compensator::QueryPoseAffineFromTF2(
28 const uint64_t& timestamp,
29 void* pose,
30 const std::string& child_frame_id) {
31 cyber::Time query_time(timestamp);
32 std::string err_string;
33 if (!tf2_buffer_ptr_->canTransform(
34 config_.world_frame_id(),
35 child_frame_id,
36 query_time,
38 &err_string)) {
39 AERROR << "Can not find transform. " << timestamp
40 << " frame_id:" << child_frame_id
41 << " Error info: " << err_string;
42 return false;
43 }
44
46
47 try {
48 stamped_transform = tf2_buffer_ptr_->lookupTransform(
49 config_.world_frame_id(), child_frame_id, query_time);
50 } catch (tf2::TransformException& ex) {
51 AERROR << ex.what();
52 return false;
53 }
54
55 Eigen::Affine3d* tmp_pose = (Eigen::Affine3d*)pose;
56 *tmp_pose = Eigen::Translation3d(
57 stamped_transform.transform().translation().x(),
58 stamped_transform.transform().translation().y(),
59 stamped_transform.transform().translation().z())
60 * Eigen::Quaterniond(
61 stamped_transform.transform().rotation().qw(),
62 stamped_transform.transform().rotation().qx(),
63 stamped_transform.transform().rotation().qy(),
64 stamped_transform.transform().rotation().qz());
65 return true;
66}
67
69 const std::shared_ptr<const PointCloud>& msg,
70 std::shared_ptr<PointCloud> msg_compensated) {
71 if (msg->height() == 0 || msg->width() == 0) {
72 AERROR << "PointCloud width & height should not be 0";
73 return false;
74 }
75 uint64_t start = cyber::Time::Now().ToNanosecond();
76 Eigen::Affine3d pose_min_time;
77 Eigen::Affine3d pose_max_time;
78
79 uint64_t timestamp_min = 0;
80 uint64_t timestamp_max = 0;
81 std::string frame_id = msg->header().frame_id();
82 GetTimestampInterval(msg, &timestamp_min, &timestamp_max);
83
84 msg_compensated->mutable_header()->set_timestamp_sec(
85 cyber::Time::Now().ToSecond());
86 msg_compensated->mutable_header()->set_frame_id(msg->header().frame_id());
87 msg_compensated->mutable_header()->set_lidar_timestamp(
88 msg->header().lidar_timestamp());
89 msg_compensated->set_measurement_time(msg->measurement_time());
90 msg_compensated->set_height(msg->height());
91 msg_compensated->set_is_dense(msg->is_dense());
92
93 uint64_t new_time = cyber::Time().Now().ToNanosecond();
94 AINFO << "compenstator new msg diff:" << new_time - start
95 << ";meta:" << msg->header().lidar_timestamp();
96 msg_compensated->mutable_point()->Reserve(240000);
97
98 // compensate point cloud, remove nan point
99 if (QueryPoseAffineFromTF2(timestamp_min, &pose_min_time, frame_id)
100 && QueryPoseAffineFromTF2(timestamp_max, &pose_max_time, frame_id)) {
101 uint64_t tf_time = cyber::Time().Now().ToNanosecond();
102 AINFO << "compenstator tf msg diff:" << tf_time - new_time
103 << ";meta:" << msg->header().lidar_timestamp();
105 msg,
106 msg_compensated,
107 timestamp_min,
108 timestamp_max,
109 pose_min_time,
110 pose_max_time);
111 uint64_t com_time = cyber::Time().Now().ToNanosecond();
112 msg_compensated->set_width(
113 msg_compensated->point_size() / msg->height());
114 AINFO << "compenstator com msg diff:" << com_time - tf_time
115 << ";meta:" << msg->header().lidar_timestamp();
116 return true;
117 }
118 return false;
119}
120
121inline void Compensator::GetTimestampInterval(
122 const std::shared_ptr<const PointCloud>& msg,
123 uint64_t* timestamp_min,
124 uint64_t* timestamp_max) {
125 *timestamp_max = 0;
126 *timestamp_min = std::numeric_limits<uint64_t>::max();
127
128 for (const auto& point : msg->point()) {
129 uint64_t timestamp = point.timestamp();
130 if (timestamp < *timestamp_min) {
131 *timestamp_min = timestamp;
132 }
133
134 if (timestamp > *timestamp_max) {
135 *timestamp_max = timestamp;
136 }
137 }
138}
139
141 const std::shared_ptr<const PointCloud>& msg,
142 std::shared_ptr<PointCloud> msg_compensated,
143 const uint64_t timestamp_min,
144 const uint64_t timestamp_max,
145 const Eigen::Affine3d& pose_min_time,
146 const Eigen::Affine3d& pose_max_time) {
147 using std::abs;
148 using std::acos;
149 using std::sin;
150
151 Eigen::Vector3d translation
152 = pose_min_time.translation() - pose_max_time.translation();
153 Eigen::Quaterniond q_max(pose_max_time.linear());
154 Eigen::Quaterniond q_min(pose_min_time.linear());
155 Eigen::Quaterniond q1(q_max.conjugate() * q_min);
156 Eigen::Quaterniond q0(Eigen::Quaterniond::Identity());
157 q1.normalize();
158 translation = q_max.conjugate() * translation;
159
160 // int total = msg->width * msg->height;
161
162 double d = q0.dot(q1);
163 double abs_d = abs(d);
164 double f = 1.0 / static_cast<double>(timestamp_max - timestamp_min);
165
166 // Threshold for a "significant" rotation from min_time to max_time:
167 // The LiDAR range accuracy is ~2 cm. Over 70 meters range, it means an
168 // angle of 0.02 / 70 = 0.0003 rad. So, we consider a rotation "significant"
169 // only if the scalar part of quaternion is less than cos(0.0003 / 2) = 1 -
170 // 1e-8.
171 if (abs_d < 1.0 - 1.0e-8) {
172 double theta = acos(abs_d);
173 double sin_theta = sin(theta);
174 double c1_sign = (d > 0) ? 1 : -1;
175 for (const auto& point : msg->point()) {
176 float x_scalar = point.x();
177 if (std::isnan(x_scalar)) {
178 // if (config_.organized()) {
179 auto* point_new = msg_compensated->add_point();
180 point_new->CopyFrom(point);
181 // } else {
182 // AERROR << "nan point do not need motion compensation";
183 // }
184 continue;
185 }
186 float y_scalar = point.y();
187 float z_scalar = point.z();
188 Eigen::Vector3d p(x_scalar, y_scalar, z_scalar);
189
190 uint64_t tp = point.timestamp();
191 double t = static_cast<double>(timestamp_max - tp) * f;
192
193 Eigen::Translation3d ti(t * translation);
194
195 double c0 = sin((1 - t) * theta) / sin_theta;
196 double c1 = sin(t * theta) / sin_theta * c1_sign;
197 Eigen::Quaterniond qi(c0 * q0.coeffs() + c1 * q1.coeffs());
198
199 Eigen::Affine3d trans = ti * qi;
200 p = trans * p;
201
202 auto* point_new = msg_compensated->add_point();
203 point_new->set_intensity(point.intensity());
204 point_new->set_timestamp(point.timestamp());
205 point_new->set_x(static_cast<float>(p.x()));
206 point_new->set_y(static_cast<float>(p.y()));
207 point_new->set_z(static_cast<float>(p.z()));
208 }
209 return;
210 }
211 // Not a "significant" rotation. Do translation only.
212 for (auto& point : msg->point()) {
213 float x_scalar = point.x();
214 if (std::isnan(x_scalar)) {
215 // AERROR << "nan point do not need motion compensation";
216 continue;
217 }
218 float y_scalar = point.y();
219 float z_scalar = point.z();
220 Eigen::Vector3d p(x_scalar, y_scalar, z_scalar);
221
222 uint64_t tp = point.timestamp();
223 double t = static_cast<double>(timestamp_max - tp) * f;
224 Eigen::Translation3d ti(t * translation);
225
226 p = ti * p;
227
228 auto* point_new = msg_compensated->add_point();
229 point_new->set_intensity(point.intensity());
230 point_new->set_timestamp(point.timestamp());
231 point_new->set_x(static_cast<float>(p.x()));
232 point_new->set_y(static_cast<float>(p.y()));
233 point_new->set_z(static_cast<float>(p.z()));
234 }
235}
236
237} // namespace compensator
238} // namespace drivers
239} // namespace apollo
double f
Cyber has builtin time type Time.
Definition time.h:31
uint64_t ToNanosecond() const
convert time to nanosecond.
Definition time.cc:83
static Time Now()
get the current time.
Definition time.cc:57
bool MotionCompensation(const std::shared_ptr< const PointCloud > &msg, std::shared_ptr< PointCloud > msg_compensated)
virtual bool canTransform(const std::string &target_frame, const std::string &source_frame, const cyber::Time &target_time, const float timeout_second=0.01f, std::string *errstr=nullptr) const
Test if a transform is possible
Definition buffer.cc:195
virtual TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const cyber::Time &time, const float timeout_second=0.01f) const
Get the transform between two frames by frame ID.
Definition buffer.cc:168
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
float sin(Angle16 a)
Definition angle.cc:25
class register implement
Definition arena_queue.h:37
optional apollo::common::Quaternion rotation
optional apollo::common::Point3D translation