19#include "absl/strings/str_cat.h"
20#include "absl/strings/str_join.h"
21#include "absl/strings/str_split.h"
23#include "cyber/proto/dag_conf.pb.h"
24#include "modules/common_msgs/monitor_msgs/system_status.pb.h"
25#include "modules/dreamview/proto/scenario.pb.h"
60using apollo::monitor::ComponentStatus;
61using apollo::monitor::SystemStatus;
62using google::protobuf::util::JsonStringToMessage;
63using RLock = boost::shared_lock<boost::shared_mutex>;
64using WLock = boost::unique_lock<boost::shared_mutex>;
65using Json = nlohmann::json;
67constexpr char kNavigationModeName[] =
"Navigation";
69template <
class FlagType,
class ValueType>
70void SetGlobalFlag(std::string_view flag_name,
const ValueType &value,
72 constexpr char kGlobalFlagfile[] =
73 "/apollo/modules/common/data/global_flagfile.txt";
77 std::ofstream fout(kGlobalFlagfile, std::ios_base::app);
78 ACHECK(fout) <<
"Fail to open global flagfile " << kGlobalFlagfile;
79 fout <<
"\n--" << flag_name <<
"=" << value << std::endl;
83void System(std::string_view cmd) {
84 const int ret = std::system(cmd.data());
86 AINFO <<
"SUCCESS: " << cmd;
88 AERROR <<
"FAILED(" << ret <<
"): " << cmd;
95 : config_(util::HMIUtil::
LoadConfig(FLAGS_dv_hmi_modes_config_path)),
101 callback_api_ = callback_api;
102 InitReadersAndWriters();
103 RegisterStatusUpdateHandler(
104 [
this](
const bool status_changed, HMIStatus *status) {
105 apollo::common::util::FillHeader(
"HMI", status);
106 status_writer_->Write(*status);
107 status->clear_header();
109 ResetComponentStatusTimer();
110 thread_future_ = cyber::Async(&HMIWorker::StatusUpdateThreadLoop,
this);
113void HMIWorker::Stop() {
115 if (thread_future_.valid()) {
116 thread_future_.get();
120bool HMIWorker::LoadVehicleDefinedMode(
const std::string &mode_config_path,
121 const std::string ¤t_vehicle_path,
123 const std::string mode_file_name =
124 cyber::common::GetFileName(mode_config_path);
125 const std::string vehicle_mode_config_path =
126 current_vehicle_path +
"/dreamview_conf/hmi_modes/" +
128 if (!cyber::common::PathExists(vehicle_mode_config_path)) {
131 ACHECK(cyber::common::GetProtoFromFile(vehicle_mode_config_path,
133 <<
"Unable to parse vehicle self defined HMIMode from file "
134 << vehicle_mode_config_path;
135 util::HMIUtil::TranslateCyberModules(self_defined_mode);
139void HMIWorker::InitStatus() {
140 static constexpr char kDockerImageEnv[] =
"DOCKER_IMG";
141 status_.set_docker_image(cyber::common::GetEnv(kDockerImageEnv));
142 status_.set_utm_zone_id(FLAGS_local_utm_zone_id);
145 const auto &modes = config_.modes();
146 for (
const auto &iter : modes) {
147 const std::string &mode = iter.first;
148 status_.add_modes(mode);
149 if (mode == FLAGS_vehicle_calibration_mode) {
150 FuelMonitorManager::Instance()->RegisterFuelMonitor(
151 mode, std::make_unique<DataCollectionMonitor>());
152 FuelMonitorManager::Instance()->RegisterFuelMonitor(
153 mode, std::make_unique<PreprocessMonitor>());
154 }
else if (mode == FLAGS_lidar_calibration_mode) {
155 FuelMonitorManager::Instance()->RegisterFuelMonitor(
156 mode, std::make_unique<PreprocessMonitor>(
"lidar_to_gnss"));
157 }
else if (mode == FLAGS_camera_calibration_mode) {
158 FuelMonitorManager::Instance()->RegisterFuelMonitor(
159 mode, std::make_unique<PreprocessMonitor>(
"camera_to_lidar"));
164 for (
const auto &map_entry : config_.maps()) {
165 status_.add_maps(map_entry.first);
168 if (map_entry.second == FLAGS_map_dir) {
169 status_.set_current_map(map_entry.first);
174 for (
const auto &vehicle : config_.vehicles()) {
175 status_.add_vehicles(vehicle.first);
183 const std::string cached_mode =
184 KVDB::Get(FLAGS_current_mode_db_key).value_or(
"");
185 if (FLAGS_use_navigation_mode && ContainsKey(modes, kNavigationModeName)) {
186 ChangeMode(kNavigationModeName);
187 }
else if (ContainsKey(modes, cached_mode)) {
188 ChangeMode(cached_mode);
189 }
else if (ContainsKey(modes, FLAGS_default_hmi_mode)) {
190 ChangeMode(FLAGS_default_hmi_mode);
192 ChangeMode(modes.begin()->first);
196void HMIWorker::InitReadersAndWriters() {
197 status_writer_ = node_->CreateWriter<HMIStatus>(FLAGS_hmi_status_topic);
198 action_command_client_ = node_->CreateClient<ActionCommand, CommandStatus>(
199 FLAGS_action_command_topic);
200 lane_follow_command_client_ =
201 node_->CreateClient<LaneFollowCommand, CommandStatus>(
202 FLAGS_lane_follow_command_topic);
203 audio_event_writer_ =
204 node_->CreateWriter<AudioEvent>(FLAGS_audio_event_topic);
205 drive_event_writer_ =
206 node_->CreateWriter<DriveEvent>(FLAGS_drive_event_topic);
208 node_->CreateReader<SystemStatus>(
209 FLAGS_system_status_topic,
210 [
this](
const std::shared_ptr<SystemStatus> &system_status) {
211 this->ResetComponentStatusTimer();
213 WLock wlock(status_mutex_);
215 const bool is_realtime_msg =
217 ? system_status->is_realtime_in_simulation()
219 system_status->header().timestamp_sec() <
220 FLAGS_system_status_lifetime_seconds;
222 if (is_realtime_msg) {
223 for (
auto &iter : *status_.mutable_modules()) {
224 auto *status = FindOrNull(system_status->hmi_modules(), iter.first);
226 status !=
nullptr && status->status() == ComponentStatus::OK;
230 for (
auto &iter : *status_.mutable_monitored_components()) {
231 auto *status = FindOrNull(system_status->components(), iter.first);
232 if (status !=
nullptr) {
233 iter.second = status->summary();
235 iter.second.set_status(ComponentStatus::UNKNOWN);
236 iter.second.set_message(
"Status not reported by Monitor.");
241 for (
auto &iter : *status_.mutable_other_components()) {
243 FindOrNull(system_status->other_components(), iter.first);
244 if (status !=
nullptr) {
245 iter.second.CopyFrom(*status);
247 iter.second.set_status(ComponentStatus::UNKNOWN);
248 iter.second.set_message(
"Status not reported by Monitor.");
253 const size_t new_fingerprint =
255 if (last_status_fingerprint_ != new_fingerprint) {
256 status_changed_ =
true;
257 last_status_fingerprint_ = new_fingerprint;
261 localization_reader_ =
262 node_->CreateReader<LocalizationEstimate>(FLAGS_localization_topic);
264 chassis_reader_ = node_->CreateReader<Chassis>(
265 FLAGS_chassis_topic, [
this](
const std::shared_ptr<Chassis> &chassis) {
267 FLAGS_system_status_lifetime_seconds) {
268 if (chassis->signal().high_beam()) {
270 const bool ret = Trigger(HMIAction::NONE);
271 AERROR_IF(!ret) <<
"Failed to execute high_beam action.";
278 AERROR <<
"HMIAction " << HMIAction_Name(action) <<
" was triggered!";
280 case HMIAction::NONE:
282 case HMIAction::SETUP_MODE:
285 case HMIAction::ENTER_AUTO_MODE:
286 return ChangeDrivingMode(Chassis::COMPLETE_AUTO_DRIVE);
287 case HMIAction::DISENGAGE:
288 return ChangeDrivingMode(Chassis::COMPLETE_MANUAL);
289 case HMIAction::RESET_MODE:
292 case HMIAction::LOAD_SCENARIOS:
295 case HMIAction::LOAD_DYNAMIC_MODELS:
298 case HMIAction::LOAD_RECORDS:
301 case HMIAction::STOP_RECORD:
305 AERROR <<
"HMIAction not implemented, yet!";
311bool HMIWorker::Trigger(
const HMIAction action,
const std::string &value) {
312 AINFO <<
"HMIAction " << HMIAction_Name(action) <<
"(" << value
313 <<
") was triggered!";
315 case HMIAction::CHANGE_MODE:
318 case HMIAction::CHANGE_MAP:
321 case HMIAction::CHANGE_VEHICLE:
322 ChangeVehicle(value);
324 case HMIAction::START_MODULE:
327 case HMIAction::STOP_MODULE:
330 case HMIAction::CHANGE_SCENARIO_SET:
331 ChangeScenarioSet(value);
333 case HMIAction::DELETE_SCENARIO_SET:
334 DeleteScenarioSet(value);
337 case HMIAction::CHANGE_SCENARIO:
338 ChangeScenario(value);
340 case HMIAction::CHANGE_DYNAMIC_MODEL:
341 ChangeDynamicModel(value);
343 case HMIAction::DELETE_DYNAMIC_MODEL:
344 DeleteDynamicModel(value);
346 case HMIAction::DELETE_RECORD:
349 case HMIAction::CHANGE_RECORD:
353 AERROR <<
"HMIAction not implemented, yet!";
359void HMIWorker::SubmitAudioEvent(
const uint64_t event_time_ms,
360 const int obstacle_id,
const int audio_type,
361 const int moving_result,
362 const int audio_direction,
363 const bool is_siren_on) {
364 std::shared_ptr<AudioEvent> audio_event = std::make_shared<AudioEvent>();
365 apollo::common::util::FillHeader(
"HMI", audio_event.get());
369 audio_event->mutable_header()->set_timestamp_sec(
370 static_cast<double>(event_time_ms) / 1000.0);
371 audio_event->set_id(obstacle_id);
372 audio_event->set_audio_type(
374 audio_event->set_moving_result(
376 audio_event->set_audio_direction(
378 audio_event->set_siren_is_on(is_siren_on);
381 localization_reader_->Observe();
382 if (localization_reader_->Empty()) {
383 AERROR <<
"Failed to get localization associated with the audio event: "
384 << audio_event->DebugString() <<
"\n Localization reader is empty!";
388 const std::shared_ptr<LocalizationEstimate> localization =
389 localization_reader_->GetLatestObserved();
390 audio_event->mutable_pose()->CopyFrom(localization->pose());
391 AINFO <<
"AudioEvent: " << audio_event->DebugString();
393 audio_event_writer_->Write(audio_event);
396void HMIWorker::SubmitDriveEvent(
const uint64_t event_time_ms,
397 const std::string &event_msg,
398 const std::vector<std::string> &event_types,
399 const bool is_reportable) {
400 std::shared_ptr<DriveEvent> drive_event = std::make_shared<DriveEvent>();
401 apollo::common::util::FillHeader(
"HMI", drive_event.get());
405 drive_event->mutable_header()->set_timestamp_sec(
406 static_cast<double>(event_time_ms) / 1000.0);
407 drive_event->set_event(event_msg);
408 drive_event->set_is_reportable(is_reportable);
409 for (
const auto &type_name : event_types) {
411 if (DriveEvent::Type_Parse(type_name, &type)) {
412 drive_event->add_type(type);
414 AERROR <<
"Failed to parse drive event type:" << type_name;
417 drive_event_writer_->Write(drive_event);
420void HMIWorker::SensorCalibrationPreprocess(
const std::string &task_type) {
421 std::string start_command = absl::StrCat(
422 "nohup bash /apollo/modules/tools/sensor_calibration/extract_data.sh -t ",
424 System(start_command);
427void HMIWorker::VehicleCalibrationPreprocess() {
428 std::string start_command = absl::StrCat(
429 "nohup bash /apollo/modules/tools/vehicle_calibration/preprocess.sh "
431 status_.current_vehicle(),
"\" --record_num=", record_count_,
" &");
432 System(start_command);
437 const std::string mode_name = Chassis::DrivingMode_Name(mode);
438 if (mode != Chassis::COMPLETE_MANUAL) {
439 if (!ChangeDrivingMode(Chassis::COMPLETE_MANUAL)) {
440 AERROR <<
"Failed to reset to MANUAL before changing to " << mode_name;
445 auto command = std::make_shared<ActionCommand>();
448 case Chassis::COMPLETE_MANUAL:
449 command->set_command(
452 case Chassis::COMPLETE_AUTO_DRIVE:
453 command->set_command(
457 AFATAL <<
"Change driving mode to " << mode_name <<
" not implemented!";
461 static constexpr int kMaxTries = 3;
462 static constexpr auto kTryInterval = std::chrono::milliseconds(500);
463 for (
int i = 0; i < kMaxTries; ++i) {
465 common::util::FillHeader(
"HMI", command.get());
466 action_command_client_->SendRequest(command);
468 std::this_thread::sleep_for(kTryInterval);
470 chassis_reader_->Observe();
471 if (chassis_reader_->Empty()) {
472 AERROR <<
"No Chassis message received!";
473 }
else if (chassis_reader_->GetLatestObserved()->driving_mode() == mode) {
477 AERROR <<
"Failed to change driving mode to " << mode_name;
481bool HMIWorker::ChangeMap(
const std::string &map_name,
482 const bool restart_dynamic_model) {
483 if (status_.current_map() == map_name && restart_dynamic_model ==
false) {
486 const std::string *map_dir = FindOrNull(config_.maps(), map_name);
487 if (map_dir ==
nullptr) {
488 AERROR <<
"Unknown map " << map_name;
492 if (map_name != status_.current_map()) {
495 WLock wlock(status_mutex_);
496 status_.set_current_map(map_name);
497 status_changed_ =
true;
499 SetGlobalFlag(
"map_dir", *map_dir, &FLAGS_map_dir);
507 if (restart_dynamic_model) {
508 callback_api_(
"RestartDynamicModel", {});
510 StopModuleByCommand(FLAGS_sim_obstacle_stop_command);
512 WLock wlock(status_mutex_);
513 status_.set_current_scenario_id(
"");
514 status_changed_ =
true;
520void HMIWorker::UpdateModeModulesAndMonitoredComponents() {
521 status_.clear_modules();
522 for (
const auto &iter : current_mode_.
modules()) {
523 status_.mutable_modules()->insert({iter.first,
false});
527 status_.clear_monitored_components();
528 for (
const auto &iter : current_mode_.monitored_components()) {
529 status_.mutable_monitored_components()->insert({iter.first, {}});
533void HMIWorker::ChangeVehicle(
const std::string &vehicle_name) {
534 const std::string *vehicle_dir = FindOrNull(config_.vehicles(), vehicle_name);
535 if (vehicle_dir ==
nullptr) {
536 AERROR <<
"Unknown vehicle " << vehicle_name;
539 std::string current_mode;
543 WLock wlock(status_mutex_);
544 current_mode = status_.current_mode();
545 if (status_.current_vehicle() == vehicle_name) {
551 const std::string vehicle_type_file_path = *vehicle_dir +
"/vehicle_type";
552 std::string vehicle_type_str;
553 cyber::common::GetContent(vehicle_type_file_path, &vehicle_type_str);
554 int vehicle_type = std::stoi(vehicle_type_str);
555 status_.set_current_vehicle_type(vehicle_type);
556 }
catch (
const std::exception &e) {
557 AWARN <<
"get vehicle type config failed: " << e.what();
558 status_.clear_current_vehicle_type();
560 status_.set_current_vehicle(vehicle_name);
561 status_changed_ =
true;
565 HMIMode vehicle_defined_mode;
566 const std::string mode_config_path = config_.modes().at(current_mode);
567 if (LoadVehicleDefinedMode(mode_config_path,
568 *vehicle_dir, &vehicle_defined_mode)) {
569 MergeToCurrentMode(&vehicle_defined_mode);
573 current_mode_ = util::HMIUtil::LoadMode(mode_config_path);
576 WLock wlock(status_mutex_);
577 UpdateModeModulesAndMonitoredComponents();
579 ACHECK(VehicleManager::Instance()->UseVehicle(*vehicle_dir));
581 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
582 if (monitors !=
nullptr) {
583 for (
const auto &monitor : *monitors) {
584 if (monitor.second->IsEnabled()) {
585 monitor.second->Restart();
591void HMIWorker::MergeToCurrentMode(HMIMode *mode) {
592 current_mode_.clear_modules();
593 current_mode_.clear_cyber_modules();
594 current_mode_.clear_monitored_components();
595 current_mode_.mutable_modules()->swap(*(mode->mutable_modules()));
596 current_mode_.mutable_monitored_components()->swap(
597 *(mode->mutable_monitored_components()));
600void HMIWorker::ChangeMode(
const std::string &mode_name) {
601 if (!ContainsKey(config_.modes(), mode_name)) {
602 AERROR <<
"Cannot change to unknown mode " << mode_name;
607 RLock rlock(status_mutex_);
609 if (status_.current_mode() == mode_name) {
616 WLock wlock(status_mutex_);
617 status_.set_current_mode(mode_name);
618 current_mode_ = util::HMIUtil::LoadMode(config_.modes().at(mode_name));
620 HMIMode vehicle_defined_mode;
621 const std::string *vehicle_dir =
622 FindOrNull(config_.vehicles(), status_.current_vehicle());
623 if (vehicle_dir !=
nullptr &&
624 LoadVehicleDefinedMode(config_.modes().at(mode_name), *vehicle_dir,
625 &vehicle_defined_mode)) {
626 MergeToCurrentMode(&vehicle_defined_mode);
628 UpdateModeModulesAndMonitoredComponents();
630 status_.clear_other_components();
631 for (
const auto &iter : current_mode_.other_components()) {
632 status_.mutable_other_components()->insert({iter.first, {}});
634 status_changed_ =
true;
637 FuelMonitorManager::Instance()->SetCurrentMode(mode_name);
638 KVDB::Put(FLAGS_current_mode_db_key, mode_name);
642 WLock wlock(status_mutex_);
643 status_.set_current_scenario_id(
"");
644 status_changed_ =
true;
646 StopModuleByCommand(FLAGS_sim_obstacle_stop_command);
649void HMIWorker::StartModule(
const std::string &module)
const {
650 const Module *module_conf = FindOrNull(current_mode_.modules(), module);
651 if (module_conf !=
nullptr) {
652 System(module_conf->start_command());
654 AERROR <<
"Cannot find module " <<
module;
657 if (module ==
"Recorder") {
658 auto *monitors = FuelMonitorManager::Instance()->GetCurrentMonitors();
659 if (monitors !=
nullptr) {
660 auto iter = monitors->find(FLAGS_data_collection_monitor_name);
661 if (iter != monitors->end()) {
662 auto *data_collection_monitor = iter->second.get();
663 if (data_collection_monitor->IsEnabled() && record_count_ == 0) {
664 data_collection_monitor->Restart();
672void HMIWorker::StopModule(
const std::string &module)
const {
673 const Module *module_conf = FindOrNull(current_mode_.modules(), module);
674 if (module_conf !=
nullptr) {
675 System(module_conf->stop_command());
677 AERROR <<
"Cannot find module " <<
module;
681HMIStatus HMIWorker::GetStatus()
const {
682 RLock rlock(status_mutex_);
686void HMIWorker::SetupMode()
const {
687 for (
const auto &iter : current_mode_.
modules()) {
688 System(iter.second.start_command());
692void HMIWorker::ResetMode()
const {
693 for (
const auto &iter : current_mode_.
modules()) {
694 System(iter.second.stop_command());
699void HMIWorker::StatusUpdateThreadLoop() {
700 constexpr int kLoopIntervalMs = 200;
702 std::this_thread::sleep_for(std::chrono::milliseconds(kLoopIntervalMs));
703 UpdateComponentStatus();
704 bool status_changed =
false;
706 WLock wlock(status_mutex_);
707 status_changed = status_changed_;
708 status_changed_ =
false;
711 if (!status_changed) {
712 static double next_update_time = 0;
714 if (now < next_update_time) {
717 next_update_time = now + FLAGS_status_publish_interval;
721 HMIStatus status = GetStatus();
722 for (
const auto handler : status_update_handlers_) {
723 handler(status_changed, &status);
728void HMIWorker::ResetComponentStatusTimer() {
730 last_status_fingerprint_ = 0;
733void HMIWorker::UpdateComponentStatus() {
734 constexpr double kSecondsTillTimeout(2.5);
736 if (now - last_status_received_s_.load() > kSecondsTillTimeout) {
737 if (!monitor_timed_out_) {
738 WLock wlock(status_mutex_);
740 const uint64_t now_ms =
static_cast<uint64_t
>(now * 2e3);
741 static constexpr bool kIsReportable =
true;
742 SubmitDriveEvent(now_ms,
"Monitor timed out", {
"PROBLEM"}, kIsReportable);
743 AWARN <<
"System fault. Auto disengage.";
744 Trigger(HMIAction::DISENGAGE);
746 for (
auto &monitored_component :
747 *status_.mutable_monitored_components()) {
748 monitored_component.second.set_status(ComponentStatus::UNKNOWN);
749 monitored_component.second.set_message(
750 "Status not reported by Monitor.");
752 status_changed_ =
true;
754 monitor_timed_out_ =
true;
756 monitor_timed_out_ =
false;
760void HMIWorker::ChangeScenarioSet(
const std::string &scenario_set_id) {
762 RLock rlock(status_mutex_);
763 auto &scenario_set = status_.scenario_set();
764 if ((!scenario_set_id.empty()) &&
765 (scenario_set.find(scenario_set_id) == scenario_set.end())) {
766 AERROR <<
"Cannot change to unknown scenario set!";
769 if (status_.current_scenario_set_id() == scenario_set_id) {
775 WLock wlock(status_mutex_);
776 status_.set_current_scenario_set_id(scenario_set_id);
777 status_changed_ =
true;
782void HMIWorker::GetScenarioResourcePath(std::string *scenario_resource_path) {
783 CHECK_NOTNULL(scenario_resource_path);
784 const std::string home = cyber::common::GetEnv(
"HOME");
785 *scenario_resource_path = home + FLAGS_resource_scenario_path;
788void HMIWorker::GetScenarioSetPath(
const std::string &scenario_set_id,
789 std::string *scenario_set_path) {
790 CHECK_NOTNULL(scenario_set_path);
791 GetScenarioResourcePath(scenario_set_path);
792 *scenario_set_path = *scenario_set_path + scenario_set_id;
796bool HMIWorker::StopModuleByCommand(
const std::string &stop_command)
const {
797 int ret = std::system(stop_command.data());
798 if (ret < 0 || !WIFEXITED(ret)) {
800 AERROR <<
"Failed to stop sim obstacle";
806bool HMIWorker::ResetSimObstacle(
const std::string &scenario_id) {
807 bool startObstacle =
true;
808 std::string cur_scenario_id;
809 if (scenario_id.empty()) {
810 startObstacle =
false;
811 cur_scenario_id = status_.current_scenario_id();
813 cur_scenario_id = scenario_id;
816 std::string absolute_path = FLAGS_sim_obstacle_path;
819 const std::string command =
"which sim_obstacle";
820 std::string result = GetCommandRes(command);
822 absolute_path = result;
823 }
else if (!cyber::common::PathExists(absolute_path)) {
824 AWARN <<
"Not found sim obstacle";
825 startObstacle =
false;
827 AINFO <<
"sim_obstacle binary path : " << absolute_path;
829 StopModuleByCommand(FLAGS_sim_obstacle_stop_command);
830 std::string scenario_set_id;
832 RLock rlock(status_mutex_);
833 scenario_set_id = status_.current_scenario_set_id();
835 std::string scenario_set_path;
836 GetScenarioSetPath(scenario_set_id, &scenario_set_path);
837 const std::string scenario_path =
838 scenario_set_path +
"/scenarios/" + cur_scenario_id +
".json";
839 AINFO <<
"scenario path : " << scenario_path;
840 if (!cyber::common::PathExists(scenario_path)) {
841 AERROR <<
"Failed to find scenario!";
844 std::string map_name =
"";
847 bool need_to_change_map =
true;
849 RLock rlock(status_mutex_);
850 auto &scenario_set = status_.scenario_set();
851 if (scenario_set.find(scenario_set_id) == scenario_set.end()) {
852 AERROR <<
"Failed to find scenario set!";
855 for (
auto &scenario : scenario_set.at(scenario_set_id).scenarios()) {
856 if (scenario.scenario_id() == cur_scenario_id) {
857 map_name = scenario.map_name();
858 x = scenario.start_point().x();
859 y = scenario.start_point().y();
863 if (map_name.empty()) {
864 AERROR <<
"Failed to find scenario and get map dir!";
867 need_to_change_map = (status_.current_map() != map_name);
870 std::vector<std::string> modules_open;
871 auto modulesMap = status_.modules();
872 for (
auto it = modulesMap.begin(); it != modulesMap.end(); ++it) {
873 if (it->second ==
true) {
874 modules_open.push_back(it->first);
877 if (need_to_change_map) {
878 if (!ChangeMap(map_name,
false)) {
879 AERROR <<
"Failed to change map!";
882 callback_api_(
"MapServiceReloadMap", {});
893 callback_api_(
"SimControlRestart", info);
896 const std::string start_command =
"nohup " + absolute_path +
" " +
897 scenario_path + FLAGS_gflag_command_arg +
899 AINFO <<
"start sim_obstacle command : " << start_command;
900 int ret = std::system(start_command.data());
902 AERROR <<
"Failed to start sim obstacle";
910std::string HMIWorker::GetCommandRes(
const std::string &cmd) {
911 if (cmd.size() > 128) {
912 AERROR <<
"command size exceeds 128";
915 const char *cmdPtr = cmd.c_str();
917 std::string result =
"";
919 FILE *pipe = popen(cmdPtr,
"r");
920 while (fgets(buffer,
sizeof(buffer), pipe) !=
nullptr) {
923 if (result.back() ==
'\n') {
930void HMIWorker::ChangeScenario(
const std::string &scenario_id) {
932 RLock rlock(status_mutex_);
934 if (status_.current_scenario_id() == scenario_id) {
937 if (scenario_id.empty()) {
941 StopModuleByCommand(FLAGS_sim_obstacle_stop_command);
943 auto scenario_set = status_.mutable_scenario_set();
944 auto &scenario_set_id = status_.current_scenario_set_id();
945 if (scenario_set->find(scenario_set_id) == scenario_set->end()) {
946 AERROR <<
"Current scenario set is invalid!";
949 bool find_res =
false;
950 for (
auto &scenario : (*scenario_set)[scenario_set_id].scenarios()) {
951 if (scenario.scenario_id() == scenario_id) {
957 AERROR <<
"Cannot change to unknown scenario!";
966 if (!ResetSimObstacle(scenario_id)) {
967 AERROR <<
"Cannot start sim obstacle by new scenario!";
972 WLock wlock(status_mutex_);
973 status_.set_current_scenario_id(scenario_id);
974 status_changed_ =
true;
979void HMIWorker::ChangeDynamicModel(
const std::string &dynamic_model_name) {
988 if (dynamic_model_name.empty()) {
989 AERROR <<
"Failed to change empty dynamic model!";
993 param_json[
"dynamic_model_name"] = dynamic_model_name;
994 Json callback_res = callback_api_(
"ChangeDynamicModel", param_json);
995 if (!callback_res.contains(
"result") || !callback_res[
"result"]) {
999 AERROR <<
"Failed to change dynamic model! Please check if the param is "
1003 std::string current_dynamic_model_name = dynamic_model_name;
1005 WLock wlock(status_mutex_);
1006 status_.set_current_dynamic_model(dynamic_model_name);
1007 status_changed_ =
true;
1013bool HMIWorker::UpdateScenarioSetToStatus(
1014 const std::string &scenario_set_id,
const std::string &scenario_set_name) {
1016 if (!UpdateScenarioSet(scenario_set_id, scenario_set_name,
1017 &new_scenario_set)) {
1018 AERROR <<
"Failed to update scenario_set!";
1022 WLock wlock(status_mutex_);
1023 auto scenario_set = status_.mutable_scenario_set();
1024 scenario_set->erase(scenario_set_id);
1025 (*scenario_set)[scenario_set_id] = new_scenario_set;
1026 status_changed_ =
true;
1031bool HMIWorker::UpdateDynamicModelToStatus(
1032 const std::string &dynamic_model_name) {
1033 Json param_json({});
1034 param_json[
"dynamic_model_name"] = dynamic_model_name;
1035 Json callback_res = callback_api_(
"AddDynamicModel", param_json);
1036 if (!callback_res.contains(
"result") || !callback_res[
"result"]) {
1037 AERROR <<
"Failed to add dynamic model to local dynamic model list for "
1042 WLock wlock(status_mutex_);
1043 for (
const auto &iter : status_.dynamic_models()) {
1044 if (iter == dynamic_model_name) {
1045 AERROR <<
"Do not need to add new dynamic model for is duplicate!";
1049 status_.add_dynamic_models(dynamic_model_name);
1050 status_changed_ =
true;
1055bool HMIWorker::UpdateScenarioSet(
const std::string &scenario_set_id,
1056 const std::string &scenario_set_name,
1058 std::string scenario_set_directory_path;
1059 GetScenarioSetPath(scenario_set_id, &scenario_set_directory_path);
1060 scenario_set_directory_path = scenario_set_directory_path +
"/scenarios/";
1061 new_scenario_set->set_scenario_set_name(scenario_set_name);
1062 if (!cyber::common::PathExists(scenario_set_directory_path)) {
1063 AERROR <<
"Scenario set has no scenarios!";
1066 DIR *directory = opendir(scenario_set_directory_path.c_str());
1067 if (directory ==
nullptr) {
1068 AERROR <<
"Cannot open directory " << scenario_set_directory_path;
1072 struct dirent *file;
1073 while ((file = readdir(directory)) !=
nullptr) {
1075 if (!strcmp(file->d_name,
".") || !strcmp(file->d_name,
"..")) {
1078 const std::string file_name = file->d_name;
1079 if (!absl::EndsWith(file_name,
".json")) {
1082 const int index = file_name.rfind(
".json");
1087 const std::string scenario_id = file_name.substr(0, index);
1088 const std::string file_path = scenario_set_directory_path + file_name;
1090 if (!cyber::common::GetProtoFromJsonFile(file_path, &new_sim_ticket)) {
1091 AERROR <<
"Cannot parse this scenario:" << file_path;
1094 if (!new_sim_ticket.has_scenario()) {
1095 AERROR <<
"Cannot get scenario.";
1098 if (!new_sim_ticket.description_en_tokens_size()) {
1099 AERROR <<
"Cannot get scenario name.";
1102 if (!new_sim_ticket.
scenario().has_map_dir()) {
1103 AERROR <<
"Cannot get scenario map dir.";
1106 if (!new_sim_ticket.
scenario().has_start()) {
1107 AERROR <<
"Cannot get scenario start_point.";
1110 auto &scenario_start_point = new_sim_ticket.
scenario().start();
1111 if (!scenario_start_point.has_x() || !scenario_start_point.has_y()) {
1112 AERROR <<
"Scenario start_point is invalid!";
1116 for (
int i = 1; i < new_sim_ticket.description_en_tokens_size(); i++) {
1120 ScenarioInfo *scenario_info = new_scenario_set->add_scenarios();
1121 scenario_info->set_scenario_id(scenario_id);
1122 scenario_info->set_scenario_name(scenario_name);
1125 const std::string map_dir = new_sim_ticket.
scenario().map_dir();
1126 size_t idx = map_dir.find_last_of(
'/');
1127 if (idx == map_dir.npos) {
1128 AERROR <<
"Cannot get scenario map name.";
1131 const std::string map_name = map_dir.substr(idx + 1);
1132 if (map_name.empty()) {
1133 AERROR <<
"Cannot get scenario map name.";
1138 scenario_info->set_map_name(util::HMIUtil::TitleCase(map_name));
1139 auto start_point = scenario_info->mutable_start_point();
1140 start_point->set_x(scenario_start_point.x());
1141 start_point->set_y(scenario_start_point.y());
1143 closedir(directory);
1147bool HMIWorker::LoadScenarios() {
1148 std::string directory_path;
1149 GetScenarioResourcePath(&directory_path);
1150 if (!cyber::common::PathExists(directory_path)) {
1151 AERROR <<
"Failed to find scenario_set!";
1154 DIR *directory = opendir(directory_path.c_str());
1155 if (directory ==
nullptr) {
1156 AERROR <<
"Cannot open directory " << directory_path;
1159 struct dirent *file;
1160 std::map<std::string, ScenarioSet> scenario_sets;
1161 while ((file = readdir(directory)) !=
nullptr) {
1163 if (!strcmp(file->d_name,
".") || !strcmp(file->d_name,
"..")) {
1166 if (file->d_type != DT_DIR) {
1169 const std::string scenario_set_id = file->d_name;
1170 const std::string scenario_set_json_path =
1171 directory_path + scenario_set_id +
"/scenario_set.json";
1173 UserAdsGroup user_ads_group_info;
1174 if (!cyber::common::GetProtoFromJsonFile(scenario_set_json_path,
1175 &user_ads_group_info)) {
1176 AERROR <<
"Unable to parse UserAdsGroup from file "
1177 << scenario_set_json_path;
1180 if (!user_ads_group_info.has_name()) {
1181 AERROR <<
"Failed to get ads group name!";
1184 const std::string scenario_set_name = user_ads_group_info.name();
1185 ScenarioSet new_scenario_set;
1186 if (!UpdateScenarioSet(scenario_set_id, scenario_set_name,
1187 &new_scenario_set)) {
1188 AERROR <<
"Failed to update scenario_set!";
1191 scenario_sets[scenario_set_id] = new_scenario_set;
1193 closedir(directory);
1195 WLock wlock(status_mutex_);
1196 auto scenario_set = status_.mutable_scenario_set();
1198 scenario_set->clear();
1199 for (
auto iter = scenario_sets.begin(); iter != scenario_sets.end();
1201 (*scenario_set)[iter->first] = iter->second;
1203 status_changed_ =
true;
1208bool HMIWorker::LoadDynamicModels() {
1209 Json load_res = callback_api_(
"LoadDynamicModels", {});
1210 if (!load_res.contains(
"result") || !load_res[
"result"]) {
1215 WLock wlock(status_mutex_);
1216 auto dynamic_models = status_.mutable_dynamic_models();
1218 for (
auto iter = dynamic_models->begin(); iter != dynamic_models->end();) {
1219 iter = dynamic_models->erase(iter);
1221 for (
const auto &dynamic_model : load_res[
"loaded_dynamic_models"]) {
1222 status_.add_dynamic_models(dynamic_model);
1224 status_changed_ =
true;
1226 return load_res[
"result"];
1229void HMIWorker::DeleteScenarioSet(
const std::string &scenario_set_id) {
1230 if (scenario_set_id.empty()) {
1233 std::string directory_path;
1234 GetScenarioResourcePath(&directory_path);
1235 directory_path = directory_path + scenario_set_id;
1236 if (!cyber::common::PathExists(directory_path)) {
1237 AERROR <<
"Failed to find scenario_set!";
1240 std::string command =
"rm -fr " + directory_path;
1243 if (std::system(command.data()) != 0) {
1244 AERROR <<
"Failed to delete scenario set directory for: "
1245 << std::strerror(errno);
1250 RLock rlock(status_mutex_);
1251 auto &scenario_set = status_.scenario_set();
1252 if (scenario_set.find(scenario_set_id) == scenario_set.end()) {
1253 AERROR <<
"Cannot find unknown scenario set!";
1257 if (scenario_set_id == status_.current_scenario_set_id()) {
1258 AERROR <<
"Cannotdelete current scenario set!";
1264 WLock wlock(status_mutex_);
1265 status_.mutable_scenario_set()->erase(scenario_set_id);
1266 status_changed_ =
true;
1271void HMIWorker::DeleteDynamicModel(
const std::string &dynamic_model_name) {
1272 if (dynamic_model_name.empty()) {
1273 AERROR <<
"Invalid param:empty dynamic model name!";
1277 RLock rlock(status_mutex_);
1279 if (dynamic_model_name == status_.current_dynamic_model()) {
1280 AERROR <<
"Cannot delete current dynamic model!";
1283 if (dynamic_model_name == FLAGS_sim_perfect_control) {
1284 AERROR <<
"Cannot delete default sim control:SimPerfectControl!";
1288 Json param_json({});
1289 param_json[
"dynamic_model_name"] = dynamic_model_name;
1290 Json callback_res = callback_api_(
"DeleteDynamicModel", param_json);
1291 if (!callback_res.contains(
"result") || !callback_res[
"result"]) {
1294 AERROR <<
"Failed to delete dynamic model!";
1298 WLock wlock(status_mutex_);
1299 auto iter = status_.dynamic_models().begin();
1300 while (iter != status_.dynamic_models().end()) {
1301 if (*iter == dynamic_model_name) {
1306 if (iter != status_.dynamic_models().end()) {
1307 status_.mutable_dynamic_models()->erase(iter);
1308 status_changed_ =
true;
1310 AWARN <<
"Can not find dynamic model to delete!";
1316void HMIWorker::GetRecordPath(std::string *record_path) {
1317 CHECK_NOTNULL(record_path);
1318 const std::string home = cyber::common::GetEnv(
"HOME");
1319 *record_path = home + FLAGS_resource_record_path;
1322bool HMIWorker::RePlayRecord(
const std::string &record_id) {
1323 std::string record_path;
1324 GetRecordPath(&record_path);
1325 record_path = record_path + record_id +
".record";
1327 if (!cyber::common::PathExists(record_path)) {
1328 AERROR <<
"Failed to find record!";
1332 const std::string play_command =
1333 absl::StrCat(
"nohup cyber_recorder play -l -f ", record_path,
" &");
1334 int ret = std::system(play_command.data());
1336 AERROR <<
"Failed to start cyber play command";
1341void HMIWorker::StopRecordPlay() {
1342 WLock wlock(status_mutex_);
1343 { status_.set_current_record_id(
""); }
1344 if (!StopModuleByCommand(FLAGS_cyber_recorder_stop_command)) {
1345 AERROR <<
"stop record failed";
1347 status_changed_ =
true;
1349void HMIWorker::ChangeRecord(
const std::string &record_id) {
1352 RLock rlock(status_mutex_);
1353 auto status_records = status_.mutable_records();
1354 if (status_records->find(record_id) == status_records->end()) {
1355 AERROR <<
"Cannot change to unknown record!";
1358 if (!RePlayRecord(record_id)) {
1362 WLock wlock(status_mutex_);
1363 status_.set_current_record_id(record_id);
1364 status_changed_ =
true;
1367bool HMIWorker::LoadRecords() {
1368 std::string directory_path;
1369 GetRecordPath(&directory_path);
1370 if (!cyber::common::PathExists(directory_path)) {
1371 AERROR <<
"Failed to find records!";
1374 DIR *directory = opendir(directory_path.c_str());
1375 if (directory ==
nullptr) {
1376 AERROR <<
"Cannot open record directory" << directory_path;
1379 struct dirent *file;
1380 std::map<std::string, LoadRecordInfo> new_records;
1381 while ((file = readdir(directory)) !=
nullptr) {
1382 if (!strcmp(file->d_name,
".") || !strcmp(file->d_name,
"..")) {
1385 if (file->d_type == DT_DIR) {
1388 const std::string record_id = file->d_name;
1389 const int index = record_id.rfind(
".record");
1391 size_t record_suffix_length = 7;
1392 if (record_id.length() - index != record_suffix_length) {
1395 if (index != -1 && record_id[0] !=
'.') {
1396 const std::string local_record_resource = record_id.substr(0, index);
1398 new_records[local_record_resource] = {};
1399 new_records[local_record_resource].set_download_status(1);
1402 closedir(directory);
1404 WLock wlock(status_mutex_);
1405 auto status_records = status_.mutable_records();
1406 status_records->clear();
1407 for (
auto iter = new_records.begin(); iter != new_records.end(); iter++) {
1408 (*status_records)[iter->first] = iter->second;
1410 status_changed_ =
true;
1415void HMIWorker::DeleteRecord(
const std::string &record_id) {
1417 if (record_id.empty()) {
1420 std::string record_path;
1421 GetRecordPath(&record_path);
1422 record_path = record_path + record_id +
".record";
1423 if (!cyber::common::PathExists(record_path)) {
1428 RLock rlock(status_mutex_);
1429 auto &status_records = status_.records();
1430 if (status_records.find(record_id) == status_records.end()) {
1433 if (record_id == status_.current_record_id()) {
1438 WLock wlock(status_mutex_);
1439 status_.mutable_records()->erase(record_id);
1440 status_changed_ =
true;
1444 std::string command =
"rm -rf " + record_path;
1445 if (std::system(command.data()) != 0) {
1446 AERROR <<
"Failed to delete record for: " << std::strerror(errno);
1451bool HMIWorker::ReloadVehicles() {
1452 AINFO <<
"load config";
1453 HMIConfig config = util::HMIUtil::LoadConfig(FLAGS_dv_hmi_modes_config_path);
1455 AINFO <<
"serialize new config";
1456 config.SerializeToString(&msg);
1458 WLock wlock(status_mutex_);
1459 AINFO <<
"parse new config";
1460 config_.ParseFromString(msg);
1461 AINFO <<
"init status";
1464 AINFO <<
"clear vehicles";
1465 status_.clear_vehicles();
1468 AINFO <<
"reload vehicles";
1469 for (
const auto &vehicle : config_.vehicles()) {
1470 status_.add_vehicles(vehicle.first);
1472 status_changed_ =
true;
1476void HMIWorker::UpdateCameraSensorChannelToStatus(
1477 const std::string &channel_name) {
1479 WLock wlock(status_mutex_);
1480 if (status_.current_camera_sensor_channel() == channel_name) {
1481 AINFO <<
"Input channel name is current camera sensor channel";
1484 status_.set_current_camera_sensor_channel(channel_name);
1485 status_changed_ =
true;
1489void HMIWorker::UpdatePointCloudChannelToStatus(
1490 const std::string &channel_name) {
1492 WLock wlock(status_mutex_);
1493 if (status_.current_point_cloud_channel() == channel_name) {
1494 AINFO <<
"Input channel name is current camera sensor channel";
1497 status_.set_current_point_cloud_channel(channel_name);
1498 status_changed_ =
true;
Lightweight key-value database to store system-wide parameters.
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
Node is the fundamental building block of Cyber RT.
std::function< nlohmann::json(const std::string &function_name, const nlohmann::json ¶m_json)> DvCallback
Some string util functions.
size_t MessageFingerprint(const google::protobuf::Message &message)
bool LoadConfig(const std::string &relative_path, T *config)
boost::shared_lock< boost::shared_mutex > RLock
boost::unique_lock< boost::shared_mutex > WLock
repeated string description_en_tokens
optional apollo::simulation::Scenario scenario