본문 바로가기

입문 SLAM 14강 (번역)

입문 Visual SLAM 14강 : 2장. SLAM과의 첫만남

Preface

이 문서는 중국어 원서인 “입문 Visual SLAM 이론에서 연습까지 14 강(视觉SLAM十四讲 从理论到实践)” 책의  원저자로부터 한글 번역 허가를 받고 구글 번역기를 이용하여 작성된 문서입니다. 본 문서는 아래의 Contribution을 특징으로 합니다.

 

  • 중국어 전공 서적을 구글 번역기를 이용해 한글로 초벌 번역했습니다.
  • 초벌 번역 후 매끄럽지 않은 문장은 문맥에 맞게 수정되었습니다. 
  • 문서 내용 중 참고할만한 웹문서를 코멘트로 추가했습니다.  
  • SLAM 연구에서 주로 사용되는 용어는 한글로 번역된 용어보다 주로 사용되는 영어로 된 용어 그대로 표시하였습니다.

그럼에도 불구하고 부정확하거나 매끄럽지 않은 부분이 있을 수 있습니다. 그런 부분은 코멘트로 제안해주시면 반영하도록 노력하겠습니다. 또한 읽으시다가 잘 이해가 가지 않는 부분도 코멘트로 질문해주시면 답변해드리도록 하겠습니다.

 

번역 참가자: 

신동원 ( 광주과학기술원 박사과정)

김선호 ( VIRNECT 선임연구원)

조원재 ( 일본국립농업기술혁신공학센터 연구원)

장형기 ( Imperial College London 석사과정)

박준영 ( 광주과학기술원 석사과정)

 

2018년 10월 1일

신동원 드림


제2장. SLAM과의 첫 만남.

주요 목표

1. 시각적 SLAM 프레임 워크로 구성되는 모듈과 각 모듈의 태스크가 무엇인지 이해하도록 합니다.

2. 개발 및 실험을 준비하기 위한 프로그래밍 환경을 설정합니다.

3. Linux에서 프로그램을 컴파일하고 실행하는 방법을 이해하고 프로그램에 문제가 있는 경우 디버깅하는 방법을 이해하도록 합니다.

4. cmake의 기본 사용을 익힙니다.

2.1 서론

  이 강의는 다음 장의 개요로서 Visual SLAM 시스템의 구조를 요약합니다. 실습 부분에서는 환경 설정 및 프로그램 개발의 기본 사항을 소개합니다. 마지막 부분에서는 “Hello SLAM” 프로그램을 만들 것입니다.

 

2.2 Little Carrot 로봇

그림 2-1과 같이 보이는 "Little Carrot"라는 로봇을 조립했다고 가정해 봅시다.

  이 로봇은 "Android" 로봇과 조금 비슷하게 생겼습니다. 우리는 언제든지 프로그램을 디버깅할 수 있도록 하기 위해 노트북을 로봇 안에 넣어두었습니다. 자 이제 이것으로 우리는 무엇을 할 수 있을까요?

  우리는 이 작은 로봇이 하나의 자율적인 기계로서 로봇이 방 안에서 자유롭게 움직일 수 있기를 바랍니다. 

  그러기 위해서 첫 번째로 로봇은 바퀴와 모터가 있어야 합니다. 그래서 우리는 이 작은 로봇 아래에 바퀴를 설치했습니다. 이제 바퀴로 로봇은 움직일 수 있지만 효과적인 내비게이션 시스템이 없으면 Little Carrot은 행동 대상이 어디에 있는지 알지 못하고 맹목적으로 돌아다닐 수밖에 없습니다. 최악의 경우 벽에 부딪혀 손상을 입을 수 있습니다. 이를 방지하기 위해 우리는 로봇이 인간과 비슷하게 보일 것이라는 직관으로 카메라를 머리에 설치했습니다. 실제로 인간은 눈, 뇌, 팔다리를 가지고 자유롭게 걸을 수 있고 어떤 환경이든 탐험할 수 있기 때문에 우리는 로봇도 그것을 달성 할 수 있어야한다고 생각합니다.  Little Carrot이 방을 탐험 할 수 있게 하려면 최소한 두 가지를 알아야 합니다. 

 

1. 나는 어디 있습니까? - 위치 추정, Localization

2. 주변 환경은 어떻습니까? - 지도 작성, Mapping

  

  위치 추정 및 지도 작성은 내적으로는 자기 자신의 위치 인식이며 외적으로는 주변 환경의 인식으로 볼 수 있습니다. 완전히 자율적인 로봇으로서 Little Carrot은 자신의 상태 (예 : 위치)와 외부 환경 (예 :지도)을 이해해야 합니다. 그러나 이러한 두 가지 문제를 해결할 수 있는 방법은 매우 다양합니다. 예를 들어 방의 바닥에 가이드 레일이나 벽면에 마커를 놓을 수 있다고 가정해 봅시다. 즉, QR 코드가 벽에 부착되고 무선 위치 확인 장치가 테이블 위에 놓여있다고 말입니다. 실외에 있다면 Little Carrot의 머리에 GNSS 수신기 (휴대폰 또는 자동차에 있는 것과 같은)를 설치할 수도 있습니다. 이런 센서들을 가지고 있으면 위치 추정 문제가 해결됐다고 할 수 있을까요? 앞서 언급한 이 센서들을 두 범주로 나누어 봅시다 (그림 2-2 참조).

그림 2-2 - 일부 센서. (a) 위치 확인을위한 증강 현실 소프트웨어, (b) GPS 위치 확인 장치, (c)레일이있는 자동차(d) 레이저 레이더, (e) IMU 유닛, (f) 양안 카메라.

  첫 번째 범주는 non-intrusive 센서로, 휠 인코더, 카메라, 레이저 스캐너 등과 같이 로봇 내부에 완전히 포함되어 있는 것을 말합니다. 그들은 로봇 주변의 협력 환경을 가정하지 않습니다. 다른 범주로는 위에서 언급 한 가이드 레일, QR 코드 등과 같이 환경 자체에 설치하는 intrusive 센서입니다. Intrusive 센서는 일반적으로 로봇의 위치를 직접적으로 계산하여 간단하고 효과적인 방식으로 위치 문제를 해결할 수 있습니다. 그러나 환경에 센서를 설치하는 과정이 필요하기 때문에 사용 범위가 어느 정도 제한되는 경우가 많습니다. 예를 들어, GPS 신호가 없거나 가이드 레일을 놓을 수없는 경우 어떻게 해야 합니까?

  우리는 그림 2-2의 intrusive 센서들이 외부 환경을 제약한다는 것을 알 수 있습니다. 이를 기반으로 한 위치 추정 시스템은 이러한 제약 조건이 실제 세계에서 충족될 때만 제대로 작동할 수 있습니다. 그렇지 않으면 GPS 위치 확인 시스템이 일반적으로 실내 환경에서 잘 작동하지 않는 것처럼 위치 확인을 더 이상 수행할 수 없습니다. 결과적으로 이 센서는 간단하고 신뢰할 수 있지만 범용적이고 다양한 솔루션을 제공하지는 못합니다. 반면에, 레이저 센서, 카메라, 휠 엔코더, 관성 측정 장치 등에서는 일반적으로 간접적인 물리량을 측정합니다. 예를 들어 휠 엔코더는 휠이 회전하는 각도를 측정하고 IMU는 움직임의 각속도와 가속도를 측정합니다. 카메라와 레이저 센서는 외부 환경에서 일부 관측 데이터를 읽습니다. 이러한 간접 관찰에서 위치를 추론하기 위해 알고리즘을 적용해야 합니다. 우회적인 방법 같아 보이지만, 이런 방법은 어떠한 주어진 환경에 별도의 추가적인 장치 없이 위치를 얻을 수 있는 프레임워크를 적용할 수 있다는 장점이 있습니다. 이것은 우회 전술처럼 들리지만 더 분명한 이점은 환경에 대한 제약조건이 필요하지 않아 이 위치 추정 방법을 미리 알지 못하는 환경에 적용할 수 있다는 것입니다. 따라서 많은 연구 분야에서 이를 self-localization이라고 합니다.

  앞서 논의한 SLAM의 정의를 되돌아보면, SLAM에서는 알려지지 않은 환경에 대한 문제를 강조하고 있습니다. 이론적으로는 Little Carrot이 어떤 환경에 있게 될지 추측해서는 안됩니다 (그러나 실제로는 실내 또는 실외와 같은 대략적인 범주가 있음). 이는 GPS와 같은 외부 센서가 원활하게 작동할 수 있다고 가정할 수 없음을 의미합니다. 따라서 SLAM을 달성하기 위해 휴대용 non-intrusive 센서를 사용하는 것이 우리의 주요 목적입니다. 특히 시각적 SLAM에 대해 이야기할 때 일반적으로 위치 추정 및 지도 작성 문제를 해결하기 위해 카메라를 사용한다는 것을 의미합니다.

  Visual SLAM은 이 책의 주제이기 때문에 로봇의 눈이 되는, 즉 카메라가, 무엇을 할 수 있는지에 대해 고려하는 것이 중요합니다. SLAM 카메라에 사용되는 카메라는 일반적으로 보는 SLR (single-lens reflex) 카메라와 달리, 더 단순합니다. 종종 훨씬 저렴하고 값 비싼 렌즈를 가지고 있지 않습니다. 이는 일정한 속도로 주변 환경을 촬영하여 연속적인 비디오 스트림을 형성합니다. 보통의 카메라는 초당 30 프레임으로 이미지를 캡처하며 고속 카메라는 더 빠릅니다. 작동하는 방식에 따라서 구분하자면 다른 점은 단안 용 카메라 (Monocular), 양안 용 카메라 (Stereo) 및 깊이 카메라 (RGB-D)로 분류할 수 있습니다. 그런 세 가지 종류의 카메라가 그림 2-3에 나와 있습니다. 직관적으로 단안 카메라에는 단 하나의 카메라만 있고 양안 카메라에서는 두 개의 카메라가 있으며 깊이 카메라의 RGB-D 원리는 더 복잡합니다. 이는 컬러 이미지를 캡처할 수 있을 뿐만 아니라 각 물체와 카메라 사이의 거리도 읽을 수 있습니다. 깊이 카메라는 일반적으로 여러 대의 카메라를 가지고 있으며 작동 원리는 일반적인 카메라와 다릅니다.  다섯 번째 강의에서 우리는 그들의 작동 원리를 자세히 설명할 것이며, 독자들은 여기서는 그저 간단히 살펴보고 넘어가도 좋습니다. 파노라마 카메라 [6], 이벤트 카메라 [7]와 같은 일부 새롭고 새로운 특수 카메라 유형도 SLAM에 적용할 수 있습니다. 이런 센서들은 SLAM 애플리케이션에서 가끔 볼 수 있지만 지금까지는 주류가 되지 않았습니다. 외관을 보면 Little Carrot은 스테레오 카메라를 가지고 있는 것처럼 보입니다.

