카테고리 없음

(라이다/YDLidar) YDLidar-SDK example 코드 오류 발생 시

미친토끼 2025. 3. 27. 08:25

YDLidar를 구입하면, YDLidar-SDK를 우분투에 설치하게 되는데, 이 SDK(software development kit)는 개발자 라이브러리로서 ROS와는 무관하게 사용할 수도 있습니다. ROS2 드라이버도 이 SDK 위에서 돌아가구요.

YDLidar-SDK 안에 tri_test 같은, 실행 파일들이 몇 개 생겨 있는데, 실행해보면 좋습니다. G2, X2 같은 라이다는 Triangle 타입으로, 줄여서 tri라고 부르기도 합니다. 이 회사에서 워낙 많은 타입과 종류의 라이다를 내놓기 때문에, G2, X4 사용자가 실행할 수 있는 실행파일은 두세 개에 불과하지만 그마저도 유의미한 tri_test가 거의 유일해보입니다. tri_test를 실행하면, 몇 가지를 선택해야 하는데,

 

[0] ydlidar /dev/ttyACM1
[1] ydlidar1.1 /dev/ttyUSB1
[2] ydlidar1.2 /dev/ttyUSB0
Please select the lidar port:2
Baudrate:
[0] 115200
[1] 128000
[2] 150000
[3] 153600
[4] 230400
[5] 460800
[6] 512000
Please select the lidar baudrate:0
Whether the Lidar is one-way communication [yes/no]: yes

 

저는  G2, X2 두 개가 꽂혀 있어서 USB0, USB1이 나와 있네요. 라즈베라파이4/우분투 24.04/ROS2 Jazzy 환경입니다.

그 다음에 baudrate를 선택하는데, G2는 230400이고 X2는 115200입니다. 현재는 X2로 테스트 중.

세 번째 질문은 단방향 통신인지, 양방향 통신인지 묻는 건데, X2는 단방향입니다. G2 같은 양방향은 command 입력을 지원하고요, X2 같은 단방향 기종은, 명령으로 세팅을 따로 할 수 없고 기계가 그냥 지가 알아서 메시지를 뿌려줍니다. 개발자 메뉴얼을 보니, X4는 양방향, X4 Pro는 단방향으로 보이네요.

(양방향 G2로 설정할 때는, 단방향이냐 물음에 no로 해야 하고, scan frequency [5-12]: 를 하나 더 묻습니다. 기본은 8이고, 5-12 사이 아무거 넣아도 좋습니다. 12로 넣어보죠)

 

그러면, 빨간색 에러가 보통 한두 가지가 생깁니다. 장치 정보 base plate를 얻을 수 없다고 나오는 것은 괜찮아 보이는데,

health status 정보를 얻을 수 없다고 에러를 내고, 어쩌다 된다고 해도 check sum에러가 무수히 나옵니다. health status와 check sum 관련은 소스 코드를 수정하는 게 건강에 좋습니다. 

YDLidar-SDK/src

안으로 들어가면 소스 파일들이 있습니다.

 

1) CYdLidar.cpp : 1830 라인 (YdLidar 클래스 정의 파일)

checkStatus() 클래스 함수가 있는데, 여기에서 getDeviceHealth(), getDeviceInfo()를 호출하는데 전자를 호출하지 못하도록 주석 처리합니다.

getDeviceHealth();  ==> // getDeviceHealth();

 

2) YDlidarDriver.cpp : 1179 라인

calcuteCheckSum() 함수 안에 에러를 내뱉는 녀석이 있습니다. 이 녀석을 주석 처리합니다.

error("Check Sum 0x%04X != 0x%04X", CheckSumCal, CheckSum);

=> // error("Check Sum 0x%04X != 0x%04X", CheckSumCal, CheckSum);

 

개발자 메뉴얼과 SDK를 들여다보면서 느낀 점은, 얘네들(회사 측)이 너무 많은 라이다 타입과 기종을 내놓느라, 이에 대한 세밀한 서비스가 부족하다는 점입니다. 우리가 주로 테스트하는 타입이 triangle 기종인데, 겨우 테스트 실행 파일 1~2개 정도만 제공하고 있고, G2, X2, X4, X4 Pro 모두 패킷 값이 달라서 G2, X2 코드 포팅을 하는 저조차도 번거로운데 G4, X4... 그리고 다른 타입의 기종에 모두 맞는 옵션을 일일이 제공하는 일은 쉽지 않아 보이지만, 개발자 메뉴얼도 저리 엉성하게 만들 정도로 YDLidar 측이 게으르거나, 적어도 영어 못한다는 핑계로 영어 메뉴얼 작성에 소극적인 점은 있습니다.

 

3) YDLidar-SDK/examples/tri_test.cpp

이 폴더 안에 샘플 코드들이 있습니다.

tri_test.cpp 제일 밑에 보면, 주석 처리된 print 문이 있습니다. 구체적인 포인트 데이터를 출력하는 부분인데요, 이 부분을 주석 해제합니다.

 

4) 다시 컴파일...

build 안에서 cmake .. ; make; sudo make install

하시면 되겠죠.

찜찜하다 싶으시면, 싹 지우고 다시 소스 git clone 해서, 필요한 부분만 수정한 뒤, 컴파일하면 되겠죠.

 

tri_test는 make install 단계에서 이미 PATH 걸린 곳에 설치되어 있기 때문에, 아무 곳에서 실행해도 됩니다.

이제 정상적으로 출력이 되네요. 

