AEGLOSLAB Arduino UNO Q 완전 가이드

제4부 프로그래밍 가이드

4.1 첫 스케치 — Arduino IDE와 App Lab 워크플로우

UNO Q의 MCU(STM32U585)에 코드를 업로드하는 방법은 두 가지다. 하나는 익숙한 Arduino IDE로 스케치만 업로드하는 경로이고, 다른 하나는 Arduino App Lab으로 스케치와 Python 앱을 하나의 프로젝트로 묶어 업로드하는 경로이다. 이 장은 두 경로를 실제로 따라가 보며 차이를 실습으로 익힌다. 다음 장 4.2부터는 App Lab 경로를 전제로 MCU-MPU 연동 코드를 본격적으로 다룬다.

4.1.1 두 가지 개발 경로

UNO Q는 겉보기엔 UNO 폼팩터의 평범한 보드지만, 내부에는 서로 다른 운영체제로 동작하는 두 개의 프로세서가 있다(2.1 참조). MCU(STM32U585)는 Zephyr OS 위에 구축된 Arduino Core를 쓰고, MPU(QRB2210)는 Debian Linux를 쓴다(3.1, 3.2). 이 구조 때문에 "코드를 업로드한다"는 한 문장이 실제로는 두 가지 다른 작업을 가리킬 수 있다.

MCU 코드만 MCU + MPU 연동 App 무엇을 만들 것인가? Arduino IDE 2.x 또는 arduino-cli Arduino App Lab 스케치(.ino) 작성 보드 선택 Arduino UNO Q Upload MPU가 SWD 어댑터로 동작 remoteocd가 STM32U585 플래시 App 생성 sketch/ + python/ + app.yaml Run Linux 컴포넌트 빌드 MCU 스케치 플래시(동일 경로) Python 앱 + Brick 기동 Bridge로 MCU↔MPU 통신 시작
  • Arduino IDE 경로는 클래식 아두이노 사용자에게 익숙한 흐름 그대로다. .ino 파일을 열고, 보드를 고르고, Upload를 누른다. 결과물은 MCU에서 실행되는 스케치 하나뿐이다 — Python도 Bridge도 없다.
  • App Lab 경로는 UNO Q 전용이다. "App"이라는 단위 안에 MCU 스케치와 MPU(Linux)의 Python 프로그램, 그리고 선택적으로 Bricks(사전 패키징된 기능 모듈, 3.3)를 함께 담는다. Run 버튼 하나로 두 프로세서가 동시에 기동한다.

어느 쪽이 맞는지는 목적에 달렸다. MCU만으로 끝나는 순수 실시간 작업(센서 폴링, 모터 PWM 등)이면 Arduino IDE로 충분하다. MPU의 Linux 자원(네트워크, 파일시스템, AI 추론, 웹 서버)을 MCU와 연동해야 한다면 App Lab이 필요하다.

4.1.2 Arduino IDE로 MCU 스케치만 업로드하기

4.1.2.1 설치와 보드 선택

  1. Arduino IDE 2.x를 설치한다(UNO Q는 IDE 1.x 레거시 보드 매니저를 지원하지 않는다).
  2. Tools → Board → Boards Manager에서 UNO Q 또는 Arduino Zephyr로 검색해 보드 패키지를 설치한다. 이 패키지가 곧 Arduino Core on Zephyr다(3.2).
  3. 설치가 끝나면 Tools → Board에서 Arduino UNO Q를 선택한다. 내부적으로는 FQBN(Fully Qualified Board Name) arduino:zephyr:unoq가 지정된다. arduino-cli로 커맨드라인 컴파일을 할 때도 이 FQBN을 그대로 쓴다.
arduino-cli compile --fqbn arduino:zephyr:unoq ./blink

⚠️ 검증 필요: 보드 패키지 버전은 2026년 8월 시점에도 빠르게 갱신되고 있다(0.53 → 0.55 계열로 마이그레이션한 기록이 확인됨). 버전에 따라 아래에서 다룰 PWM 관련 동작이 달라지므로, 실습 전 Boards Manager에서 최신 버전으로 업데이트했는지 반드시 확인한다.