그림 2-3 다양한 종류의 카메라 : 단안, 양안 및 RGB-D 카메라.

 

  이제, SLAM을 수행하는 데 사용되는 다양한 카메라의 장점과 단점을 살펴보겠습니다.

단안 카메라

   SLAM에 카메라 하나만 사용하는 것을 Monocular SLAM이라고 합니다. 센서 구조는 특히 간단하고 비용은 매우 낮기 때문에 연구자들은 단안 카메라를 SLAM에 적용하도록 하는 주제에 대해 많이 연구해왔습니다. 독자가 단안의 카메라로부터 촬영된 이미지를 보았다고 생각해 봅시다. 그러한 이미지의 특성은 무엇일까요?

   사진은 기본적으로 카메라의 이미지 평면에 장면을 투영하는 것입니다. 이는 2차원에서의 3차원 세계를 반영합니다. 분명히 이 투사 과정에서 전체 3차원 장면에서부터 하나의 차원을 잃어버렸습니다.단안 카메라에서 우리는 하나의 이미지로부터 장면 내의 물체들 (먼 곳과 가까운 곳) 사이의 거리를 계산할 수 없습니다. 앞서 언급한 하나의 차원을 잃어버렸기 때문입니다. 나중에 이 거리정보는 SLAM에서 매우 중요한 정보가 될 것입니다. 좀 더 거리에 대해 생각해 봅시다. 우리 인간은 일상에서 이미 많은 사진을 보았기 때문에 대부분의 장면에 대해 자연스러운 거리감을 형성하여 이미지에서 물체 간의 거리 관계를 쉽게 결정할 수 있습니다. 예를 들어, 우리는 이미지에서 물체를 인식하고 일상 경험에서 얻은 대략적인 크기와 연관시킬 수 있습니다. 가까운 물체는 멀리 있는 물체를 가립니다. 태양, 달 및 기타 천체는 무한히 멀리 떨어져 있습니다. 물체가 햇빛 아래에 있으면 그림자가 생깁니다. 이러한 정보는 물체의 거리를 판단하는 데 도움이 될 수 있지만 거리감을 무효화하는 몇 가지 상황이 있습니다. 이러한 경우에서는 물체의 거리와 실제 크기를 판단할 수 없습니다. 그림 2-4는 이러한 예를 보여줍니다. 이 이미지만으로는 이미지 평면에 투영된 어린아이들이 진짜 사람인지 장난감 모델인지 판단하는 데 어려움이 있습니다. 우리가 바라보는 시점을 바꾸지 않는 한, 이 문제를 정확히 해결하기 위해서는 장면의 3차원 구조를 관찰해야 합니다. 즉, 단일 이미지에서 객체의 실제 크기를 결정할 수 없다는 말로 생각할 수 있습니다. 이 아이들은 크지 만 멀리 있는 물체 일 수도 있고 아주 가깝지만 작은 물체 일 수도 있습니다. 원근 투영 효과로 인해 이미지에서 동일한 크기로 나타날 수 있습니다.

그림 2-4 단안 시각 : 손바닥 위에 있는 물체는 진짜 사람일까요, 장난감 모델일까요?

  단안 카메라로 찍은 이미지는 3차원 공간의 2차원 투영이므로, 실제로 3차원 구조를 복원하려면 카메라의 시점을 변경해야 합니다. 단안 SLAM문제에서도 같은 원리가 적용됩니다. 카메라를 움직여 움직임을 추정하고 장면에서 물체의 거리와 크기를 추정해야 합니다. 그렇다면 이러한 움직임과 물체의 정보를 어떻게 추정할 수 있을까요? 인간의 시각에서는, 선험적인 경험으로부터 우리는 카메라가 오른쪽으로 움직인다면 이미지의 물체들이 왼쪽으로 움직일 것이라는 것을 이미 알고 있습니다. 이것은 우리에게 움직임에 대한 추측에 대한 직관을 줍니다. 또한, 멀리 떨어진 거리의 물체에 대해서는 천천히 움직이는 반면 주변의 물체는 빠르게 움직이며 카메라가 움직이면 이미지의 물체의 움직임은 시차(disparity)를 형성합니다. 바로 이 시차를 통해 우리는 어느 물체가 멀리 떨어져 있고 어느 물체가 가까운지를 결정할 수 있습니다.

  그러나 물체가 멀리 떨어져 있다는 것을 알고 있더라도 여전히 여기에는 상대적인 성질이 있습니다. 예를 들어, 우리가 영화를 볼 때 스크린의 장면에서 어떤 장면이 다른 장면보다 큰지 알 수 있지만 이러한 장면의 실제 크기를 파악할 수는 없습니다. 스크린에서 보이는 건물은 실제 고층 건물 일지? 아니면 테이블 위에 있는 모형 일지? 건물을 파괴하는 괴물이 진짜 괴물인가, 아니면 특별한 옷을 입은 배우인가? 직관적으로 카메라의 움직임과 장면 안의 물체의 크기가 동시에 두 배가되면 단안 카메라에서는 동일하게 보입니다. 마찬가지로, 이 크기에 임의의 요소를 곱하면 여전히 동일한 그림을 얻을 수 있습니다. 이것은 단안 SLAM 추정의 결과로부터 얻은 궤적 및 맵이 scale이라고 하는 알려지지 않은 요인을 가진 실제의 궤적 및 지도와는 다를 것임을 보여줍니다. 단안 SLAM은 순전히 이미지를 기반으로 이 실제 스케일을 결정할 수 없기 때문에 스케일 모호성이라고도 합니다.

  단안 SLAM에서 깊이 정보는 시점 이동 움직임과 함께 계산할 수 있지만 실제의 스케일은 결정할 수 없습니다. 이 두 가지는 실제 응용 프로그램에 단안 SLAM을 적용할 때 심각한 문제를 일으킬 수 있습니다. 근본적인 원인은 단일 이미지에서 깊이를 결정할 수 없다는 것입니다. 따라서 실제 크기의 깊이를 얻기 위해 스테레오 및 RGB-D 카메라를 사용하기 시작합니다

스테레오 카메라와 RGB-D 카메라

  스테레오 및 RGB-D 카메라를 사용하는 목적은 거리를 알 수 없는 단안 카메라의 단점을 극복하기 위해 물체와 카메라 사이의 거리를 측정하는 것입니다. 거리 정보를 알 수 있다면 장면의 3차원 구조를 단일 이미지에서 복구할 수 있으므로 앞절에서 언급한 크기의 불확실성에 대한 부분을 고려하지 않아도 됩니다. 이러한 스테레오 카메라와 RGB-D 카메라  모두 거리를 측정하기 위한 도구이지만, 이것을 측정하기 위한 스테레오 카메라와 RGB-D 카메라의 원리는 동일하지 않습니다. 스테레오 카메라는 두 개의 단안 카메라로 구성되어 있으며, 이 두 카메라 간의 거리는 직접 지정할 수 있습니다. 이 말은 우리가 카메라 간 거리(Baseline)를 알고 있다는 말과 동일합니다. 우리는 이 베이스라인(Baseline)을 사용하여 인간의 눈과 마찬가지로 각 픽셀의 공간적 위치를 추정할 수 있습니다. 인간은 왼쪽 눈과 오른쪽 눈 이미지의 차이로 물체의 거리를 판단할 수 있으며 컴퓨터에서도 이러한 원리를 적용하는 것이  가능합니다 (그림 2-5 참조). 필요한 경우 스테레오 카메라를 멀티 카메라 시스템으로 확장할 수도 있지만 기본적으로 원리 상의 큰 차이는 없습니다.

그림 2-5 양안 카메라 데이터 : 왼쪽 눈 이미지, 오른쪽 눈 이미지. 왼쪽 눈과 오른쪽 눈의 차이를 사용하여 장면의 물체와 카메라 간의 거리를 결정할 수 있습니다.

  스테레오 카메라는 각 픽셀의 깊이를 추정하기 위해 많은 계산 능력이 필요합니다. 이것은 인간에 비해 매우 다르다고 볼 수 있습니다. 스테레오 카메라로 측정 한 깊이 범위는 베이스 라인과 관련이 있습니다. 베이스 라인의 거리가 멀수록 먼 거리를 측정할 수 있기 때문에 자율주행 자동차에 장착된 스테레오 카메라는 일반적으로 베이스라인이 큽니다. 양안 카메라의 거리 추정은 왼쪽 카메라와 오른쪽 카메라의 이미지를 비교하여 얻어지며, 다른 감지 장치에 의존하지 않으므로 실내외에서 적용할 수 있습니다. 양안 또는 멀티 카메라의 단점은 구성과 캘리브레이션이 복잡하다는 것입니다. 깊이의 범위와 정확도는 베이스라인과 카메라 해상도에 의해 제한됩니다. 또한 스테레오 매칭 및 디스 패리티(disparity) 계산은 많은 계산 리소스를 소비하며 실시간 깊이 맵을 생성하기 위해 가속화하려면 일반적으로 GPU 또는 FPGA가 필요합니다. 따라서 대부분의 최신 알고리즘에서 높은 계산 비용은 여전히 스테레오 카메라의 주요 문제 중 하나입니다.

  깊이 카메라 (RGB-D 카메라라고도 함, 이 책에서는 RGB-D가 사용됨)는 2010 년 이후로 떠오르는 새로운 유형의 카메라입니다. 레이저 스캐너와 마찬가지로 RGB-D 카메라는 적외선을 사용한 구조광 방식 (structured light) 또는 ToF (Time-of-Flight) 원리를 채택하여 물체에 능동적으로 빛을 방출하고 반사된 빛을 수신하여 물체와 카메라 사이의 거리를 측정합니다. 이 부분은 양안 카메라와 같은 소프트웨어 계산으로는 해결되지 않지만 물리적 측정 수단을 통해 해결되므로 양안 카메라와 비교하여 큰 계산을 줄일 수 있습니다 (그림 2-6 참조). 현재 일반적으로 사용되는 RGB-D 카메라에는 Kinect / Kinect V2, Xtion Pro Live, RealSense 등이 있습니다. 그러나 대부분의 RGB-D 카메라는 짧은 거리 탐지 범위, 많은 노이즈, 좁은 시야, 자연광에 취약,  투과 물질 측정 불가 등의 많은 문제점을 품고 있습니다. SLAM 목적을 위해 RGB-D 카메라는 주로 실내 환경에서 사용되며 실외 애플리케이션에는 적합하지 않습니다.

