엔지니어링 · 2024
2D 라이다 안전 감지 영역 설정·모니터링 프로그램
라이다 센서의 스캔 데이터를 실시간으로 표시하고, 감지 영역을 화면에서 직접 그려 설정하는 데스크톱 앱
라이다 안전 센서의 감지 영역을 수치 입력 대신 화면 위에서 직접 끌어 맞추도록 하고, 센서가 보내는 스캔 데이터를 영역 안팎으로 구분해 실시간으로 표시하는 Windows 프로그램입니다.
- 고객
- 비공개 고객
- 분야
- 엔지니어링

개요
이 프로그램은 LIDAR 센서를 PC에 연결해 쓰는 Windows 데스크톱 앱입니다. 센서가 보내는 스캔 데이터를 실시간으로 그리고, 감지 영역의 모양과 크기를 화면에서 직접 조정하며, 센서 내부 설정값을 센서로 돌려보냅니다. 센서를 설치하는 기술자와 현장에서 감지 범위를 조정하는 담당자가 사용합니다.

과제
감지 영역은 센서가 설치된 자리마다 다릅니다. 통로 폭, 장비 위치, 사람이 지나는 동선에 따라 매번 달라지므로 설치할 때마다 맞춰야 합니다.
영역을 좌표나 수치로 입력하는 방식에서는 그 값이 실제 현장에서 어디를 가리키는지 확인할 방법이 없습니다. 값을 바꾸고, 물체를 놓아 보고, 반응을 보고, 다시 값을 바꾸는 과정을 반복하게 됩니다. 센서가 지금 무엇을 보고 있는지와 그 점들이 설정한 영역의 안쪽인지 바깥쪽인지를 같은 화면에서 볼 수 있어야 했습니다.
해결 방법
- 센서가 보내는 900개 거리값을 극좌표에서 직교좌표로 바꿔 캔버스에 점으로 찍습니다. 감지 영역 안에 들어온 점과 바깥에 있는 점을 다른 색으로 표시합니다.
- 감지 영역은 원형(270도 부채꼴), 타원형, 사각형, 다각형(8점) 중에서 고릅니다. 각 영역의 꼭짓점에는 제어 포인트가 붙어 있어, 스캔 데이터를 보면서 마우스로 끌어 모양과 크기를 맞춥니다.
- 센서의 원점 위치도 캔버스에서 끌어 옮길 수 있어, 감지 범위가 한쪽으로 치우친 경우에도 화면을 넓게 씁니다.
- 감지 영역 안에 점이 연속으로 다섯 번 들어왔을 때만 경고음을 냅니다. 한 번 튀는 측정값으로 경고가 울리는 것을 막습니다.
- 누적 모드를 켜면 최근 열 번의 스캔을 겹쳐서 보여 줍니다. 오래된 스캔일수록 흐리게 그려, 움직이는 물체의 궤적과 고정된 구조물을 구분합니다.
- 센서의 High Voltage와 Threshold 값을 입력해 센서로 전송합니다. 수신 중에는 센서가 보내 온 현재 값이 같은 칸에 표시됩니다.
- 배경, 그리드, 센싱 포인트, 감지 영역의 색과 크기, 그리드 종류(직교좌표 또는 극좌표), 표시 범위를 바꿀 수 있습니다. 종료할 때 설정과 감지 영역 모양이
config.ini에 저장되어 다음 실행에서 그대로 복원됩니다.

