Apollo 10.0
自动驾驶开放平台
driver.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 <cmath>
20#include <cstring>
21#include <ctime>
22#include <string>
23#include <thread>
24
25#include "cyber/cyber.h"
27
28namespace apollo {
29namespace drivers {
30namespace velodyne {
31
33
35 if (poll_thread_.joinable()) {
36 poll_thread_.join();
37 }
38 if (positioning_thread_.joinable()) {
40 }
41}
42
44 double frequency = (config_.rpm() / 60.0); // expected Hz rate
45
46 // default number of packets for each scan is a single revolution
47 // (fractions rounded up)
48 config_.set_npackets(static_cast<int>(ceil(packet_rate_ / frequency)));
49 AINFO << "publishing " << config_.npackets() << " packets per scan";
50
51 // open Velodyne input device
52
53 input_.reset(new SocketInput());
54 writer_ = node_->CreateWriter<VelodyneScan>(config_.scan_channel());
58
59 // raw data output topic
61 std::thread(&VelodyneDriver::PollPositioningPacket, this);
62 poll_thread_ = std::thread(&VelodyneDriver::DevicePoll, this);
63 return true;
64}
65
67 uint64_t* basetime) {
68 struct tm time;
69 std::memset(&time, 0, sizeof(tm));
70 time.tm_year = nmea_time->year + (2000 - 1900);
71 time.tm_mon = nmea_time->mon - 1;
72 time.tm_mday = nmea_time->day;
73 time.tm_hour = nmea_time->hour;
74
75 // set last gps time using gps socket packet
77 static_cast<uint32_t>((nmea_time->min * 60 + nmea_time->sec) * 1e6);
78
79 AINFO << "Set base unix time : " << time.tm_year << "-" << time.tm_mon << "-"
80 << time.tm_mday << " " << time.tm_hour << ":" << time.tm_min << ":"
81 << time.tm_sec;
82 uint64_t unix_base = static_cast<uint64_t>(timegm(&time));
83 *basetime = unix_base * static_cast<uint64_t>(1e6);
84}
85
87 NMEATimePtr nmea_time(new NMEATime);
88 while (true) {
89 int rc = input_->get_positioning_data_packet(nmea_time);
90 if (rc == 0) {
91 break; // got a full packet
92 }
93 if (rc < 0) {
94 return false; // end of file reached
95 }
96 }
97
100 return true;
101}
102
107bool VelodyneDriver::Poll(const std::shared_ptr<VelodyneScan>& scan) {
108 // Allocate a new shared pointer for zero-copy sharing with other nodelets.
109 if (basetime_ == 0) {
110 // waiting for positioning data
111 std::this_thread::sleep_for(std::chrono::microseconds(100));
112 AWARN << "basetime is zero";
113 return false;
114 }
115
116 int poll_result = PollStandard(scan);
117
118 if (poll_result == SOCKET_TIMEOUT || poll_result == RECEIVE_FAIL) {
119 return false; // poll again
120 }
121
122 if (scan->firing_pkts().empty()) {
123 AINFO << "Get an empty scan from port: " << config_.firing_data_port();
124 return false;
125 }
126
127 // publish message using time of last packet read
128 ADEBUG << "Publishing a full Velodyne scan.";
129 scan->mutable_header()->set_timestamp_sec(cyber::Time().Now().ToSecond());
130 scan->mutable_header()->set_frame_id(config_.frame_id());
131 scan->set_model(config_.model());
132 scan->set_mode(config_.mode());
133 // we use first packet gps time update gps base hour
134 // in cloud nodelet, will update base time packet by packet
135 uint32_t current_secs = *(reinterpret_cast<uint32_t*>(
136 const_cast<char*>(scan->firing_pkts(0).data().data() + 1200)));
137
138 UpdateGpsTopHour(current_secs);
139 scan->set_basetime(basetime_);
140
141 return true;
142}
143
144int VelodyneDriver::PollStandard(std::shared_ptr<VelodyneScan> scan) {
145 // Since the velodyne delivers data at a very high rate, keep reading and
146 // publishing scans as fast as possible.
147 while ((config_.use_poll_sync() &&
149 scan->firing_pkts_size() < config_.npackets()) ||
152 scan->firing_pkts_size() < config_.npackets())) {
153 while (true) {
154 // keep reading until full packet received
155 VelodynePacket* packet = scan->add_firing_pkts();
156 int rc = input_->get_firing_data_packet(packet);
157
158 if (rc == 0) {
159 break; // got a full packet?
160 } else if (rc < 0) {
161 return rc;
162 }
163 }
164 }
165 if (config_.use_poll_sync()) {
166 if (config_.is_main_frame()) {
167 ++sync_counter;
168 } else {
170 }
171 }
172 return 0;
173}
174
176 while (!cyber::IsShutdown()) {
177 NMEATimePtr nmea_time(new NMEATime);
178 bool ret = true;
179 if (config_.has_use_gps_time() && !config_.use_gps_time()) {
180 time_t t = time(NULL);
181 struct tm current_time;
182 localtime_r(&t, &current_time);
183 nmea_time->year = static_cast<uint16_t>(current_time.tm_year - 100);
184 nmea_time->mon = static_cast<uint16_t>(current_time.tm_mon + 1);
185 nmea_time->day = static_cast<uint16_t>(current_time.tm_mday);
186 nmea_time->hour = static_cast<uint16_t>(current_time.tm_hour);
187 nmea_time->min = static_cast<uint16_t>(current_time.tm_min);
188 nmea_time->sec = static_cast<uint16_t>(current_time.tm_sec);
189 AINFO << "Get NMEA Time from local time :"
190 << "year:" << nmea_time->year << "mon:" << nmea_time->mon
191 << "day:" << nmea_time->day << "hour:" << nmea_time->hour
192 << "min:" << nmea_time->min << "sec:" << nmea_time->sec;
193 } else {
194 while (!cyber::IsShutdown()) {
195 int rc = positioning_input_->get_positioning_data_packet(nmea_time);
196 if (rc == 0) {
197 break; // got a full packet
198 }
199 if (rc < 0) {
200 ret = false; // end of file reached
201 }
202 }
203 }
204
205 if (basetime_ == 0 && ret) {
207 } else {
208 std::this_thread::sleep_for(std::chrono::milliseconds(1));
209 }
210 }
211}
212
213void VelodyneDriver::UpdateGpsTopHour(uint32_t current_time) {
214 if (last_gps_time_ == 0) {
215 last_gps_time_ = current_time;
216 return;
217 }
218 if (last_gps_time_ > current_time) {
219 if ((last_gps_time_ - current_time) > 3599000000) {
220 basetime_ += static_cast<uint64_t>(3600 * 1e6);
221 AINFO << "Base time plus 3600s. Model: " << config_.model() << std::fixed
222 << ". current:" << current_time << ", last time:" << last_gps_time_;
223 } else {
224 AWARN << "Current stamp:" << std::fixed << current_time
225 << " less than previous stamp:" << last_gps_time_
226 << ". GPS time stamp maybe incorrect!";
227 }
228 }
229 last_gps_time_ = current_time;
230}
231
233 const std::shared_ptr<::apollo::cyber::Node>& node, const Config& config) {
234 auto new_config = config;
235 if (new_config.prefix_angle() > 35900 || new_config.prefix_angle() < 100) {
236 AWARN << "invalid prefix angle, prefix_angle must be between 100 and 35900";
237 if (new_config.prefix_angle() > 35900) {
238 new_config.set_prefix_angle(35900);
239 } else if (new_config.prefix_angle() < 100) {
240 new_config.set_prefix_angle(100);
241 }
242 }
243 VelodyneDriver* driver = nullptr;
244 switch (config.model()) {
245 case HDL64E_S2: {
246 driver = new Velodyne64Driver(node, config);
248 break;
249 }
250 case HDL64E_S3S: {
251 driver = new Velodyne64Driver(node, config);
253 break;
254 }
255 case HDL64E_S3D: {
256 driver = new Velodyne64Driver(node, config);
258 break;
259 }
260 case HDL32E: {
261 driver = new VelodyneDriver(node, config);
263 break;
264 }
265 case VLP32C: {
266 driver = new VelodyneDriver(node, config);
268 break;
269 }
270 case VLP16: {
271 driver = new VelodyneDriver(node, config);
273 break;
274 }
275 case VLS128: {
276 driver = new VelodyneDriver(node, config);
278 break;
279 }
280 default:
281 AERROR << "invalid model, must be 64E_S2|64E_S3S"
282 << "|64E_S3D|VLP16|HDL32E|VLS128";
283 break;
284 }
285 return driver;
286}
287
289 while (!apollo::cyber::IsShutdown()) {
290 // poll device until end of file
291 std::shared_ptr<VelodyneScan> scan = std::make_shared<VelodyneScan>();
292 bool ret = Poll(scan);
293 if (ret) {
294 apollo::common::util::FillHeader("velodyne", scan.get());
295 writer_->Write(scan);
296 } else {
297 AWARN << "device poll failed";
298 }
299 }
300}
301
302} // namespace velodyne
303} // namespace drivers
304} // namespace apollo
Cyber has builtin time type Time.
Definition time.h:31
std::shared_ptr< cyber::Node > node_
Definition driver_base.h:66
Live Velodyne input from socket.
static VelodyneDriver * CreateDriver(const std::shared_ptr<::apollo::cyber::Node > &node, const Config &config)
Definition driver.cc:232
std::unique_ptr< Input > positioning_input_
Definition driver.h:66
void SetBaseTimeFromNmeaTime(NMEATimePtr nmea_time, uint64_t *basetime)
Definition driver.cc:66
std::unique_ptr< Input > input_
Definition driver.h:65
void SetPacketRate(const double packet_rate)
Definition driver.h:58
virtual bool Poll(const std::shared_ptr< VelodyneScan > &scan)
poll the device
Definition driver.cc:107
bool Init() override
Initialize the lidar driver.
Definition driver.cc:43
std::shared_ptr< apollo::cyber::Writer< VelodyneScan > > writer_
Definition driver.h:64
virtual int PollStandard(std::shared_ptr< VelodyneScan > scan)
Definition driver.cc:144
void UpdateGpsTopHour(uint32_t current_time)
Definition driver.cc:213
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
Some string util functions.
bool IsShutdown()
Definition state.h:46
constexpr double PACKET_RATE_HDL64E_S2
Definition driver.h:38
std::shared_ptr< NMEATime > NMEATimePtr
Definition input.h:46
constexpr double PACKET_RATE_HDL64E_S3D
Definition driver.h:40
constexpr double PACKET_RATE_VLP16
Definition driver.h:36
constexpr double PACKET_RATE_HDL32E
Definition driver.h:37
constexpr double PACKET_RATE_HDL64E_S3S
Definition driver.h:39
constexpr double PACKET_RATE_VLP32C
Definition driver.h:42
constexpr double PACKET_RATE_VLS128
Definition driver.h:41
class register implement
Definition arena_queue.h:37