35 tf2_buffer_ptr_ = apollo::transform::Buffer::Instance();
42 readers_.emplace_back(reader);
45 filter_map_.emplace(filter_config.frame_id(), &filter_config);
51 auto target = writer_->AcquireMessage();
53 target->mutable_point()->Reserve(reserved_point_size_);
54 target->mutable_header()->set_lidar_timestamp(point_cloud->header().lidar_timestamp());
55 if (conf_.has_target_frame_id()) {
58 target->mutable_header()->set_frame_id(point_cloud->header().frame_id());
62 std::vector<std::shared_ptr<PointCloud>> point_clouds = {point_cloud};
63 auto fusion_readers = readers_;
64 while ((
Time::Now().ToSecond() - start_time) < conf_.
wait_time_s() && fusion_readers.size() > 0) {
65 for (
auto itr = fusion_readers.begin(); itr != fusion_readers.end();) {
67 if (!(*itr)->Empty()) {
68 auto source = (*itr)->GetLatestObserved();
72 point_clouds.emplace_back(source);
73 itr = fusion_readers.erase(itr);
79 std::this_thread::sleep_for(std::chrono::milliseconds(5));
83 AINFO <<
"Pointcloud fusion diff: " << diff / 1000000 <<
"ms";
85 uint64_t timestamp_min = 0;
86 uint64_t timestamp_max = 0;
87 GetTimestampInterval(point_clouds, ×tamp_min, ×tamp_max);
89 for (
const auto& pc : point_clouds) {
90 if (!FusionAndCompensator(pc, timestamp_min, timestamp_max, target)) {
95 target->mutable_header()->set_sequence_num(seq_num_++);
97 target->set_height(point_cloud->height());
98 target->set_width(target->point_size() / target->height());
99 target->set_is_dense(point_cloud->is_dense());
100 target->set_measurement_time(point_cloud->measurement_time());
102 writer_->Write(target);
106void FusionAndCompensatorComponent::GetTimestampInterval(
107 const std::vector<std::shared_ptr<PointCloud>>& point_clouds,
108 uint64_t* timestamp_min,
109 uint64_t* timestamp_max) {
111 *timestamp_min = std::numeric_limits<uint64_t>::max();
112 for (
const auto& pc : point_clouds) {
113 for (
const auto& point : pc->point()) {
114 if (point.timestamp() < *timestamp_min) {
115 *timestamp_min = point.timestamp();
118 if (point.timestamp() > *timestamp_max) {
119 *timestamp_max = point.timestamp();
125bool FusionAndCompensatorComponent::IsExpired(
126 const std::shared_ptr<PointCloud>& target,
127 const std::shared_ptr<PointCloud>& source) {
128 auto diff = target->measurement_time() - source->measurement_time();
132bool FusionAndCompensatorComponent::QueryPoseAffineFromTF2(
133 const uint64_t& timestamp,
134 const std::string& target_frame_id,
135 const std::string& source_frame_id,
136 Eigen::Affine3d* pose) {
137 cyber::Time query_time(timestamp);
138 std::string err_string;
141 AERROR <<
"Can not find transform, target_frame_id: " << target_frame_id
142 <<
", source_frame_id: " << source_frame_id <<
", Error info: " << err_string;
148 stamped_transform = tf2_buffer_ptr_->
lookupTransform(target_frame_id, source_frame_id, query_time);
149 }
catch (tf2::TransformException& ex) {
154 *pose = Eigen::Translation3d(
158 * Eigen::Quaterniond(
166bool FusionAndCompensatorComponent::FusionAndCompensator(
167 const std::shared_ptr<PointCloud> source,
168 const uint64_t& timestamp_min,
169 const uint64_t& timestamp_max,
170 std::shared_ptr<PointCloud> target) {
171 auto& target_frame_id = target->header().frame_id();
172 auto& source_frame_id = source->header().frame_id();
174 auto lidar_tf_f = static_tf_map_.find(source_frame_id);
175 if (lidar_tf_f == static_tf_map_.end()) {
176 Eigen::Affine3d lidar_tf_d;
177 if (!QueryPoseAffineFromTF2(0, target_frame_id, source_frame_id, &lidar_tf_d)) {
180 static_tf_map_[source_frame_id] = lidar_tf_d.cast<
float>();
184 Eigen::Affine3d world_tf_min_time;
185 Eigen::Affine3d world_tf_max_time;
186 if (!QueryPoseAffineFromTF2(timestamp_min, conf_.
world_frame_id(), target_frame_id, &world_tf_min_time)
187 || !QueryPoseAffineFromTF2(timestamp_max, conf_.
world_frame_id(), target_frame_id, &world_tf_max_time)) {
188 AERROR <<
"compensator transform query error.";
197 static_tf_map_[source_frame_id],
203bool FusionAndCompensatorComponent::IsFilteredPoint(
const Eigen::Vector3f& point,
const std::string& frame_id)
const {
204 if (filter_map_.find(frame_id) == filter_map_.end()) {
207 const auto& x = point.x();
208 const auto& y = point.y();
209 const auto& z = point.z();
210 const auto& filter = filter_map_.at(frame_id);
211 if (filter->has_min_x() && x < filter->min_x()) {
214 if (filter->has_max_x() && x > filter->max_x()) {
217 if (filter->has_min_y() && y < filter->min_y()) {
220 if (filter->has_max_y() && y > filter->max_y()) {
223 if (filter->has_min_z() && z < filter->min_z()) {
226 if (filter->has_max_z() && z > filter->max_z()) {
232void FusionAndCompensatorComponent::MotionCompensation(
233 const std::shared_ptr<PointCloud>& source,
234 const uint64_t& timestamp_min,
235 const uint64_t& timestamp_max,
236 const Eigen::Affine3d& world_tf_min_time,
237 const Eigen::Affine3d& world_tf_max_time,
238 const Eigen::Affine3f& lidar_tf,
239 std::shared_ptr<PointCloud> target) {
240 Eigen::Vector3d translation_d = world_tf_min_time.translation() - world_tf_max_time.translation();
241 Eigen::Quaterniond q_max(world_tf_max_time.linear());
242 Eigen::Quaterniond q_min(world_tf_min_time.linear());
243 Eigen::Quaterniond q1_d(q_max.conjugate() * q_min);
244 Eigen::Quaterniond q0_d(Eigen::Quaterniond::Identity());
245 Eigen::Quaternionf q1 = q1.cast<
float>();
246 Eigen::Quaternionf q0 = q0_d.cast<
float>();
248 Eigen::Vector3f translation = (q_max.conjugate() * translation_d).cast<float>();
250 double d = q0.dot(q1);
251 double abs_d = std::abs(d);
252 float f = 1.0 /
static_cast<float>(timestamp_max - timestamp_min);
261 float theta =
static_cast<float>(std::acos(abs_d));
262 float sin_theta = std::sin(theta);
263 float c1_sign = (d > 0) ? 1 : -1;
264 for (
const auto& point : source->point()) {
265 float x_scalar = point.x();
266 float y_scalar = point.y();
267 float z_scalar = point.z();
268 if (std::isnan(x_scalar) || std::isnan(y_scalar) || std::isnan(z_scalar)) {
272 Eigen::Vector3f p(x_scalar, y_scalar, z_scalar);
274 auto fusion_p = lidar_tf * p;
275 if (IsFilteredPoint(fusion_p, source->header().frame_id())) {
279 uint64_t tp = point.timestamp();
280 float t =
static_cast<float>(timestamp_max - tp) *
f;
282 Eigen::Translation3f ti(t * translation);
284 float c0 = std::sin((1 - t) * theta) / sin_theta;
285 float c1 = std::sin(t * theta) / sin_theta * c1_sign;
286 Eigen::Quaternionf qi(c0 * q0.coeffs() + c1 * q1.coeffs());
288 Eigen::Affine3f trans = ti * qi;
289 p = trans * fusion_p;
291 auto* point_new = target->add_point();
292 point_new->set_intensity(point.intensity());
293 point_new->set_timestamp(point.timestamp());
294 point_new->set_x(p.x());
295 point_new->set_y(p.y());
296 point_new->set_z(p.z());
300 for (
auto& point : source->point()) {
301 float x_scalar = point.x();
302 float y_scalar = point.y();
303 float z_scalar = point.z();
304 if (std::isnan(x_scalar) || std::isnan(y_scalar) || std::isnan(z_scalar)) {
309 Eigen::Vector3f p(x_scalar, y_scalar, z_scalar);
311 auto fusion_p = lidar_tf * p;
312 if (IsFilteredPoint(fusion_p, source->header().frame_id())) {
317 uint64_t tp = point.timestamp();
318 float t =
static_cast<float>(timestamp_max - tp) *
f;
319 Eigen::Translation3f ti(t * translation);
325 auto* point_new = target->add_point();
326 point_new->set_intensity(point.intensity());
327 point_new->set_timestamp(point.timestamp());
328 point_new->set_x(p.x());
329 point_new->set_y(p.y());
330 point_new->set_z(p.z());
bool GetProtoConfig(T *config) const
const std::string & ConfigFilePath() const
std::shared_ptr< Node > node_
Cyber has builtin time type Time.
uint64_t ToNanosecond() const
convert time to nanosecond.
static Time Now()
get the current time.
double ToSecond() const
convert time to second.
bool Proc(const std::shared_ptr< PointCloud > &point_cloud) override
float diff(Image< float > *I, int x1, int y1, int x2, int y2)
Dissimilarity measure between pixels
repeated FilterConfig filter_config
optional string output_channel
optional string target_frame_id
optional bool rotation_compensation
repeated string input_channel
optional uint32 max_interval_ms
optional float transform_query_timeout
optional string world_frame_id
optional bool translation_compensation
optional float wait_time_s
optional bool drop_expired_data