Apollo 11.0
自动驾驶开放平台
point_cloud_updater.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 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 <utility>
20#include <vector>
21
22#include "nlohmann/json.hpp"
23#include "pcl/filters/voxel_grid.h"
24#include "yaml-cpp/yaml.h"
25
26#include "modules/dreamview/proto/point_cloud.pb.h"
27
28#include "cyber/common/file.h"
29#include "cyber/common/log.h"
30#include "cyber/time/clock.h"
33namespace apollo {
34namespace dreamview {
35
38using Json = nlohmann::json;
39
40boost::shared_mutex PointCloudUpdater::mutex_;
41
43 : node_(cyber::CreateNode("point_cloud")),
44 websocket_(websocket) {
45 localization_reader_ = node_->CreateReader<LocalizationEstimate>(
46 FLAGS_localization_topic,
47 [this](const std::shared_ptr<LocalizationEstimate> &msg) {
48 UpdateLocalizationTime(msg);
49 });
50}
51
53
54PointCloudChannelUpdater* PointCloudUpdater::GetPointCloudChannelUpdater(
55 const std::string &channel_name) {
56 std::lock_guard<std::mutex> lck(channel_updater_map_mutex_);
57 if (channel_updaters_.find(channel_name) == channel_updaters_.end()) {
58 channel_updaters_[channel_name] =
59 new PointCloudChannelUpdater(channel_name);
60 channel_updaters_[channel_name]->point_cloud_reader_ =
61 node_->CreateReader<drivers::PointCloud>(
62 channel_name, [channel_name, this](
63 const std::shared_ptr<drivers::PointCloud> &msg) {
64 UpdatePointCloud(msg, channel_name);
65 });
66 }
67 return channel_updaters_[channel_name];
68}
69
70void PointCloudUpdater::StartStream(const double &time_interval_ms,
71 const std::string &channel_name,
72 nlohmann::json *subscribe_param) {
73 if (channel_name.empty()) {
74 AERROR << "Failed to subscribe channel for channel is empty!";
75 return;
76 }
77 if (std::find(channels_.begin(), channels_.end(), channel_name) ==
78 channels_.end()) {
79 AERROR << "Failed to subscribe point cloud updater, for channel: "
80 << channel_name << " is invalid.";
81 return;
82 }
83 if (time_interval_ms > 0) {
85 GetPointCloudChannelUpdater(channel_name);
86 updater->timer_.reset(new cyber::Timer(
87 time_interval_ms,
88 [channel_name, this]() { this->OnTimer(channel_name); }, false));
89 updater->timer_->Start();
90 } else {
91 this->OnTimer(channel_name);
92 }
93}
94void PointCloudUpdater::Stop() { enabled_ = false; }
95void PointCloudUpdater::OnTimer(const std::string &channel_name) {
96 PublishMessage(channel_name);
97}
98void PointCloudUpdater::StopStream(const std::string& channel_name) {
99 if (channel_name.empty()) {
100 AERROR << "Failed to unsubscribe channel for channel is empty!";
101 return;
102 }
103 PointCloudChannelUpdater *updater = GetPointCloudChannelUpdater(channel_name);
104 if (updater->timer_) {
105 updater->timer_->Stop();
106 }
107 // 回到初始值
108 updater->last_point_cloud_time_ = 0.0;
109 updater->point_cloud_str_ = "";
110 updater->future_ready_ = true;
111}
112void PointCloudUpdater::PublishMessage(const std::string &channel_name) {
113 PointCloudChannelUpdater *updater = GetPointCloudChannelUpdater(channel_name);
114 std::string to_send;
115 // the channel has no data input, clear the sending object.
116 if (!updater->point_cloud_reader_->HasWriter()) {
117 updater->last_point_cloud_time_ = 0.0;
118 updater->point_cloud_str_ = "";
119 to_send = "";
120 } else {
121 if (updater->point_cloud_str_ != "" &&
122 std::fabs(last_localization_time_ - updater->last_point_cloud_time_) >
123 2.0) {
124 boost::unique_lock<boost::shared_mutex> writer_lock(mutex_);
125 updater->point_cloud_str_ = "";
126 }
127 {
128 boost::shared_lock<boost::shared_mutex> reader_lock(mutex_);
129 to_send = updater->point_cloud_str_;
130 }
131 }
132 StreamData stream_data;
133 std::string stream_data_string;
134 stream_data.set_action("stream");
135 stream_data.set_data_name("pointcloud");
136 stream_data.set_channel_name(channel_name);
137 std::vector<uint8_t> byte_data(to_send.begin(), to_send.end());
138 stream_data.set_data(&(byte_data[0]), byte_data.size());
139 stream_data.set_type("pointcloud");
140 stream_data.SerializeToString(&stream_data_string);
141 websocket_->BroadcastBinaryData(stream_data_string);
142}
143
144void PointCloudUpdater::GetChannelMsg(std::vector<std::string> *channels) {
145 enabled_ = true;
146 GetChannelMsgWithFilter(channels, "PointCloud", "sensor");
147}
148
149pcl::PointCloud<pcl::PointXYZ>::Ptr PointCloudUpdater::ConvertPCLPointCloud(
150 const std::shared_ptr<drivers::PointCloud> &point_cloud,
151 const std::string &channel_name) {
152 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_ptr(
153 new pcl::PointCloud<pcl::PointXYZ>);
154 pcl_ptr->width = point_cloud->width();
155 pcl_ptr->height = point_cloud->height();
156 pcl_ptr->is_dense = false;
157
158 if (point_cloud->width() * point_cloud->height() !=
159 static_cast<unsigned int>(point_cloud->point_size())) {
160 pcl_ptr->width = 1;
161 pcl_ptr->height = point_cloud->point_size();
162 }
163 pcl_ptr->points.resize(point_cloud->point_size());
164
165 for (size_t i = 0; i < pcl_ptr->points.size(); ++i) {
166 const auto &point = point_cloud->point(static_cast<int>(i));
167 pcl_ptr->points[i].x = point.x();
168 pcl_ptr->points[i].y = point.y();
169 pcl_ptr->points[i].z = point.z();
170 }
171
172 TransformPointCloud(pcl_ptr, point_cloud->header().frame_id());
173
174 return pcl_ptr;
175}
176
177void PointCloudUpdater::UpdatePointCloud(
178 const std::shared_ptr<drivers::PointCloud> &point_cloud,
179 const std::string& channel_name) {
180 PointCloudChannelUpdater *updater = GetPointCloudChannelUpdater(channel_name);
181 if (point_cloud->header().has_timestamp_sec()) {
182 updater->last_point_cloud_time_ = point_cloud->header().timestamp_sec();
183 } else {
184 updater->last_point_cloud_time_ = point_cloud->measurement_time();
185 }
186 if (std::fabs(last_localization_time_ - updater->last_point_cloud_time_) >
187 0.1) {
188 AWARN << "skipping outdated point cloud data";
189 return;
190 }
191 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_ptr;
192 // Check if last filter process has finished before processing new data.
193 if (enable_voxel_filter_) {
194 if (updater->future_ready_) {
195 updater->future_ready_ = false;
196 // transform from drivers::PointCloud to pcl::PointCloud
197 pcl_ptr = ConvertPCLPointCloud(point_cloud, channel_name);
198 std::future<void> f = cyber::Async(&PointCloudUpdater::FilterPointCloud,
199 this, pcl_ptr, channel_name);
200 updater->async_future_ = std::move(f);
201 }
202 } else {
203 pcl_ptr = ConvertPCLPointCloud(point_cloud, channel_name);
204 this->FilterPointCloud(pcl_ptr, channel_name);
205 }
206}
207
208void PointCloudUpdater::FilterPointCloud(
209 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_ptr,
210 const std::string &channel_name) {
211 PointCloudChannelUpdater *updater = GetPointCloudChannelUpdater(channel_name);
212 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_filtered_ptr(
213 new pcl::PointCloud<pcl::PointXYZ>);
214
215 /*
216 By default, disable voxel filter since it's taking more than 500ms
217 ideally the most efficient sampling method is to
218 use per beam random sample for organized cloud(TODO)
219 */
220 if (enable_voxel_filter_) {
221 pcl::VoxelGrid<pcl::PointXYZ> voxel_grid;
222 voxel_grid.setInputCloud(pcl_ptr);
223 voxel_grid.setLeafSize(static_cast<float>(FLAGS_voxel_filter_size),
224 static_cast<float>(FLAGS_voxel_filter_size),
225 static_cast<float>(FLAGS_voxel_filter_height));
226 voxel_grid.filter(*pcl_filtered_ptr);
227 } else {
228 pcl_filtered_ptr = pcl_ptr;
229 }
230
231 apollo::dreamview::PointCloud point_cloud_pb;
232 for (size_t idx = 0; idx < pcl_filtered_ptr->size(); ++idx) {
233 pcl::PointXYZ &pt = pcl_filtered_ptr->points[idx];
234 if (!std::isnan(pt.x) && !std::isnan(pt.y) && !std::isnan(pt.z)) {
235 point_cloud_pb.add_num(pt.x);
236 point_cloud_pb.add_num(pt.y);
237 point_cloud_pb.add_num(pt.z);
238 }
239 }
240 {
241 boost::unique_lock<boost::shared_mutex> writer_lock(mutex_);
242 point_cloud_pb.SerializeToString(&updater->point_cloud_str_);
243 updater->future_ready_ = true;
244 }
245}
246
247void PointCloudUpdater::UpdateLocalizationTime(
248 const std::shared_ptr<LocalizationEstimate> &localization) {
249 last_localization_time_ = localization->header().timestamp_sec();
250}
251
252void PointCloudUpdater::TransformPointCloud(
253 pcl::PointCloud<pcl::PointXYZ>::Ptr &point_cloud,
254 const std::string &frame_id) {
255 if (frame_id.empty()) {
256 AERROR << "Failed to get frame id";
257 return;
258 }
259 apollo::transform::Buffer *tf2_buffer = apollo::transform::Buffer::Instance();
260 apollo::transform::TransformStamped stamped_transform;
261 try {
262 stamped_transform = tf2_buffer->lookupTransform("localization", frame_id,
264 } catch (tf2::TransformException &ex) {
265 AERROR << ex.what();
266 AERROR << "Failed to get matrix of frame id: " << frame_id;
267 return;
268 }
269
270 auto &matrix = stamped_transform.transform();
271
272 // Define a translation vector
273 Eigen::Vector3f translation(
274 matrix.translation().x(), matrix.translation().y(),
275 matrix.translation().z()); // Replace with your actual values
276
277 // Define a quaternion for rotation
278 Eigen::Quaternionf rotation(
279 matrix.rotation().qw(), matrix.rotation().qx(), matrix.rotation().qy(),
280 matrix.rotation().qz()); // Replace with your actual values (w, x, y, z)
281 rotation.normalize(); // Ensure the quaternion is a valid unit quaternion
282
283 // Combine into a transformation matrix
284 Eigen::Affine3f transform = Eigen::Affine3f::Identity();
285 transform.translation() << translation;
286 transform.rotate(rotation);
287
288 // Transform the point cloud
289 pcl::transformPointCloud(*point_cloud, *point_cloud, transform);
290 // Define the rotation matrix for 90 degree counter-clockwise rotation in
291 // the xy-plane
292 Eigen::Matrix4f counter_transform = Eigen::Matrix4f::Identity();
293 counter_transform(0, 0) = 0;
294 counter_transform(0, 1) = 1;
295 counter_transform(1, 0) = -1;
296 counter_transform(1, 1) = 0;
297
298 // Perform the transformation
299 pcl::transformPointCloud(*point_cloud, *point_cloud, counter_transform);
300}
301
302} // namespace dreamview
303} // namespace apollo
double f
Cyber has builtin time type Time.
Definition time.h:31
Used to perform oneshot or periodic timing tasks
Definition timer.h:71
void StopStream(const std::string &channel_name="") override
Stop data flow.
void StartStream(const double &time_interval_ms, const std::string &channel_name="", nlohmann::json *subscribe_param=nullptr) override
Start data flow.
PointCloudUpdater(WebSocketHandler *websocket, SimulationWorldUpdater *sim_world_updater)
Constructor with the websocket handler.
void OnTimer(const std::string &channel_name="")
void PublishMessage(const std::string &channel_name="") override
Publish Message to dreamview frontend.
void GetChannelMsgWithFilter(std::vector< std::string > *channels, const std::string &filter_message_type, const std::string &filter_channel, bool reverse_filter_channel=false)
GetChannelMsgWithFilter:by msg type and channel filter field to filter channels for DataUpdater
The WebSocketHandler, built on top of CivetWebSocketHandler, is a websocket handler that handles diff...
bool BroadcastBinaryData(const std::string &data, bool skippable=false)
Sends the provided binary data to all the connected clients.
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 AWARN
Definition log.h:43
nlohmann::json Json
std::string frame_id
Point cloud frame id
class register implement
Definition arena_queue.h:37
std::shared_ptr< cyber::Reader< drivers::PointCloud > > point_cloud_reader_