본문 바로가기

FOSCAR-(Autonomous Driving)/대학생 창작 모빌리티 경진대회

[LiDAR팀] 라이다 스터디 Lesson 1

반응형

Lidar 교육은 Udacity에서 올려주는 강의(ls1~4) 및 깃허브 코드로 스터디하는 내용을 정리할거다.

(출처:https://github.com/udacity/SFND_Lidar_Obstacle_Detection/https://www.youtube.com/watch?v=f4bx0tzpBBU)

LESSON1) introduction to Lidar and Point Clouds

레슨 1부터 4의 과정에서 우리는 sensor fusion에 대해서 배울것이고, 이는 다양한 센서에서 받아온 정보들을 결합해 우리 주변의 환경에 대해 정확히 이해하는 과정이다. (주로 라이다와 레이더)

이 강의의 목적은 두가지 센서를 이용해 도로위의 여러 차들을 인지하고, 그것들의 속도와 위치를 파악하는데 있다.

라이다의 높은 해상도와 레이더의 물체의 속도 측정 능력을 결합해서 센서의 성능을 높일 수 있다.

우선, 이번 강의에서는 물체의 위치를 Raw data(날것의 데이터)로부터 얻어내는 과정에 대해서 알아볼 것이다.

라이다는 몇 천개 정도의 레이져 신호를 보냄으로, 높은 해상도의 값들을 줄 수 있다. 이러한 레이저는 물체에 닿고, 부딪혀서 다시 센서로 돌아온다. 센서는 걸린 시간을 바탕으로 물체가 얼마나 떨어져있는지 판별한다. 각 레이저는 적외선 스펙트럼으로, 다양한 각도로(보통 360도 범위) 발사한다. 매우 좋은 센서이지만, 매우 비싸다.

예시로, velodyne HDL 64 lidar을 살펴보자.

velodyne 라이다

라이다는 64개의 층을 가진다.(z축 기준으로 다른 각도의 층)

각각의 층은 360도의 시선을 가지고 있고, 0.08도의 각도 해상도를 가지고있다. 평균적으로 라이다는 초당 10번의 탐색을 진행한다. 120M거리까지 차를 탐지할 수 있고, 길의 파임은 50M까지 탐지할 수 있다.

그러면, 매초당 얼만큼의 점들을 탐색할 수 있을까?(average update rate:10Hz)

(64(layers)*(360/0.08)*10) = 2,880,00개의 점을 탐색할 수 있다.

이제, Point Cloud에 대한 것을 알아보자. Point cloud는 라이다가 반사해서 측정하는 모든 값들의 모임이다.

'3D 공간 상에서 x,y,z 좌표로 정의되는 vertex(정점)들을 이루는 집합체' 라고 한다.

([출처] Point Cloud & Mesh|작성자 중소기업개발자)

라이다에서 수집한 값들은 Point Cloud Data(PCD)에 저장된다. PCD 파일은 데카르트 좌표의 (x,y,z)값들의 배열이다.(빛의 강도 값도 저장)

왼쪽의 그림이 PCD의 예시이다. 다른 빛의 강도는 다른 색으로 구현되고, 가운데의 검정 부분이 라이다 센서가 놓여있는 부분이다.

PCD의 좌표계와 차체의 좌표계는 동일하다. PCD의 x축은 차의 앞면을 향하고 있고, y축은 차의 왼쪽을 향하고 있다, 그리고 z축은 위를 향하고있다.

Q. VLP 64로 스캔할때, 레이저 신호가 방출되고 다시 돌아오는 데 66.7ns가 걸렸다고 하자. 레이저는 x축 기준 -24.8도의 각도로 x축에 평행하게 이동한다. (빛의 속도는 299792458m/s)

그렇다면 레이저가 찍은 포인트의 (x,y,z)의 값을 구해보자.

A. 편도로 걸린 시간은 66.7/2 값이다. 거리는 속도 * 시간이므로, 빛의속도 * (66.7/2) = 10 m.

레이저는 x축과 평행하게만 이동하므로, y 값은 0이다.

x축의 값은 10(거리) * cos(24.8)(각도) 이고, z값은 -10 * sin(24.8) 이다.

