이번 포스트는 Slamtec사에서 판매 중인 RPLIDAR에 대해 다뤄볼 것입니다.
시리즈 별로 몇 가지가 있는데, 이 중 A1과 A2를 사용하는 방식에 대해 설명해 보도록 하겠습니다.
우선, LiDAR에 대해 간단히 정리해보겠습니다.
LiDAR는 Light Detection And Ranging를 의미합니다. 모터를 회전시키면서 레이저 펄스를 출력하고 이 레이저가 다시 돌아오는 시간을 측정하여 스캔하는 기술이 적용된 센서를 LiDAR라고 합니다.
보통 RADAR(레이더)와 혼동되는 경우가 많습니다. 저 또한 잘 모를 때는 같은 것인 줄 알았습니다ㅎ
레이더와 라이다의 원리 자체는 같습니다. 어떠한 것을 출력하고 이 출력이 다시 반사되어 돌아오는 시간 차이를 계산해서 Object의 위치, 크기, 모양을 판독한다는 것이니까요. 여기서 차이점은 RADAR는 안테나에서 출력되는 전파를 사용하는 것이고 LIDAR는 광원인 레이저를 사용한다는 것입니다. 실제로는 이 둘을 병행해서 사용하는 경우가 많다고 합니다.
LiDAR는 RADAR에 비해 왜곡이 발생될 가능성이 낮고 정밀도가 높습니다. 오차범위가 mm단위이고 높은 수평 방위각 때문에 작은 물체를 감지하는 부분에서 RADAR에 비해 더 뛰어납니다. 그러나 출력을 높이기 어려워 탐지 범위가 RADAR에 비해 작습니다. 탐지 범위를 넓히기 위해 모터를 이용해 회전시키는 방식 등과 같은 추가적인 방법들이 필요한데, 이 경우 수명이 짧아지고 잦은 고장이 발생될 위험이 높다는 특징이 있습니다. 또한 광원을 생성하고 모터를 구동시키는 등 소비 전력이 높은 동작을 많이 취한다는 것과 아직까지는 단가가 높다는 것이 LiDAR의 단점이라고 볼 수 있습니다.
보통 많이 사용되는 제품은 HOKUYO사의 UST-10LX 정도일 것입니다. 이 제품의 경우 대략 250만 원 정도 합니다...ㅎㄷㄷ 때문에 일반인이나 개인이 사용하기에는 좀... 많은 고민과 결심이 필요합니다ㅎ
최근 몇 년 전부터, 중국산 LiDAR 센서를 비교적 저렴한 가격으로 사용해 볼 수 있습니다. 이러한 중국산 저가 LIDAR를 한 번 사용해 볼 것인데, 많은 중국산 센서들 중, SLAMTEC이라는 중국 회사가 판매하고 있는 A 시리즈 라이다는 조금은 합리적인(?) 가격으로 꽤 괜찮은 제품을 판매하고 있습니다. 이번 포스트는 이 제품을 사용해 어떠한 프로그램을 개발하는 과정을 수행해 볼 것입니다.
그러면, 이제 본격적으로 구체적인 LiDAR 사용방법을 다뤄보도록 하겠습니다.
RPLIDAR A1
SLAMTEC사에서 판매하는 가장 기본적인 LiDAR 제품입니다. 가격은 대략 15만 원 정도 합니다.
이 제품의 경우 실험용, 초기 개발용으로 많이 쓰이는 것 같습니다. 그도 그럴 것이 외관이 "나는 센서라네~"라고 말하고 있기에...ㅎ 외관과 비슷하게 PC와 같은 프로세서에 연결할 수 있는 단자를 LOW 한 HW 형태로 제공합니다. 때문에 아두이노나 라즈베리파이 같은 프로세서에 연결하기 편합니다.
PC에 USB 형태로 연결해서 사용할 수 있긴 하지만, 이번에 저는 다음과 같이 Arduino에 연결해 사용해 볼 것입니다.
연결이 완료되었다면 우선, RPLIDAR와 관련된 Libray 파일을 포함시켜 줍니다.
그리고 다음과 같은 코드를 이용해 LiDAR Data를 받아옵니다.
#include <RPLidar.h>
#define RPLIDAR_MOTOR 3
RPLidar lidar;
bool transmit = false;
byte incomingByte;
void setup() {
// bind the RPLIDAR driver to the arduino hardware serial
lidar.begin(Serial1);
// set pin modes
pinMode(RPLIDAR_MOTOR, OUTPUT);
// send to pc
Serial.begin(115200);
while (!Serial) { ; }
}
void loop() {
if (IS_OK(lidar.waitPoint())) {
float distance = lidar.getCurrentPoint().distance; // mm unit
float angle = lidar.getCurrentPoint().angle; // degree
bool startBit = lidar.getCurrentPoint().startBit; // whether this point is belong to a new scan
byte quality = lidar.getCurrentPoint().quality; // quality of the current measurement
if (Serial.available() > 0) {
incomingByte = Serial.read();
transmit = !transmit;
}
Serial.println(distance);
}
else {
// stop the rplidar motor
analogWrite(RPLIDAR_MOTOR, 0);
// try to detect RPLIDAR...
rplidar_response_device_info_t info;
// HW detected
if (IS_OK(lidar.getDeviceInfo(info, 100))) {
lidar.startScan();
analogWrite(RPLIDAR_MOTOR, 255);
delay(1000);
}
}
}
아주 간단한 코드입니다. LiDAR를 Arduino에 연결하여 Serial 형태로 Data 값을 받아옵니다. 모터가 360도 회전하면서 레이저를 분사하여 동작하는 센서이므로 Serial 연결이 완료되었다면, 코드로 Motor를 On/Off 하여 센서를 동작시켜야 정상적으로 Data를 측정할 수 있습니다.
최종적으로, 주로 활용할 데이터는 Distance와 Angle, 그리고 Quality 값입니다. 일정 Quality에 부합되는 Distance와 Angle 값만을 사용하여 어떠한 프로그램을 만들면 됩니다.
Arduino 자체에서 어떤 객체가 검출되면 LED를 켰다던지 사운드를 만든다던지 하는 등의 기능을 만들 수 있을 것이며, 더 나아가 공간을 구성하고 이에 따른 물리적 이벤트를 수행하도록 만들 수도 있을 것입니다. 데이터 활용 부분은 따로 다루지는 않겠습니다.
RPLIDAR A2
모델명에서도 알 수 있듯이, A1 제품보다 조금 Spec이 향상된 모델로, 가격은 대략 30만 원 정도 합니다. A1과 큰 차이점은 검출 범위가 4M 정도 늘어났고 제품 형태가 조금은 시판 제품스럽게 바뀌었다는 점입니다. 뭐... 이 이외에는 큰 차이점은 없다고 느껴집니다.ㅎ
이 제품의 경우는 프로세서와의 연결을 USB로 합니다. A1 제품과는 다르게 제품스러운 선을 제공하기에 굳이 Arduino나 Raspberry Pi와 같은 프로세서에 연결하지 않고 바로 PC에 연결해서 사용해 볼 것입니다.
다음과 같은 Library를 사용하여 개발을 진행할 수 있습니다. 보통 Pytho, C++, ROS를 많이 활용하는 것 같습니다.
- Python
- C++
- ROS
위 라이브러리들을 사용하면, 쉽게 LiDAR를 활용한 프로그램 개발을 진행할 수 있습니다. 그러나 저는 Unity에서 LiDAR를 활용할 것이기에 C#에 부합하는 Library를 사용하도록 하겠습니다.
우선, 다음 파일을 포함시켜 줍니다.
이후, 다음과 같은 코드를 통해 RPLIDAR의 Data(= Distance, Angle)를 받아옵니다.
class Program
{
// socket
static Socket client;
static EndPoint remoteEP;
static bool startSig = true;
static void Main(string[] args) {
// socket //////////////////////////////////////////////
IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
remoteEP = (EndPoint)sender;
byte[] _data = Encoding.UTF8.GetBytes("CONNECT" + args[0]);
client.SendTo(_data, _data.Length, SocketFlags.None, serverEP);
Thread socket = new Thread(() => { socketThread(); });
socket.Start();
/////////////////////////////////////////////////////////
String port = loadData(args[0]);
LidarData[] data = new LidarData[720];
RplidarBinding.OnConnect(port);
RplidarBinding.StartMotor();
RplidarBinding.StartScan();
while (startSig) {
var datalen = RplidarBinding.GetData(ref data);
for (var i = 0; i < datalen; i++) { Console.WriteLine($"{data[i].distant} {data[i].theta}"); }
}
}
static void socketThread() {
while(true) {
byte[] data = new byte[1024];
int recv = client.ReceiveFrom(data, ref remoteEP);
string stringData = Encoding.UTF8.GetString(data);
if (stringData.Contains("END") == true) {
RplidarBinding.EndScan();
RplidarBinding.EndMotor();
RplidarBinding.OnDisconnect();
break;
}
}
client.Close();
startSig = false;
}
static private string loadData(string _id) {
Queue<string> comport = new Queue<string>();
// read file
StreamReader sr = new StreamReader(System.Environment.CurrentDirectory + "/RPLIDAR_Parameter/RPLIDAR_Comport" + _id +".txt");
while (sr.Peek() >= 0) comport.Enqueue(sr.ReadLine());
sr.Close();
return comport.Dequeue();
}
}
위 코드의 Flow에 대해 설명하자면, 어떤 외부 프로그램에서 이 프로그램에 UDP를 통해 "CONNECT ID" Message를 보내면 해당하는 ID의 RPLIDAR 센서의 Comport 정보를 TXT File에서 받아와 해당 Comport에 연결된 RPLIDAR를 구동시킵니다. 구동이 되면 Distance와 Angle에 해당하는 Data를 출력하고 이 데이터는 외부 프로그램에서 StreamReader를 이용해 표준 출력 스트림을 읽는 방식으로 Read 할 수 있습니다. 외부 프로그램에서 더 이상 LiDAR를 구동시킬 필요가 없다면 "END" Message를 보내어 RPLIDAR 프로그램을 종료시킵니다.
참고로 StreamReader를 활용하여 Process 간 통신하는 방법에 대한 포스트는 다음과 같습니다.
이와 같이 아주 간단하게 RPLIDAR를 사용할 수 있습니다.
그러면 이제 이러한 LiDAR를 활용해 볼 수 있는 간단한 예시를 수행해 보도록 하겠습니다.
LiDAR의 기본적인 활용 방법
LiDAR를 이용하는 가장 기본적인 방법은 어떠한 공간에 어떠한 객체가 검출되었을 때 이 Position에서 어떠한 Event를 발생시키는 것일 것입니다.
LiDAR가 전달하는 값을 제대로 이용하기 위해서는 센서의 0도 선이 어디인지 파악하는 것이 중요합니다. RPLiDAR A2는 0도 선은 다음과 같습니다.
위와 같은 Line 방향을 고려한 채, LiDAR에서 제공하는 Data는 Distance와 Angle을 이용해 공간에서의 Object의 위치를 계산하는 과정은 다음과 같습니다.
위 이미지에서의 빨간 점이 Object의 위치라고 할 때, 초등학생들도 계산할 수 있을 정도로 아주 간단한 수학 식을 통해 좌표를 측정할 수 있습니다.
만일 LiDAR의 0도 Line을 LiDAR를 설치할 때 정확하게 배치할 수 없다면 Calibration을 수행하는 프로그램을 하나 만들어 설치된 방향을 저장하고 좌표 값을 회전 변환시켜 다음과 같은 계산을 통해 Mapping 해주면 됩니다.
(x, y)를 $\theta$만큼 회전시키면 (x', y')를 얻을 수 있게 됩니다. 이때 $\theta$는 Calibration을 수행할 때 설정해주어야 하는 값입니다.
이와 같은 과정을 통해 평면 좌표에서의 어떠한 Object들의 위치 값을 측정할 수 있으며, 해당 좌표 값을 통해 어떠한 Event를 부여해 줄 수 있을 것입니다. 간단한 수학식으로 구성되었기에 아주 쉽게 프로그램으로 구현할 수 있을 것입니다.
이번 포스트에서는 LiDAR 센서를 다루는 일련의 과정에 대해 다루어보았습니다.
센서 자체를 다루는 것은 그리 어렵지 않기에 쉽게 수행할 수 있을 것입니다. 다만, 이 값을 이용함에 있어서 어떠한 예외 처리를 할지, 어떠한 알고리즘으로 계산을 수행할지 등에 따라 난이도는 달라지겠지요...?
오늘 포스트는 여기서 마무리하도록 하겠습니다.
향후 LiDAR를 이용한 여러 가지 방식에 대해 다룰 기회가 생긴다면 정리해 보도록 하겠습니다.
'Technology > Products, Tools' 카테고리의 다른 글
[GitHub] GitHub를 통한 코드 관리 - 기초 (feat. Git Bash) (0) | 2023.04.13 |
---|---|
[Version Control] SVN, Git, GitHub, GitLab (0) | 2023.04.06 |
[Touch Sensor] Zytronic Zyfilm 사용기 (0) | 2023.02.01 |
[Motion Capture Sensor] 퍼셉션 뉴런과 로코코 스마트 수트 사용기 (0) | 2023.01.26 |
[Dataset] Custom Face Landmark Dataset 생성 방법 (0) | 2023.01.04 |
댓글