버스 도착 알림 전광판 만들기

발단

서울시 번화가를 지나다니다 보면 아래 사진처럼 도착 안내 전광판이 설치된 버스 정류장들이 자주 보인다. 이런 전광판을 나도 하나쯤 갖고 싶다는 생각이 들었다.

그래서 만들기로 했다.

재료

당연히 이런 전광판이 기성품으로 있을 리 없다. 하지만 알리익스프레스에는 모든 것이 있다. 알리에서 아래와 같은 64×32 LED 전광판 모듈을 팔길래 뒷일은 생각하지 않고 일단 구매했다. 어떻게든 연결해서 돌리면 돌아는 가겠지라는 생각으로… 6개를 구매해서 3×2, 196*64 해상도가 되도록 배치했다.

이외에 프레임이나 받침대, 전원 분배 보드 등은 모두 커스텀으로 제작했다.

제작

하드웨어

다음으로 각각의 패널에 전원과 신호, 두 가지의 배선을 연결해야 한다. 이들 패널은 5V 전원을 사용하고, 전원과는 별개로 ‘HUB75’라는 인터페이로 데이터 신호를 입력받는다.

우선 전원 공급. 이 패널들은 5V 전원을 사용한다. 때문에 처음에는 남는 PC용 파워 서플라이에서 5V 배선을 따서 사용해 보았다. 처음에는 크게 문제없이 작동하는 듯 보였지만, 흰색 배경을 띄우자 오래 가지 못하고 꺼졌다.

확인해 보니 64×32짜리 LED 모듈 한 장이 먹는 전력이 20W, 4A에 육박한다. 패널 여섯 장이면 120W 수준. 5V에 120W를 공급하려면 파워서플라이가 24A를 내 주어야 하는데, 5V에서 20A를 넘게 내는 전원 장치는 구하기 쉽지 않다. 일반적인 PC용 파워는 5V 공급 용량이 100W정도에 불과하다. 때문에 일반적인 내용을 표시하는데에는 큰 문제가 없었지만, 흰색 배경을 사용하면 20A정도의 전류가 흐르면서 파워서플라이의 과전류 차단(OCP) 기능이 걸려버린 것이다. 그래서 하는 수 없이 5V 300W SMPS를 따로 구매했다.

처음에는 PC용 ATX 파워 서플라이를 사용했으나, 흰색 배경 등 전력을 많이 사용하는 환경에서 전원이 꺼져버렸다.

다음으로 이렇게 구매한 LED 패널에 원하는 내용을 띄워야 한다. 알리익스프레스에서 판매하는 LED 전광판 모듈은 대부분 신호 입력에 HUB75라는 규격을 사용한다. HUB75는 데이지 체인으로 여러개의 패널을 줄줄히 연결한 뒤 각 픽셀에 해당하는 데이터를 클럭에 따라 PWM 제어로 직접 넣어 주는 간단한 병렬 인터페이스로, 2×10(2.54mm 피치)의 IDC 커넥터를 사용한다. 각각의 패널에는 시프트 레지스터가 내장되어 있기 때문에 주사율이 허락하는 한 원하는 수만큼 패널을 여러개 직렬로 연결해서 사용할 수 있다.

HUB75는 위 그림처럼 여러개의 패널을 직렬로 줄줄이 연결해서(daisy chain) 사용하는 인터페이스이다.

패널을 제어하기 위해 처음에는 ESP32를 사용해 보았다. 직접 점퍼선으로 HUB75 인터페이스 핀 배열에 맞추어 패널과 컨트롤러를 연결해 보았는데, 어떻게 해도 정상적으로 화면이 출력되지 않았다. 몇 개의 픽셀이 노란색이나 흰색으로 빛나며 튈 뿐이었다. 아마 신호의 전압 레벨 때문에 문제가 있는 것 같았다. ESP32는 3.3V MCU이기 때문에 GPIO도 3.3V로 동작하는데, LED 패널은 5V로 동작하기 때문에 ESP32에서 주는 신호를 제대로 인식하지 못하는 상황으로 보였다.

따라서 전용 제어 보드를 구매하기로 했다. 사실 알리익스프레스에는 원하는 이미지나 영상을 띄울 수 있는 다양한 HUB75 LED 패널 제어 보드를 판매하고 있다. 지원하는 해상도도 다양하고, 한 보드에 여러개의 HUB75 인터페이스를 연결할 수 있는 보드도 많은데다 Wi-Fi나 USB메모리 등을 지원하는 제품도 있다. 이들 보드는 자체 AP에다가 HUB75 인터페이스 신호를 발생시키기 위한 FPGA를 탑재하고 있어서 SD급에서 거의 FHD에 이르는 고해상도 디스플레이를 안정적으로 연결할 수 있다.