따라서 레이저가 찍은 포인트는 (9.08,0,-4,19)이다.

 

다음으로 알아볼 내용은 PCL(library)이다. 여기서는 PCD를 처리해서 장애물들을 발견하는 과정에 대해 공부할 것이다. 모든 코드는 C++ 환경에서 구현할 것이다. PCL은 point clouds에 관해 작업할 수 있는 오픈소스 C++ 라이브러리이다. PCL을 이용하여 값들을 시각화하고, 모양을 rendering 해주고 여러 내장 함수(segmentation,extraction,clustering관련)와 친숙해 질 수 있다.

Rendering이라는 표현이 자주 나오는데

렌더링: '평면인 그림에 형태·위치·조명 등 외부의 정보에 따라 다르게 나타나는 그림자·색상·농도 등을 고려하면서 실감나는 3차원 화상을 만들어내는 과정 또는 그러한 기법을 일컫는다.' 라고 한다.

(출처: https://terms.naver.com/entry.naver?docId=1231713&cid=40942&categoryId=32828)

이제 간단한 실습을 진행해 볼 것이다.

대략적인 설명을 하자면, 글 맨 위에 깃허브 주소를 들어가서 코드를 클론해주면, 실습에 필요한 파일들을 사용할 수 있다. 앞으로의 실습과정에서는 주로 environment.cpp 와 processPointClouds.cpp를 사용할 것인다. environment.cpp에는 메인함수가 포함되어있어 프로그램을 실행가능하게 해준다.

processPointClouds.cpp에는 pcd를 실행하기위한 함수들이 들어있다. 추가적으로, sensors/lidar.h 파일은 라이다를 시뮬레이션 시켜주고 pcd를 생성해준다. render.cpp와 render.h는 물체들을 화면에 렌더링해주기 위한 함수들을 담고있다.

이제 라이다 시뮬레이터를 컴파일 해보자. 먼저 깃허브에 다운받은 코드로 이동해준다

나 같은 경우에는 cd/home/SFND-Lidar-Obstacle-Detection이다. 이동해준 뒤, build라는 새로운 디렉토리를 생성해주고 들어가준다.(mkdir build && cd build). 이후, cmake..해준뒤 make를 쳐줘 target environment 100%가 된다면, 실행 파일이 생성됐을 거다.(environment)

실행파일을 생성해줬다면, ./environment를 통해 실행시켜줄 수 있다. 고속도로가 보이고, 초록차 1대와 파란차 3대가 보인다. 가운데 있는 초록색 차가 내 차고 나머지 차들이 파란색 차이다. 모든 구성 요소들이 PCL을 이용해 렌더링 되었다. (using simple boxes,lines,and colors)

environment.cpp에 pcl viewer가 생성되었다. 이 뷰어는 화면의 모든 물체의 시각화를 조절할 수 있도록 도와준다. initCamera라는 함수가 environment.cpp안에서 사용되는데, initCamera 함수는 창 시각화에서 다양한 각도로 조절할 수 있게 도와준다.(XY,Topdown,Side,FPS의 값들을 통해 구현한다.)

다음으로는, 아까 봤던 시뮬레이터에 라이다를 넣어보자. 처음 해야되는 작업은 라이다를 생성해주는 것이다. 라이다는 src/sensors/lidar,h에 정의되어 있고, environment.cpp파일의 위쪽에 포함된다.

우선, simpleHighway함수에 라이다 객체에 대한 포인터를 instantiate 한다. 라이더 포인터를 힙에 생성해준다. lidar 생성자는 두개의 인수를 가지는데, cars 와 slope of the ground 이다. 라이다 객체는 매우 큰 pcd를 처리하게 되기에 2MB정도만 처리할 수 있는 스택 대신에 힙에 생성하게 된다.(처리속도의 단점이 있긴하다.)

instantiate: 클래스 내의 객체에 대해 특정한 변형을 정의하고, 이름을 붙인 다음, 그것을 물리적인 어떤 장소에 위치시키는 등의 작업을 통해, 인스턴스를 만드는 것을 의미한다.(출처: http://www.terms.co.kr/instance.htm)

그러면 이제, 직접 라이다 객체를 사용해보자. src/sensors/lidar.h를 보면 모든것들이 정의 되어있는 것을 알 수 있다. 특히, 이 헤더파일에는 ray객체가 정의되어있는것을 볼 수 있는데, 라이다는 이를 이용한 ray casting을 통해 주변 환경을 파악하게 된다.(scan 함수내용)

뒤에 나오게 될 실습과정에 lidar.h 내용을 수정할 일이 있는데 그때 한번 자세하게 살펴보자

이제, lidar scan 함수를 불러와서 lidar rays가 어떤 형태로 보여지는 살펴보자.

코드 설명) point cloud를 생성하기 위해서, 라이더 scan() 함수를 라이다객체에 불러오자. 결과값들을 PointCloud pointer객체에 저장할 것이다.

pcl::PointCloud<pcl::PointXYZ>::Ptr > 결과값들을 PointCloud 포인터객체에 저장한다.

PointCloud의 point type은 pcl::PointXYZ 이다. 생성된 PointCloud 포인터로 renderRays함수를 불러온다.

make 후 실행시킨 화면

근데 왜 템플릿을 이용하는 걸까? 우리가 이전 실습에서 라이다 함수를 사용하며 PointCloud 객체와 pointXYZ객체가 생성됐다. 결과적으로는 point clouds에 다양한 타입들이 생기기 때문에 템플렛을 이용한다. (2D,3D,어떤 것들은 색깔과 밀도를 가지는 등등). 일일이 다양한 상황들에서의 개별적인 함수들을 정의하기보다는 템플렛을 사용해서 이 과정을 자동화 할 수 있다. 템플렛을 이용하면, 우리는 함수를 한번만 적어주고 템플렛을 인수처럼 이용해, 포인트 타입을 구체화 시킬 수 있다. 포인터가 템플릿에 의하여 결정을 내리게 되면, typename을 항상 써주게된다.

그 이유는 typename을 안써주게 되면 컴파일러는 코드가 값인지 타입인지에 대한 결정을 내릴수가 없다.

(템플릿에 대한 자세한 내용은 https://modoocode.com/219의 글을 읽어보면 좋을 것 같다)

이제 아까 실습했던 lidar.h 코드를 수정해서, 즉 라이더 변수들을 조정해보는 실습을 해볼것이다.

기존에 실습했던 라이다 코드는 저해상도이고 오직 하나의 광선만이 차에 도달하는 것을 볼 수 있다. 따라서, 이번에는 라이더의 해상도를 높여서 주변의 차들을 정확하게 볼 수 있도록 해주는 것이다.

방법은 numLayers의 값을 3에서 8로 증가시키고/ horizontalLayerIncrement를 pi/6에서 pi/64로 증가시키고/ minDistance를 5로 설정해주고/ noise를 0.2로 설정해준다.

 

왼쪽의 처럼 lidar.h코드를 변환 시켜주면 오른쪽과 같은 환경이 출력된다.

이제 라이더 광선에 관한 생김새와 내용을 살펴봤으니, 실제 point cloud data에 대해서 살펴보자.

renderRays함수 대신 renderPointCloud 함수를 사용하면 된다. 이때, 고속도로 환경을 꺼서, 포인트 클라우드 그 자체의 생김새를 살펴볼 것이다.

추가로, 우리는 noise를 없애고 mindistance를 0으로 해줘서 차의 지붕을 찍는 점들을 무시해 줄 것이다.

(obstacles, 즉 주변 차들의 생김새를 없애는 방법은 renderScene을 false로 설정해주는 것이다)

 

왼쪽에 보이는 코드와 같이, renderRays를 주석처리해주고 renderPointCloud를 적어주면 point cloud data를 관찰할 수 있다.

나는 고속도로 환경과 주변 차들을 그대로 내비두고 rays를 pointcloud형식으로만 바꿔줬다.

Lesson2 실습부터는 고속도로와 주변 차들 생김새 삭제하고 기준 차 지붕에 찍히는 point들 없애주고 시작할 예정이다.

Lesson1 내용은 여기까지다! ^^

 

반응형