그림 2-6 RGB-D 데이터 : 깊이 카메라는 이미지와 객체의 거리를 직접 측정하여 3차원 구조를 복원 할 수 있습니다.

  우리는 몇 가지 일반적인 카메라에 대해 논의했습니다. 이를 바탕으로  위의 설명들을 통해 독자들이 직관적인 이해가 가능하다고 생각됩니다. 이제 장면에서 카메라를 움직이는 과정을 상상해보십시오. 우리는 연속적으로 변화하는 일련의 이미지를 얻을 것입니다. Visual SLAM의 목표는 이러한 이미지를 사용하여 위치 추정 및 지도 작성을 수행하는 것입니다. 이 문제는 우리가 생각하는 것처럼 간단하지 않습니다. 입력 데이터가 들어오면 지속적으로 위치 및 지도 정보를 출력하는 단순한 하나의 알고리즘이 아닙니다. SLAM은 알고리즘 프레임 워크를 필요로 하며 수십 년간의 연구자들의 노력 끝에 프레임 워크는 최근 몇 년간 성숙해졌습니다.

2.3 고전적인 시각적  SLAM 프레임워크

다음 그림 2-7에 표시된 전통적인 Visual SLAM 프레임 워크를 살펴보겠습니다. 

 

그림 2-7 전체 시각적 SLAM 흐름도. 전체 시각적 SLAM 프로세스에는 다음 단계가 포함됩니다. 

다음 단계들은 전형적인 Visual SLAM을 구성하는 모듈입니다. 

 

1. Sensor data 취득. Visual SLAM에서 이것은 주로 카메라 이미지의 획득 및 전처리를 의미합니다. 모바일 로봇의 경우 여기에는 모터 엔코더, IMU 센서 등과 같은 센서로부터의 데이터 수집 및 동기화도 포함됩니다.

 

2. Visual odometry (VO). Visual odometry는 연속적인 이미지 사이의 카메라 움직임과 로컬 맵의 모양을 추정하는 것입니다. VO는 frontend라고도 합니다. 

 

3. Backend optimization: 백엔드는 VO와 loop closure에서 카메라 포즈를 받고 최적화를 적용하여 완전히 최적화된 궤적 및 맵을 생성 합니다. VO 이후에 연결되기 때문에 백엔드(backend)라고도 합니다.

 

4. Loop Closure는 로봇의 현재 위치가 과거에 방문했던 적이 있는지 확인하는 역할을 수행합니다. loop closure가 감지되면 추가적인 처리를 위해 백엔드에 이 loop closure정보를 제공합니다. 

 

5.Reconstruction. 추정된 카메라 궤적을 기반으로 주변 환경에 대한 지도를 구성합니다.

 

  앞서 설명한 Visual SLAM 프레임 워크는 많은 연구자들에 의해 10년 이상 연구되어온 결과입니다. 프레임 워크 자체와 이 프레임 워크에 포함된 알고리즘은 기본적으로 기본 틀이 있으며 많은 라이브러리에서 이미 사용할 수 있습니다. 이 알고리즘을 사용하여 일반적인 작업 환경에서 실시간으로 위치를 추정하고 매핑하는 Visual SLAM 시스템을 구축할 수 있습니다. 따라서 작업 환경이 안정된 조명 조건과 사람의 간섭 없이 정적으로 제한된다면 이러한 환경 아래에서 Visual SLAM 문제는 기본적으로 해결된 문제이다라는 대략적인 결론에 도달할 수 있습니다 [8].

  독자는 위 모듈의 개념을 완전히 이해하지 못할 수도 있기 때문에, 각 모듈에서 일어나는 구체적인 동작을 자세히 설명해 드리도록 하겠습니다. 그러나 그것이 어떻게 작동하는지에 대한 정확한 이해는 수학적 지식을 필요로 하는데, 우리는 책의 두 번째 부분에 넣을 것입니다. 현재로서는 각 모듈에 대한 직관적인 이해만으로도 충분합니다.

Visual Odometry 

  Visual odometry는 인접한 이미지 사이의 카메라 움직임과 관련이 있습니다. 가장 간단한 경우는 두 이미지 간의 모션 관계입니다. 예를 들어, 그림 2-8을 보면, 오른쪽 이미지는 왼쪽 이미지를 특정 각도만큼 왼쪽으로 회전시킨 결과여야만 한다는 것을 자연스럽게 알 수 있습니다. 이것에 대해 좀 더 생각해 봅시다 : 이미지가 "왼쪽으로 회전"하는 것을 어떻게 알수 있을까요? 인간은 오랫동안 세계를 자신의 눈으로 탐험하고 자신의 위치를 추측하는 데 익숙해져 왔지만 언어로 이러한 직감을 표현하는 것은 종종 어렵습니다. 우리가 이러한 이미지를 볼 때 자연스럽게 테이블이 우리 가까이에 있고 벽과 칠판이 더 멀리 떨어져 있다고 생각할 수 있습니다. 카메라를 왼쪽으로 돌리면 테이블의 더 가까운 부분이 나타나기 시작하고 오른쪽의 캐비닛이 시야에서 벗어나기 시작합니다. 이 정보를 통해 우리는 카메라가 왼쪽으로 회전해야 한다는 결론을 내립니다.

그림 2-8 두 개의 연속 이미지 프레임에서 카메라 움직임을 추론 할 수 있습니다. 이미지는 NYUD 데이터 세트에서 가져온 것입니다 [9].

  그러면 조금 더 나아가서 얼마나 많은 회전 각도와 몇 센티미터를 이동했는지 확인할 수 있습니까? 이 질문에 대해 우리는 확실한 답을 내리는 것이 어렵습니다. 우리의 직감이 특정한 숫자에 민감하게 반응하지 않기 때문입니다. 그러나 컴퓨터에서는 이 동작 정보를 정확하게 측정해야 합니다.그래서 우리는 컴퓨터가 이미지를 통해 어떻게 카메라의 움직임을 결정할 수 있을까에 대한 질문을 가지게 됩니다.

  앞서 언급했듯이 컴퓨터 비전 분야에서 인간에게 자연스러운 작업은 컴퓨터에게는 매우 어려울 수 있습니다. 이미지는 컴퓨터의 숫자 행렬 일뿐입니다. 컴퓨터는 이러한 행렬이 무엇을 의미하는지 알지 못합니다 (이는 기계 학습이 해결하려고 하는 문제입니다). Visual SLAM에서는 픽셀 블록만 볼 수 있으며 이는 카메라의 2차원 영상 평면 위에 3차원 공간 점이 투영된 결과임을 알 수 있습니다. 따라서 카메라의 움직임을 정량적으로 추정하려면 먼저 카메라와 공간 점 사이의 기하학적 관계를 이해해야 합니다. 

  이러한 기하학적 관계와 VO 방법의 구현을 명확히 하기 위해서는 약간의 배경 지식이 필요합니다. 여기에서는 먼저 독자가 VO의 직관적인 개념을 갖도록 합니다. 지금은 VO가 인접한 프레임의 이미지에서 카메라 움직임을 추정하고 장면의 3D 구조를 복원할 수 있다는 점을 알고 가면 됩니다. 이는 wheel odometry처럼 자기 자신의 움직임만을 계산하고 주변 환경에 대한 구조를 계산하지는 않기 때문에 odometry(오도메트리)라고 합니다.  이 점에서 VO는 short memory를 가진 작업이라고 할 수 있습니다.

  이제 Visual odometry 모듈이 있다고 가정하면 연속된 두 프레임 사이의 카메라 움직임을 추정할 수 있습니다. 인접한 움직임을 연결하면 자연스럽게 로봇의 궤적에 대한 움직임을 구성하고 위치 추정 문제를 해결수 있습니다. 그러는 한편, 우리는 각 시간에서의 카메라 위치에 따라 각 픽셀에 대한 3D 위치를 계산할 수 있으며 이를 통해 주변 환경에 대한 지도를 형성할 수 있습니다.

  Visual odometry는 SLAM의 핵심이며, 이를 소개하는 데 많은 시간을 할애할 것입니다. 그러나 visual odometry를 통해서만 궤도를 추정하면 필연적으로 에러가 누적됩니다. 이것은 visual odometry (가장 간단한 경우)가 두 이미지 사이의 움직임만을 추정하기 때문입니다. 각 추정치에는 일정한 오류가 있으며 odometry가 작동하기 때문에 이전 순간의 오류가 다음 순간으로 전달되어 누적되어 예측된 궤적이 어느 정도 시간이 지난 후에는 정확하지 않게 됩니다 (그림 2.9 참조).예를 들어, 로봇이 먼저 왼쪽으로 90 ° 회전하고 오른쪽으로 90 ° 회전했다고 해봅시다. 오류로 인해 우리는 처음의 90 °를 89 °로 추정했다고 생각해 봅시다. 그런 경우 다시 로봇이 우회전 후 로봇의 예상 위치가 원래의 위치로 돌아오지 않았음을 알 수 있습니다. 설상가상으로, 후속의 추정치가 정확하더라도, 실제 값과 비교하면 항상 -1 °의 오차가 나타납니다.

그림 2-9 누적 오류 및 loop closing 감지 수정 결과

  이것은 drift problem이라고 합니다. 이 때문에 일관된 전체 지도를 만들 수 없게 됩니다. 위 그림을 통해 처음에 만들어진 일자로 쭉 뻗어진 복도가 누적된 에러로 인해 나중에는 기울어졌음을 알 수 있습니다. 이러한 드리프트 문제를 해결하려면 Backend optimization 및 Loop closure detection의 두 가지 기술이 필요합니다. Loop closure detection는 "로봇의 현재 위치가 이전에 방문했던 곳인가 "를 감지하는 기술이고 Backend optimization는 이 정보를 기반으로 전체 궤적의 모양을 수정합니다.

