Apollo 10.0
自动驾驶开放平台
velodyne64_parser.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
19namespace apollo {
20namespace drivers {
21namespace velodyne {
22
24 : VelodyneParser(config) {
25 for (int i = 0; i < 4; i++) {
26 gps_base_usec_[i] = 0;
27 previous_packet_stamp_[i] = 0;
28 }
30 // init Unpack function and order function by model.
31 if (config_.model() == HDL64E_S2) {
33 is_s2_ = true;
34 } else { // 64E_S3
36 is_s2_ = false;
37 }
38
39 if (config_.mode() == LAST) {
40 mode_ = LAST;
41 } else if (config_.mode() == DUAL) {
42 mode_ = DUAL;
43 }
44}
45
49 InitOffsets();
50 }
51}
52
53void Velodyne64Parser::SetBaseTimeFromPackets(const VelodynePacket& pkt) {
54 // const RawPacket* raw = (const RawPacket*)&pkt.data[0];
55 const RawPacket* raw = (const RawPacket*)pkt.data().c_str();
56 StatusType status_type = StatusType(raw->status_type);
57 char status_value = raw->status_value;
58
59 static int year = -1, month = -1, day = -1, hour = -1, minute = -1,
60 second = -1;
61 static int gps_status = 0;
62 static tm time;
63
64 switch (status_type) {
65 case YEAR:
66 year = status_value + 2000;
67 break;
68 case MONTH:
69 month = status_value;
70 break;
71 case DATE:
72 day = status_value;
73 break;
74 case HOURS:
75 hour = status_value;
76 break;
77 case MINUTES:
78 minute = status_value;
79 break;
80 case SECONDS:
81 second = status_value;
82 break;
83 case GPS_STATUS:
84 gps_status = status_value;
85 break;
86 default:
87 break;
88 }
89
90 AINFO << "Get base time from packets. Obtained (" << year << "." << month
91 << "." << day << " " << hour << ":" << minute << ":" << second;
92
93 if (status_type == GPS_STATUS && year > 0 && month > 0 && day > 0 &&
94 hour >= 0 && minute >= 0 && second >= 0) {
95 if (gps_status != 65) {
96 AWARN << "Sync failed because Velodyne-GPS Sync is NOT good! "
97 << "Status: " << static_cast<int>(gps_status)
98 << " (65 = both; 86 = gps only; 80 = PPS only; 0 "
99 << "= GPS not connected)";
100 }
101
102 time.tm_year = year - 1900;
103 time.tm_mon = month - 1;
104 time.tm_mday = day;
105 time.tm_hour = hour;
106 time.tm_min = 0;
107 time.tm_sec = 0;
108
109 // AINFO << "Set base unix time: (%d.%d.%d %d:%d:%d)", time.tm_year,
110 // time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec;
111
112 uint64_t unix_base = static_cast<uint64_t>(timegm(&time));
113 for (int i = 0; i < 4; ++i) {
114 gps_base_usec_[i] = unix_base * 1000000;
115 }
116 }
117}
118
119void Velodyne64Parser::CheckGpsStatus(const VelodynePacket& pkt) {
120 // const RawPacket* raw = (const RawPacket*)&pkt.data[0];
121 const RawPacket* raw = (const RawPacket*)pkt.data().c_str();
122 StatusType status_type = StatusType(raw->status_type);
123 char status_value = raw->status_value;
124
125 if (status_type == StatusType::GPS_STATUS) {
126 if (status_value != 65) {
127 AWARN << "Sync failed because Velodyne-GPS Sync is NOT good! "
128 << "Status: " << static_cast<int>(status_value)
129 << " (65 = both; 86 = gps only; 80 = PPS only; "
130 << "0 = GPS not connected)";
131 }
132 }
133}
134
135void Velodyne64Parser::InitOffsets() {
136 int width = 64;
137 // pre compute col offsets
138 for (int i = 0; i < width; ++i) {
139 int col = velodyne::ORDER_64[i];
140 // compute offset, NOTICE: std::map doesn't have const [] since [] may
141 // insert new values into map
142 const LaserCorrection& corrections = calibration_.laser_corrections_[col];
143 int offset =
144 static_cast<int>(corrections.rot_correction / ANGULAR_RESOLUTION + 0.5);
145 offsets_[i] = offset;
146 }
147}
148
150 const std::shared_ptr<VelodyneScan>& scan_msg,
151 std::shared_ptr<PointCloud> pointcloud) {
153 if (online_calibration_.decode(scan_msg) == -1) {
154 return;
155 }
156 calibration_ = online_calibration_.calibration();
157 if (config_.organized()) {
158 InitOffsets();
159 }
160 }
161
162 // allocate a point cloud with same time and frame ID as raw data
163 pointcloud->mutable_header()->set_frame_id(scan_msg->header().frame_id());
164 pointcloud->set_height(1);
165 pointcloud->mutable_header()->set_sequence_num(
166 scan_msg->header().sequence_num());
167
168 bool skip = false;
169 size_t packets_size = scan_msg->firing_pkts_size();
170 for (size_t i = 0; i < packets_size; ++i) {
171 if (gps_base_usec_[0] == 0) {
172 // only set one time type when call this function, so cannot break
173 SetBaseTimeFromPackets(scan_msg->firing_pkts(static_cast<int>(i)));
174 // If base time not ready then set empty_unpack true
175 skip = true;
176 } else {
177 CheckGpsStatus(scan_msg->firing_pkts(static_cast<int>(i)));
178 Unpack(scan_msg->firing_pkts(static_cast<int>(i)), pointcloud);
179 last_time_stamp_ = pointcloud->measurement_time();
180 ADEBUG << "stamp: " << std::fixed << last_time_stamp_;
181 }
182 }
183
184 if (skip) {
185 pointcloud->Clear();
186 } else {
187 int size = pointcloud->point_size();
188 if (size == 0) {
189 // we discard this pointcloud if empty
190 AERROR << "All points is NAN! Please check velodyne:" << config_.model();
191 } else {
192 uint64_t timestamp = pointcloud->point(size - 1).timestamp();
193 pointcloud->set_measurement_time(static_cast<double>(timestamp) / 1e9);
194 pointcloud->mutable_header()->set_lidar_timestamp(timestamp);
195 }
196 pointcloud->set_width(pointcloud->point_size());
197 }
198}
199
200uint64_t Velodyne64Parser::GetTimestamp(double base_time, float time_offset,
201 uint16_t block_id) {
202 double t = base_time - time_offset;
203 double timestamp = 0.0;
204 int index = 0;
205
206 if (is_s2_) {
207 index = block_id & 1; // % 2
208 double& previous_packet_stamp = previous_packet_stamp_[index];
209 uint64_t& gps_base_usec = gps_base_usec_[index];
210 timestamp = static_cast<double>(
211 GetGpsStamp(t, &previous_packet_stamp, &gps_base_usec));
212 } else { // 64E_S3
213 index = block_id & 3; // % 4
214 double& previous_packet_stamp = previous_packet_stamp_[index];
215 uint64_t& gps_base_usec = gps_base_usec_[index];
216 timestamp = static_cast<double>(
217 GetGpsStamp(t, &previous_packet_stamp, &gps_base_usec));
218 }
219 return static_cast<uint64_t>(timestamp);
220}
221
222int Velodyne64Parser::IntensityCompensate(const LaserCorrection& corrections,
223 const uint16_t raw_distance,
224 int intensity) {
225 float tmp = 1.0f - static_cast<float>(raw_distance) / 65535.0f;
226 intensity +=
227 static_cast<int>(corrections.focal_slope *
228 (fabs(corrections.focal_offset - 256 * tmp * tmp)));
229
230 if (intensity < corrections.min_intensity) {
231 intensity = corrections.min_intensity;
232 }
233
234 if (intensity > corrections.max_intensity) {
235 intensity = corrections.max_intensity;
236 }
237 return intensity;
238}
239
240void Velodyne64Parser::Unpack(const VelodynePacket& pkt,
241 std::shared_ptr<PointCloud> pc) {
242 ADEBUG << "Received packet, time: " << pkt.stamp();
243
244 // const RawPacket* raw = (const RawPacket*)&pkt.data[0];
245 const RawPacket* raw = (const RawPacket*)pkt.data().c_str();
246 double basetime = raw->gps_timestamp; // usec
247
248 for (int i = 0; i < BLOCKS_PER_PACKET; ++i) { // 12
249 if (mode_ != DUAL && !is_s2_ && ((i & 3) >> 1) > 0) {
250 // i%4/2 even-numbered block contain duplicate data
251 continue;
252 }
253
254 // upper bank lasers are numbered [0..31], lower bank lasers are [32..63]
255 // NOTE: this is a change from the old velodyne_common implementation
256 int bank_origin = (raw->blocks[i].laser_block_id == LOWER_BANK) ? 32 : 0;
257
258 for (int j = 0, k = 0; j < SCANS_PER_BLOCK;
259 ++j, k += RAW_SCAN_SIZE) { // 32, 3
260 // One point
261 uint8_t laser_number =
262 static_cast<uint8_t>(j + bank_origin); // hardware laser number
263 LaserCorrection& corrections =
264 calibration_.laser_corrections_[laser_number];
265
266 union RawDistance raw_distance;
267 raw_distance.bytes[0] = raw->blocks[i].data[k];
268 raw_distance.bytes[1] = raw->blocks[i].data[k + 1];
269
270 // compute time
271 uint64_t timestamp = GetTimestamp(basetime, (*inner_time_)[i][j],
272 static_cast<uint16_t>(i));
273
274 if (j == SCANS_PER_BLOCK - 1) {
275 // set header stamp before organize the point cloud
276 pc->set_measurement_time(static_cast<double>(timestamp) / 1e9);
277 }
278
279 float real_distance = raw_distance.raw_distance * DISTANCE_RESOLUTION;
280 float distance = real_distance + corrections.dist_correction;
281
282 if (raw_distance.raw_distance == 0 ||
283 !is_scan_valid(raw->blocks[i].rotation, distance)) {
284 // if organized append a nan point to the cloud
285 if (config_.organized()) {
286 apollo::drivers::PointXYZIT* point_new = pc->add_point();
287 point_new->set_x(nan);
288 point_new->set_y(nan);
289 point_new->set_z(nan);
290 point_new->set_timestamp(timestamp);
291 point_new->set_intensity(0);
292 }
293 continue;
294 }
295
296 apollo::drivers::PointXYZIT* point = pc->add_point();
297 point->set_timestamp(timestamp);
298 // Position Calculation, append this point to the cloud
299 ComputeCoords(real_distance, corrections, raw->blocks[i].rotation, point);
300 point->set_intensity(IntensityCompensate(
301 corrections, raw_distance.raw_distance, raw->blocks[i].data[k + 2]));
302 // append this point to the cloud
303 }
304 }
305}
306
307void Velodyne64Parser::Order(std::shared_ptr<PointCloud> cloud) {
308 int height = 64;
309 cloud->set_height(height);
310 int width = cloud->point_size() / cloud->height();
311 cloud->set_width(width);
312
313 std::shared_ptr<PointCloud> cloud_origin = std::make_shared<PointCloud>();
314 cloud_origin->CopyFrom(*cloud);
315
316 for (int i = 0; i < height; ++i) {
317 int col = velodyne::ORDER_64[i];
318
319 for (int j = 0; j < width; ++j) {
320 // make sure offset is initialized, should be init at setup() just once
321 int row = (j + offsets_[i] + width) % width;
322 int target_index = j * height + i;
323 int origin_index = row * height + col;
324 cloud->mutable_point(target_index)
325 ->CopyFrom(cloud_origin->point(origin_index));
326 }
327 }
328}
329} // namespace velodyne
330} // namespace drivers
331} // namespace apollo
std::map< int, LaserCorrection > laser_corrections_
Definition calibration.h:70
int decode(const std::shared_ptr< VelodyneScan > &scan_msgs)
void GeneratePointcloud(const std::shared_ptr< VelodyneScan > &scan_msg, std::shared_ptr< PointCloud > out_msg)
Set up for data processing.
void setup() override
Set up for on-line operation.
void Order(std::shared_ptr< PointCloud > cloud)
virtual void setup()
Set up for on-line operation.
bool is_scan_valid(int rotation, float distance)
uint64_t GetGpsStamp(double current_stamp, double *previous_stamp, uint64_t *gps_base_usec)
void ComputeCoords(const float &raw_distance, const LaserCorrection &corrections, const uint16_t rotation, PointXYZIT *point)
Compute coords with the data in block
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
uint32_t width
Width of point cloud
const float INNER_TIME_64[12][32]
const float INNER_TIME_64E_S3[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