시스템 구조
- UI: wxPython. 왼쪽은 스크롤되는 설정 패널, 오른쪽은 캔버스입니다.
- 렌더링: VisPy의 OpenGL 씬 캔버스를 wx 패널 위에 올렸습니다. 점 900개를 매 프레임 다시 그려야 하므로 GPU 렌더링을 씁니다.
- 통신: TCP 소켓으로 센서에 접속합니다. 데이터 수신과 경고음 재생은 각각 데몬 스레드에서 돌고, UI 스레드는 막히지 않습니다.
- 감지 영역:
BaseArea를 상속한 네 개의 클래스가 각자 경계선과 제어 포인트의 위치, 점의 내부 판별을 맡습니다. 활성화된 영역은 한 번에 하나이며 클래스 변수로 관리합니다. - 설정: 시작할 때
config.ini를 읽어 상수 클래스의 값을 덮어쓰고, 종료할 때 현재 상태를 다시 씁니다.
데이터 흐름
- 센서가 한 프레임을 보냅니다. 8바이트 헤더, 900바이트 블록 네 개, 4바이트 꼬리(High Voltage, Threshold)로 이루어집니다.
- 수신 스레드가 상위 바이트와 하위 바이트를 묶어 거리값을 미터로 환산하고, Gain과 Offset을 적용합니다.
- 각 점이 활성화된 감지 영역의 안쪽인지 판별하고 색을 정합니다.
- 캔버스에 점을 그리고, 영역 안에 점이 있으면 경고 플래그를 쌓습니다.
구현
프레임 경계가 흔들리는 수신 처리
recv 한 번에 들어오는 바이트 수는 매번 같지 않습니다. 900바이트씩 와야 할 블록이 854바이트와 946바이트로 나뉘어 들어오는 경우가 있습니다. 8바이트 헤더를 만날 때까지 받은 것을 버리고, 거기서부터 여섯 번에 걸쳐 받은 뒤 전체 길이가 맞는지 확인합니다. 길이가 맞지 않으면 그 프레임은 그리지 않고 다음 프레임으로 넘어갑니다. 정해진 횟수 안에 헤더를 찾지 못하면 수신을 멈추고 사용자에게 알립니다.
다각형 영역의 내부 판별
원형, 타원형, 사각형은 점 하나씩 식에 넣어 판별하면 됩니다. 다각형은 같은 방식으로 하면 한 프레임마다 900번의 판별을 파이썬 반복문으로 돌게 됩니다. 다각형만 900개 점을 한 번에 넘겨 NumPy 배열 연산으로 판별하도록 분리했습니다. 누적 모드에서는 화면에 남은 점이 9,000개까지 늘어나므로 이 차이가 커집니다.
그리드를 선 하나로 그리기
그리드의 가로선과 세로선을 각각 별도의 선으로 만들면 visual 개수가 그만큼 늘어납니다. 한 선을 끝까지 그은 뒤 왔던 길을 되짚어 다음 선의 시작점으로 가도록 좌표를 이어, 전체 그리드를 끊기지 않는 선 하나로 그립니다. 눈금 간격은 표시 범위에 따라 미리 정해 둔 값(0.1, 0.2, 0.5, 1.0부터 10.0m까지) 중에서 고르므로, 표시 범위를 바꿔도 눈금 숫자가 어중간하게 나오지 않습니다.
색상 선택 창
OS 기본 색상 대화상자 대신 HSV 평면과 채도 슬라이더로 된 창을 직접 만들었습니다. 어두운 배경 위에 찍히는 점의 색을 고르는 일이 많아, 바꾸기 전 색과 바꾼 뒤 색을 나란히 보여 줍니다.

배포
PyInstaller로 묶어 배포합니다. VisPy의 셰이더와 freetype 데이터는 자동으로 수집되지 않아 spec 파일에서 직접 지정합니다.
결과
감지 영역을 수치로 입력하고 결과를 짐작하는 대신, 센서가 실제로 보고 있는 점 위에 영역을 겹쳐 놓고 끌어 맞추게 되었습니다. 물체를 놓아 보고 점의 색이 바뀌는 것을 그 자리에서 확인할 수 있습니다.
누적 모드로 여러 번의 스캔을 겹쳐 보면 한 번 튀는 측정값과 실제 물체를 구분할 수 있고, 연속 감지 조건 덕분에 그런 값 때문에 경고음이 울리지 않습니다.
표시 설정과 감지 영역의 모양이 파일로 저장되므로, 현장에서 맞춰 둔 상태를 다음 실행에서 그대로 이어서 씁니다.
사용 기술
- Python
- wxPython
- VisPy
- NumPy
- OpenGL
- TCP/IP
- PyInstaller
화면




진행하려는 프로젝트가 있으신가요?
해결하려는 문제와 지금 상황을 알려 주시면, 어떤 방식이 맞을지 함께 검토합니다.
프로젝트 문의하기