Backend optimization

  일반적으로 Backend optimization에서는 주로 SLAM 중 노이즈를 처리하는 문제를 수행합니다. 모든 데이터가 정확하기를 바랄지라도 실제 센서에는 아무리 비싼 센서에도 약간의 노이즈가 존재합니다. 값이 저렴한 센서는 측정 오류가 큰 대신에 비용이 적게 듭니다. 또한, 일부 센서는 자기장과 온도에 영향을 받습니다. 따라서 우리는 "이미지에서 카메라 모션을 추정하는 방법"을 해결하는 것 외에도 이 추정치에 노이즈가 얼마나 많은지, 이전 순간에서 다음 순간으로 노이즈가 얼마나 전달되는지,  현재 예측값이 얼마나 확실한지에 대해 고려해야 합니다. 백엔드 최적화는 잡음이 있는 입력 데이터에서 전체 시스템의 상태를 추정하는 문제를 해결하고 불확실성을 계산합니다. 여기의 상태에는 로봇의 자체 궤적과 환경 맵이 모두 포함됩니다.

  반대로 Visual odometry 부분을 frontend(프런트 엔드)라고도 합니다. SLAM 프레임 워크에서 프런트 엔드는 백엔드에 최적화할 데이터와 데이터의 초기 값을 제공합니다. 백엔드는 전반적인 최적화 프로세스를 담당하며 데이터가 어디서 왔는지에 신경을 쓰는 것보단 데이터 자체를 다룹니다. Visual SLAM에서 프런트 엔드는 이미지 특징 추출 및 매칭과 같은 컴퓨터 비전 주제와 더 관련이 있으며 백엔드는 상태 추정 연구 영역과 관련이 있습니다.

  역사적으로 우리가 지금 Backend optimization라고 부르는 것이 오래전부터 "SLAM 연구"로 불려 왔습니다. 초기 SLAM 문제는 상태 추정 문제였습니다. 이것이 바로 Backend optimization가 해결하고자 했던 문제였습니다. SLAM에 관한 초기 논문에서 그 당시 연구자들은 이것을 "공간 불확실성 추정"이라고 불렀습니다 [3, 11]. SLAM 문제를 해결하려면 위치 추정 및  지도 작성의 불확실성을 표현한 다음 상태의 평균과 불확실성 (공분산)을 추정하기 위해 필터 또는 비선형 최적화를 사용하는 상태 추정 이론이 필요합니다. 상태 추정 및 비선형 최적화에 대한 자세한 내용은 6, 9, 10 장에서 설명합니다.

Loop Closing

  Loop Closing으로 알려진 루프 감지는 주로 SLAM에서 위치 추정의 drift 문제를 다룹니다. 그러면 이 문제를 어떻게 풀 수 있을까요? 로봇이 어느 정도 이동한 후에 원점으로 다시 돌아왔다고 가정해보면 예측된 로봇의 현재의 위치는 드리프트로 인해 원점으로 돌아오지 않을 수 있습니다. 어떻게 이 에러를 보정할 수 있을까요? 로봇이 원점으로 돌아왔다는 사실을 로봇에게 알릴 수 있는 방법이 있다면 예상 위치를 원점으로 가져와 드리프트를 제거할 수 있다고 상상해보십시오. 이것이 바로 Loop closing이 하는 일입니다.

  Loop closing은 위치 추정 및 지도 작성과 밀접한 관계가 있습니다. 사실, 지도를 만드는 주된 목적은 로봇이 그것이 있었던 장소를 알 수 있도록 하는 것입니다. Loop closing을 수행하려면 로봇이 이전에 방문한 장면을 식별할 수 있도록해야합니다. 이 목표를 달성하기위한 몇가지 방법이 있습니다. 예를 들어 앞에서 언급했듯이 QR 코드와 같이 로봇이 시작하는 위치에 마커를 설정할 수 있습니다. 표지판이 다시 보이면 로봇이 원점으로 돌아온 것입니다. 그러나 마커는 본질적으로 애플리케이션 환경에 추가 제약을 설정하는 intrusive 센서입니다. 로봇이이 작업을 완료하기 위해 이미지 자체와 같은 non-intrusive 센서를 사용할 수있는 것을 선호합니다. 가능한 접근 방식은 이미지 간의 유사성을 감지하는 것입니다. 이것은 우리 인간에게서 영감을 받았습니다. 우리 인간은 두 개의 유사한 이미지를 보면 동일한 장소에서 가져온 것임을 쉽게 식별 할 수 있습니다. Loop closing 테스트가 성공하면 누적 오류를 크게 줄일 수 있습니다. 따라서 visual loop detection은 기본적으로 이미지 데이터의 유사도를 계산하는 알고리즘입니다. Loop closing 문제는 레이저 기반 SLAM에도 존재합니다. 이미지에 포함된 풍부한 정보는 정확한 루프 감지의 어려움을 현저히 줄일 수 있습니다.

  Loop를 감지한 이후에 Backend optimization 알고리즘에 "A와 B는 같은 지점입니다."라는 메시지를 알려줍니다. 이 새로운 정보를 기반으로 궤적과 맵이 루프 감지 결과와 일치하도록 조정됩니다. 이러한 방식으로 충분하고 신뢰할 수 있는 루프 감지 기능이 있는 경우 누적 오류를 제거하고 전역 적으로 일관된 궤적 및 지도를 얻을 수 있습니다.

Mapping

  맵핑은 맵을 빌드하는 과정을 나타냅니다.(그림 2-10 참조) 맵은 주변 환경을 설명해주지만 고정되어 있지 않으며 SLAM의 응용 프로그램에 따라 다르게 구현됩니다.

그림 2-10 : 다양한 종류의 맵 : 2D 그리드 맵, 2D 토폴로지 맵, 3D 포인트 클라우드 및 3D 메시 [101].

  가정용 청소 로봇을 예로 들어 보겠습니다. 이는 기본적으로 바닥에서 이동하기 때문에 단일 라인 레이저 스캐너로 만든 자유 영역과 장애물에 대한 표시가 있는 2차원 지도가 탐색에 충분할 것입니다. 카메라의 경우 6 자유도 이동을 위한 3차원 지도가 필요합니다. 때로는 점 집합뿐만 아니라 삼각형면의 질감도 부드럽고 아름다운 재구성 결과를 원합니다. 다른 경우에는 지도가 보이는 방식에 신경 쓰지 않고 "A에서 B까지 통과할 수 있고 B에서 C까지 통과 할 수 없습니다"와 같은 정보를 알아야 합니다. 때로는 지도가 필요하지 않을 수도 있습니다. 예를 들어, 레벨 2 자율 주행 자동차는 차선과의 상대적인 움직임만 알면 차선 추종 주행을 할 수 있습니다.

  지도에는 다양한 아이디어와 필요에 의한 요구가 많습니다. 따라서 앞서 언급 한 Visual odometry, Loop closure detection 및 Backend optimization와 비교할 때, 매핑을 위한 고정된 형식과 알고리즘은 없습니다. 단순히 공간 점 들의 집합은 지도라고 할 수 있습니다. 맵의 형식은 SLAM의 응용 프로그램에 따라 다릅니다. 일반적으로 지도를 metric map(메트릭 맵)topological map(토폴로지 맵)으로 나눌 수 있습니다.

 

  Metric map : 메트릭 맵은 지도에 있는 객체에 대해 미터법에 의거한 정확한 위치를 강조합니다. 일반적으로 sparse 또는 dense로 분류됩니다. sparse 맵은 장면을 압축 형식으로 저장하고 모든 객체를 표현하지 않습니다. 예를 들어 차선, 교통 표지판 등 대표적인 랜드 마크를 선택하고 다른 부분은 무시하여 sparse 한지도를 만들 수 있습니다. 반대로 dense 맵은 보이는 모든 것을 모델링하는 데 중점을 둡니다. sparse 맵은 위치 추정에 충분하지만 내비게이션에는 일반적으로 dense 맵이 필요합니다 (그렇지 않으면 두 랜드 마크 사이의 벽에 부딪힐 수 있습니다). Dense 맵은 일반적으로 특정 해상도에서 여러 개의 작은 그리드로 구성됩니다. 2D 메트릭 맵의 경우 작은 점유 그리드이거나 3D 맵의 경우 작은 복셀 그리드 일 수 있습니다. 예를 들어, 2D 점유 그리드 맵에서 그리드는 점유됨(occupied), 점유 안됨(not occupied) 및 알 수 없음(unknown)의 세 가지 상태를 가질 수 있으며 객체가 있는지 여부를 나타냅니다. 공간에서의 목적지가 주어지면 지도는 이 목적지로의 경로가 로봇이 통과 가능한지 여부에 대한 정보를 제공할 수 있습니다. 이러한 유형의 지도는 A-star search, D-star search 등과 같은 다양한 내비게이션 알고리즘에 사용될 수 있어 로봇 연구자들의 관심을 끌고 있습니다. 그러나 모든 그리드 상태가 맵에 저장되어있어 스토리지 비용이 많이 든다는 것도 알 수 있습니다. 메트릭 맵을 작성할 때도 몇 가지 해결하기 어려운 문제가 있습니다. 예를 들어, large-scale의 메트릭 맵에서 작은 조향 오류로 인해 두 방의 벽이 겹치게 되어 지도가 비 효과적 일 수 있습니다.

 

  Topological map : 토폴로지 맵은 맵 요소의 관계를 메트릭 맵의 정확도와 비교하여 강조합니다. 토폴로지 맵은 노드와 에지로 구성된 그래프로 노드 간의 연결만 고려합니다. 예를 들어 A 지점에서 B 지점에 도달하는 방법에 관계없이 A 지점과 B 지점이 연결되어 있습니다. 정확한 위치에 대한 지도의 필요성을 완화하고, 지도의 세부 사항을 제거하여보다 콤팩트 한 표현을 제공합니다. 그러나 토폴로지 맵은 복잡한 구조의 맵을 표현하는 데 적합하지 않습니다. 노드와 에지를 구성하기 위해 맵을 분할하는 방법과 탐색 및 경로 계획에 토폴로지 맵을 사용하는 방법은 여전히 연구해야 할 문제입니다.