4.1.2.2 실제 업로드 경로 — remoteocd와 SWD

클래식 UNO는 PC가 USB-시리얼(부트로더)로 MCU에 직접 펌웨어를 전송한다. UNO Q는 다르다. USB-C는 MPU(QRB2210)에 연결되고, PC는 ADB(Android Debug Bridge)를 거쳐 MPU와 통신한다. 업로드 시점에 MPU가 STM32U585를 향한 SWD(Serial Wire Debug) 어댑터로 동작하며, 보드 내부의 remoteocd(OpenOCD를 감싼 도구)가 실제 플래싱을 수행한다.

USB-C, ADB SWD (온보드 배선) remoteocd = OpenOCD 래퍼 PC (Arduino IDE) QRB2210 (MPU) Debian Linux STM32U585 (MCU)

이 경로는 로컬 USB뿐 아니라 SSH를 통한 원격 플래싱도 가능하게 해준다 — 보드가 이미 네트워크에 연결되어 있다면 USB 케이블 없이도 스케치를 업로드할 수 있다는 뜻이다(5.2에서 SSH 배포를 다룬다). 반대로 이 구조 때문에 생기는 함정도 있다.

  • 일부 사용자는 최초 인식 시 "remoteocd 파일 누락" 오류를 겪었고, 원인은 백신 소프트웨어가 실행 파일을 격리·차단한 것이었다(커뮤니티 보고, 검증 필요 — 환경마다 다를 수 있음). PC의 백신 예외 목록에 Arduino IDE·remoteocd 관련 경로를 추가하면 대체로 해결된다.
  • 최초 부팅에는 Linux가 기동하는 20~30초가 필요하다. LED 매트릭스에 부팅 로고(하트 아이콘 등 애니메이션)가 표시되고 사라질 때까지는 업로드를 시도하지 않는다 — MPU가 SWD 어댑터로 준비되지 않은 상태이기 때문이다.

4.1.2.3 첫 스케치 — Blink

UNO Q의 사용자 LED는 클래식 UNO처럼 단색 LED 하나가 아니라 RGB LED이고, 게다가 active-low(로직 0을 인가해야 켜짐)다. LED_BUILTIN 매크로는 이 RGB LED의 한 채널(빨강)에 매핑되어 있다. 코드 자체는 클래식 Blink와 똑같이 쓰지만, 켜짐/꺼짐의 전기적 의미가 반대라는 점만 기억해 두면 된다.

// blink.ino — UNO Q MCU용 최소 예제
// LED_BUILTIN은 active-low RGB LED의 빨강 채널에 매핑된다.
// (공식 데이터시트: "RGB LEDs are active-low")

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);   // LOW = 켜짐 (active-low)
  delay(1000);
  digitalWrite(LED_BUILTIN, HIGH);  // HIGH = 꺼짐
  delay(1000);
}

Upload를 누르면 IDE가 컴파일 → ADB 연결 → remoteocd 플래싱까지 자동으로 처리한다. 성공하면 보드의 RGB LED 빨강 채널이 1초 간격으로 깜빡인다. App Lab의 "Hello World" 예제도 정확히 이 동작을 보여준다(4.1.3.3 참조) — App Lab이 내부적으로 같은 플래싱 경로를 쓰기 때문이다.

4.1.3 App Lab 워크플로우

4.1.3.1 App Lab이란

Arduino App Lab은 보드의 두 프로세서를 함께 빌드·실행하는 통합 에디터다. 하나의 App은 다음을 포함할 수 있다(공식 사용자 매뉴얼 기준).

  • MPU(Linux)에서 실행되는 Python 프로그램
  • MCU에서 실행되는 Arduino 스케치
  • 선택적 Brick(AI 모델, 웹 서버, API 클라이언트 등 사전 패키징된 기능, App과 함께 Linux 쪽에 배포됨)