알리익스프레스에서 판매하는 HUB75 제어 보드. ARM AP와 FPGA를 탑재하고 있다. 두 번째로 만든 고해상도(192×128) 전광판은 위 보드를 사용했다.

하지만 이러한 완제품 보드를 쓰면 원하는 내용을 마음껏 띄울 수가 없다. 게다가 모처럼 직접 전광판을 만들려고 하는데 내가 만들 수 있는 부분까지 이미 있는 솔루션에 의존하면 재미가 없지 않은가. 그래서 검색하던 도중 Adafruit에서 파는 라즈베리파이용 HUB75 인터페이스 보드가 있길래 구매했다.

HUB75는 데이지 체인 형태의 인터페이스로 여러개의 패널을 줄줄이 이어서 연결한다. 물론 프레임률을 높이기 위해서는 각 패널을 따로 연결할 수도 있다. 하지만 Adafruit의 RGB Matrix HAT은 출력 단자가 하나뿐이므로 줄줄이 연결하는 것 외에는 선택지가 없다. 다행히 해상도가 192×64 수준으로 아주 높지는 않다 보니 테스트 결과 60fps 이상으로 제어할 수 있었다.

그리고 https://github.com/hzeller/rpi-rgb-led-matrix 라이브러리를 사용해서 라즈베리파이가 원하는 정보를 출력할 수 있도록 프로그래밍해 보았다. 기본적인 제어 모듈은 C++ 기반이지만, Python 모듈도 준비되어 있었다. 예제 코드들을 응용해서 먼저 간단한 내용을 출력하도록 만들어 보았다. 잘 된다.

이제 각각의 패널들을 전광판 모양으로 배열하고 여러개의 패널에 전원선과 데이터선을 모두 연결해 줄 방법을 찾아야 한다.

우선 패널을 격자모양으로 배열해서 전광판처럼 만들기 위한 프레임을 설계했다. 프레임은 전광판의 나사홀과 튀어나온 부분들의 위치를 잘 측정한 뒤 대충 캐드로 그렸다. 재료를 효율적으로 사용하면서도 각각의 프레임 부품을 모듈화시켜 전광판의 배열을 바꾸더라도 쉽게 대응할 수 있게 했다. 각 단위를 십자(十) 모양으로 만들고, 서로 연결해서 격자모양으로 결합할 수 있도록 했다.

프레임 도면. 각 십자(十)모양 부품을 직사각형 모양 부품으로 서로 연결해서 격자모양으로 만들 수 있다.

+ 모양으로 생긴 것이 각각의 프레임 조각이고, 사각형 모양 조각은 프레임 조각끼리 서로 연결하는 부품이다. 그린 도면대로 5mm 아크릴(PMMA)판을 레이저커터로 자른 뒤 볼트와 너트로 조립했다. 처음에는 강도와 가공성을 고려해 아크릴로 프레임을 만들었는데, 너무 무겁고 비싸서 나중에는 MDF로 바꿨다. MDF가 오히려 덜 깨지는데다 프레임이 그렇게까지 단단할 필요는 없어서 더 좋은 선택인 것 같다.

위 사진처럼 M3 볼트와 너트로 프레임을 먼저 짠 뒤, 패널(3mm 볼트홀이 마련되어 있다)을 조립했다. 사진은 두 번째로 만든 전광판이라 프레임이 3×4로 짜여 있는데, 버스 전광판은 3×2로 만들었다.

다음으로는 전광판을 세워 놓기 위한 다리(받침대)를 만들어야 한다. 프레임 부품과 마찬가지로 Fusion 360으로 적당히 모델링한 뒤 3D프린터로 출력했다. 프린터는 Anycubic Photon Mono SE를 사용했고, 재료는 Anycubic Basic resin과 Resione G217 레진을 사용해 보았는데 Basic resin이 훨씬 나았다. G217은 볼트홀이 실제보다 작게 출력돼서 따로 드릴로 홀을 넓혀 주어야 했다.

받침대는 Anycubic Photon Mono SE로 출력했다. 이건 LCD 프린터지만 FDM프린터로도 큰 문제 없이 출력할 수 있을 것으로 보인다.

다음으로 여러 장의 LED 패널에 전원을 효율적으로 분배해야 한다. 알리익스프레스에서 파는 LED 패널 모듈은 모두 3.96mm 피치의 4핀 JST-VH 단자로 전원을 공급받도록 되어 있는데, 패널을 구매하면 기본적으로 주는 전원선은 한쪽 끝이 그냥 터미널 압착단자로 마감되어 있기 때문에 여러 장의 패널을 사용하려면 각각 따로 전원을 연결해야 한다. 이를 위해 전원 분배용 PCB를 설계하고 제작했다. 전광판과 같은 JST-VH단자로 전원을 분배해주도록 만들었다.

