25#include <boost/algorithm/string.hpp>
27#include "absl/strings/str_cat.h"
41namespace trafficlight {
49 AERROR <<
"TrafficLightsPerceptionComponent InitConfig failed.";
54 AERROR <<
"TrafficLightsPerceptionComponent InitAlgorithmPlugin failed.";
59 AERROR <<
"TrafficLightsPerceptionComponent InitCameraFrame failed.";
64 AERROR <<
"TrafficLightsPerceptionComponent InitCameraListeners failed.";
71int TrafficLightsPerceptionComponent::InitConfig() {
74 AINFO <<
"load trafficlights perception component proto param failed";
81 AINFO <<
"tl_tf2_frame_id: " << tf2_frame_id_
82 <<
" tl_tf2_child_frame_id: " << tf2_child_frame_id_
83 <<
" tf2_buff_size: " << tf2_timeout_second_;
85 std::string camera_names_str =
"";
87 boost::algorithm::split(camera_names_, camera_names_str,
88 boost::algorithm::is_any_of(
","));
90 std::string camera_channel_names_str =
"";
92 boost::algorithm::split(input_camera_channel_names_, camera_channel_names_str,
93 boost::algorithm::is_any_of(
","));
95 gpu_id_ = traffic_light_param.
gpu_id();
96 proposal_output_channel_name_ =
101 AINFO <<
" _image_timestamp_offset: " << image_timestamp_offset_;
104 proc_interval_seconds_ = 1.0 / max_process_image_fps_;
105 AINFO <<
"_proc_interval_seconds: " << proc_interval_seconds_;
107 image_sys_ts_diff_threshold_ =
116 traffic_detect_writer_ =
117 node_->CreateWriter<TrafficDetectMessage>(proposal_output_channel_name_);
122int TrafficLightsPerceptionComponent::InitAlgorithmPlugin() {
124 trafficlight::BaseTLPreprocessor* preprocessor =
125 trafficlight::BaseTLPreprocessorRegisterer::GetInstanceByName(
126 tl_preprocessor_name_);
127 CHECK_NOTNULL(preprocessor);
128 preprocessor_.reset(preprocessor);
130 preprocessor_init_options_.
camera_names = camera_names_;
131 if (!preprocessor_->Init(preprocessor_init_options_)) {
132 AERROR <<
"TrafficLightsPerceptionComponent init preprocessor failed";
135 const auto camera_names_by_descending_focal_len =
136 preprocessor_->GetCameraNamesByDescendingFocalLen();
137 if (camera_names_by_descending_focal_len.empty()) {
138 AERROR <<
"empty camera_names in preprocessor";
141 if (camera_names_.size() != input_camera_channel_names_.size() ||
142 camera_names_.empty()) {
143 AERROR <<
"invalid camera_names config";
146 SensorManager* sensor_manager = SensorManager::Instance();
147 for (
size_t i = 0; i < camera_names_.size(); ++i) {
148 if (!sensor_manager->IsSensorExist(camera_names_[i])) {
149 AERROR << (
"sensor_name: " + camera_names_[i] +
" not exists.");
154 std::string tf2_camera_child_frame_id =
155 sensor_manager->GetFrameId(camera_names_[i]);
156 std::shared_ptr<TransformWrapper> trans_wrapper(
new TransformWrapper);
157 trans_wrapper->Init(tf2_camera_child_frame_id);
158 camera2world_trans_wrapper_map_[camera_names_[i]] = trans_wrapper;
160 if (camera_names_[i] == camera_names_by_descending_focal_len.back()) {
161 image_border_sizes_[camera_names_[i]] = 0;
163 image_border_sizes_[camera_names_[i]] = default_image_border_size_;
168 hd_map_ = map::HDMapInput::Instance();
169 if (hd_map_ ==
nullptr) {
170 AERROR <<
"PreprocessComponent get hdmap failed.";
174 if (!hd_map_->
Init()) {
175 AERROR <<
"PreprocessComponent init hd-map failed.";
182int TrafficLightsPerceptionComponent::InitCameraListeners() {
184 for (
size_t i = 0; i < camera_names_.size(); ++i) {
185 const auto& camera_name = camera_names_[i];
186 const auto& camera_channel_name = input_camera_channel_names_[i];
187 const std::string camera_listener_name =
"tl_" + camera_name +
"_listener";
189 typedef const std::shared_ptr<apollo::drivers::Image>
ImageMsgType;
190 std::function<void(
const ImageMsgType&)> sub_camera_callback =
191 std::bind(&TrafficLightsPerceptionComponent::OnReceiveImage,
this,
192 std::placeholders::_1, camera_name);
193 auto sub_camera_reader =
194 node_->CreateReader(camera_channel_name, sub_camera_callback);
195 last_sub_camera_image_ts_[camera_name] = 0.0;
201int TrafficLightsPerceptionComponent::InitCameraFrame() {
202 data_provider_init_options_.
image_height = image_height_;
203 data_provider_init_options_.
image_width = image_width_;
205 data_provider_init_options_.
device_id = gpu_id_;
206 AINFO <<
"trafficlights data_provider_init_options_.device_id: "
207 << data_provider_init_options_.
device_id;
211 for (
const auto& camera_name : camera_names_) {
212 data_provider_init_options_.
sensor_name = camera_name;
213 std::shared_ptr<camera::DataProvider> data_provider(
214 new camera::DataProvider);
215 if (!data_provider->Init(data_provider_init_options_)) {
216 AERROR <<
"trafficlights init data_provider failed. "
217 <<
" camera_name: " << camera_name;
220 data_providers_map_[camera_name] = data_provider;
226void TrafficLightsPerceptionComponent::OnReceiveImage(
227 const std::shared_ptr<apollo::drivers::Image> msg,
228 const std::string& camera_name) {
230 std::lock_guard<
std::mutex> lck(mutex_);
231 double receive_img_timestamp =
Clock::NowInSeconds();
232 double image_msg_ts = msg->measurement_time();
233 image_msg_ts += image_timestamp_offset_;
234 last_sub_camera_image_ts_[camera_name] = image_msg_ts;
236 if (!CheckCameraImageStatus(image_msg_ts, check_image_status_interval_thresh_,
238 AERROR <<
"CheckCameraImageStatus failed";
242 std::shared_ptr<TrafficDetectMessage> preprocess_message(
243 new (std::nothrow) TrafficDetectMessage);
244 preprocess_message->timestamp_ = image_msg_ts;
246 auto& frame = preprocess_message->traffic_light_frame_;
247 frame.reset(
new camera::TrafficLightFrame);
248 frame->timestamp = image_msg_ts;
250 trafficlight::TLPreprocessorOption preprocess_option;
251 preprocess_option.image_borders_size = &image_border_sizes_;
254 if (!UpdateCameraSelection(image_msg_ts, preprocess_option, frame)) {
255 AWARN <<
"add_cached_camera_selection failed, ts: " << image_msg_ts;
259 if (last_proc_image_ts_ > 0.0 &&
260 receive_img_timestamp - last_proc_image_ts_ < proc_interval_seconds_) {
262 <<
" , receive_img_timestamp: "
265 <<
" , _proc_interval_seconds: "
271 preprocessor_->SyncInformation(image_msg_ts, camera_name);
273 if (!sync_image_ok) {
274 AINFO <<
"PreprocessComponent not publish image, ts:" << image_msg_ts
275 <<
", camera_name: " << camera_name;
281 camera::DataProvider::ImageOptions image_options;
283 frame->data_provider = data_providers_map_.at(camera_name);
284 frame->data_provider->FillImageData(
285 image_height_, image_width_,
286 reinterpret_cast<const uint8_t*
>(msg->data().data()), msg->encoding());
287 frame->timestamp = image_msg_ts;
289 const auto& diff_image_sys_ts = image_msg_ts - receive_img_timestamp;
290 if (fabs(diff_image_sys_ts) > image_sys_ts_diff_threshold_) {
291 const std::string metric_name =
"perception traffic_light exception";
292 const std::string debug_string =
293 absl::StrCat(
"diff_image_sys_ts:", diff_image_sys_ts,
294 ",camera_id:", camera_name,
",camera_ts:", image_msg_ts);
295 AWARN <<
"image_ts - system_ts(in seconds): " << diff_image_sys_ts
296 <<
". Check if image timestamp drifts."
297 <<
", camera_id: " + camera_name
298 <<
", debug_string: " << debug_string;
301 if (!VerifyLightsProjection(image_msg_ts, preprocess_option, camera_name,
302 frame, preprocess_message)) {
303 AINFO <<
"VerifyLightsProjection on image failed, ts: " << image_msg_ts
304 <<
", camera_name: " << camera_name
305 <<
" last_query_tf_ts_: " << last_query_tf_ts_
306 <<
" need update_camera_selection immediately,"
307 <<
" reset last_query_tf_ts_ to -1";
308 last_query_tf_ts_ = -1.0;
312 preprocess_message->stoplines_ = stoplines_;
314 bool send_message_ret = traffic_detect_writer_->Write(preprocess_message);
315 AINFO <<
"send out preprocess msg, ts: " << image_msg_ts
316 <<
"ret: " << send_message_ret;
319void TrafficLightsPerceptionComponent::GenerateTrafficLights(
320 const std::vector<apollo::hdmap::Signal>& signals,
321 std::vector<base::TrafficLightPtr>* traffic_lights) {
322 traffic_lights->clear();
323 for (
auto signal : signals) {
325 light.reset(
new base::TrafficLight);
326 light->id = signal.id().id();
327 for (
int i = 0; i < signal.boundary().point_size(); ++i) {
329 point.x = signal.boundary().point(i).x();
330 point.y = signal.boundary().point(i).y();
331 point.z = signal.boundary().point(i).z();
332 light->region.points.push_back(point);
335 int cur_semantic = 0;
337 light->semantic = cur_semantic;
338 traffic_lights->push_back(light);
339 stoplines_ = signal.stop_line();
343bool TrafficLightsPerceptionComponent::QueryPoseAndSignals(
344 const double ts, camera::CarPose* pose,
345 std::vector<apollo::hdmap::Signal>* signals) {
347 if (!GetCarPose(ts, pose)) {
348 AINFO <<
"query_pose_and_signals failed to get car pose, ts:" << ts;
353 AERROR <<
"hd_map_ not init.";
357 Eigen::Vector3d car_position = pose->getCarPosition();
358 if (!hd_map_->
GetSignals(car_position, forward_distance_to_query_signals,
360 if (ts - last_signals_ts_ < valid_hdmap_interval_) {
361 *signals = last_signals_;
362 AWARN <<
"query_pose_and_signals failed to get signals info. "
363 <<
"Now use last info. ts:" << ts <<
" pose:" << *pose
364 <<
" signals.size(): " << signals->size();
366 AERROR <<
"query_pose_and_signals failed to get signals info. "
367 <<
"ts:" << ts <<
" pose:" << *pose;
370 AINFO <<
"query_pose_and_signals succeeded, signals.size(): "
373 last_signals_ts_ = ts;
374 last_signals_ = *signals;
379bool TrafficLightsPerceptionComponent::VerifyLightsProjection(
380 const double& ts,
const trafficlight::TLPreprocessorOption& option,
381 const std::string& camera_name,
382 std::shared_ptr<camera::TrafficLightFrame> frame,
383 std::shared_ptr<TrafficDetectMessage> msg) {
384 camera::CarPose* pose_ptr =
new camera::CarPose();
385 auto& pose = *pose_ptr;
386 std::vector<apollo::hdmap::Signal> signals;
387 if (!QueryPoseAndSignals(ts, pose_ptr, &signals)) {
388 AERROR <<
"query_pose_and_signals failed, ts: " << ts;
391 auto& carpose_ptr = msg->carpose_;
392 carpose_ptr.reset(pose_ptr);
394 GenerateTrafficLights(signals, &frame->traffic_lights);
396 if (!preprocessor_->UpdateLightsProjection(pose, option, camera_name,
397 &frame->traffic_lights)) {
398 AWARN <<
"verify_lights_projection failed to update_lights_projection, "
403 AINFO <<
"VerifyLightsProjection success " << frame->traffic_lights.size();
408bool TrafficLightsPerceptionComponent::UpdateCameraSelection(
409 double timestamp,
const trafficlight::TLPreprocessorOption& option,
410 std::shared_ptr<camera::TrafficLightFrame> frame) {
412 if (last_query_tf_ts_ > 0.0 &&
413 current_ts - last_query_tf_ts_ < query_tf_interval_seconds_) {
418 AINFO <<
"start select camera";
420 camera::CarPose pose;
421 std::vector<apollo::hdmap::Signal> signals;
422 if (!QueryPoseAndSignals(timestamp, &pose, &signals)) {
423 AINFO <<
"query_pose_and_signals failed, ts: "
427 last_query_tf_ts_ = current_ts;
429 GenerateTrafficLights(signals, &frame->traffic_lights);
430 AINFO <<
"hd map signals " << frame->traffic_lights.size();
432 if (!preprocessor_->UpdateCameraSelection(pose, option,
433 &frame->traffic_lights)) {
434 AERROR <<
"add_cached_lights_projections failed, ts: "
437 AINFO <<
"add_cached_lights_projections succeed, ts: "
441 for (
auto& light : frame->traffic_lights) {
442 AINFO <<
"x " << light->region.projection_roi.x <<
" y "
443 << light->region.projection_roi.y <<
" w "
444 << light->region.projection_roi.width <<
" h "
445 << light->region.projection_roi.height;
450bool TrafficLightsPerceptionComponent::CheckCameraImageStatus(
451 double timestamp,
double interval,
const std::string& camera_name) {
452 bool camera_ok =
true;
453 std::string no_image_camera_names =
"";
454 for (
const auto& pr : last_sub_camera_image_ts_) {
455 const auto cam_name = pr.first;
456 double last_sub_camera_ts = pr.second;
458 if (last_sub_camera_ts < 1.0 || timestamp - last_sub_camera_ts > interval) {
459 preprocessor_->SetCameraWorkingFlag(cam_name,
false);
460 AWARN <<
"camera is probably not working"
463 <<
" , camera_name: " << cam_name;
465 AINFO <<
"camera status:" << camera_ok;
466 no_image_camera_names += (
" " + cam_name);
470 bool is_camera_working =
false;
471 if (!preprocessor_->GetCameraWorkingFlag(camera_name, &is_camera_working)) {
473 <<
" camera_name: " << camera_name;
477 if (!is_camera_working) {
478 if (!preprocessor_->SetCameraWorkingFlag(camera_name,
true)) {
480 <<
" camera_name: " << camera_name;
487bool TrafficLightsPerceptionComponent::GetCarPose(
const double timestamp,
488 camera::CarPose* pose) {
489 Eigen::Matrix4d pose_matrix;
491 if (!GetPoseFromTF(timestamp, tf2_frame_id_, tf2_child_frame_id_,
493 AERROR <<
"get pose from tf failed, child_frame_id: "
494 << tf2_child_frame_id_;
498 pose->pose_ = pose_matrix;
502 Eigen::Affine3d affine3d_trans;
503 for (
const auto& camera_name : camera_names_) {
504 const auto trans_wrapper = camera2world_trans_wrapper_map_[camera_name];
505 ret = trans_wrapper->GetSensor2worldTrans(timestamp, &affine3d_trans);
506 pose_matrix = affine3d_trans.matrix();
508 pose->ClearCameraPose(camera_name);
509 AERROR <<
"get pose from tf failed, camera_name: " << camera_name;
511 pose->c2w_poses_[camera_name] = pose_matrix;
518bool TrafficLightsPerceptionComponent::GetPoseFromTF(
519 const double timestamp,
const std::string& frame_id,
520 const std::string& child_frame_id, Eigen::Matrix4d* pose_matrix) {
522 std::string err_string;
523 if (!tf2_buffer_->
canTransform(frame_id, child_frame_id, query_time,
524 static_cast<float>(tf2_timeout_second_),
527 <<
" frame_id: " <<
frame_id <<
" child_frame_id: " << child_frame_id
528 <<
" Error info: " << err_string;
535 Eigen::Translation3d translation(
543 *pose_matrix = (translation * rotation).matrix();
544 ADEBUG <<
"get pose: " << *pose_matrix;
545 }
catch (tf2::TransformException& ex) {
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
bool GetProtoConfig(T *config) const
std::shared_ptr< Node > node_
Cyber has builtin time type Time.
bool Init() override
Initialize configuration files, algorithm plug-ins, callback functions and create listening channels.
Math-related util functions.
std::string GetAbsolutePath(const std::string &prefix, const std::string &relative_path)
Get absolute path by concatenating prefix and relative_path.
std::string frame_id
Point cloud frame id
std::shared_ptr< TrafficLight > TrafficLightPtr
Point< double > PointXYZID
std::shared_ptr< apollo::drivers::Image > ImageMsgType
#define PERF_FUNCTION(...)
Some string util functions.
#define FORMAT_TIMESTAMP(timestamp)
float sync_interval_seconds
std::vector< std::string > camera_names
optional string proposal_output_channel_name
optional double query_tf_interval_seconds
optional int32 max_process_image_fps
optional perception::PluginParam plugin_param
optional double sync_interval_seconds
optional double tf2_timeout_second
optional double tl_image_timestamp_offset
optional double image_sys_ts_diff_threshold
optional string camera_names
optional int32 default_image_border_size
optional string tl_tf2_child_frame_id
optional string camera_channel_names
optional double valid_hdmap_interval
optional string tl_tf2_frame_id