Apollo 10.0
自动驾驶开放平台
velodyne32_parser.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
19namespace apollo {
20namespace drivers {
21namespace velodyne {
22
24 : VelodyneParser(config), previous_firing_stamp_(0), gps_base_usec_(0) {
27 if (config_.model() == VLP32C) {
29 }
30}
31
33 const std::shared_ptr<VelodyneScan>& scan_msg,
34 std::shared_ptr<PointCloud> out_msg) {
35 // allocate a point cloud with same time and frame ID as raw data
36 out_msg->mutable_header()->set_frame_id(scan_msg->header().frame_id());
37 out_msg->set_height(1);
38 out_msg->mutable_header()->set_sequence_num(
39 scan_msg->header().sequence_num());
40 gps_base_usec_ = scan_msg->basetime();
41
42 size_t packets_size = scan_msg->firing_pkts_size();
43 if (config_.model() == VLP32C) {
44 for (size_t i = 0; i < packets_size; ++i) {
45 UnpackVLP32C(scan_msg->firing_pkts(static_cast<int>(i)), out_msg);
46 }
47 } else {
48 for (size_t i = 0; i < packets_size; ++i) {
49 Unpack(scan_msg->firing_pkts(static_cast<int>(i)), out_msg);
50 }
51 }
52
53 // set measurement and lidar_timestampe
54 int size = out_msg->point_size();
55 if (size == 0) {
56 // we discard this pointcloud if empty
57 AERROR << "All points is NAN!Please check velodyne:" << config_.model();
58 } else {
59 // take the last point's timestamp as the whole frame's measurement time.
60 uint64_t timestamp = out_msg->point(size - 1).timestamp();
61 out_msg->set_measurement_time(static_cast<double>(timestamp) / 1e9);
62 out_msg->mutable_header()->set_lidar_timestamp(timestamp);
63 }
64
65 // set default width
66 out_msg->set_width(out_msg->point_size());
67
68 last_time_stamp_ = out_msg->measurement_time();
69}
70
71uint64_t Velodyne32Parser::GetTimestamp(double base_time, float time_offset,
72 uint16_t block_id) {
73 double t = base_time - time_offset;
74 if (config_.model() == VLP32C) {
75 t = base_time + time_offset;
76 }
77 // Now t is the exact laser firing time for a specific data point.
78 if (t < previous_firing_stamp_) {
79 // plus 3600 when large jump back, discard little jump back for wrong time
80 // in lidar
81 if (std::abs(previous_firing_stamp_ - t) > 3599000000) {
82 gps_base_usec_ += static_cast<uint64_t>(3600 * 1e6);
83 AINFO << "Base time plus 3600s. Model: " << config_.model() << std::fixed
84 << ". current:" << t << ", last time:" << previous_firing_stamp_;
85 } else if (config_.model() != VLP32C ||
86 (previous_firing_stamp_ - t > 34.560f) ||
87 (previous_firing_stamp_ - t < 34.559f)) {
88 AWARN << "Current stamp:" << std::fixed << t
89 << " less than previous stamp:" << previous_firing_stamp_
90 << ". GPS time stamp maybe incorrect!";
91 }
92 } else if (previous_firing_stamp_ != 0 &&
93 t - previous_firing_stamp_ > 100000) { // 100ms
94 AERROR << "Current stamp:" << std::fixed << t
95 << " ahead previous stamp:" << previous_firing_stamp_
96 << " over 100ms. GPS time stamp incorrect!";
97 }
98
99 previous_firing_stamp_ = t;
100 // in nano seconds
101 uint64_t gps_stamp = gps_base_usec_ * 1000 + static_cast<uint64_t>(t * 1000);
102
103 return gps_stamp;
104}
105
106void Velodyne32Parser::UnpackVLP32C(const VelodynePacket& pkt,
107 std::shared_ptr<PointCloud> pc) {
108 const RawPacket* raw = (const RawPacket*)pkt.data().c_str();
109 // This is the packet timestamp which marks the moment of the first data point
110 // in the first firing sequence of the first data block. The time stamp’s
111 // value is the number of microseconds elapsed since the top of the hour. The
112 // number ranges from 0 to 3,599,999,999, the number of microseconds in one
113 // hour (Sec. 9.3.1.6 in VLP-32C User Manual).
114 double basetime = static_cast<double>(raw->gps_timestamp); // usec
115 float azimuth = 0.0f;
116 float azimuth_diff = 0.0f;
117 float last_azimuth_diff = 0.0f;
118 float azimuth_corrected_f = 0.0f;
119 int azimuth_corrected = 0;
120
121 for (int i = 0; i < BLOCKS_PER_PACKET; i++) { // 12
122 azimuth = static_cast<float>(raw->blocks[i].rotation);
123 if (i < (BLOCKS_PER_PACKET - 1)) {
124 azimuth_diff = static_cast<float>(
125 (36000 + raw->blocks[i + 1].rotation - raw->blocks[i].rotation) %
126 36000);
127 last_azimuth_diff = azimuth_diff;
128 } else {
129 azimuth_diff = last_azimuth_diff;
130 }
131 for (int laser_id = 0, k = 0; laser_id < SCANS_PER_BLOCK;
132 ++laser_id, k += RAW_SCAN_SIZE) { // 32, 3
133 LaserCorrection& corrections = calibration_.laser_corrections_[laser_id];
134
135 union RawDistance raw_distance;
136 raw_distance.bytes[0] = raw->blocks[i].data[k];
137 raw_distance.bytes[1] = raw->blocks[i].data[k + 1];
138
139 // compute the actual timestamp associated with the data point at data
140 // block i and laser_id
141 uint64_t timestamp = GetTimestamp(basetime, (*inner_time_)[i][laser_id],
142 static_cast<uint16_t>(i));
143
144 azimuth_corrected_f =
145 azimuth + (azimuth_diff * (static_cast<float>(laser_id) / 2.0f) *
146 CHANNEL_TDURATION / SEQ_TDURATION);
147 azimuth_corrected =
148 static_cast<int>(round(fmod(azimuth_corrected_f, 36000.0)));
149
150 float real_distance =
151 raw_distance.raw_distance * VLP32_DISTANCE_RESOLUTION;
152 float distance = real_distance + corrections.dist_correction;
153
154 // AINFO << "raw_distance:" << raw_distance.raw_distance << ", distance:"
155 // << distance;
156 if (raw_distance.raw_distance == 0 ||
157 !is_scan_valid(azimuth_corrected, distance)) {
158 if (config_.organized()) {
159 apollo::drivers::PointXYZIT* point_new = pc->add_point();
160 point_new->set_x(nan);
161 point_new->set_y(nan);
162 point_new->set_z(nan);
163 point_new->set_timestamp(timestamp);
164 point_new->set_intensity(0);
165 }
166 continue;
167 }
168
169 apollo::drivers::PointXYZIT* point = pc->add_point();
170 point->set_timestamp(timestamp);
171 // Position Calculation, append this point to the cloud
172 ComputeCoords(real_distance, corrections,
173 static_cast<uint16_t>(azimuth_corrected), point);
174 point->set_intensity(raw->blocks[i].data[k + 2]);
175 }
176 }
177}
178
179void Velodyne32Parser::Unpack(const VelodynePacket& pkt,
180 std::shared_ptr<PointCloud> pc) {
181 // const RawPacket* raw = (const RawPacket*)&pkt.data[0];
182 const RawPacket* raw = (const RawPacket*)pkt.data().c_str();
183 double basetime = raw->gps_timestamp; // usec
184
185 for (int i = 0; i < BLOCKS_PER_PACKET; i++) { // 12
186 for (int laser_id = 0, k = 0; laser_id < SCANS_PER_BLOCK;
187 ++laser_id, k += RAW_SCAN_SIZE) { // 32, 3
188 LaserCorrection& corrections = calibration_.laser_corrections_[laser_id];
189
190 union RawDistance raw_distance;
191 raw_distance.bytes[0] = raw->blocks[i].data[k];
192 raw_distance.bytes[1] = raw->blocks[i].data[k + 1];
193
194 // compute time
195 uint64_t timestamp = static_cast<uint64_t>(GetTimestamp(
196 basetime, (*inner_time_)[i][laser_id], static_cast<uint16_t>(i)));
197
198 int rotation = static_cast<int>(raw->blocks[i].rotation);
199 float real_distance = raw_distance.raw_distance * DISTANCE_RESOLUTION;
200 float distance = real_distance + corrections.dist_correction;
201
202 if (raw_distance.raw_distance == 0 ||
203 !is_scan_valid(rotation, distance)) {
204 // if organized append a nan point to the cloud
205 if (config_.organized()) {
206 apollo::drivers::PointXYZIT* point_new = pc->add_point();
207 point_new->set_x(nan);
208 point_new->set_y(nan);
209 point_new->set_z(nan);
210 point_new->set_timestamp(timestamp);
211 point_new->set_intensity(0);
212 }
213 continue;
214 }
215
216 apollo::drivers::PointXYZIT* point = pc->add_point();
217 point->set_timestamp(timestamp);
218 // Position Calculation, append this point to the cloud
219 ComputeCoords(real_distance, corrections, static_cast<uint16_t>(rotation),
220 point);
221 point->set_intensity(raw->blocks[i].data[k + 2]);
222 // append this point to the cloud
223 }
224 }
225}
226
227void Velodyne32Parser::Order(std::shared_ptr<PointCloud> cloud) {
228 if (config_.model() == VLP32C) {
229 return;
230 }
231 int width = 32;
232 cloud->set_width(width);
233 int height = cloud->point_size() / cloud->width();
234 cloud->set_height(height);
235
236 std::shared_ptr<PointCloud> cloud_origin = std::make_shared<PointCloud>();
237 cloud_origin->CopyFrom(*cloud);
238
239 for (int i = 0; i < width; ++i) {
240 int col = velodyne::ORDER_HDL32E[i];
241
242 for (int j = 0; j < height; ++j) {
243 // make sure offset is initialized, should be init at setup() just once
244 int target_index = j * width + i;
245 int origin_index = j * width + col;
246 cloud->mutable_point(target_index)
247 ->CopyFrom(cloud_origin->point(origin_index));
248 }
249 }
250}
251
252} // namespace velodyne
253} // namespace drivers
254} // namespace apollo
std::map< int, LaserCorrection > laser_corrections_
Definition calibration.h:70
void Order(std::shared_ptr< PointCloud > cloud)
void GeneratePointcloud(const std::shared_ptr< VelodyneScan > &scan_msg, std::shared_ptr< PointCloud > out_msg)
Set up for data processing.
bool is_scan_valid(int rotation, float distance)
void ComputeCoords(const float &raw_distance, const LaserCorrection &corrections, const uint16_t rotation, PointXYZIT *point)
Compute coords with the data in block
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
const float INNER_TIME_HDL32E[12][32]
const float INNER_TIME_VLP32C[12][32]
constexpr int BLOCKS_PER_PACKET
Definition driver.h:33
class register implement
Definition arena_queue.h:37
Velodyne HDL-64E 3D LIDAR data accessors