2.4 SLAM 문제의 수학적 표현

  이전 절에 소개된 내용으로부터 독자는 SLAM의 각 모듈의 구성과 주요 기능을 직관적으로 이해했을 것입니다. 그러나 직관적인 측면에만 의존한다고 해서 우리가 실행할 수 있는 프로그램을 작성하는 데 도움이 되지는 않습니다. 합리성을 위해서는 SLAM 프로세스를 수학 언어로 설명해야 합니다. 우리는 변수와 공식을 사용할 것이지만 충분히 명확하게 유지하기 위해 최선을 다할 것입니다.

  어떤 환경에서 자율적으로 이동하기 위해 Mini Carrot 로봇이 특정 센서를 들고 있다고 가정해봅시다. 어떻게 이것을 수학적인 언어로 설명할까요? 첫째, 카메라는 보통 특정 시간에 데이터를 수집하기 때문에 이러한 순간의 위치와 지도만 신경 씁니다. 이것은 연속 시간 운동을 이산적인 타임프레임 $1, \cdots, k$로 바꿉니다. 이 순간에 변수 $\mathbf{x}$는 로봇 자체의 위치를 나타내는 데 사용됩니다. 그러면 각 순간의 위치는 작은 로봇의 궤도를 구성하는 $\mathbf{x}_1,\cdots,\mathbf{x}_k$ 로 기록됩니다. 지도의 관점에서 우리는 지도가 여러 개의 landmark로 구성되어 있다고 가정하고 각 시간에서 센서는 landmark들의 일부를 보고 관찰을 기록할 수 있습니다. $\mathbf{y}_1, \cdots, \mathbf{y}_N$ 으로 표현되는 총 N 개의 랜드 마크를 가정합시다.

  이러한 세팅에서 Mini Carrot 로봇이 센서와 함께 환경과 상호작용하는 과정을 두 가지 개념으로 설명합니다.

 

1. 운동 모델 (motion model) : 로봇의 위치 $x$가 $k-1$에서 $k$로 어떻게 변하는지 고려해야 합니다.

 

2. 관찰 모델 (sensor model) :로봇은 시간 $k$의 위치 $x_k$에서 특정 랜드 마크 $y_j$를 검출했다고 가정해 봅시다. 이 문제가 어떻게 수학 언어로 기술되는지 고려해야 합니다.

 

  먼저 운동 모델을 예로 살펴봅시다. 우리는 일반적으로 "왼쪽으로 15도 회전"과 같은 일부 움직임 명령을 로봇에 보낼 수 있습니다. 이러한 명령은 최종적으로 제어기에 의해 수행되며 로봇에 따라 여러 가지 방법으로 수행될 것입니다. 그러나 제어기가 무엇이든 상관없이 보편적이고 추상적인 수학적 모델을 사용하여 다음과 같이 설명할 수 있습니다.

여기에서 $\mathbf{u}_k$는 움직임 명령 입력이고 $\mathbf{w}_k$는 노이즈입니다. $f(\cdot)$는 운동 모델을 나타내는 함수입니다. 이를 통해 함수가 특정 움직임 명령 입력으로 제한되지 않고 모든 움직임 명령 입력을 나타낼 수 있습니다. 우리는 이를 운동 방정식이라고 부릅니다.

  노이즈에 대한 개념이 포함되면 이 모델은 확률 모델로 바뀝니다. 즉,“1 미터 앞으로 이동”명령을 내린다고 해서 우리 로봇이 실제로 1 미터 앞으로 이동할 수 있다 의미는 아닙니다. 만약 모든 명령이 정확하게 수행된다면 아무것도 예측할 필요가 없습니다. 실제로는 로봇이 0.9m 앞으로 만 이동할 수도 있으며, 또 다른 순간에는 1.1m를 이동할 수도 있습니다. 따라서 각 이동 중에 노이즈는 랜덤입니다. 이 노이즈를 무시하면 움직임 명령 입력에 의해서만 결정되는 로봇의 위치는 몇 분 후에는 실제 위치에서 수백 마일 떨어진 위치에 있을 수 있습니다.

  운동 모델에 대한 방정식과 마찬가지로 관찰 모델에 대한 방정식도 있습니다. 관측 방정식은 로봇이 $\mathbf{x}_k$ 위치에서 어떤 랜드 마크 점  $\mathbf{y}_j$를 볼 때 관측 데이터  $\mathbf{z}_{k,j}$가 생성된다는 것을 설명합니다. 다시, 이 관계를 설명하기 위해 추상 함수 $h(\cdot)$를 사용합니다.

  여기서  $\mathbf{v}_{k,j}$는 이 관찰에서의 노이즈입니다. 관측에 사용되는 센서는 형태가 다양하므로 관측값 $\mathbf{z}$와 관측 방정식 $h$는 여러 가지 형태로 존재합니다.

  여기서 독자들은 함수 $f,h$의 운동 방정식과 관찰 방정식에서 정확히 무슨 일이 일어나고 있는지를 자세히 설명하지 않는 것 같다는 궁금증이 생길 수도 있습니다. 또한 $\mathbf{x}$, $\mathbf{y}$, $\mathbf{z}$는 무엇일까요? 사실, 로봇의 실제 동작과 센서의 유형에 따라 운동 방정식과 관찰 방정식은 다양한 표현 방법이 있습니다. 예를 들어, 작은 로봇이 2차원의 평면에서 움직인다고 가정하면 로봇 포즈는 위치와 각도, 즉 $\mathbf{x}_k = [x_1,x_2,\theta]_k^\mathrm{T}$ 에 의해 설명됩니다 (여기서 $x_1, x_2$는 로봇의 두 좌표축에 대한 위치이고 $\theta$는 회전각을 의미). 동시에 입력 명령은 시간 인터벌 사이의 위치와 각도 변화 $\mathbf{u}_k = [ \Delta x_1, \Delta x_2, \Delta \theta ]_k^\mathrm{T} $ 이고 운동 방정식은 다음과 같이 구현할 수 있습니다.

여기서 $\mathbf{w}_k$는 노이즈에 대한 항입니다. 그러나 입력 명령이 위치 및 각도 변경만 있는 것은 아닙니다. 예를 들어, 가속 페달은 가속도를 나타내므로 더 복잡한 모션 방정식의 형태가 있습니다. 그러한 경우 로봇에 대한 운동 분석이 필요할 것입니다.

  관찰 방정식에 관해서는, 예를 들어, 로봇에 2차원 레이저 센서가 장착되어 있다고 생각해 봅시다. 우리는 레이저 센서가 2D 랜드마크를 관찰할 때 랜드마크와 로봇 사이의 거리 $r$과 각도 $\phi$의 두 가지 양을 측정할 수 있다는 것을 알고 있습니다. 랜드마크는 $\mathbf{y}_j = [y_1, y_2]_j^\mathrm{T}$ 로 나타내고 로봇 포즈는 $\mathbf{x}_k=[x_1,x_2]_k^\mathrm{T}$ 이며 관찰 값은 $\mathbf{z}_{k,j} = [r_{k,j}, \phi_{k,j}]^\mathrm{T}$으로 나타낸다고 할 때 관찰 방정식은 다음과 같이 나타낼 수 있습니다. 

  Visual SLAM을 고려할 때 사용하는 센서는 카메라이므로 관측 방정식은 장면을 촬영한 후 이미지에서 픽셀을 가져오는 과정입니다. 이 과정에는 카메라 모델에 대한 설명이 포함되어 있으며 여기서는 자세히 다루지 않지만 다섯 번째 강의에서 자세히 다룹니다.

  이러한 두 방정식은 센서마다 다른  형태를 가지고 있음을 알 수 있습니다. 다목적성을 유지하면서 공통된 추상 형식으로 식을 만들면 SLAM 프로세스를 두 가지 기본 방정식으로 요약할 수 있습니다.

여기서 O는 랜드 마크가 관찰된 포즈 정보를 포함하는 집합입니다 (보통 모든 랜드 마크를 매 순간 볼 수 있는 것은 아닙니다. 우리는 한순간에 랜드 마크의 일부만 볼 가능성이 높습니다).

이 두 방정식을 이용하여 가장 기본적인 SLAM 문제를 설명합니다 잡음이 있는 제어 입력 u와 센서의 측정값 z를 알고 있을 때 위치 추정 값 x 및 랜드마크의 위치 y 문제를 해결하는 방법은 무엇입니까? 이제 우리는 SLAM 문제를 상태 추정 문제로 모델링했습니다. 노이즈가 포함된 측정 데이터를 통해 실제의 상태 변수를 추정하는 방법은 무엇입니까?

  상태 추정 문제에 대한 해답은 두 방정식의 형태와 노이즈가 어떤 분포를 갖는가와 관련이 있습니다. 움직임 및 관측 방정식이 선형인가, 잡음이 가우스 분포를 따르고 있는가에 따라 linear / nonlinear 및 Gaussian / non-Gaussian 시스템으로 분류할 수 있습니다. 그중에서도 Linear Gaussian (LG 시스템)은 가장 간단하며, Kalman Filter (KF)를 사용하여 최적의 추정치를 얻을 수 있습니다. 복잡한 non-linear non-Gaussian (NLNG 시스템)에서는 확장된 칼만 필터 (EKF)와 비선형 최적화 방법을 사용하여 이를 해결합니다. 21 세기 초까지 EKF 기반 필터 방법이 SLAM을 지배했었습니다. 우리는 시스템을 선형화하고 두 가지 주요 단계를 업데이트하여 예측을 해결해왔습니다 (9 장 참조). 최초의 실시간 시각 SLAM 시스템은 EKF를 기반으로 개발되었습니다 [1]. 결과적으로 EKF의 단점 (선형화 오차 및 잡음 가우스 분포 가정)을 극복하기 위해 사람들은 파티클 필터와 같은 다른 필터를 사용하기 시작했고 비선형 최적화 방법을 사용하기 시작했습니다. 현재 Visual SLAM의 대표적인 기술은 Graph Optimization [12]으로 알려져 있습니다. 이 그래프 최적화 기술은 필터 기술보다 훨씬 뛰어나며 컴퓨팅 리소스가 허용하는 한 그래프 최적화 방법을 선호하는 경향이 있습니다 (제9강 및 제10강 참조).

  이제 독자가 SLAM의 수학적 모델을 전반적으로 이해하고 있다고 생각하지만 여전히 몇 가지 문제를 명확히 해야 합니다. 먼저, 로봇 포즈 x가 무엇인지 설명하고 싶습니다. 방금 말한 포즈라는 단어는 다소 모호합니다. 아마도 독자는 평면에서 움직이는 로봇이 두 좌표와 각도로 매개 변수화 될 수 있다는 것을 이해할 수 있을 것입니다. 그러나 현실에서의 로봇은 3차원 공간에서 움직입니다. 

