목차
위치 모니터링
코드
class LocalizationMonitor : public RecurrentRunner {
public:
LocalizationMonitor();
void RunOnce(const double current_time) override;
};
void LocalizationMonitor::RunOnce(const double current_time) {
auto manager = MonitorManager::Instance();
auto* component = apollo::common::util::FindOrNull(
*manager->GetStatus()->mutable_components(),
FLAGS_localization_component_name);
if (component == nullptr) {
// localization is not monitored in current mode, skip.
return;
}
static auto reader =
manager->CreateReader<LocalizationStatus>(FLAGS_localization_msf_status);
reader->Observe();
const auto status = reader->GetLatestObserved();
ComponentStatus* component_status = component->mutable_other_status();
component_status->clear_status();
if (status == nullptr) {
SummaryMonitor::EscalateStatus(ComponentStatus::ERROR,
"No LocalizationStatus received",
component_status);
return;
}
// Translate LocalizationStatus to ComponentStatus. Note that ERROR and FATAL
// will trigger safety mode in current settings.
switch (status->fusion_status()) {
case MeasureState::OK:
SummaryMonitor::EscalateStatus(ComponentStatus::OK, "", component_status);
break;
case MeasureState::WARNNING:
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("WARNNING: ", status->state_message()),
component_status);
break;
case MeasureState::ERROR:
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("ERROR: ", status->state_message()), component_status);
break;
case MeasureState::CRITICAL_ERROR:
SummaryMonitor::EscalateStatus(
ComponentStatus::ERROR,
absl::StrCat("CRITICAL_ERROR: ", status->state_message()),
component_status);
break;
case MeasureState::FATAL_ERROR:
SummaryMonitor::EscalateStatus(
ComponentStatus::FATAL,
absl::StrCat("FATAL_ERROR: ", status->state_message()),
component_status);
break;
default:
AFATAL << "Unknown fusion_status: " << status->fusion_status();
break;
}
}
분석하다
- 포지셔닝 모듈이 모니터링되는 모듈에 속하는지 확인
- localization_msf_status 구독, 읽을 수 없으면 ERROR 수준 오류 보고
- 주제의 상태 정보를 직접 판단하고 상태에 따라 해당 오류를 보고합니다.
주목
## MSF 현지화 상태 확인 LiDAR 현지화, GNSS 현지화 및 융합 현지화 상태를 확인하는 간단한 방법을 제공합니다. 현지화 상태에는 {NOT_VALID, NOT_STABLE, OK, VALID} 네 가지 상태가 있습니다. 단순히 `rostopic echo /apollo/localization/msf_status`를 사용하여 현지화 상태를 확인할 수 있습니다. fusion_status가 VALID 또는 OK이면 msf 지역화 출력이 신뢰할 수 있습니다.
위는 apollo MSF 포지셔닝 상태의 판단 논리이며 위의 결함은 모두 비즈니스 모듈의 포지셔닝 부분에서 설정 및 발행됩니다.
다음은 module/localization/rtk/rtk_localization.cc의 상태 감지 부분입니다.
void RTKLocalization::FillLocalizationStatusMsg(
const drivers::gnss::InsStat &status,
LocalizationStatus *localization_status) {
apollo::common::Header *header = localization_status->mutable_header();
double timestamp = apollo::cyber::Clock::NowInSeconds();
header->set_timestamp_sec(timestamp);
localization_status->set_measurement_time(status.header().timestamp_sec());
if (!status.has_pos_type()) {
localization_status->set_fusion_status(MeasureState::ERROR);
localization_status->set_state_message(
"Error: Current Localization Status Is Missing.");
return;
}
카메라 모니터링
코드
class CameraMonitor : public RecurrentRunner {
public:
CameraMonitor();
void RunOnce(const double current_time) override;
private:
static void UpdateStatus(ComponentStatus* status);
};
void CameraMonitor::RunOnce(const double current_time) {
auto* manager = MonitorManager::Instance();
auto* component = apollo::common::util::FindOrNull(
*manager->GetStatus()->mutable_components(), FLAGS_camera_component_name);
if (component == nullptr) {
// camera is not monitored in current mode, skip.
return;
}
auto* status = component->mutable_other_status();
UpdateStatus(status);
}
분석하다
카메라가 모니터링 구성으로 구성되었는지 여부를 판단하는 것 외에도 핵심 기능은 UpdateStatus에 있습니다.
void CameraMonitor::UpdateStatus(ComponentStatus* status) {
status->clear_status();
std::string frame_id = "";
for (const auto& topic : camera_topic_set) {
const auto& reader_message_pair = CreateReaderAndLatestsMessage(topic);
const auto& reader = reader_message_pair.first;
const auto& message = reader_message_pair.second;
if (reader != nullptr && message != nullptr) {
if (frame_id.empty()) {
const auto& header = message->header();
if (header.has_frame_id()) {
frame_id = header.frame_id();
}
} else {
SummaryMonitor::EscalateStatus(
ComponentStatus::ERROR,
absl::StrCat("Only one camera is permitted"), status);
}
}
}
if (frame_id.empty()) {
SummaryMonitor::EscalateStatus(
ComponentStatus::ERROR, absl::StrCat("No camera is detected"), status);
} else {
SummaryMonitor::EscalateStatus(
ComponentStatus::OK, absl::StrCat("Detected one camera: ", frame_id),
status);
}
}
static const auto camera_topic_set = std::set<std::string>{
FLAGS_image_long_topic, FLAGS_camera_image_long_topic,
FLAGS_camera_image_short_topic, FLAGS_camera_front_6mm_topic,
FLAGS_camera_front_6mm_2_topic, FLAGS_camera_front_12mm_topic,
// Add more cameras here if you want to monitor.
};
- 최신 뉴스를 얻다
- 메시지 헤더 가져오기, 프레임 ID 가져오기, 두 세트의 프레임 ID가 있는 경우 ERROR 보고
absl::StrCat("하나의 카메라만 허용됩니다."), status);
프레임 ID가 비어 있으면 ERROR를 보고합니다.
ComponentStatus::ERROR, absl::StrCat("감지된 카메라가 없습니다."), status);
기능 안전 모니터링
코드
// Check if we need to switch to safe mode, and then
// 1. Notify driver to take action.
// 2. Trigger Guardian if no proper action was taken.
class FunctionalSafetyMonitor : public RecurrentRunner {
public:
FunctionalSafetyMonitor();
void RunOnce(const double current_time);
private:
bool CheckSafety();
};
void FunctionalSafetyMonitor::RunOnce(const double current_time) {
auto* system_status = MonitorManager::Instance()->GetStatus();
// Everything looks good or has been handled properly.
if (CheckSafety()) {
system_status->clear_passenger_msg();
system_status->clear_safety_mode_trigger_time();
system_status->clear_require_emergency_stop();
return;
}
if (system_status->require_emergency_stop()) {
// EStop has already been triggered.
return;
}
// Newly entered safety mode.
system_status->set_passenger_msg("Error! Please disengage.");
if (!system_status->has_safety_mode_trigger_time()) {
system_status->set_safety_mode_trigger_time(current_time);
return;
}
// Trigger EStop if no action was taken in time.
if (system_status->safety_mode_trigger_time() +
FLAGS_safety_mode_seconds_before_estop <
current_time) {
system_status->set_require_emergency_stop(true);
}
}
분석하다
CheckSafety 기능 분석
bool FunctionalSafetyMonitor::CheckSafety() {
// We only check safety in self driving mode.
auto manager = MonitorManager::Instance();
if (!manager->IsInAutonomousMode()) {
return true;
}
// Check HMI modules status.
const auto& mode = manager->GetHMIMode();
const auto& hmi_modules = manager->GetStatus()->hmi_modules();
for (const auto& iter : mode.modules()) {
const std::string& module_name = iter.first;
const auto& module = iter.second;
if (module.required_for_safety() &&
!IsSafe(module_name, hmi_modules.at(module_name))) {
return false;
}
}
// Check monitored components status.
const auto& components = manager->GetStatus()->components();
for (const auto& iter : mode.monitored_components()) {
const std::string& component_name = iter.first;
const auto& component = iter.second;
if (component.required_for_safety() &&
!IsSafe(component_name, components.at(component_name).summary())) {
return false;
}
}
// Everything looks good.
return true;
}
- 자동 조종 모드인지 판단하고 그렇지 않으면 직접 뛰어 내립니다.
- 모니터링되는 모든 구성 요소의 상태가 ERROR 또는 FATAL인지 확인하십시오.
- 있으면 안전하지 않고 안전하지 않으면 안전합니다.
RunOnce 함수 분석
- 현재 보안 상태 확인
- 안전하다면 이전 상태 정보를 지우고 돌아갑니다.
- 안전하지 않은 경우 보안 조치가 호출되었는지 판단: Estop, Estop이 이미 작동 중인 경우 반환
- ESTOP이 동작하지 않는 것으로 판단되면 트리거가 ESTOP을 안전하게 처리할 수 있는 시간을 확인하고 타임아웃이 없으면 대기한다.
기록 기능 모니터링
녹음기 모니터는 녹음기 상태를 얻기 위해 주제 /apollo/data/recorder/status를 구독하여 apollo가 녹음 서비스를 모니터링하기 위한 것입니다.
코드
class RecorderMonitor : public RecurrentRunner {
public:
RecorderMonitor();
void RunOnce(const double current_time) override;
};
void RecorderMonitor::RunOnce(const double current_time) {
auto manager = MonitorManager::Instance();
auto* component = apollo::common::util::FindOrNull(
*manager->GetStatus()->mutable_components(),
FLAGS_smart_recorder_component_name);
if (component == nullptr) {
// SmartRecorder is not monitored in current mode, skip.
return;
}
static auto reader =
manager->CreateReader<SmartRecorderStatus>(FLAGS_recorder_status_topic);
reader->Observe();
const auto status = reader->GetLatestObserved();
ComponentStatus* component_status = component->mutable_other_status();
component_status->clear_status();
if (status == nullptr) {
SummaryMonitor::EscalateStatus(ComponentStatus::ERROR,
"No SmartRecorderStatus received",
component_status);
return;
}
// Translate SmartRecorderStatus to ComponentStatus. Note that ERROR and FATAL
// will trigger safety mode in current settings.
switch (status->recording_state()) {
case RecordingState::RECORDING:
SummaryMonitor::EscalateStatus(ComponentStatus::OK, "", component_status);
break;
case RecordingState::TERMINATING:
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("WARNNING: ", status->state_message()),
component_status);
break;
case RecordingState::STOPPED:
SummaryMonitor::EscalateStatus(
ComponentStatus::OK,
absl::StrCat("STOPPED: ", status->state_message()), component_status);
break;
default:
AFATAL << "Unknown recording status: " << status->recording_state();
break;
}
}
분석하다
첫 번째 단계는 여전히 레코더가 구성된 모니터링 모듈인지 여부를 판단하는 것입니다. 그렇지 않은 경우 직접 반환합니다.
그런 다음 status->recording_state()를 직접 판단하여 RecordingState::TERMINATING(종료) 상태이면 WARNING 오류를 보고합니다.
SmartRecorderStatus 프로토타입
enum RecordingState {
STOPPED = 0;
RECORDING = 1;
TERMINATING = 2;
}
message SmartRecorderStatus {
optional apollo.common.Header header = 1;
optional RecordingState recording_state = 2;
optional string state_message = 3;
}
상태 보고 위치 분석
모듈/데이터/도구/smart_recorder/realtime_record_processor.cc
위의 파일에서 레코더 상태 할당을 찾을 수 있지만 안타깝게도 현재 아폴로에는 RecordingState::TERMINATING(종료) 상태를 적극적으로 채울 모듈이 없습니다.
모니터링 정보 요약 서비스
코드
// A monitor which summarize other monitors' result and publish the whole status
// if it has changed.
class SummaryMonitor : public RecurrentRunner {
public:
SummaryMonitor();
void RunOnce(const double current_time) override;
// Escalate the status to a higher priority new status:
// FATAL > ERROR > WARN > OK > UNKNOWN.
static void EscalateStatus(const ComponentStatus::Status new_status,
const std::string& message,
ComponentStatus* current_status);
private:
size_t system_status_fp_ = 0;
double last_broadcast_ = 0;
};
void SummaryMonitor::RunOnce(const double current_time) {
auto manager = MonitorManager::Instance();
auto* status = manager->GetStatus();
// Escalate the summary status to the most severe one.
for (auto& component : *status->mutable_components()) {
auto* summary = component.second.mutable_summary();
const auto& process_status = component.second.process_status();
EscalateStatus(process_status.status(), process_status.message(), summary);
const auto& module_status = component.second.module_status();
EscalateStatus(module_status.status(), module_status.message(), summary);
const auto& channel_status = component.second.channel_status();
EscalateStatus(channel_status.status(), channel_status.message(), summary);
const auto& resource_status = component.second.resource_status();
EscalateStatus(resource_status.status(), resource_status.message(),
summary);
const auto& other_status = component.second.other_status();
EscalateStatus(other_status.status(), other_status.message(), summary);
}
// Get fingerprint of current status.
// Don't use DebugString() which has known bug on Map field. The string
// doesn't change though the value has changed.
static std::hash<std::string> hash_fn;
std::string proto_bytes;
status->SerializeToString(&proto_bytes);
const size_t new_fp = hash_fn(proto_bytes);
if (system_status_fp_ != new_fp ||
current_time - last_broadcast_ > FLAGS_system_status_publish_interval) {
static auto writer =
manager->CreateWriter<SystemStatus>(FLAGS_system_status_topic);
apollo::common::util::FillHeader("SystemMonitor", status);
writer->Write(*status);
status->clear_header();
system_status_fp_ = new_fp;
last_broadcast_ = current_time;
}
}
분석하다
모든 이전 모니터에서 보고된 오류 정보를 통합하고 /apollo/monitor/system_status 항목으로 보냅니다.