App들은 Bridge(3.4에서 내부 구조를 다룸)로 MCU와 MPU 사이에 데이터를 주고받는다. App Lab은 PC에 설치해 쓸 수도 있고, UNO Q 자체를 SBC(Single-Board Computer)로 부팅해 보드 위에서 직접 실행할 수도 있다. SBC 모드로 쓸 계획이라면 4GB RAM 모델(1.1)이 메모리 여유 면에서 권장된다(공식 매뉴얼 명시).

4.1.3.2 최초 설정

  1. App Lab을 설치하고 실행한 뒤, PC-hosted 모드는 USB-C 데이터 케이블로 보드를 연결하고, SBC 모드는 전원만 공급한다.
  2. 보드가 자동으로 업데이트를 확인한다 — 업데이트가 있으면 설치 후 App Lab이 재시작된다.
  3. 최초 설정 중 기기 이름·비밀번호를 지정하고 Wi-Fi 자격증명을 입력한다(4.4에서 이 Wi-Fi 설정을 nmcli로도 다시 다룬다).
  4. Examples 섹션에서 예제 App을 열어 우측 상단 Run을 누른다. Apps 섹션에서 새 App을 만들 수도 있다.
  5. App의 상태는 해당 App의 Console 탭에서 확인한다.

USB-C는 5V/3A 전원과 데이터를 동시에 지원한다. PC-hosted 모드 최초 설정에는 데이터 연결이 필요하지만, 이후에는 SSH를 통한 Network 타깃으로 전환해 USB 없이 작업할 수 있다(공식 매뉴얼).

4.1.3.3 실습 — Hello World(Blink) App

App Lab에서 가장 먼저 실행해 볼 예제는 클래식 Blink를 App 구조로 옮긴 것이다.

  1. App Lab Examples 섹션을 연다.
  2. PC-hosted 모드라면 UNO Q를 PC에 연결한다.
  3. Blink LED 예제를 연다 — 예제 노트에서 App 구성을 미리 살펴본다.
  4. Run을 누르고 업로드가 끝날 때까지 기다린다.

내장 RGB LED의 빨강 채널이 1초 켜짐·1초 꺼짐을 반복하면 성공이다. LED는 STM32U585가 직접 구동하지만, App을 실행할 때마다 MCU 스케치 컴파일과 Python 애플리케이션 기동이 함께 일어난다 — 복잡도에 따라 최대 1분 정도 걸릴 수 있다(공식 매뉴얼).

4.1.3.4 Run 버튼이 실제로 하는 일

Run을 누르면 App Lab은 다음을 순서대로 처리한다.

  1. Linux(Python) 컴포넌트를 빌드한다.
  2. MCU 스케치를 컴파일하고 플래시한다 — 앞서 본 remoteocd/SWD 경로와 동일하다.
  3. App이 선택한 Brick이 있다면 배포한다.
  4. 보드 위에서 전체(Python + 스케치 + Brick)를 기동한다.

이후 로그는 App의 Console 탭에서 세 가지로 나뉘어 보인다.

탭내용
Start-up실행 시퀀스 로그 — MCU 컴파일, Linux 배포 과정
Main (Python)Python 애플리케이션의 print() 출력
Sketch (Microcontroller)스케치의 Serial.println() 출력(정확히는 Monitor — 4.2 참조)

App이 "성공적으로 실행"되었다고 해서 런타임 오류가 없다는 뜻은 아니다 — 스케치 컴파일 오류는 실행 자체를 막지만, Python 쪽 런타임 예외는 Console의 Main (Python) 로그를 따로 확인해야 발견된다.

4.1.4 두 워크플로우 비교

항목Arduino IDE (스케치만)App Lab (App)
실행 결과물MCU 스케치 1개MCU 스케치 + Python 앱(+선택적 Brick)
Bridge 사용스케치에 라이브러리로 직접 포함 가능(선택)기본 전제 — Bridge로 두 프로세서를 연동
MPU 관여플래싱 경로(SWD 어댑터)로만실행 주체 — Python 프로세스가 Linux 위에서 상시 구동
대표 용도순수 MCU 로직(센서 폴링, PWM 제어 등)네트워크·AI·웹 UI 등 Linux 자원과 MCU를 함께 쓰는 앱
배포 방식USB(ADB) 또는 SSH + arduino-cliApp Lab GUI, 또는 arduino-app-cli로 SSH 배포(4.2.7 참조)
프로젝트 구조.ino 파일 하나(+선택적 .h)app.yaml + python/ + sketch/(4.2에서 상세)