3차원 공간에서의 움직임은 3개의 축으로 이루어져 있으므로 로봇의 움직임은 3축에서의 이동과 3축에서의 회전이 있는  6자 유도가 공간에 의해 설명됩니다. 그것은 내가 $\mathbb{R}^6$ 벡터로 설명할 수 있다는 것을 의미할까요? 우리는 사물이 그렇게 단순하지 않다는 것을 알게 될 것입니다. 6 자유도 포즈와 이것의 표현 방법 및 최적화 방법은 세 번째 및 네 번째 강의의 주요 내용이 될 것입니다. 이어서, Visual SLAM에서 관측 방정식이 어떻게 매개 변 수화되는지 설명합니다. 즉, 3차원 공간의 랜드 마크 포인트가 어떻게 2차원 사진에 투영되는지에 대해서는 5 장에서 다룰 카메라 이미징 모델에 대한 설명이 필요합니다. 마지막으로, 우리가 이 정보를 알면 위의 방정식을 어떻게 풀 수 있을까요? 이를 위해서는 6 번째 강의의 내용인 비선형 최적화에 대한 지식이 필요합니다.

  이 내용은 이 책의 수학적 지식의 일부입니다. 그들을 위한 지식 토대를 마련한 후, Visual odometry, Backend optimization 등에 대한 보다 자세한 지식을 논의할 수 있습니다. 이 장에서의 강의 내용이 이 책의 요약을 구성한다는 것을 알 수 있습니다. 위의 개념을 잘 이해하지 못하면 다시 돌아가서 다시 읽을 수 있습니다. 이제 우리는 프로그래밍을 시작할 것입니다!

2.5 연습 : 프로그래밍 기초

