0. 들어가기 전에
1. spinOnce
void BackendModule::spinOnce(const BackendInput& input, bool force_update) {
status_.reset();
std::lock_guard<std::mutex> lock(mutex_);
ScopedTimer timer("backend/update", input.timestamp_ns);
updateFactorGraph(input);
updateFromLcdQueue();
status_.total_loop_closures = num_loop_closures_;
if (!config.use_mesh_subscribers) {
copyMeshDelta(input);
}
if (!updatePrivateDsg(input.timestamp_ns, force_update)) {
VLOG(2) << "Backend skipping input @ " << input.timestamp_ns << " [ns]";
logStatus();
return;
}
timer.reset("backend/spin");
if (config.optimize_on_lc && have_loopclosures_) {
optimize(input.timestamp_ns);
} else {
updateDsgMesh(input.timestamp_ns);
callUpdateFunctions(input.timestamp_ns);
}
if (logs_) {
logStatus();
}
if (zmq_sender_) {
zmq_sender_->send(*private_dsg_->graph, config.zmq_send_mesh);
}
ScopedTimer sink_timer("backend/sinks", input.timestamp_ns);
Sink::callAll(sinks_, input.timestamp_ns, *private_dsg_->graph, *deformation_graph_);
}
2. updateFactorGraph
- updateFactorGraph 함수는 백엔드의 변형 그래프를 최신 데이터로 업데이트하는 핵심 역할을 합니다. 주요 동작은 다음과 같습니다:
- 메쉬 그래프 처리: 프론트엔드에서 전달된 새로운 메쉬 데이터(
input.deformation_graph
)를 받아 변형 그래프(deformation_graph_
)에 통합하여 로봇의 포즈와 메쉬 간의 관계를 유지합니다.
- 포즈 그래프 처리: 로봇의 새로운 경로 데이터(
input.agent_updates.pose_graphs
) 를 변형 그래프(deformation_graph_
)에 반영하고, 루프 클로저가 발생했는지 감지하여 기록합니다.
- 외부 위치 정보 반영: 외부에서 제공된 추가적인 위치 정보(
input.agent_updates.external_priors
)를 그래프에 적용하여 암묵적인 루프 클로저를 처리하고 변형 그래프(deformation_graph_
)를 보강합니다.
- 루프 클로저 상태 업데이트: 새로운 루프 클로저 발생 여부를 확인하고, 루프 클로저 수와 그래프의 상태 정보를 업데이트하여 이후의 최적화에 대비합니다.
- 전체 내용
- input
input.deformation_graph
- FrontendModule::updateDeformationGraph 에서
kimera_pgmo::makePoseGraph
로 만들어짐
- 새롭게 추가된 mesh 정보를 담고 있음
input.agent_updates
- input.agent_updates
- FrontendModule::updatePoseGraph 에서 만들어짐
갱신된 포즈 그래프를 포함한 PoseGraphPacket 형태를 반환
input.agent_updates.pose_graphs
)
- 로봇의 현재 위치와 이전 위치를 바탕으로 포즈 그래프를 갱신
- agent 위치를 pose graph 로 만들었다고 생각하면 됨
- input.agent_updates.external_priors
3. updateFromLcdQueue
4. copyMeshDelta
copyMeshDelta
메서드는 프론트엔드로부터 받은 메쉬 업데이트
를 기반으로 백엔드의 메쉬 표현과 백엔드의 프라이빗 DSG의 메쉬와 관련된 부분을 갱신
를 갱신
- 메쉬 업데이트 수신: 프론트엔드에서 전달된 메쉬 변경 사항을 받아옵니다.
- 메쉬 업데이트 적용: 이 변경 사항을
백엔드의 DSG 메쉬에 적용
하여 정점과 면을 업데이트합니다.
- 원본 정점 및 타임스탬프 동기화:
메쉬의 원본 정점 위치
와 각 정점의 타임스탬프를 업데이트
하여 메쉬 데이터의 일관성을 유지합니다.
- 아카이브된 정점 수 추적: 비활성화된(아카이브된) 정점의 수를 업데이트하여, 활성 정점에만 변형이 적용되도록 관리합니다.
- 2D 장소 노드 업데이트:
DSG 내의 모든 2D 장소 노드의 메쉬 연결과 경계 정보를 메쉬 업데이트에 따라 갱신
합니다.
- 공간적 관계 유지: 메쉬와 장소 노드의 업데이트를 통해 DSG 내의 모든 공간적 관계가 정확하고 유효하게 유지되도록 합니다.
4. updatePrivateDsg
updatePrivateDsg
메서드는 공유된 backend_graph DSG
로부터 변경 사항을 가져와 백엔드의 프라이빗 DSG 전체
(mesh 제외) 를 최신 상태로 유지하기 위해 사용
- mesh를 제외하고, object, agent, place 등의 모든 계층을 병합
백엔드의 프라이빗 DSG
:
- 백엔드 모듈이 독립적으로 유지하고 관리하는 DSG의 사본
- 백엔드 모듈은 주기적으로 또는 필요에 따라 공유된 backend_graph DSG로부터 변경 사항을 받아와서 프라이빗 DSG에 병합
- 이를 통해 백엔드 모듈은 최신 상태의 그래프 정보를 사용하면서도, 자신의 처리 로직을 안정적으로 수행할 수 있습니다.
- 현재 타임스탬프와
force_update
플래그를 확인하여 업데이트가 필요한지 판단
- 이미 최신 상태라면 업데이트를 생략하여 불필요한 작업을 줄입니다.
- 업데이트 결과를 반환하여 이후의 처리 단계에서 활용합니다.
- https://velog.io/@jk01019/Backend-hydra-code-srcbackendbackendmodule.cpp-updatePrivateDsg
- input
shared_dsg = *state_->backend_graph
- reconstruction / front / backend / lcd 가 모두 공통으로 공유하고 있는 backend_graph
5. 마지막 코드 로직
핵심 요약! 이거만 보면 돼
- 최적화 여부 결정:
- 루프 클로저가 감지되고 최적화를 위한 설정이 활성화되어 있으면 최적화를 수행합니다.
- optimize 메서드 실행
- addPlacesToDeformationGraph
- 그래프 최적화
- updateDsgMesh
- callUpdateFunctions
- DSG에 mesh를 제외한 모든 나머지 계층 업데이트
- 그렇지 않으면
updateDsgMesh
와 callUpdateFunctions
만 실행합니다.
- DSG 전송: ZeroMQ를 통해 다른 시스템이나 모듈로 DSG를 전송합니다.
- 추가 처리 호출:
- 등록된 모든 sink 함수를 호출하여 추가적인 데이터 처리나 저장 등의 작업을 수행합니다.
optimize 핵심요약!
optimize
메서드는 루프 클로저가 감지되었을 때 메쉬 변형과 그래프 최적화를 수행합니다.
- 먼저, 장소(place) 노드들을 변형 그래프에 추가하여 메쉬 변형 시 공간적 일관성을 유지합니다.
- 변형 그래프를 최적화하여 메쉬 변형에 필요한 제어점의 위치를 업데이트합니다.
- 최적화된 결과를 기반으로 DSG의 메쉬를 업데이트하여 환경 지도의 왜곡을 보정합니다.
- 업데이트된 정보를 바탕으로 에이전트와 각 레이어의 업데이트 함수를 호출하여 DSG의 노드와 엣지를 갱신합니다.
- 객체, 장소, 방, 건물 등의 레이어를 각각 업데이트하고, 필요한 경우 노드 병합을 수행합니다.
- 병합 처리와 콜백 실행을 통해 DSG의 일관성과 정확성을 유지합니다.
- 이를 통해 로봇의 위치 추정과 환경 모델이 최신 상태로 유지되도록 지원합니다.