3×2(192×64) 패널의 뒷면. 프레임은 5mm MDF로 만든 것이다.

이후 전원 배선은 3.96mm 4핀 하네스 단자를 레버형 커넥터로 연결해서 만들었는데, 선이 너무 꼬이는데다 배선 수도 많아서 이 과정이 꽤 고역이었다. 다음에 만들라면 무탈피 단자와 2P 와이어를 사용했을 것 같다.

그나마 HUB75 인터페이스는 데이지 체인 방식으로 패널을 줄줄이 연결하므로 데이터 케이블을 패널마다 연결해줄 필요는 없다는 게 다행이었다. 때문에 데이터 케이블은 복잡한 작업을 하지 않아도 그냥 패널을 구매할 때 동봉된 케이블을 줄줄이 연결하면 된다. 다만 동봉된 케이블은 길이가 15cm정도에 불과하므로 첫 패널에 연결하는 데이터 케이블은 따로 조금 긴 케이블을 사용했다.

이제 라즈베리파이에서 간단한 출력 테스트를 해 본다. 프레임률은 프로그램의 최적화 수준에 따라 다른데, 라즈베리파이 4에서 rpi-rgb-led-matrix 라이브러리의 Python 바인딩을 adafruit-hat-pwm 모드로 썼을 때 192×64 패널에 대해 70fps정도까지 나오는 것 같다.

패널 뒷면. MDF로 만든 뼈대에 3D프린터로 만든 다리를 붙이고, 라즈베리파이4를 연결해서 제어한다. 전원 분배 보드는 커스텀 PCB이다.

소프트웨어

이제 실제 버스 전광판 내용을 출력해야 한다.

먼저 버스 전광판에 쓰이는 폰트를 그렸다. 전광판의 폰트는 기본적으로 비트맵 굴림체 계열 폰트기는 한데, 글자의 폭과 높이 설정을 정확히 알 수 없었던데다 굴림체를 어떻게 변형해도 버스 전광판에서 사용하는 폰트의 모양이 나오지는 않았기에 실제 전광판 사진을 보며 각각의 글자를 직접 도트를 찍어 그릴 수밖에 없었다.

제어 프로그램은 아예 LED 패널 출력 모듈과 버스 전광판 렌더링 모듈을 분리해서 각각 별개의 Python 라이브러리로 만들었다. 버스 도착 정보 외에도 다양한 내용을 Pillow 이미지로 만든 뒤 전광판 모듈에 입력하면 바로 렌더링되도록 했다. 두 라이브러리는 최대한 OOP의 컨셉을 차용해 편리하게 만들었다. add_bus() 나 add_arrive() 같은 함수로 버스 노선별 정보, ‘곧도착’ 정보 등을 추가할 수 있도록 했다. 전반적으로 rpi-rgb-led-matrix 라이브러리와 Pillow 라이브러리를 사용하니 꽤나 편하게 작업할 수 있었다.

실시간 버스 도착 정보는 공공데이터포털의 서울특별시 정류소정보조회 서비스 API를 사용했다. (https://data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15000303) API의 반환 포맷이 XML인데다가 출력되는 데이터도 불필요하다 싶을 정도로 많고 레이블링이 비직관적이어서 좀 사용하기 불편하기는 했다. 좀 더 개선되었으면 좋겠다 싶긴 했지만 괜히 말을 보탰다간 개악되기만 할 것 같다.

그리고 완성. 불완전하지만 애니메이션도 넣었다. 애니메이션을 제외하고 정적으로 출력되는 부분은 서울시 버스정류장의 도착 안내판과 픽셀 단위로 정확히 일치한다. (다만 버스정류장의 도착 안내판을 모두 같은 업체에서 납품한 게 아니기 때문에 제품에 따라서 약간 차이는 있다.)

애니메이션도 대략적으로 구현해 보았다.
전광판에 디스플레이되는 내용은 실제 전광판과 픽셀 단위로 일치한다.

사용한 모든 설계도면 및 소스 파일은 https://github.com/hletrd/LED_bus_panel 에 올려놓았다.

사용한 부품 및 재료와 전광판 프레임 설계도면, 받침대 설계도면, 전원 분배용 PCB 설계도면, 기타 필요한 파트 목록 및 Python 라이브러리 소스코드와 예제를 해당 GitHub repository에 업로드하였으니 참고하시길.

4 comments
  1. 븜구리
    븜구리
    06/14/2023 at 15:37

    되게 재밌게 봤어요 알리는 진짜 없는게 없네요

    Reply
    • 안녕하세요
      안녕하세요
      11/16/2023 at 16:44

      혹시 구매 가능할까요 ??

      Reply
Leave a Reply

Your email address will not be published. Required fields are marked *