X2의 경우 은색 모터 부분이 0도이고, G2는 검은 케이블 튀어나오는 쪽이 0도이고, 시계 방향으로 90, 180...으로 쭉 올라갑니다. 180 넘어서는 -179, -178.... -35... -1.. 0 이렇게 되니, 헷갈리지 마시길...

 

출력결과:

187 a:-120.19 d:2364.0
188 a:-118.73 d:2334.0
189 a:-117.30 d:2302.0
190 a:-115.84 d:2275.0
191 a:-114.41 d:2249.0
192 a:-112.98 d:2296.0
193 a:-111.58 d:2450.0
194 a:-110.16 d:2513.0
195 a:-108.75 d:2673.0
196 a:-107.33 d:2832.0
197 a:-105.89 d:2808.0

...

 

5. 파이썬 테스트 코드 tri_test.py (부제: 아, 이 빌어먹을 놈들!)

놈들이 tri_test.py라는 파이썬용 테스트 프로그램을 제공합니다. make install 시에 /usr/local/bin에 설치되는데, 실행시켜보면 아무런 반응이 없습니다. 30분을 헤맸네요. 시키들..! 파이썬 코드에 실행권한을 주고 /usr/local/bin에 복사해두었으면 실행가능하게 해두어야지 아이쿵... 

제일 윗줄에

#!/bin/python3

을 추가합니다. 그래야 bash가 이 파일을 읽어오면서 이 스크립트를 무엇으로 인터프리팅을 해야 하는지 알 수가 있지요. 이 문구가 없으니 아무 반응이 없을 수밖에.... 대충대충 일할래!  YD놈들아...

실행해보면, ModuleNotFoundError: No module named 'ydlidar'  메시지가 나옵니다. 핵심 모듈인 ydlidar.py를 찾을 수 없어서 그런데요. 여길 내버려두고,

YDLidar-SDK/build/python

로 이동합니다. 여기에 ydlidar.py와 _ydlidar.so가 있습니다. tri_test.py를 여기로 복사합니다.

cp  YDLidar-SDK/python/examples/tri_test.py   .

이 SDK를 사용하여 파이썬으로 코드를 작성한다면 해당 폴더에 이 두 파일을 복사해두어야겠네요. 실행해보면 또 에러가 떱니다.

 

..........tri_test.py", line 33, in <module>
    print("Scan received[",scan.stamp,"]:",scan.points.size(),"ranges is [",1.0/scan.config.scan_time,"]Hz");
                                                                            ~~~^~~~~~~~~~~~~~~~~~~~~~
ZeroDivisionError: float division by zero

 

0으로 나누어서 생긴 문제인데, 33 라인에 보면, ' 1.0/scan.config.scan_time' 이 있는데 이 녀석이 범인입니다. scan.config.scan_time이 0이어서 그런데, 여기에 아주 작은 값을 더해줍니다. 즉, '1.0/(scan.config.scan_time + 0.000000001)'으로 수정합니다. (너무 작은 값은 0이 될 수도 있고, 분명 8인줄 알았는데 7.9999999인 경우가 있더라고요. float과 int를 번갈아 다루는 경우에는 안전하게 소수점을 round해주는 게 좋지요. 이 작은 실수로, True이어야 할 것이 False가 되어서, 화성에 착륙하려는 우주선이 폭발할 수도 있겠지요.)

 

출력:

Scan received[ 1743037173893003000 ]: 250 ranges is [ 12.000336393254173 ]Hz
Scan received[ 1743037173976341000 ]: 251 ranges is [ 11.999327910878893 ]Hz
Scan received[ 1743037174059672000 ]: 251 ranges is [ 12.000336393254173 ]Hz
...

앞의 긴 숫자는 받아올때의 타임스탬프이고, 250은 받아온 포인트 갯수이고, 이 작업을 1초에 12번 가량 수행했다는 뜻입니다. 즉, 12번 회전했다는 이야기인데, scan frequency가 12라는 뜻이죠. 저의 X2가 기본으로 초당 12번 회전하더라구요. 이 값은 우리가 1억분의1을 더해서 뽑아냈기 때문에 아주 정확하지는 않습니다.

뭔가 부족합니다. 각도와 거리 데이터가 궁금한데요. tri_test.cpp라는 파일을 참고하면 파이썬의 변수명도 동일합니다. 앞서 살펴본 CYdLidar.cpp 도 참고해볼 수 있고요. 앵글과 거리 정보를 추가로 출력해봅시다.

 

import math

print("Scan received[",scan.stamp,"]:",scan.points.size(),
	"ranges is [",1.0/(scan.config.scan_time+0.000000001),"]Hz");
for i in range(scan.points.size()):
	print(round(scan.points[i].angle * 180 / math.pi, 2), 
    	round(scan.points[i].range * 1000.0, 0))

 

먼저 math를 import합니다. math.pi를 사용해야 해서요. 두 번째 for문이 추가한 것인데, 포인트 갯수만큼 for문을 돌려서, 앵글은 scan.points[i].angle로 받아 degree 각도로 변환해줍니다. 라디안 각도로 변화시키려면 math.pi/180을 곱하면 되지요. pi가 위(분자)로 올라오면 라디안으로, 밑에 있으면 360도 degree로 바꿔줍니다. round(..., 2)는 소수점 2개에서 반올림하겠다는 이야기지요. 뒤의 range는 미터 단위 거리인데, 이것을 mm단위로 바꿔줍니다. 찾아보니 좌표값을 담는 변수는 안 보이네요. 앵글과 거리 정보에서 좌표값 출력은 알아서 해야겠어요. 쉬운 일이죠...홓