Raspberry Pi 연동
이 글에서는 
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 이상 (OS: Debian GNU/Linux 11 기준) 
- pyserial 패키지 설치 
Raspberry Pi 시리얼 포트 설정
- 터미널에 다음 명령어 입력: - sudo raspi-config
- 메뉴 이동: - Interface Options → Serial Port 
- Login shell via serial: No 
- Enable serial port hardware: Yes 
 
- 설정 완료 후 - sudo reboot명령어로 재부팅
시리얼 핀 연결 (UART)
GrowSpace 개발자 태그의 3.3V 커넥터(좌측) 기준으로 다음과 같이 연결합니다:
개발자 태그 핀
라즈베리파이 핀 번호
GPIO 번호
TX
10번 (RXD)
GPIO15
RX
8번 (TXD)
GPIO14
3.3V
1번
-
GND
6번
-
⚠️ 반드시 TX ↔ RX 교차 연결을 확인해 주세요. 태그의 TX → Pi의 RX, 태그의 RX → Pi의 TX

참고: Raspberry Pi GPIO 핀 배치도
아래는 Raspberry Pi 40핀 헤더의 전체 핀맵입니다. 다음 핀 번호를 기준으로 정확히 연결하세요:
- TX0: GPIO14 (Pin 8) 
- RX0: GPIO15 (Pin 10) 
- 3.3V: Pin 1 
- GND: Pin 6 
이 다이어그램을 참고하면 개발자 태그와의 시리얼 연결을 더욱 명확히 이해할 수 있습니다.
공식 문서에서 전체 GPIO 구성도와 회로 정보를 자세히 보고 싶다면 다음 링크를 확인해 주세요: 라즈베리 파이 공식 핀아웃 및 도면 보기

주의사항: GrowSpace 태그의 시리얼 포트 구분
GrowSpace 개발자 태그에는 좌우 측에 각각 다른 전압 레벨의 시리얼 포트가 존재합니다. 단순한 핀 위치 차이가 아니라, 전기적으로 완전히 다른 레벨이므로 반드시 구분하여 사용해야 합니다.
- 포트 1 (좌측 커넥터) - 구성: TX, RX, 3.3V, GND 
- 동작 전압: 3.3V 레벨 
- 사용 용도: Raspberry Pi, ESP32 등 3.3V 기반 장치와 연결 시 사용 
 
- 포트 2 (우측 커넥터) - 구성: TX, RX, 5V, GND 
- 동작 전압: 5V 레벨 
- 사용 용도: Arduino UNO 등 5V 기반 장치와 연결 시 사용 
 
반드시 확인하세요
- Raspberry Pi의 GPIO는 3.3V 전압만 허용합니다. 
- 5V 포트(우측 커넥터)를 잘못 연결하면 라즈베리파이의 UART 회로가 손상될 수 있습니다. 
- 본 매뉴얼에서는 반드시 **좌측 커넥터(3.3V 포트)**를 사용해야 합니다. 

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()- read_from_uwb()는 실시간 수신 데이터를 출력
- write_to_uwb()는 명령어를 입력 받아 전송 (- \r포함)
예: si 명령어 입력 시, 장치 정보가 출력되면 통신 성공
위치 데이터 파싱 예제 (lep, lec 명령어)
lep, lec 명령어)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- POS,로 시작하면 LEP 파싱
- DIST,로 시작하면 LEC 파싱
- 기타 응답도 모두 출력 
마무리
이 매뉴얼에서는 Raspberry Pi 환경에서 GrowSpace 개발자 태그와 시리얼 통신을 구성하고, Python을 통해 lep, lec 명령어 기반의 위치 데이터를 실시간으로 수신 및 파싱하는 과정을 소개했습니다.
이 과정을 통해:
- Raspberry Pi의 - /dev/serial0포트를 활용한 안정적인 통신 구성
- Python 기반 파싱 로직으로 실시간 위치 정보 확인 가능 
- RTLS 실험 및 프로토타이핑 테스트베드로 확장 가능 
실습 중 문제가 발생할 경우, TX/RX 교차 연결 여부와 포트 활성화 상태를 꼭 다시 확인해 주세요.
Last updated