std_msgs::PointCloud, std_msgs::PointCloud2

카테고리 없음

2019. 9. 20. 16:54

* 주의 *

 

시작하기에 앞서, 본인은 아직 주니어 소프트웨어 개발자이고, 본 포스팅은 ros wiki의 문서를 참조하여 정리목적으로 게시하는 글이기 때문에 부정확한 내용이 있을 수 있습니다. 너무 맹신하지는 마시고 참고목적으로만 활용하시기 바랍니다.

 

개요

 

Point는 좌표이다. Cloud는 구름이다. Point Cloud는 좌표가 구름처럼 모여있는 자료구조다. Point Cloud Library는 좌표의 모음을 잘 활용할 수 있게끔 도와주는 라이브러리라고 생각하면 된다. PCL의 자료구조에는 크게 세 가지가 있다. ros에서 메세지 타입으로 사용하는 sensor_msgs::PointCloud, sensor_msgs::PointCloud2 두 개와 템플릿 형태로 제공되며 여러가지 편의 메소드가 정의되어 있는 클래스인 pcl::PointCloud<T>이다. PointCloud2는 PointCloud<T>로 변환할 수 있으며 PointCloud는 PointCloud2로 변환할 수 있기 때문에 어떤 패키지에서 PointCloud나 PointCloud2 타입의 메세지를 publish한다면 이를 subscribe하는 노드를 작성하여 PointCloud<T>로 변환한 후에 미리 정의된 편의 메소드들을 사용할 수 있을것이다. 이번 포스팅에서는 PointCloud와 PointCloud2에 대해서만 알아보도록 하자.

 

sensor_msgs/PointCloud

 

sensor_msgs/PointCloud의 정의를 살펴보면 아래와 같다.

std_msgs/Header header
geometry_msgs/Point32[] points
sensor_msgs/ChannelFloat32[] channels

다른 메세지 타입에도 공통으로 들어가는 header를 제외하면, Point와 Channel의 배열을 담고있다고 간략화 할 수 있다.

하나씩 살펴보자.

 

먼저 geometry_msgs/Point32의 정의이다.

float32 x
float32 y
float32 z

Point는 말 그대로 3차원 좌표계 상의 좌표를 의미한다.

 

다음은 sensor_msgs/ChannelFloat32의 정의이다.

string name
float32[] values

 

위 문서에 따르면, ChannelFloat32는 PointCloud 메세지 타입 내의 Point32배열의 각각의 좌표점들과 매칭되며, 해당 점에 대한 부가적인 정보를 나타낸다고 한다.

 

name은 "u", "v", "rgb", "intensity", "distance" 등을 가질 수 있다.

예를 들어 보자. 좌표계상의 각 점에 대한 색상을 표현하려고 한다. 그러면 PointCloud 자료구조 내의 Point32는 좌표계 상의 각 점(x, y, z)을 나타내고, ChannelFloat32내의 name은 "rgb"라고 설정해야 할 것이고, values 배열은 3의 길이를 가지며 해당하는 좌표에서 r, g, b값을 가지게 될 것이다.

 

정리하면 PointCloud 메세지 타입은 좌표계 상의 여러 좌표들과 각 좌표에서의 부가적인 데이터를 가지는 자료구조이다.

 

sensor_msgs/PointCloud2

 

새로 개편된 ros의 PointCloud 메세지 타입이며, 기존의 sensor_msgs/PointCloud가 3차원의 좌표묶음을 나타낸 것과 달리 n차원의 좌표묶음을 나타낼 수 있다. 또한 좌표를 나타내는 자료형으로 float32를 사용했던 것에서 진화하여 int, float, double 등의 primitive 타입을 사용할 수 있다.

 

sensor_msgs/PointCloud2의 정의를 살펴보자.

std_msgs/Header header
uint32 height
uint32 width
sensor_msgs/PointField[] fields
bool is_bigendian
uint32 point_step
uint32 row_step
uint8[] data
bool is_dense

PointCloud2는 data 안에 좌표점의 위치를 넣는다. 그런데 이상하지 않은가 ? data는 uint8타입을 원소로 가지는 배열이며, 적어도 한 점의 x좌표를 표현하기 위해서도 4바이트 크기인 float32가 필요한데 말이다. 아래에서 다루기로 하고 우선 지금은 data 안에 실제 좌표값이 들어간다는 것만 알아두고 넘어가자.

fields는 sensor_msgs/PointCloud의 channels처럼 각 좌표에 대한 부가적인 정보를 가지고 있다. sensor_msgs/PointField의 정의를 살펴보자.

uint8 INT8=1
uint8 UINT8=2
uint8 INT16=3
uint8 UINT16=4
uint8 INT32=5
uint8 UINT32=6
uint8 FLOAT32=7
uint8 FLOAT64=8
string name
uint32 offset
uint8 datatype
uint32 count

name은 필드의 이름을 나타내며, offset은 좌표 배열의 시작지점으로부터의 offset이다. datatype은 1~8까지 위의 자료형에 맞게 설정해 주면 된다. cound는 필드에 몇 개의 요소가 있는지를 의미한다.

 

이쯤에서 왜 '필드'라는 이름을 사용했는지 생각해 볼 필요가 있다. 프로그래머는 각 점에서의 좌표값 뿐만이 아니라 다른 부가적인 정보까지도 한 번에 처리하고 싶어할 것이다. 각각의 점들이 다른 자료형으로 표현되거나, 다른 부가정보를 가질 수도 있고, 이렇게 되면 각 점을 표현하는 구조체의 크기가 달라지기 때문에 메모리 상에서 점과 점 사이에 padding이 생길 수도 있다. 이는 메세지 통신 방식이 거의 전부라고 할 수 있는 ROS에서 통신에 오버헤드를 야기할 수도 있다.

즉, data 안에 좌표값,sensor_msgs/PointCloud의 channels가 가지고 있었던 부가정보 뿐만 아니라 각 점에 대한 offset과 데이터타입까지 포함시킴으로써 이러한 문제점들을 방지하고자 하는것이 아닐까 추측해 본다. 이 모두를 '필드'라고 칭하면서 말이다.