2024 캔위성 경진대회를 돌아보며 - 프로그래밍
임무 요구사항과 시스템 설계
ForeRover_SAT 프로젝트의 목표는 지상에서 자율 주행이 가능한 탐사 로버를 만드는 것이었다. 단순히 모터를 굴리는 수준이 아니라, 실시간 전력 모니터링, GUI 기반의 관제, 블루투스 원격 제어, 데이터 기록 등 꽤나 다양한 요구사항이 한꺼번에 몰려 있었다. 어떻게 프로그램을 짜서 넣어야 충족할지에 관해 고민이 많았다.
하드웨어 제어와 펌웨어 설계
1. 모터 제어부
로버의 구동은 듀얼 모터에 맡겼다. 모터 드라이버는 H-브리지 방식으로, motor.cpp와 motor.h에서 모든 제어가 이루어진다. 핀 배치는 global.h에 상수로 정의했다. 각 모터는 PWM 신호로 속도를 조절할 수 있도록 설계했다.
1
2
3
4
5
void motorAForward(int speed) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, speed);
}
좌우 모터의 속도를 각각 조절하며, 좌회전·우회전은 한쪽 모터만 속도를 줄이거나 반대로 돌리는 식으로 구현했다. 정지 명령은 모든 핀을 LOW로, PWM도 0으로 맞춘다.
2. 전력 모니터링
배터리 잔량을 실시간으로 확인하는 기능도 필수였다. 아날로그 핀(A5)에 분압 회로를 연결해서 전압을 측정하고, 10번 샘플링해서 평균값을 구한 뒤 실제 배터리 전압으로 환산한다.
1
2
float batteryVoltage = averageVoltage * ((R1 + R2) / R2);
float batteryLevel = getBatteryLevel(batteryVoltage);
이 값은 시리얼로 송출해서 GUI에서 실시간으로 볼 수 있게 했다.
3. 블루투스 통신
BluetoothSerial 라이브러리를 이용해 스마트폰 앱이나 PC GUI에서 명령을 받아 모터를 제어한다. “전진”, “후진”, “좌측”, “우측”, “정지” 등 한글 명령어로도 동작하도록 했다.
1
2
3
4
if (command == "전진") {
forward();
SerialBT.println("전진");
}
명령어가 들어오면 즉시 해당 동작을 수행하고, 응답 메시지를 다시 블루투스로 돌려보낸다.
GUI와 데이터 로깅
1. Tkinter 기반 관제 프로그램
관제 소프트웨어는 Python의 Tkinter로 만들었다. 전력 현황을 3개 그래프로 실시간 시각화하고, 각 전압값도 별도 라벨로 표시했다.
1
2
self.fig, self.axs = plt.subplots(3, 1, figsize=(8, 10))
self.power_value_labels = [tk.Label(...)]
GUI에는 고도 표시, 통신 모듈 조작, 착륙 기능, 포트 선택 및 연결, 실시간 데이터 로그 등 필요한 기능을 한 화면에 모두 집어넣었다.
2. 시리얼 데이터 처리
시리얼 포트로부터 데이터를 읽는 부분은 스레드로 분리해서 GUI가 멈추지 않도록 했다.
1
2
3
4
5
6
def read_serial_data(self):
while not self.stop_thread:
if self.serial_port and self.serial_port.is_open:
data = self.serial_port.readline().decode('utf-8').strip()
if data:
self.process_serial_data(data)
수신한 데이터는 그래프와 라벨에 반영하고, 동시에 CSV 파일로 저장해서 나중에 분석할 수 있도록 했다.
3. 모터/착륙 제어 버튼
GUI에서 “전진”, “좌회전”, “우회전”, “정지”, “강제 착륙” 버튼을 누르면 시리얼로 명령이 전송된다. 각 버튼은 단순히 숫자 코드(예: b’1\n’, b’4\n’)를 전송하는 방식으로 MCU 쪽에서 해당 코드를 받아 모터를 제어한다.
통신/연결 유틸리티
1. 시리얼 포트 점검 스크립트
1
2
3
4
5
6
7
8
import serial
port = 'COM5'
try:
ser = serial.Serial(port, 115200)
ser.close()
print(f"Serial port {port} is now available.")
except serial.SerialException as e:
print(f"Error: {e}")
포트가 점유 중인지 확인하는 용도로 썼다.
2. BLE 데이터 수신 테스트
seriallll.py는 BLE(Bluetooth Low Energy)로 이미지 데이터를 수신받아 파일로 저장하는 예제다. 아두이노 Nano 33 BLE와 연결해서 특정 UUID로 데이터를 받아 누적 저장한다.
패착과 시행착오
소프트웨어 측면에서도 시리얼 통신이 불안정해서 데이터가 누락되거나 GUI가 멈추는 현상이 있었다. 이를 해결하기 위해 스레드와 버퍼링, 예외처리를 추가하면서 조금씩 안정성을 높여갔다. 또한 핀 플로팅 문제역시 소프트웨어적으로 해결할 수 있어 해결하였다. —
결론 및 다짐
이번 프로젝트를 통해 임베디드 시스템에서 하드웨어와 소프트웨어의 경계가 얼마나 얇고, 사소한 실수 하나가 전체 시스템을 무너뜨릴 수 있는지 깨달았다.
하지만 그만큼 얻은 것도 많다. 직접 회로를 설계하고, 펌웨어를 짜고, GUI까지 만들어보면서 임베디드 개발의 전 과정을 몸소 체험할 수 있었다.
다음에는 더 완성도를 높인 시스템을 만들어보고 싶다.