Raspberry Pi + 개발자 태그 Q1 연동 및 위치 데이터 수신

본 가이드는 GrowSpace UWB 개발자 태그를 Raspberry Pi 4 Model B와 연결하여,
lec, lep 명령어 기반으로 실시간 위치 데이터를 수신 및 파싱하는 실습 방법을 안내합니다.
Python 환경에서 시리얼 통신을 구현하고, 수신된 데이터를 분석 및 출력하는 방법까지 다룹니다.

준비물

  • Raspberry Pi 4 Model B
  • USB-C 전원 어댑터 (5V 3A 이상)
  • GrowSpace UWB 개발자 태그
  • 점퍼 케이블 (TX, RX, GND, 3.3V)
  • Python 3.9.2 이상
  • pyserial 패키지

사전 설정 환경

OS: Debian GNU/Linux 11 (bullseye)

Python 버전: 3.9.2

필수 패키지: pyserial

UART 포트 활성화

  1. 터미널에서 다음 명령어 입력:
  1. 메뉴 이동: Interface Options → Serial Port
  • Login shell via serial: No
  • Enable serial port hardware: Yes
  1. 설정 완료 다시 터미널로 이동
  • 터미널에 ‘sudo reboot’ 입력하여 라즈베리파이 리부팅

시리얼 핀 연결

GrowSpace 개발자 태그는 3.3V 전압 기준 좌측 커넥터를 통해 Raspberry Pi의 Serial0 포트와 연결합니다.
이 포트는 3.3V 레벨의 UART 통신을 지원합니다.

개발자 태그 핀라즈베리파이 핀 번호GPIO 번호
TX10번 (RXD)GPIO15
RX8번 (TXD)GPIO14
3.3V1번
GND6번

주의: TX ↔ RX는 반드시 교차 연결해야 합니다.
태그의 TX → Pi의 RX / 태그의 RX → Pi의 TX

📌참고용: 라즈베리파이 GPIO 핀 배치도

아래는 Raspberry Pi 40핀 헤더의 전체 핀맵입니다.

TX0 (GPIO14, Pin 8), RX0 (GPIO15, Pin 10), 3.3V (Pin 1), GND (Pin 6)의 위치를 꼭 확인해 주세요!

이 다이어그램을 참고해 개발자 태그와의 시리얼 연결을 정확하게 구성하시면 됩니다.

GrowSpace 개발자 태그의 시리얼 포트 구분

GrowSpace GrowSpace 개발자 태그에는 두 개의 시리얼 통신 포트가 있으며, 단순히 핀 구성만 다른 것이 아니라 TX/RX 신호의 전압 레벨이 다릅니다.

  • 포트 1: TX, RX, 3.3V, GND → 3.3V 레벨 통신용 (좌측 커넥터)
  • 포트 2: TX, RX, 5V, GND → 5V 레벨 통신용 (우측 커넥터)

이 실습에서는 Raspberry Pi의 UART는 3.3V 레벨이기 때문에, 반드시 3.3V 포트(포트 1) 를 사용해야 합니다.
5V 포트를 잘못 연결할 경우, Raspberry Pi의 GPIO가 손상될 수 있으니 주의해 주세요

시리얼 통신 테스트 코드 (Python)

import serial
import threading

uwb = serial.Serial('/dev/serial0', baudrate=115200, timeout=0.5)

def read_from_uwb():
    while True:
        if uwb.in_waiting:
            data = uwb.readline().decode(errors='ignore').strip()
            if data:
                print(f"[UWB 응답] {data}")

def write_to_uwb():
    while True:
        try:
            cmd = input(">>> ")
            if cmd.strip():
                uwb.write((cmd + '\r').encode())
        except KeyboardInterrupt:
            print("\n종료합니다.")
            break

if __name__ == "__main__":
    print("UWB 시리얼 중계 시작 (/dev/serial0)")
    threading.Thread(target=read_from_uwb, daemon=True).start()
    write_to_uwb()

위 코드는 main() 함수에서 두 개의 스레드를 동시에 실행합니다:

  • read_from_uwb()는 개발자 태그(UWB 모듈)로부터 들어오는 데이터를 실시간으로 읽어 콘솔에 출력합니다.
  • write_to_uwb()는 사용자가 입력한 명령어를 시리얼로 태그에 전송합니다. (전송 시 ‘\r’ 캐리지리턴을 자동으로 붙여줍니다.)

그리고 si 명령어를 직접 입력하면 UWB 태그에서 응답이 출력되며, 통신이 성공적으로 이루어졌다는 것을 확인할 수 있습니다.

위치 데이터 파싱 예제 (lec / lep)

lep 위치 정보 파싱

def parse_lep(line):
    print("\n[LEP 위치 결과]")
    parts = line.strip().split(',')
    if len(parts) >= 5:
        print(f"X: {parts[1]}")
        print(f"Y: {parts[2]}")
        print(f"Z: {parts[3]}")
        print(f"품질(QF): {parts[4]}")
    else:
        print("→ 잘못된 LEP 형식입니다.")

lec 거리 + 위치 정보 파싱

def parse_lec(line):
    print("\n[LEC 거리 + 위치 결과]")
    try:
        pos_idx = line.index("POS,")
        dist_part = line[:pos_idx].strip()
        pos_part = line[pos_idx:].strip()

        anchors = []
        tokens = dist_part.split(',')
        i = 2
        while i < len(tokens):
            if tokens[i].startswith("AN"):
                anchor_id = tokens[i+1]
                x = float(tokens[i+2])
                y = float(tokens[i+3])
                z = float(tokens[i+4])
                d = float(tokens[i+5])
                anchors.append((anchor_id, x, y, z, d))
                i += 6
            else:
                i += 1

        for idx, (aid, x, y, z, d) in enumerate(anchors):
            print(f"AN{idx} (ID {aid}): x={x}, y={y}, z={z}, 거리={d}m")

        parse_lep(pos_part)

    except Exception as e:
        print(f"lec 파싱 실패: {e}")

전체 수신 루프 구성

input_buffer = ""

def read_from_uwb():
    global input_buffer
    while True:
        if uwb.in_waiting:
            data = uwb.read().decode(errors='ignore')
            if data == '\n':
                line = input_buffer.strip()
                if line.startswith("POS,"):
                    parse_lep(line)
                elif line.startswith("DIST,"):
                    parse_lec(line)
                else:
                    print(f"[기타 응답] {line}")
                input_buffer = ""
            else:
                input_buffer += data
  • 실행 결과
lep 실행 결과
lec 실행 결과

결론

본 실습을 통해 Raspberry Pi에서 GrowSpace UWB 태그의 실시간 위치 데이터를 수신하고,
Python 코드로 분석하여 출력하는 전체 과정을 다루었습니다.

  • Raspberry Pi의 Serial0 포트를 통해 안정적인 시리얼 통신 가능
  • Python 기반 파싱 로직으로 데이터 분석/활용의 확장성 확보
  • RTLS 실험용 테스트베드로 활용 가능

여러분도 이 방법을 따라 하여 효율적인 위치 추적 시스템을 구현해 보세요!

궁금한 점이 있거나 문제가 발생하면 언제든지 문의주세요! 😊

목차