2.5.1 Linux 운영 체제 설치

  마지막으로, 실제 코드로 연습을 해보도록 하겠습니다! 준비가 되어 있습니까? 이 책의 실습을 완료하려면 컴퓨터를 준비해야 합니다. 노트북이나 데스크톱 컴퓨터를 사용할 수 있습니다. 물론 운영 체제를 설치하고 실험해야 하기 때문에 개인 컴퓨터를 사용하는 것이 가장 좋습니다.

  우리의 프로그램은 주로 Linux의 C ++ 프로그램에 중점을 둘 것입니다. 우리는 실험 중에 많은 오픈 소스 라이브러리를 사용합니다. 우리는 당신이 이미 소프트웨어의 설치 방법을 이해하기 위한 기본적인 명령을 사용하는 것을 포함하여, 당신이 이미 리눅스의 기초를 가지고 있다고 생각하겠습니다. 물론, 당신은 리눅스에서 C ++ 프로그램을 개발하는 법을 아직 알지 못합니다. 이것에 대해서는 아래에서부터 자세히 설명할 것입니다.

  이 책에 필요한 실험 환경부터 시작해 보겠습니다. 초보자를 위한 책으로 우분투를 개발 환경으로 사용합니다. Ubuntu와 그 파생물은 주요 Linux 배포판에서 항상 사용자 친화적입니다. 우분투는 오픈 소스 운영체제이며 시스템 및 소프트웨어는 공식 웹 사이트 (http://ubuntu.com)에서 무료로 다운로드할 수 있으며 설치 방법에 대한 자세한 지침을 제공합니다. 동시에 Tsinghua University, China Science and Technology University 및 중국의 다른 주요 대학에서도 Ubuntu 소프트웨어 미러를 제공하여 소프트웨어 설치가 매우 편리해졌습니다 (아마도 해당 국가에 미러 웹 사이트가 있을 것입니다).

  이 책의 첫 번째 버전은 Ubuntu 14.04를 기본 개발 환경으로 사용합니다. 두 번째 버전에서는 추후 연구를 위해 기본 버전을 최신 Ubuntu 18.04 (그림 2-11)로 업데이트했습니다. 스타일을 변경하려면 Ubuntu Kylin, Debian, Deepin 및 Linux Mint도 좋은 선택입니다. 책의 모든 코드가 Ubuntu 18.04에서 잘 테스트되었음을 약속하지만 다른 배포판을 선택하면 사소한 문제가 발생할지 확실하지 않습니다. 사소한 문제를 해결하는 데 약간의 시간을 투자해야 할 수도 있습니다 (하지만 스스로 연습할 기회로 삼을 수도 있습니다). 일반적으로 다양한 라이브러리에 대한 Ubuntu의 지원은 비교적 완전하고 풍부합니다. 사용하는 Linux 배포를 제한하지는 않지만 설명에서는 Ubuntu 18.04를 예로 사용하고 주로 Ubuntu 명령 (예 : apt-get)을 사용합니다. 따라서 다른 버전의 Ubuntu에서는 아래에 명백한 차이점이 없습니다. 일반적으로 Linux 간의 프로그램 마이그레이션은 그리 어렵지 않습니다. 그러나 이 책의 프로그램을 Windows 또는 OS X에서 사용하려면 포팅 경험이 있어야 합니다.

그림 2-11 : 가상 머신의 Ubuntu 18.04.

  이제 PC에 Ubuntu 18.04가 설치되어 있다고 가정합니다. Ubuntu 설치와 관련하여 인터넷에서 많은 자습서를 찾을 수 있습니다. 여기서는 건너뛰겠습니다. 가장 쉬운 방법은 가상 머신을 사용하는 것입니다 (그림 2-11 참조). 하지만 많은 메모리 (우리 경험은 4GB 이상)와 CPU가 원활하게 작동해야 합니다. 더 빠른 듀얼 부팅 시스템을 설치할 수도 있지만 부팅 디스크로 빈 USB 플래시 드라이브가 필요합니다. 또한 외부 하드웨어에 대한 가상 컴퓨터 소프트웨어 지원은 종종 충분하지 않습니다. 실제 센서 (카메라, Kinect 등)를 사용하려면 듀얼 부팅 시스템을 사용하여 Linux를 설치하는 것이 좋습니다. 

  이제, 독자가 가상 ​​머신 또는 듀얼 부팅 시스템을 사용하여 Ubuntu를 성공적으로 설치했다고 가정합니다. 우분투에 익숙하지 않다면 다양한 소프트웨어를 사용해보고 인터페이스와 상호 작용을 경험하십시오. 특히 이 책에서 리눅스를 사용하여 SLAM을 배우므로 SLAM을 배우는 데 시간을 투자할 것입니다.

  자 이제 디렉터리를 선택하고 이 책의 SLAM 프로그램에 대한 코드를 넣어 봅시다. 예를 들어 홈 디렉토리 (/home)의 slambook2 경로 아래에 코드를 넣을 수 있습니다. 앞으로 이 디렉토리를 code root 디렉터리라고 부릅니다. 동시에 다른 디렉터리를 선택하고 이 책의 코드를 복사하면 실험 중에 언제든지 비교할 수 있습니다. 이 책의 코드는 챕터로 나뉩니다. 예를 들어, 이 장의 코드는 slambook/ch2 아래에 있고 다음 장의 코드는 slambook2/ch3에 있습니다. 이제 slambook2/ch2 디렉터리로 이동하십시오 (새 폴더를 만들고 폴더 이름을 입력해야 합니다).

2.5.2 Hello SLAM

  많은 컴퓨터 책처럼, HelloSLAM 프로그램을 작성해 봅시다. 그러나 이것을 하기 전에 프로그램이 무엇 인지에 대해 이야기해 봅시다. 

  Linux에서 프로그램은 실행 권한이 있는 파일입니다. 스크립트 또는 바이너리 파일 일 수 있지만 접미어 이름은 제한하지 않습니다 (Windows는 이와 달리 exe 파일로 지정해야 함). cd, ls 등과 같이 일반적으로 사용되는 명령은 /bin 디렉터리에 있는 실행 파일입니다. 다른 곳에서 실행 가능한 프로그램의 경우 실행 권한이 있는 한, 터미널에 프로그램 이름을 입력하면 실행됩니다. C++로 프로그래밍할 때 먼저 다음과 같이 텍스트 파일을 작성합니다.

  그런 다음 컴파일러라는 프로그램을 사용하여이 텍스트 파일을 실행 가능한 프로그램으로 변환합니다. 분명히 이것은 hello slam 텍스트를 인쇄하는 매우 간단한 프로그램입니다. 쉽게 이해할 수 있어야 하므로 여기에 설명이 없으면 C++의 기본 사항을 살펴보세요. 이 프로그램은 화면에 문자열을 출력합니다. gedit (또는 이전 튜토리얼에서 vim을 배운 경우 vim)와 같은 텍스트 편집기를 사용하고 코드를 입력하고 위에 나열된 경로에 저장할 수 있습니다. 이제 컴파일러 g++ (g++는 C++ 컴파일러)를 사용하여 실행 파일로 컴파일합니다. 다음과 같이 입력하세요.

  컴파일이 잘 진행되었으면 터미널에 아무런 출력이 없어야 합니다. 컴퓨터에 "명령을 찾을 수 없습니다."라는 오류 메시지가 표시되면 g ++가 아직 설치되지 않았으므로 다음을 사용하십시오.

 

다른 오류가 있으면 방금 입력 한 프로그램이 올바른지 다시 확인하십시오.

  이제 이 컴파일 명령은 helloSLAM.cpp라는 텍스트 파일을 실행 가능한 프로그램으로 컴파일합니다. 현재 디렉터리를 검사할 때 추가 a.out 파일을 발견할 수 있으며 실행 권한이 있습니다 (터미널의 색상이 다릅니다). ./a.out을 입력하여이 프로그램을 실행할 수 있습니다.

  우리가 예상한 대로 이 프로그램은 "Hello SLAM!"을 출력하여 올바르게 실행되고 있음을 알려줍니다.

  이전에 우리가 한 일을 한번 살펴봅시다. 이 예제에서는 편집기를 사용하여 helloSLAM.cpp의 소스 코드를 입력 한 다음 g ++ 컴파일러로 컴파일하여 실행 파일을 가져왔습니다. g++은 기본적으로 소스 파일 이름이 a.out 인 프로그램으로 컴파일됩니다. 원하는 경우 이 출력의 파일 이름을 지정할 수도 있습니다. 이것은 매우 간단한 예입니다. 우리는 독자에게 간단한 예제를 살펴보기 위해 거의 모든 중간 단계를 생략 한 기본 매개 변수를 사용했습니다. 다음으로 아래에서는 CMake를 사용하여 이 프로그램을 컴파일합니다.

2.5.3 CMake 사용하기

  이론적으로 모든 C++ 프로그램은 g ++로 컴파일할 수 있습니다. 그러나 프로그램 크기가 커지면 프로젝트에 폴더와 소스 파일이 많이 있을 수 있으며 컴파일된 명령은 더 길어질 수 있습니다. 일반적으로 작은 C++ 프로젝트에는 12 개가 넘는 클래스가 포함되어 있으며 클래스 간에 복잡한 종속성이 있습니다. 일부는 실행 파일로 컴파일되고 일부는 라이브러리 파일로 컴파일됩니다. g++ 명령에만 의존한다면 많은 컴파일러 지침을 입력해야 하므로 전체 컴파일 프로세스가 매우 복잡해집니다. 따라서 C++ 프로젝트의 경우 일부 엔지니어링 관리 도구를 사용하는 것이 더 효율적입니다. 역사적으로 엔지니어들은 자동 편집을 위해 makefile을 사용했지만 cmake는 그보다 더 편리합니다. 또한, 나중에 언급되는 대부분의 라이브러리가 cmake를 사용하여 소스 코드를 관리한다는 것을 알 수 있습니다.

  cmake 프로젝트에서 cmake 명령을 사용하여 makefile을 생성 한 다음 make 명령을 사용하여 makefile의 내용을 기반으로 전체 프로젝트를 컴파일합니다. 독자는 makefile이 무엇인지 알지 못하지만, 중요하지는 않습니다. 예제를 통해 배우겠습니다. 위의 helloSLAM.cpp을 예로 들겠습니다. 이번에는 g++를 직접 사용하지 않고 cmake를 사용하여 프로젝트를 만든 다음 컴파일합니다. slambook2/ch2/에 새로운 CMakeLists.txt 파일을 만들고 다음을 입력하십시오 :

   CMakeLists.txt 파일은  디렉터리에 있는 파일로 수행할 작업을 CMake에 알리는 데 사용됩니다. CMakeLists.txt 파일의 내용은 cmake의 문법을 따라야 합니다. 이 예제에서는 프로젝트 이름과 실행 프로그램을 지정하는 가장 기본적인 프로젝트를 보여줍니다. 

  이제 현재 디렉터리 (slambook2/ch2/)에서 cmake를 호출하여 프로젝트를 분석합니다.

  cmake는 컴파일과 관련된 정보를 출력하고 현재 디렉터리에 중간 파일을 생성합니다. 가장 중요한 것은 makefile 입니다. makefile은 자동으로 생성되기 때문에 수정할 필요가 없습니다. 이제 make 명령어로 프로젝트를 컴파일해봅시다.

 

컴파일 진행 상황이 출력됩니다. 컴파일이 성공하면 CMakeLists.txt에 선언된 실행 가능한 프로그램 helloSLAM이 생성됩니다. 그것을 실행해봅시다.

  소스 코드를 수정하지 않았으므로 결과는 이전과 같습니다. 독자는 이 cmake 방법과 g ++을 사용한 방법과의 차이점에 대해 생각해보아야 합니다. 이번에는 cmake-make 프로세스를 사용했습니다. cmake 프로세스는 프로젝트 파일 간의 관계를 처리하고 make 프로세스는 실제로 프로그램을 컴파일하기 위해 g++를 호출합니다. 이 cmake-make 프로세스를 호출함으로써 우리는 프로젝트를 잘 관리할 수 있습니다. g++ 명령 문자열 입력에서 비교적 직관적인 여러 CMakeLists.txt 파일 유지 관리에 이르기까지 전체 프로젝트 유지 관리의 어려움을 크게 줄일 수 있습니다. 예를 들어, 실행 파일을 추가하려면 CMakeLists.txt에 "add_executable"행을 추가하면 되고 이후 단계는 변경되지 않습니다. Cmake는 일련의 g++ 명령을 입력할 필요 없이 코드 의존성을 해결하는 데 도움이 될 것입니다.

  이 과정에서 불만을 갖게 하는 유일한 이유가 있다면 cmake가 생성 한 중간 파일이 여전히 코드 파일에 있다는 것입니다. 나중에 우리가 코드를 공개하고자 할 때의 중간 파일을 함께 게시하고 싶지는 않을 것입니다. 현재로서는 하나씩 삭제해야 하므로 매우 불편합니다. 더 좋은 방법은 중간 디렉터리에 이러한 중간 파일을 넣는 것입니다. 컴파일이 완료되면 중간 디렉터리를 삭제하십시오. 따라서 cmake 프로젝트를 컴파일하는 가장 일반적인 방법은 다음과 같습니다.

  새로운 중간 폴더 "build"를 만든 다음 build 폴더로 가서 "cmake .." 명령을 사용하여 코드가 있는 폴더 인 이전 폴더를 컴파일합니다. 이렇게 하면 cmake가 생성 한 중간 파일이 소스 코드와 별도로 build 폴더에 생성됩니다. 소스 코드를 공개할 때 build 폴더만 삭제하면 됩니다. 이런 식으로 ch2의 코드를 컴파일 한 다음 생성된 실행 파일을 호출하십시오 (마지막 섹션에서 생성 된 중간 파일을 삭제하는 것을 잊지 마십시오).

2.5.4 라이브러리 사용하기

  C++ 프로젝트에서 모든 코드가 실행 파일로 컴파일되는 것은 아닙니다. main 함수가 있는 실행 파일만 실행 가능 프로그램을 생성합니다. 다른 코드의 경우, 다른 프로그램이 호출할 수 있도록 한 패키지에 담기를 원합니다. 이것을 라이브러리라고 부릅니다.

  라이브러리는 종종 많은 알고리즘과 프로그램을 모아 놓은 것으로 우리는 나중에 연습할 때 많은 라이브러리에 노출될 것입니다. 예를 들어, OpenCV 라이브러리는 많은 컴퓨터 비전 관련 알고리즘을 제공하고 Eigen 라이브러리는 행렬 대수에 대한 계산을 제공합니다. 따라서 cmake를 사용하여 라이브러리를 생성하고 라이브러리의 함수를 사용하는 방법을 배워야 합니다. 이제 libHelloSLAM.cpp 파일을 작성해 보겠습니다.

  이 라이브러리는 이 함수를 호출하여 메시지를 출력하는 printHello 함수를 제공합니다. 그러나 이 라이브러리는 아래와 같은 주요 기능이 없습니다. CMakeLists.txt에 문장을 추가합시다 :

 이 명령은 cmake에게 이 파일을 "hello"라 불리는 라이브러리로 컴파일하려고 한다고 전합니다. 그런 다음 아까와 같이 cmake를 사용하여 전체 프로젝트를 컴파일합니다.

  이때 우리가 선언 한 라이브러리 인 build 폴더에 “libhello.a”파일이 생성됩니다. 

  Linux에서 라이브러리 파일은 정적 라이브러리와 동적 라이브러리로 구분됩니다. 정적 라이브러리에는 .a 확장자가 있고 동적 라이브러리에는 .so로 끝납니다. 모든 라이브러리는 패키지 된 함수의 모음입니다. 차이점은 정적 라이브러리는 호출될 때마다 복사본을 생성하지만 동적 라이브러리는 복사본을 하나만 가지므로 공간이 절약된다는 것입니다. 정적 라이브러리 대신 동적 라이브러리를 생성하려면 다음을 사용하십시오.

  동적 라이브러리로 컴파일할 수 있습니다. 현재 얻은 파일은 libhello_shared.so입니다.

  라이브러리 파일은 컴파일된 바이너리 기능이 있는 압축 패키지입니다. 그러나 .a 또는 .so 라이브러리 파일만으로는 함수의 기능 및 호출 형식을 알 수 없습니다. 다른 사람 (또는 그 자신)이 이 라이브러리를 사용하려면, 라이브러리에 무엇이 있는지를 나타내는 헤더 파일을 제공해야 합니다. 따라서 라이브러리 사용자는 헤더 파일과 라이브러리 파일을 가져오는 동안 라이브러리를 호출할 수 있습니다. libhello 헤더 파일을 작성해 보겠습니다.

  이런 식으로 이 파일과 방금 컴파일 한 라이브러리 파일에 따라 printHello 함수를 사용할 수 있습니다. 마지막으로 다음과 같은 간단한 함수를 호출하는 실행 프로그램을 작성합니다.

그런 다음 CMakeLists.txt에서 실행 파일에 대한 빌드 명령을 추가하고 방금 사용한 라이브러리를 링크해봅시다.

  이 두 문장으로, useHello 프로그램은 hello_shared 라이브러리에서 코드를 성공적으로 사용할 수 있습니다. 이 작은 예제는 라이브러리를 생성하고 호출하는 방법을 보여줍니다. 다른 사람들이 제공한 라이브러리의 경우에도 같은 방법으로 호출하여 자신의 프로그램에 통합할 수 있습니다.

  이미 설명된 기능 외에도 cmake에는 더 많은 구문과 옵션이 있습니다. 물론 여기에 모두 나열할 수는 없습니다. 사실 cmake는 변수와 조건부 제어문이 있는 일반 프로그래밍 언어와 매우 유사하므로 프로그래밍 학습처럼 cmake를 배울 수 있습니다. 연습 문제에는 관심 있는 독자가 읽을 수 있는 cmake에 대한 몇 가지 읽기 자료가 포함되어 있습니다. 이제 이전에 수행한 작업에 대해 한번 살펴봅시다.

 

1. 먼저 프로그램 코드는 헤더 파일과 소스 파일로 구성됩니다. 

 

2. main 함수가 있는 소스 파일은 실행 가능한 프로그램으로 컴파일되고 다른 것은 라이브러리 파일로 컴파일됩니다.

 

3. 실행 파일이 라이브러리 파일의 함수를 호출하려면 함수 형식을 이해하기 위해 라이브러리의 헤더 파일을 참조해야 합니다. 또한 실행 파일을 라이브러리 파일에 연결해야 합니다.

 

  이 단계는 간단하고 명확해야 하지만 실제 작업에서 몇 가지 문제가 발생할 수 있습니다. 예를 들어, 라이브러리의 함수가 코드에서 참조되지만 프로그램을 라이브러리에 링크하는 것을 잊은 경우 어떻게 됩니까? CMakeLists.txt의 링크를 제거해보십시오. cmake의 오류 메시지를 읽을 수 있습니까?

2.5.5 IDE 사용

  마지막으로 통합 개발 환경 (IDE)을 사용하는 방법에 대해 이야기해 보겠습니다. 이전의 프로그래밍은 간단한 텍스트 편집기로 수행할 수 있습니다. 그러나 각 함수의 선언 및 구현을 쿼리 하려면 파일 사이를 이동해야 할 수도 있습니다. IDE는 점프, 자동완성, 중단 점 디버깅 등과 같은 많은 편리한 기능을 개발자에게 제공합니다. 따라서 독자는 개발 용 IDE를 선택하는 것이 좋습니다.

  Linux에는 여러 종류의 IDE가 있습니다. 최고의 IDE (Windows의 Visual Studio를 의미)와는 여전히 약간의 차이가 있지만 Linux에는 Eclipse, Qt Creator, Code :: Blocks, CLion, Visual Studio Code 등과 같은 여러 C IDE가 있습니다. 다시 말하지만 독자에게 특정 IDE를 사용하도록 강요하지 않고 조언만 제공합니다. 우리는 KDevelop과 CLion을 사용하고 있습니다 (그림 2-12 및 그림 2-15 참조). KDevelop은 Ubuntu의 소프트웨어 저장소에 있는 무료 소프트웨어입니다. 즉, apt-get으로 설치할 수 있습니다. CLion은 유료 소프트웨어이지만 처음 1 년 동안 무료로 사용할 수 있습니다. 둘 다 좋은 C++ 개발 환경이며 장점은 다음과 같습니다.

 

1. 기본적으로 CMake 프로젝트를 지원합니다.

 

2. C ++ (C++11 표준 포함)에 대한 지원 향상. 강조 표시, 점프 및 함수 자동완성 기능이 있습니다.

 

3. 개별 파일과 디렉터리 트리를 쉽게 볼 수 있습니다.

 

4. 원 클릭 컴파일, 중단 점 디버깅 및 기타 기능.

 

그림 2-12 : Ubuntu의 Kdevelop.

아래에서 KDevelop과 CLion을 소개하도록 하겠습니다.

KDE 사용하기

  기본적으로 Kdevelop는 cmake 프로젝트를 지원합니다. 이렇게 하려면 터미널에서 CMakeLists.txt를 만든 후 KDevelop에서 "Project-Open / Import Project"를 사용하여 CMakeLists.txt를 열어야 합니다. 소프트웨어는 몇 가지 내용을 물어보고, 기본적으로 cmake를 호출하고 명령을 내리는 데 도움이 되는 build 폴더를 만듭니다. 바로 가기 F8을 입력하면 자동으로 수행할 수 있습니다. 컴파일 정보는 그림 2-12에 나와 있습니다.

  필자는 IDE에 대한 자세한 설명을 하기보다는 독자들이 자신에게 맞는 IDE를 찾기 바랍니다. Windows를 사용하는 경우 Visual C ++ 또는 Visual Studio와 유사한 인터페이스를 사용할 수 있습니다. KDevelop를 사용하여 이전 프로젝트를 열고 컴파일하여 어떤 정보가 출력되는지 확인하십시오. 터미널을 여는 것보다 더 편리할 것입니다.

  다음으로 IDE에서 디버그 하는 방법을 보여 드리겠습니다. Windows에서 프로그래밍하는 학생은 Visual Studio에서 중단 점 디버깅에 대한 경험이 있습니다. 그러나 Linux에서 기본 디버깅 도구 인 gdb는 텍스트 인터페이스만 제공하므로 초보자에게는 그리 편리하지 않습니다. 일부 IDE는 중단 점 디버깅을 제공합니다 (맨 아래의 계층은 여전히 gdb임). KDevelop도 그중 하나입니다. KDevelop의 중단 점 디버깅 기능을 사용하려면 다음을 수행해야 합니다.

 

1. CMakeLists.txt에서 프로젝트를 디버그 컴파일 모드로 설정하고 최적화 옵션을 사용하지 않습니다 (기본적으로 사용되지 않음).

 

2. 실행하려는 프로그램을 KDevelop에 알려주십시오. 매개 변수가 있는 경우 매개 변수와 작업 디렉터리도 구성하십시오.

 

3. 중단 점 디버깅 인터페이스를 입력하면 단계별로 중간 변수의 값을 볼 수 있습니다. 

 

  첫 번째 단계에서는 CMakeLists.txt에 다음 명령을 추가하여 컴파일 모드를 설정합니다.

  Cmake에는 컴파일 과정에 대한 보다 세밀한 제어를 제공하는 컴파일 관련 내부 변수가 있습니다. 컴파일 유형에는 일반적으로 디버깅을 위한 디버그 모드와 게시를 위한 릴리스 모드가 있습니다. 디버그 모드에서는 프로그램 실행 속도가 느리지만 중단 점 디버깅을 수행할 수 있습니다. 릴리스 모드는 빠르지만 디버깅 정보는 없습니다. 프로그램을 디버그 모드로 설정하여 중단점을 배치할 수 있습니다. 다음으로 KDevelop에 어떤 프로그램을 시작할지 알려주십시오.

  두 번째 단계에서는 "Run-Configure Launcher"를 열고 왼쪽의 "Add New-Application"을 클릭합니다. 이 단계에서 우리는 KDevelop에게 어떤 프로그램을 시작할 것인지 알려줄 수 있습니다. 그림 2-13에서 볼 수 있듯이 cmake (즉, add_executable 지시문을 사용하여 빌드 한 실행 파일)에 대한 프로젝트 대상을 직접 선택하거나 직접 이진 파일을 가리킬 수 있습니다. 저는 두 번째 방법을 사용하는 것이 추천하며, 제 경험상 이 방법은 문제가 적습니다.

 

그림 2-13 : Config launcher. 여기에서 시작 대상을 선택하고 매개 변수를 설정할 수 있습니다.

  두 번째 열에서는 프로그램의 실행 매개 변수와 작업 디렉터리를 설정할 수 있습니다. 때때로 우리의 프로그램은 main 함수에 인수로 전달되는 런타임 매개 변수를 가지고 있습니다. 파라미터가 필요하지 않은 경우 작업 디렉터리와 마찬가지로 공백으로 두십시오. 이 두 항목을 구성한 후 "확인"버튼을 클릭하여 구성 결과를 저장할 수 있습니다.

  이 단계에서는 application launcher를 구성했습니다. "Execute"버튼을 클릭하여 프로그램을 직접 시작하거나 "Debug"버튼을 클릭하여 각 응용 프로그램에 대해 디버그 할 수 있습니다. 독자는 "Execute"버튼을 클릭하여 출력 결과를 볼 수 있습니다. 이 프로그램을 디버깅하려면 "printHello"줄의 왼쪽을 클릭하고 중단 점을 추가합니다. 그런 다음“Debug”버튼을 클릭하면 프로그램은 그림 2-14와 같이 중단 점에서 대기합니다.

그림 2-14 : 디버그 인터페이스.

  디버깅할 때 KDevelop은 디버그 모드로 전환되고 인터페이스가 약간 변경됩니다. 중단 점에서 단일 단계 작동 (F10 키), 단일 단계 후속 작업 (F11 키) 및 단일 단계 점프 (F12 키) 기능으로 프로그램의 작동을 제어할 수 있습니다. 동시에 왼쪽의 인터페이스를 클릭하여 로컬 변수의 값을 볼 수 있습니다. 또는 "Stop"버튼을 선택하여 디버깅을 종료합니다. 디버깅 후 KDevelop은 일반 개발 인터페이스로 돌아갑니다.

  이제 독자는 중단 점 디버깅의 전체 프로세스에 익숙해져야 합니다. 앞으로 프로그램의 실행 단계에서 오류가 발생하여 프로그램이 중단되는 경우 중단 점 디버깅을 사용하여 오류의 위치를 확인한 다음 오류를 수정할 수 있어야 합니다. 

CLion 사용하기

  CLion은 KDevelop보다 완벽하지만 사용자 계정이 필요하며 호스트의 메모리 / CPU 요구 사항이 더 높습니다. CLion에서는 CMakeLists.txt를 열거나 디렉터리를 지정할 수도 있습니다. CLion이 cmake-make 프로세스를 완료합니다. 실행 중인 인터페이스는 그림 2-15에 나와 있습니다.

  마찬가지로 CLion을 연 후 인터페이스의 오른쪽 상단에서 실행하거나 디버깅할 프로그램을 선택하고 시작 매개 변수와 작업 디렉터리를 조정할 수 있습니다. 중단 점 디버깅 모드를 시작하려면이 열에서 작은 딱정벌레 버튼을 클릭합니다. CLion에는 클래스 자동 생성, 함수 변경, 코딩 스타일 자동 조정과 같은 몇 가지 편리한 기능도 있습니다.

  좋습니다. IDE의 사용법에 이미 익숙하다면 두 번째 장은 여기서 마무리하겠습니다. 다음 연습 섹션에서는 새 빌드 폴더 만들기, cmake 호출 및 프로그램 컴파일 명령 만들기와 같은 내용들은 반복하여 소개하지 않을 것입니다. 독자들은 이 간단한 단계를 마스터해야 한다고 생각합니다. 마찬가지로 이 책에 사용된 대부분의 다른 오픈소스 라이브러리는 cmake 프로젝트이므로 이와 같은 컴파일 프로세스에 계속 익숙해질 것입니다. 

 

연습문제

1. * [8, 15–18] 등과 같은 SLAM의 리뷰 문헌을 읽어보십시오. SLAM에 대한이 논문과 이 책의 유사점과 차이점은 무엇입니까?
 
2. g++ 명령의 매개 변수는 무엇입니까? 생성된 프로그램 파일 이름을 변경하려면 g++을 어떻게 호출해야 합니까?
 
4. build 폴더를 사용하여 cmake 프로젝트를 컴파일하고 KDevelop에서 시도하십시오.
 
4. 의도적으로 코드에 구문 오류를 추가하여 빌드에서 생성되는 정보를 확인하십시오. g++의 오류를 읽을 수 있습니까?
 
5. 라이브러리를 실행 파일에 링크하는 것을 잊은 경우 컴파일러에서 어떤 오류를 보고합니까? 어떤 종류의 에러가 보고되나요?
 
6. * cmake의 다른 구문에 대해 배우려면 "cmake Practice"를 읽으십시오.
 
7. * hello SLAM를 개선하여 작은 라이브러리로 만들고 로컬 하드 드라이브에 설치해봅시다. 그런 다음 새 프로젝트를 만들고 find_package를 사용하여 라이브러리를 찾은 다음 호출합니다.
 
8. * https://github.com/TheErk/CMake-tutorial 를 참고하여 CMake에 대해서 자세히 살펴봅시다.
 
9. Kdevelop의 공식 웹 사이트를 찾아서 다른 기능이 있는지 확인하십시오. 그것을 사용하고 있습니까?
 
10. 지난 강의에서 vim을 배웠다면 KDevelop/CLion의 vim 편집 기능을 사용해보십시오.