두 경로는 배타적이지 않다. Arduino IDE로 작성한 스케치를 나중에 App Lab 프로젝트의 sketch/ 폴더로 옮기고 Python 쪽을 추가하는 방식의 점진적 전환도 자연스럽다 — 다만 IDE 단독으로 넣었던 라이브러리가 App Lab에서도 아키텍처 태그(zephyr)를 만족하는지는 4.1.5에서 다룰 라이브러리 호환성 주의사항을 확인한다.

4.1.5 엣지케이스와 트러블슈팅

4.1.5.1 라이브러리 호환성 — AVR 전용 라이브러리 함정

Arduino 라이브러리는 library.properties에 지원 아키텍처를 선언한다(avr, samd, * 등). UNO Q는 zephyr 아키텍처를 요구하는데, 다음과 같은 문제가 실제로 보고되었다(Arduino 포럼, "UNO Q library compatibility" 스레드).

  • 일부 라이브러리(예: Adafruit Motor Shield v1)는 실제로는 AVR·PIC32 전용인데 메타데이터에 와일드카드(*, 모든 보드 호환)로 잘못 선언되어 있어, App Lab/Library Manager가 UNO Q에서도 설치 가능한 것처럼 보여준다.
  • 컴파일이 되더라도 런타임에 레지스터 접근이 STM32와 맞지 않아 동작하지 않을 수 있다.
  • 반대로 실제로는 동작하지만 아키텍처 태그가 zephyr를 포함하지 않아 App Lab에 안 보이는 라이브러리도 있다(예: Adafruit MLX90640 — 커뮤니티가 태그를 수정한 포크를 공유한 사례).

대응: 라이브러리를 쓰기 전에 GitHub 저장소의 이슈·포럼에서 "UNO Q" 검색으로 실동작 여부를 먼저 확인한다. 의심스러우면 Wire·SPI·digitalRead/Write 같은 Arduino 표준 API만으로 직접 레지스터 프로토콜을 구현하는 편이 오히려 안전하다(4.3에서 이 접근을 실제로 쓴다).

4.1.5.2 App 실행 중 USB 점유

App이 실행 중일 때는 App Lab이 USB 인터페이스를 점유할 수 있다. 외부 CLI 도구(arduino-cli, adb 직접 사용 등)로 USB를 통해 보드에 접근하려면 App Lab에서 해당 App을 중지하거나 보드를 먼저 분리해야 한다(공식 매뉴얼).

4.1.5.3 전원 요구사항

USB Power Delivery는 5V/3A 계약만 요청한다(더 높은 전압 프로파일 요청 없음). 5V/3A를 보장하지 못하는 케이블·전원 어댑터를 쓰면 Wi-Fi 버스트나 디스플레이 초기화 같은 순간 부하에서 전압 강하가 생겨 재부팅되는 사례가 보고된다. 정격 5V/3A USB-C 케이블·전원을 쓰거나, JANALOG1의 VIN(7-24V DC)으로 별도 전원을 공급한다(공식 데이터시트, 2.4에서 전원 설계를 상세히 다룬다).

4.1.6 다음 장으로

이 장에서는 MCU에 코드를 "업로드하는" 두 가지 경로와 그 내부 메커니즘(remoteocd/SWD, App Lab의 Run 파이프라인)을 확인했다. 4.2에서는 App Lab 프로젝트의 실제 파일 구조(app.yaml, sketch.yaml, python/main.py)와 Bridge API(스케치 쪽 Bridge.provide/Bridge.call, Python 쪽 arduino.app_utils)를 구체적인 코드로 이어간다.

교차참조: 2.1(MPU/MCU 아키텍처) · 3.1(Debian) · 3.2(Zephyr 기반 Arduino Core) · 3.3(App Lab 아키텍처) · 3.4(Bridge 내부) · 4.2(App Lab 연동 앱) · 5.2(SSH 원격 배포)