19#include "gflags/gflags.h"
20#include "google/protobuf/descriptor.h"
21#include "google/protobuf/message.h"
36using google::protobuf::FieldDescriptor;
37using Json = nlohmann::json;
46bool GetProtobufFloatByFieldName(
const google::protobuf::Message& message,
47 const google::protobuf::Descriptor* descriptor,
48 const google::protobuf::Reflection* reflection,
49 const std::string& field_name,
float* value) {
51 AERROR <<
"Protobuf descriptor not found";
55 const auto* field_descriptor = descriptor->FindFieldByName(field_name);
56 const auto cpp_type = field_descriptor->cpp_type();
57 if (cpp_type == FieldDescriptor::CppType::CPPTYPE_FLOAT) {
58 *value = reflection->GetFloat(message, field_descriptor);
59 }
else if (cpp_type == FieldDescriptor::CppType::CPPTYPE_DOUBLE) {
60 double value_in_double = reflection->GetDouble(message, field_descriptor);
61 *value =
static_cast<float>(value_in_double);
62 }
else if (cpp_type == FieldDescriptor::CppType::CPPTYPE_ENUM) {
63 int value_in_int = reflection->GetEnumValue(message, field_descriptor);
64 *value =
static_cast<float>(value_in_int);
66 AERROR << field_name <<
" has unsupported conversion type: "
67 << field_descriptor->cpp_type();
74bool IsCompliedWithCriterion(
float actual_value,
77 switch (comparison_operator) {
79 return std::fabs(actual_value - target_value) <
82 return (actual_value > target_value);
84 return (actual_value >= target_value);
86 return (actual_value < target_value);
88 return (actual_value <= target_value);
90 return (actual_value != target_value);
92 AERROR <<
"Unsupported comparison operator found:" << comparison_operator;
101 node_(cyber::CreateNode(
"data_collection_monitor")) {
108void DataCollectionMonitor::InitReaders() {
109 node_->CreateReader<
Chassis>(FLAGS_chassis_topic,
110 [
this](
const std::shared_ptr<Chassis>& chassis) {
111 this->OnChassis(chassis);
115void DataCollectionMonitor::LoadConfiguration() {
116 const std::string& vehicle_dir =
117 VehicleManager::Instance()->GetVehicleDataPath();
118 std::string data_collection_config_path =
119 vehicle_dir +
"/data_collection_table.pb.txt";
120 if (!PathExists(data_collection_config_path)) {
121 AWARN <<
"No corresponding data collection table file found in "
122 << vehicle_dir <<
". Using default one instead.";
123 data_collection_config_path = FLAGS_default_data_collection_config_path;
127 &data_collection_table_))
128 <<
"Unable to parse data collection configuration from file "
129 << data_collection_config_path;
131 ConstructCategories();
133 ADEBUG <<
"Configuration loaded.";
136void DataCollectionMonitor::ConstructCategories() {
137 scenario_to_categories_.clear();
139 for (
const auto& scenario_iter : data_collection_table_.scenario()) {
140 const std::string& scenario_name = scenario_iter.first;
141 const Scenario& scenario = scenario_iter.second;
144 ConstructCategoriesHelper(scenario_name, scenario, 0,
"", category);
148void DataCollectionMonitor::ConstructCategoriesHelper(
149 const std::string& scenario_name,
const Scenario& scenario,
int feature_idx,
150 std::string current_category_name,
const Category& current_category) {
151 if (feature_idx == scenario.feature_size()) {
152 scenario_to_categories_[scenario_name].insert(
153 {current_category_name, current_category});
155 category_consecutive_frame_count_[scenario_name][current_category_name] =
157 category_frame_count_[scenario_name][current_category_name] = 0.0;
158 current_progress_json_[scenario_name][current_category_name] = 0.0;
162 const Feature& feature = scenario.feature(feature_idx);
163 for (
const auto& range : feature.range()) {
164 Category new_category(current_category);
165 new_category.push_back(range);
168 std::string new_category_name(current_category_name);
169 const std::string& range_name = range.name();
170 if (feature.range().size() > 1 && !range_name.empty()) {
171 if (!new_category_name.empty()) {
172 new_category_name +=
", ";
174 new_category_name += range_name;
177 ConstructCategoriesHelper(scenario_name, scenario, feature_idx + 1,
178 new_category_name, new_category);
184 category_consecutive_frame_count_.clear();
185 category_frame_count_.clear();
186 current_progress_json_.clear();
194 AINFO <<
"DataCollectionMonitor stopped";
197void DataCollectionMonitor::OnChassis(
const std::shared_ptr<Chassis>& chassis) {
202 const size_t frame_threshold = data_collection_table_.
frame_threshold();
203 const auto total_frames = data_collection_table_.
total_frames();
204 for (
const auto& scenario_iter : scenario_to_categories_) {
205 const std::string& scenario_name = scenario_iter.first;
206 const auto& categories = scenario_iter.second;
208 for (
const auto& category_iter : categories) {
209 const std::string& category_name = category_iter.first;
210 const Category& category = category_iter.second;
213 if (category_frame_count_[scenario_name][category_name] >= total_frames) {
217 if (!IsCompliedWithCriteria(chassis, category)) {
218 category_consecutive_frame_count_[scenario_name][category_name] = 0;
223 const size_t consecutive_count =
224 ++category_consecutive_frame_count_[scenario_name][category_name];
225 if (consecutive_count == frame_threshold) {
226 category_frame_count_[scenario_name][category_name] +=
228 }
else if (consecutive_count >= frame_threshold) {
229 category_frame_count_[scenario_name][category_name] += 1;
233 const double progress_percentage =
236 category_frame_count_[scenario_name][category_name]) /
237 static_cast<double>(total_frames);
239 boost::unique_lock<boost::shared_mutex> writer_lock(mutex_);
240 current_progress_json_[scenario_name][category_name] =
247bool DataCollectionMonitor::IsCompliedWithCriteria(
248 const std::shared_ptr<Chassis>& chassis,
const Category& category) {
250 const auto* vehicle_param_descriptor = vehicle_param.GetDescriptor();
251 const auto* vehicle_param_reflection = vehicle_param.GetReflection();
253 const auto* chassis_descriptor = chassis->GetDescriptor();
254 const auto* chassis_reflection = chassis->GetReflection();
256 for (
const auto& range : category) {
257 for (
const auto& criterion : range.criterion()) {
259 if (criterion.has_value()) {
260 target_value = criterion.value();
261 }
else if (!GetProtobufFloatByFieldName(
262 vehicle_param, vehicle_param_descriptor,
263 vehicle_param_reflection, criterion.vehicle_config(),
269 if (!GetProtobufFloatByFieldName(*chassis, chassis_descriptor,
270 chassis_reflection, criterion.field(),
275 if (!IsCompliedWithCriterion(
276 actual_value, criterion.comparison_operator(), target_value)) {
286 boost::unique_lock<boost::shared_mutex> reader_lock(mutex_);
287 return current_progress_json_;
@Brief This is a helper class that can load vehicle configurations.
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
DataCollectionMonitor()
Constructor of DataCollectionMonitor.
void Stop() override
stop monitoring collection progress
void Start() override
start monitoring collection progress
nlohmann::json GetProgressAsJson() override
return collection progress of categories and overall as json
A base class that monitor progress for Fuel client
constexpr double kMathEpsilon
bool PathExists(const std::string &path)
Check if the path exists.
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
std::vector< Range > Category
optional VehicleParam vehicle_param
required uint32 total_frames
required uint32 frame_threshold