고등학생 대상 로봇 AI 교육 커리큘럼 (12차시)
본 문서는 고등학생을 위한 로봇 AI 교육 커리큘럼을 소개합니다. 아두이노 기반 4WD 자율주행차를 제작하고, C언어와 Python을 활용하여 센서와 모터를 제어하며, TensorFlow를 통해 AI 객체 인식 모델을 적용하는 12차시 교육 과정입니다. 학생들은 실습을 통해 미래 로봇·AI 기술을 이해하고 활용하는 능력을 기를 수 있습니다.
교육 목표
본 커리큘럼은 고등학생들이 로봇공학과 인공지능의 기초를 실습을 통해 배울 수 있도록 설계되었습니다. 이론적 지식뿐만 아니라 실제 하드웨어와 소프트웨어를 다루는 경험을 통해 미래 기술에 대한 이해도를 높이고자 합니다.
아두이노 기반 자율주행차
아두이노(UNO/Nano)를 활용하여 4WD 자율주행차를 직접 제작하고 제어하는 방법을 학습합니다. 하드웨어 조립부터 프로그래밍까지 전 과정을 경험하며 로봇공학의 기초를 다집니다.
프로그래밍 언어 활용
C언어(Arduino IDE)를 통해 센서와 모터 제어 원리를 이해하고, Python을 활용하여 OpenCV 영상 처리와 블루투스/시리얼 통신을 구현합니다. 두 언어의 특성과 활용법을 배웁니다.
AI 객체 인식 적용
TensorFlow를 이용한 간단한 AI 객체 인식 모델을 직접 학습시키고 적용해봅니다. 머신러닝의 기본 개념부터 실제 구현까지 체험하며 AI의 원리를 이해합니다.
융합적 사고력 개발
자율주행과 AI의 융합 실습을 통해 미래 로봇·AI 기술의 가능성을 탐색합니다. 실생활 문제 해결에 첨단 기술을 적용하는 사고력을 키웁니다.
이 교육 과정을 통해 학생들은 단순한 코딩을 넘어 하드웨어와 소프트웨어의 연동, 그리고 인공지능의 적용까지 경험하며 4차 산업혁명 시대에 필요한 융합적 사고력과 문제 해결 능력을 기를 수 있습니다. 특히 팀 프로젝트를 통해 협업 능력도 함께 향상시키는 것을 목표로 합니다.
준비물
성공적인 로봇 AI 교육을 위해서는 적절한 하드웨어와 소프트웨어 준비가 필수적입니다. 아래는 12차시 교육과정에서 필요한 주요 준비물 목록입니다.
위 이미지는 본 교육과정에 필요한 주요 하드웨어 구성품을 보여줍니다. 모든 부품은 교육용으로 안전하게 설계되었으며, 학생들이 직접 조립하고 프로그래밍할 수 있도록 준비되었습니다.
하드웨어 구성품
  • Arduino Uno 또는 Nano + USB 케이블
  • 4WD 섀시 + DC 기어드 모터 4개
  • L298N 모터 드라이버 모듈
  • IR 라인트레이서 센서(3~5채널)
  • 초음파 센서 HC-SR04 (장애물 감지용)
  • 블루투스 모듈 HC-06 또는 BT-05
  • 7.4V 배터리(18650 ×2) + 홀더/스위치
  • 점퍼 와이어 및 브레드보드
  • USB 카메라 또는 노트북 내장 카메라
소프트웨어 환경
학생들의 컴퓨터(노트북 또는 PC)에는 다음 소프트웨어가 설치되어 있어야 합니다:
Arduino IDE
아두이노 프로그래밍을 위한 통합 개발 환경으로, C/C++ 기반의 코드 작성 및 업로드가 가능합니다. 공식 웹사이트(arduino.cc)에서 무료로 다운로드할 수 있습니다.
Python 3.8 이상
OpenCV 및 TensorFlow 라이브러리 사용을 위한 기본 프로그래밍 언어입니다. Anaconda 배포판 설치를 권장합니다.
OpenCV
컴퓨터 비전 라이브러리로, 카메라 영상 처리 및 이미지 분석에 사용됩니다. pip install opencv-python 명령으로 설치합니다.
TensorFlow 2.x
구글에서 개발한 오픈소스 머신러닝 라이브러리로, 인공지능 모델 학습 및 추론에 사용됩니다. pip install tensorflow 명령으로 설치합니다.

준비물 구매 팁: 아두이노 4WD 자동차 키트는 온라인 쇼핑몰에서 교육용 세트로 구매 가능합니다. 학교에서 다수 구매 시 할인을 받을 수 있으니 견적을 비교해보세요. 학생 3~4명당 1세트를 준비하는 것이 효율적입니다.
모든 준비물은 수업 시작 전에 미리 확인하고 테스트해보는 것이 좋습니다. 특히 소프트웨어 설치는 시간이 소요될 수 있으므로, 첫 수업 전에 학생들이 미리 설치할 수 있도록 안내하는 것이 좋습니다.
차시별 수업 구성 (12차시 × 1시간)
본 교육과정은 총 12차시로 구성되며, 각 차시는 1시간씩 진행됩니다. 체계적인 학습을 위해 기초 이론부터 시작하여 점진적으로 심화된 내용을 다루며, 마지막에는 종합 프로젝트로 학습 내용을 통합적으로 적용하게 됩니다.
1차시 — 로봇 AI 개론 & 안전교육
첫 번째 수업에서는 로봇공학과 인공지능의 기본 개념을 소개하고, 안전한 실습을 위한 교육을 진행합니다.
이론 학습
  • 4차 산업혁명의 핵심 기술과 미래 직업 변화
  • 로봇과 AI의 정의 및 역사적 발전 과정
  • 자율주행 자동차 기술의 발전과 현재 상용화 사례
  • 로봇 제어의 기본 원리 (센서-처리-액추에이터)
하드웨어 소개
  • 아두이노의 역할과 주요 특징 설명
  • 각종 센서(IR, 초음파)의 작동 원리
  • 모터 드라이버(L298N)를 통한 DC모터 제어 방식
  • 블루투스 모듈의 무선 통신 원리
안전수칙 교육
전기 안전
배터리 극성 확인, 단락(쇼트) 방지, 적정 전압 사용, 화재 예방 수칙
공구 사용
드라이버, 니퍼, 와이어 스트리퍼 등 공구 안전 사용법
부품 취급
정전기 방지, 민감한 전자부품 보관법, 파손 예방 수칙
첫 차시에서는 실제 조립이나 코딩보다는 전체 과정에 대한 로드맵을 제시하고, 학생들의 흥미를 유발하는 데 중점을 둡니다. 영상 자료를 통해 완성된 프로젝트의 모습을 미리 보여주고, 앞으로 배울 내용에 대한 기대감을 높이는 것이 좋습니다.

교사 팁: 학생들의 사전 지식 수준을 파악하기 위해 간단한 퀴즈나 토론을 진행해보세요. 로봇과 AI에 대한 미디어 속 이미지와 실제 기술의 차이점을 이야기하며 오개념을 바로잡는 것도 좋은 시작입니다.
2차시 — 아두이노 기초 & C언어 코딩
두 번째 수업에서는 아두이노 개발 환경을 설치하고 기본적인 C언어 프로그래밍을 학습합니다. 간단한 실습을 통해 프로그래밍의 기초 개념을 이해하고 아두이노 하드웨어와의 상호작용 방법을 배웁니다.
아두이노 개발 환경 설정
  1. Arduino IDE 설치 및 실행
  1. 보드 선택 (Arduino UNO/Nano)
  1. 포트 설정 및 드라이버 설치
  1. 기본 예제 프로그램 열기
아두이노 프로그램 구조 이해
void setup() { // 초기화 코드: 한 번만 실행 pinMode(13, OUTPUT); } void loop() { // 반복 실행 코드 digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); }
C언어 기초 문법
  • 변수 선언과 데이터 타입 (int, float, boolean)
  • 연산자 (+, -, *, /, %, ==, !=, >, <, &&, ||)
  • 조건문 (if, else, switch)
  • 반복문 (for, while)
  • 함수 정의와 호출
실습 과제: LED 제어
기본 회로 구성
아두이노 디지털 핀에 LED와 저항 연결하기
Blink 프로그램
LED를 일정 간격으로 깜빡이게 하는 코드 작성
순차점멸 프로그램
여러 개의 LED를 순차적으로 켜고 끄는 코드 작성
버튼 입력 추가
푸시버튼으로 LED 동작을 제어하는 코드 작성
심화 실습: 부저 제어
아두이노의 tone() 함수를 사용하여 간단한 멜로디를 만들어보는 실습을 진행합니다. 학생들은 주파수와 음계의 관계를 이해하고, 다양한 음악적 패턴을 프로그래밍해봅니다.
"프로그래밍은 단순히 코드를 작성하는 것이 아니라, 논리적 사고를 통해 문제를 해결하는 과정입니다. 오늘 배운 기초 개념들은 앞으로 로봇을 제어하는 모든 과정의 토대가 됩니다."

주의사항: LED 연결 시 극성을 확인하고, 반드시 저항을 사용하세요. 버튼 연결 시에는 풀업/풀다운 저항의 필요성을 설명하고, 플로팅 현상을 방지하는 방법을 알려주세요.
이 차시에서는 아두이노와 C언어의 기본 개념을 이해하는 것이 중요합니다. 학생들이 코드를 단순히 따라 치는 것이 아니라, 각 명령어의 의미와 프로그램의 실행 흐름을 이해할 수 있도록 충분한 설명을 제공해야 합니다. 디버깅 과정도 함께 경험하게 하여 문제 해결 능력을 기를 수 있도록 지도하세요.
3차시 — 4WD 자동차 조립 & 모터 제어
세 번째 수업에서는 4륜 구동(4WD) 자동차 섀시를 조립하고, DC 모터를 제어하는 방법을 학습합니다. 하드웨어 조립과 모터 제어 프로그래밍을 통해 로봇의 기본 움직임을 구현해봅니다.
섀시 조립 과정
01
부품 확인
섀시 프레임, 모터 마운트, 바퀴, 나사 및 기타 부속품을 확인하고 분류합니다.
02
모터 장착
DC 기어드 모터 4개를 섀시의 지정된 위치에 나사로 고정합니다. 모터 축의 방향을 확인하세요.
03
바퀴 설치
모터 축에 바퀴를 장착하고 고정 나사로 단단히 조입니다. 바퀴가 흔들리지 않도록 주의하세요.
04
배터리 홀더 장착
18650 배터리 홀더를 섀시 하단에 부착하고, 전원 스위치를 연결합니다.
05
아두이노 & 드라이버 보드 설치
아두이노 UNO와 L298N 모터 드라이버를 섀시 상단에 장착하고 케이블 관리를 합니다.
L298N 모터 드라이버 연결
L298N 모터 드라이버는 아두이노의 디지털 신호를 받아 DC 모터를 구동하는 중요한 부품입니다. 모터는 많은 전류를 소모하기 때문에 아두이노에서 직접 구동할 수 없으며, 모터 드라이버를 통해 제어합니다.
아두이노와 L298N의 연결 방법은 다음과 같습니다:
  • L298N의 ENA, ENB 핀 → 아두이노 PWM 핀 (속도 제어)
  • L298N의 IN1, IN2, IN3, IN4 핀 → 아두이노 디지털 핀 (방향 제어)
  • L298N의 전원 → 7.4V 배터리 연결
  • L298N의 GND → 아두이노 GND (공통 접지)
모터 제어 코드
// 모터 핀 정의 const int ENA = 10; const int IN1 = 9; const int IN2 = 8; const int ENB = 5; const int IN3 = 7; const int IN4 = 6; void setup() { // 모터 제어 핀을 출력으로 설정 pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); } void loop() { // 앞으로 이동 forward(150); delay(2000); // 정지 stop(); delay(1000); // 뒤로 이동 backward(150); delay(2000); // 좌회전 left(150); delay(1000); // 우회전 right(150); delay(1000); }
모터 제어 함수 구현
앞으로 이동
void forward(int speed) { analogWrite(ENA, speed); analogWrite(ENB, speed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); }
뒤로 이동
void backward(int speed) { analogWrite(ENA, speed); analogWrite(ENB, speed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); }
좌회전
void left(int speed) { analogWrite(ENA, speed); analogWrite(ENB, speed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); }
우회전
void right(int speed) { analogWrite(ENA, speed); analogWrite(ENB, speed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); }

안전 주의사항: 모터 연결 시 극성에 주의하세요. 배터리는 완전히 충전된 상태에서 사용하고, 과열 방지를 위해 장시간 연속 구동은 피하세요. 처음 테스트할 때는 자동차를 들어올린 상태에서 바퀴의 회전 방향을 확인하세요.
이 차시에서는 하드웨어 조립과 소프트웨어 프로그래밍을 연결하는 중요한 단계입니다. 학생들이 모터의 작동 원리와 PWM(Pulse Width Modulation)을 통한 속도 제어 개념을 이해할 수 있도록 충분한 설명을 제공하세요. 조립 과정에서 팀워크가 중요하므로, 3~4명의 소그룹으로 나누어 협업하도록 지도하는 것이 효과적입니다.
4차시 — 라인트레이서 센서 활용
네 번째 수업에서는 IR(적외선) 라인트레이서 센서의 원리를 이해하고, 이를 활용하여 자동차가 검은색 라인을 따라 주행하도록 프로그래밍합니다. 라인트레이싱은 자율주행의 기본적인 형태로, 센서 입력에 따른 판단과 제어를 경험할 수 있는 중요한 학습 과정입니다.
IR 센서의 원리
라인트레이서 센서는 적외선 LED와 포토트랜지스터로 구성되어 있습니다. 적외선 LED에서 방출된 빛이 표면에서 반사되어 포토트랜지스터로 돌아오는 원리를 이용합니다.
흰색 표면
적외선을 많이 반사 → 포토트랜지스터에 많은 빛 감지 → HIGH 신호 출력
검은색 표면
적외선을 많이 흡수 → 포토트랜지스터에 적은 빛 감지 → LOW 신호 출력
센서 배치 및 연결
일반적으로 3~5개의 IR 센서를 자동차 전면 하단에 일렬로 배치합니다. 센서 간격은 라인의 폭을 고려하여 조정해야 합니다.
센서 연결 방법:
  • 각 센서의 VCC → 아두이노 5V
  • 각 센서의 GND → 아두이노 GND
  • 각 센서의 OUT → 아두이노 디지털 핀 (A0~A4 권장)
센서 배치 시 주의사항:
  • 센서와 바닥 사이 거리는 5~10mm가 적절함
  • 센서가 바닥과 평행을 이루도록 설치
  • 주변 광원의 영향을 최소화하도록 설계
센서값 읽기 및 임계값 설정
// 센서 핀 정의 const int sensorPin[3] = {A0, A1, A2}; int sensorValue[3] = {0, 0, 0}; int threshold = 500; // 임계값 void setup() { Serial.begin(9600); // 센서 핀을 입력으로 설정 for(int i=0; i<3; i++) { pinMode(sensorPin[i], INPUT); } } void loop() { // 센서값 읽기 for(int i=0; i<3; i++) { sensorValue[i] = analogRead(sensorPin[i]); Serial.print(sensorValue[i]); Serial.print("\t"); } Serial.println(); delay(100); }
시리얼 모니터에서 센서값을 관찰하며 흰색과 검은색 표면에서의 값을 확인하고, 적절한 임계값을 설정합니다.
라인 추종 알고리즘
3채널 센서를 사용한 기본적인 라인 추종 알고리즘은 다음과 같습니다:
라인 추종 코드 구현
void followLine() { // 센서값 읽기 for(int i=0; i<3; i++) { sensorValue[i] = analogRead(sensorPin[i]); } // 라인 감지 여부 확인 (threshold 기준) bool leftOnLine = (sensorValue[0] < threshold); bool centerOnLine = (sensorValue[1] < threshold); bool rightOnLine = (sensorValue[2] < threshold); // 라인 위치에 따른 동작 결정 if(leftOnLine && !centerOnLine && !rightOnLine) { // 라인이 왼쪽에 있음 left(150); } else if(!leftOnLine && centerOnLine && !rightOnLine) { // 라인이 중앙에 있음 forward(200); } else if(!leftOnLine && !centerOnLine && rightOnLine) { // 라인이 오른쪽에 있음 right(150); } else if(!leftOnLine && !centerOnLine && !rightOnLine) { // 라인을 찾지 못함 searchLine(); } else if(leftOnLine && centerOnLine && rightOnLine) { // 모든 센서가 라인 위에 있음 (교차로 등) forward(100); // 속도를 줄이고 진행 } } void searchLine() { // 라인을 잃었을 때 찾는 알고리즘 // 간단한 구현: 제자리에서 회전 stop(); delay(100); left(120); delay(300); }

학습 심화: 5채널 센서를 사용하면 더 정밀한 라인 추종이 가능합니다. PID 제어 알고리즘을 적용하여 더 부드러운 주행을 구현할 수도 있습니다. 관심 있는 학생들에게는 PID 제어의 개념과 구현 방법을 소개해보세요.
이 차시에서는 센서의 물리적 원리와 이를 활용한 제어 알고리즘을 이해하는 것이 중요합니다. 학생들이 센서값의 변화를 시각적으로 확인하고, 알고리즘의 동작을 단계별로 이해할 수 있도록 지도하세요. 또한 실제 환경에서 발생할 수 있는 다양한 상황(교차로, 곡선, 라인 유실 등)에 대한 대응 방법도 함께 논의하면 좋습니다.
5차시 — 장애물 회피 주행
다섯 번째 수업에서는 초음파 센서(HC-SR04)를 활용하여 자동차가 주행 중 장애물을 감지하고 회피하는 기능을 구현합니다. 이 과정을 통해 센서 데이터를 기반으로 한 의사결정과 알고리즘 구현 능력을 기릅니다.
초음파 센서 원리
HC-SR04 초음파 센서는 초음파를 발사하고 물체에 반사되어 돌아오는 시간을 측정하여 거리를 계산하는 원리로 작동합니다.
  1. Trig 핀에 10μs 이상의 HIGH 신호를 보내면 센서가 40kHz 초음파 펄스 8개를 발사
  1. 초음파가 물체에 반사되어 돌아와 Echo 핀이 HIGH 상태가 됨
  1. Echo 핀의 HIGH 지속 시간이 초음파의 왕복 시간
  1. 거리 = 시간 × 음속(340m/s) ÷ 2
센서 연결 방법:
  • VCC → 아두이노 5V
  • GND → 아두이노 GND
  • Trig → 아두이노 디지털 핀 (예: D12)
  • Echo → 아두이노 디지털 핀 (예: D13)
거리 측정 코드
// 초음파 센서 핀 정의 const int trigPin = 12; const int echoPin = 13; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } // 초음파 센서로 거리 측정 함수 float getDistance() { // 초음파 발사 전 Trig 핀 초기화 digitalWrite(trigPin, LOW); delayMicroseconds(2); // 10μs 동안 Trig 핀에 HIGH 신호 인가 digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Echo 핀의 HIGH 상태 지속 시간 측정 long duration = pulseIn(echoPin, HIGH); // 거리 계산 (cm) // 음속: 340m/s = 0.034cm/μs // 왕복이므로 나누기 2 float distance = duration * 0.034 / 2; return distance; }
장애물 회피 알고리즘
거리 측정
주행 중 정기적으로 전방 거리 측정
장애물 감지
측정 거리가 안전 거리(예: 20cm) 이하면 장애물로 판단
일시 정지
장애물 감지 시 안전을 위해 즉시 정지
회전 방향 결정
좌우 회전 중 하나를 선택 (무작위 또는 추가 센서 활용)
회피 기동
결정된 방향으로 회전 후 직진하여 장애물 회피
장애물 회피 코드 구현
// 안전 거리 설정 (cm) const float safeDistance = 20.0; void loop() { // 현재 전방 거리 측정 float currentDistance = getDistance(); // 장애물 감지 및 회피 if(currentDistance < safeDistance) { // 장애물 감지, 회피 동작 실행 avoidObstacle(); } else { // 안전 거리 확보, 정상 주행 계속 followLine(); // 라인 트레이싱 함수 호출 } delay(100); // 측정 간격 } void avoidObstacle() { // 장애물 감지 시 회피 알고리즘 // 1. 일시 정지 stop(); delay(500); // 2. 회피 방향 결정 (여기서는 무작위로 선택) bool turnRight = random(2); // 0 또는 1 반환 // 3. 회피 기동 실행 if(turnRight) { // 우회전으로 회피 right(150); delay(700); // 약 90도 회전 forward(150); delay(1000); // 장애물 옆으로 이동 left(150); delay(700); // 다시 원래 방향으로 } else { // 좌회전으로 회피 left(150); delay(700); // 약 90도 회전 forward(150); delay(1000); // 장애물 옆으로 이동 right(150); delay(700); // 다시 원래 방향으로 } // 4. 정상 주행 재개 forward(150); }
라인트레이싱과 장애물 회피 통합
라인트레이싱과 장애물 회피를 통합하기 위해서는 두 기능 간의 우선순위를 결정해야 합니다. 일반적으로 안전을 위해 장애물 회피가 더 높은 우선순위를 갖습니다.
거리 확인
전방 장애물 거리 측정
판단
안전 거리 이내 장애물 유무 확인
장애물 회피
장애물 감지 시 회피 알고리즘 실행
라인 추종
장애물 없을 시 라인트레이싱 계속

심화 학습: 단일 초음파 센서로는 회피 방향을 효과적으로 결정하기 어렵습니다. 초음파 센서를 서보모터에 장착하여 좌우 스캔 후 더 넓은 공간이 있는 방향으로 회피하거나, 여러 개의 센서를 다른 방향으로 배치하여 더 정확한 장애물 감지를 구현할 수 있습니다.
이 차시에서는 다중 센서 데이터를 활용한 알고리즘 개발과 실제 상황에서의 로봇 제어를 학습합니다. 학생들이 단순히 코드를 따라하는 것이 아니라, 로봇이 마주할 수 있는 다양한 상황을 예측하고 해결 방법을 스스로 고민할 수 있도록 지도하세요. 센서의 한계(측정 각도, 오차, 반사 문제 등)와 그에 따른 대응 방법에 대한 토론도 유익할 것입니다.
6차시 — 블루투스 무선 제어
여섯 번째 수업에서는 블루투스 모듈(HC-06)을 활용하여 자동차를 무선으로 제어하는 방법을 학습합니다. 스마트폰이나 PC에서 명령을 전송하여 자동차를 원격으로 조종하고, 자율/수동 모드를 전환하는 기능을 구현합니다.
블루투스 모듈 개요
HC-06은 아두이노에 무선 통신 기능을 추가하는 블루투스 슬레이브 모듈입니다. 스마트폰이나 PC와 페어링하여 시리얼 통신을 무선으로 수행할 수 있습니다.
모듈 특징
  • 블루투스 버전: 2.0 EDR
  • 통신 거리: ~10m (개방 공간)
  • 동작 전압: 3.3V (5V 호환)
  • 기본 통신 속도: 9600bps
  • 기본 페어링 PIN: 1234
모듈 연결
  • VCC → 아두이노 5V
  • GND → 아두이노 GND
  • TXD → 아두이노 RX (디지털 핀 0)
  • RXD → 아두이노 TX (디지털 핀 1)
주의: RX/TX 연결 시 아두이노의 RX는 모듈의 TX와, 아두이노의 TX는 모듈의 RX와 연결해야 합니다(교차 연결).
블루투스 설정 및 테스트 코드
#include // 소프트웨어 시리얼 핀 설정 // 하드웨어 시리얼(0,1)은 업로드 시 충돌 가능성 const int BT_RX = 2; // 아두이노 D2 핀 const int BT_TX = 3; // 아두이노 D3 핀 // 소프트웨어 시리얼 객체 생성 SoftwareSerial BTSerial(BT_RX, BT_TX); void setup() { Serial.begin(9600); // PC와 통신용 BTSerial.begin(9600); // 블루투스 통신용 Serial.println("블루투스 통신 테스트"); } void loop() { // 블루투스로 받은 데이터를 PC로 전송 if (BTSerial.available()) { char data = BTSerial.read(); Serial.write(data); } // PC에서 받은 데이터를 블루투스로 전송 if (Serial.available()) { char data = Serial.read(); BTSerial.write(data); } }
블루투스 페어링 방법
01
모듈 전원 공급
아두이노에 블루투스 모듈을 연결하고 전원을 공급하면 LED가 빠르게 깜빡입니다.
02
기기 검색
스마트폰/PC의 블루투스 설정에서 새 기기 검색을 실행하면 'HC-06'이 검색됩니다.
03
페어링 요청
HC-06을 선택하고 페어링을 요청하면 PIN 코드 입력창이 나타납니다.
04
PIN 입력
기본 PIN 코드 '1234'를 입력하고 확인하면 페어링이 완료됩니다.
05
연결 확인
페어링이 완료되면 HC-06의 LED가 천천히 깜빡이거나 계속 켜진 상태가 됩니다.
스마트폰에서 블루투스 제어 앱 사용
안드로이드 기기에서는 'Bluetooth Terminal', 'Arduino Bluetooth Controller' 등의 앱을 사용할 수 있습니다. 이러한 앱에서 페어링된 HC-06을 선택하고 연결한 후, 다음과 같은 명령어를 보낼 수 있습니다:
블루투스 제어 코드 구현
#include // 소프트웨어 시리얼 설정 SoftwareSerial BTSerial(2, 3); // RX, TX // 모터 제어 핀 (이전 차시와 동일) // 변수 및 함수 정의는 생략... // 주행 모드 변수 bool autoMode = false; // 기본값은 수동 모드 void setup() { // 모터 핀 설정 // 센서 핀 설정 // 이전 차시와 동일... // 블루투스 통신 시작 BTSerial.begin(9600); } void loop() { // 블루투스 명령 확인 if (BTSerial.available()) { char command = BTSerial.read(); executeCommand(command); } // 자율주행 모드일 경우 센서 기반 주행 실행 if (autoMode) { // 장애물 감지 float distance = getDistance(); if (distance < safeDistance) { // 장애물 회피 avoidObstacle(); } else { // 라인 트레이싱 followLine(); } } delay(50); } // 블루투스 명령 실행 함수 void executeCommand(char command) { switch(command) { case 'F': // 전진 forward(200); break; case 'B': // 후진 backward(200); break; case 'L': // 좌회전 left(150); break; case 'R': // 우회전 right(150); break; case 'S': // 정지 stop(); break; case 'A': // 자율주행 모드 autoMode = true; BTSerial.println("Auto mode activated"); break; case 'M': // 수동 제어 모드 autoMode = false; stop(); // 안전을 위해 정지 BTSerial.println("Manual mode activated"); break; } }
블루투스 통신 데이터 수신 개선
블루투스 통신은 때때로 데이터 유실이나 오류가 발생할 수 있습니다. 이를 개선하기 위한 방법은 다음과 같습니다:
명령 확인 응답
명령을 수신할 때마다 확인 메시지를 송신하여 명령이 제대로 처리되었음을 알립니다.
// 명령 수신 후 응답 전송 BTSerial.print("Received: "); BTSerial.println(command);
상태 정보 전송
정기적으로 자동차의 상태 정보(센서값, 모드 등)를 송신하여 모니터링할 수 있게 합니다.
// 주기적으로 상태 정보 전송 if (millis() - lastStatusTime > 1000) { // 1초마다 BTSerial.print("Distance: "); BTSerial.print(getDistance()); BTSerial.print("cm, Mode: "); BTSerial.println(autoMode ? "Auto" : "Manual"); lastStatusTime = millis(); }

배터리 주의: 블루투스 모듈은 추가적인 전력을 소모합니다. 배터리 용량을 확인하고, 전압이 낮아지면 모터와 센서 동작이 불안정해질 수 있으므로 정기적으로 배터리 상태를 확인하세요.
이 차시에서는 무선 통신을 통한 로봇 제어의 기본 개념을 학습합니다. 블루투스 통신은 IoT(사물인터넷)의 기초가 되는 기술이므로, 이를 통해 학생들에게 연결된 기기의 개념과 원격 제어의 가능성을 소개할 수 있습니다. 또한 자율/수동 모드 전환 기능은 실제 자율주행 시스템에서도 중요한 기능이므로, 이러한 개념을 이해하는 것이 중요합니다.
8차시 — AI 기초 & TensorFlow 환경 구축
여덟 번째 수업에서는 인공지능의 기본 개념을 이해하고, TensorFlow 라이브러리를 설치하여 간단한 모델을 실행해봅니다. 머신러닝과 딥러닝의 차이점, 학습 데이터의 중요성, 그리고 기본적인 신경망 구조에 대해 학습합니다.
인공지능, 머신러닝, 딥러닝 개념
인공지능 (AI)
인간의 지능을 모방하여 문제를 해결하고 의사결정을 수행하는 광범위한 기술 분야
  • 규칙 기반 시스템
  • 전문가 시스템
  • 자연어 처리
  • 컴퓨터 비전
머신러닝 (ML)
데이터로부터 패턴을 학습하여 예측이나 의사결정을 수행하는 AI의 하위 분야
  • 지도학습 (분류, 회귀)
  • 비지도학습 (군집화)
  • 강화학습
딥러닝 (DL)
여러 층의 인공 신경망을 사용하여 복잡한 패턴을 학습하는 머신러닝의 하위 분야
  • 인공 신경망 (ANN)
  • 합성곱 신경망 (CNN)
  • 순환 신경망 (RNN)
머신러닝 vs 딥러닝
TensorFlow 환경 구축
TensorFlow는 구글에서 개발한 오픈소스 머신러닝 라이브러리로, 다양한 AI 모델을 쉽게 구현하고 학습할 수 있도록 도와줍니다.
TensorFlow 설치
# 기본 TensorFlow 설치 pip install tensorflow # 추가 유용한 패키지들 pip install matplotlib pip install pandas pip install scikit-learn pip install pillow
GPU 가속을 원할 경우, CUDA와 cuDNN을 설치한 후 tensorflow-gpu를 설치할 수 있습니다. 하지만 학습용으로는 CPU 버전으로도 충분합니다.
주요 TensorFlow 모듈
  • tf.keras: 고수준 신경망 API로, 모델 생성과 학습이 쉬움
  • tf.data: 데이터 파이프라인 구축을 위한 도구
  • tf.image: 이미지 처리 기능
  • tf.math: 수학적 연산 함수
  • tf.nn: 저수준 신경망 연산
  • tf.saved_model: 모델 저장 및 로드
TensorFlow의 가장 큰 장점 중 하나는 Keras API를 통해 빠르고 간단하게 딥러닝 모델을 구현할 수 있다는 점입니다. 또한 학습된 모델을 다양한 환경(웹, 모바일, 임베디드)에 배포할 수 있는 도구도 제공합니다.
TensorFlow 버전 확인
import tensorflow as tf print(tf.__version__)
MNIST 예제: 손글씨 숫자 인식
TensorFlow의 기본 작동 방식을 이해하기 위해 MNIST 데이터셋을 활용한 손글씨 숫자 인식 예제를 실습합니다. MNIST는 0부터 9까지의 손글씨 숫자 이미지로 구성된 데이터셋으로, 머신러닝 입문자들이 자주 사용하는 예제입니다.
import tensorflow as tf from tensorflow.keras import layers, models import matplotlib.pyplot as plt import numpy as np # MNIST 데이터셋 로드 (train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data() # 데이터 전처리: 정규화 (0-1 범위로 스케일링) train_images = train_images / 255.0 test_images = test_images / 255.0 # 모델에 입력하기 위해 이미지 차원 확장 (28x28 -> 28x28x1) train_images = train_images.reshape(train_images.shape[0], 28, 28, 1) test_images = test_images.reshape(test_images.shape[0], 28, 28, 1) # 간단한 CNN 모델 구성 model = models.Sequential([ # 첫 번째 합성곱 층 layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), # 두 번째 합성곱 층 layers.Conv2D(64, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), # 세 번째 합성곱 층 layers.Conv2D(64, (3, 3), activation='relu'), # 완전 연결 층을 위한 펼치기 layers.Flatten(), layers.Dense(64, activation='relu'), layers.Dense(10, activation='softmax') # 10개 클래스 (0-9) ]) # 모델 컴파일 model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 모델 구조 요약 model.summary() # 모델 학습 history = model.fit(train_images, train_labels, epochs=5, validation_data=(test_images, test_labels)) # 모델 평가 test_loss, test_acc = model.evaluate(test_images, test_labels) print(f'테스트 정확도: {test_acc:.3f}') # 학습 과정 시각화 plt.figure(figsize=(12, 4)) plt.subplot(1, 2, 1) plt.plot(history.history['accuracy'], label='Training Accuracy') plt.plot(history.history['val_accuracy'], label='Validation Accuracy') plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.legend() plt.subplot(1, 2, 2) plt.plot(history.history['loss'], label='Training Loss') plt.plot(history.history['val_loss'], label='Validation Loss') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.show() # 몇 가지 테스트 이미지에 대한 예측 결과 확인 predictions = model.predict(test_images[:5]) for i in range(5): plt.figure(figsize=(6, 3)) plt.subplot(1, 2, 1) plt.imshow(test_images[i].reshape(28, 28), cmap='gray') plt.title(f"실제: {test_labels[i]}") plt.subplot(1, 2, 2) plt.bar(range(10), predictions[i]) plt.xticks(range(10)) plt.title(f"예측: {np.argmax(predictions[i])}") plt.show()
데이터셋의 구조와 학습 과정 이해
데이터셋 준비
훈련 데이터와 테스트 데이터로 분리, 전처리 수행
모델 설계
적합한 신경망 구조 설계 (CNN, RNN 등)
모델 학습
훈련 데이터로 모델 파라미터 최적화 (역전파 알고리즘)
모델 평가
테스트 데이터로 모델 성능 평가 (정확도, 손실)
모델 배포
학습된 모델을 저장하고 실제 환경에서 사용
CNN(합성곱 신경망) 기본 구조
CNN은 이미지 처리에 특화된 신경망 구조로, 다음과 같은 주요 층으로 구성됩니다:
합성곱 층 (Convolutional Layer)
이미지의 특징을 추출하는 필터(커널)를 사용하여 이미지의 지역적 패턴 인식
풀링 층 (Pooling Layer)
이미지의 크기를 줄이고 중요한 특징을 보존하여 계산량 감소 및 과적합 방지
활성화 함수 (Activation Function)
비선형성을 추가하여 복잡한 패턴 학습 가능 (ReLU 등)
완전 연결 층 (Fully Connected Layer)
추출된 특징을 바탕으로 최종 분류 수행

이해를 돕는 비유: CNN의 작동 방식은 사람이 이미지를 인식하는 과정과 유사합니다. 초기 층에서는 단순한 선이나 모서리 같은 기본 특징을 감지하고, 더 깊은 층으로 갈수록 더 복잡한 패턴(눈, 코, 입 등)을 인식합니다. 마지막으로 이러한 특징들을 종합하여 전체 이미지가 무엇인지 판단합니다.
이 차시에서는 AI의 기본 개념과 TensorFlow 환경 설정, 그리고 간단한 모델 실행까지 배웁니다. 실제 손글씨 숫자 인식 모델을 학습시키고 그 결과를 확인함으로써, 머신러닝의 기본 원리와 과정을 이해할 수 있습니다. 다음 차시에서는 이를 바탕으로 직접 카메라로 데이터를 수집하고 모델을 학습시키는 과정으로 넘어갑니다.
9차시 — 카메라 데이터 수집 & 전처리
아홉 번째 수업에서는 자체 데이터셋을 구축하기 위한 카메라 데이터 수집과 전처리 방법을 학습합니다. 실제 환경에서 이미지를 캡처하고, 이를 AI 모델 학습에 적합한 형태로 가공하는 과정을 경험합니다.
데이터셋의 중요성
AI 모델의 성능은 학습에 사용되는 데이터셋의 질과 양에 크게 의존합니다. 좋은 데이터셋의 특징은 다음과 같습니다:
충분한 데이터 양
딥러닝 모델은 일반적으로 많은 양의 데이터를 필요로 합니다. 적어도 클래스당 100개 이상의 이미지가 권장됩니다.
데이터 다양성
다양한 각도, 조명 조건, 배경, 크기 등의 변화를 포함해야 모델이 실제 환경에서도 잘 작동합니다.
정확한 라벨링
지도학습에서는 각 데이터에 정확한 레이블(정답)이 부여되어야 합니다. 잘못된 라벨은 모델 학습에 악영향을 미칩니다.
균형 잡힌 클래스 분포
각 클래스별 데이터 수가 균등하게 분포되어야 특정 클래스에 편향되지 않은 모델을 학습할 수 있습니다.
OpenCV로 카메라 영상 캡처
학습용 데이터셋을 구축하기 위해 OpenCV를 사용하여 카메라로부터 이미지를 캡처하고 저장하는 코드를 작성합니다.
import cv2 import os import time def capture_images(class_name, output_folder, num_images=50): # 출력 폴더 생성 class_folder = os.path.join(output_folder, class_name) os.makedirs(class_folder, exist_ok=True) # 카메라 열기 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("카메라를 열 수 없습니다.") return print(f"{class_name} 클래스의 이미지 캡처를 시작합니다.") print("준비되면 아무 키나 누르세요...") # 카메라 미리보기 표시 while True: ret, frame = cap.read() if not ret: break cv2.putText(frame, f"Press any key to start capturing {class_name}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) cv2.imshow("Camera Preview", frame) # 키 입력 대기 if cv2.waitKey(1) != -1: break # 이미지 캡처 시작 count = 0 while count < num_images: ret, frame = cap.read() if not ret: break # 캡처 화면에 정보 표시 cv2.putText(frame, f"Capturing {class_name}: {count+1}/{num_images}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imshow("Camera Preview", frame) # 이미지 저장 filename = os.path.join(class_folder, f"{class_name}_{count:04d}.jpg") cv2.imwrite(filename, frame) print(f"저장됨: {filename}") count += 1 time.sleep(0.2) # 약간의 지연으로 다양한 이미지 캡처 # ESC 키를 누르면 중단 if cv2.waitKey(1) == 27: break # 자원 해제 cap.release() cv2.destroyAllWindows() print(f"{class_name} 클래스의 이미지 캡처가 완료되었습니다.") def main(): # 데이터셋 저장 경로 output_folder = "dataset" os.makedirs(output_folder, exist_ok=True) # 캡처할 클래스 목록 (예: 병, 컵, 책) classes = ["bottle", "cup", "book"] # 각 클래스별로 이미지 캡처 for class_name in classes: capture_images(class_name, output_folder, num_images=50) print("다음 클래스로 넘어가기 전에 객체를 바꿔주세요.") input("준비되면 Enter 키를 누르세요...") if __name__ == "__main__": main()
라벨링 툴 소개: LabelImg
객체 감지 모델을 학습시키기 위해서는 이미지 내 객체의 위치 정보(바운딩 박스)와 클래스 정보를 포함한 라벨링이 필요합니다. LabelImg는 이러한 라벨링 작업을 쉽게 할 수 있는 오픈소스 도구입니다.
LabelImg 설치 및 실행
# pip로 설치 pip install labelImg # 실행 labelImg
LabelImg 사용법
  1. Open Dir: 이미지가 있는 폴더 열기
  1. Change Save Dir: 라벨 저장 폴더 설정
  1. Create RectBox (단축키 W): 객체 주변에 박스 그리기
  1. 클래스 이름 입력 (예: bottle, cup, book)
  1. Save (단축키 Ctrl+S): 라벨 정보 저장
  1. Next Image (단축키 D): 다음 이미지로 이동
라벨링 파일 형식
LabelImg는 PASCAL VOC 또는 YOLO 형식으로 라벨 정보를 저장합니다. 예를 들어 PASCAL VOC 형식은 다음과 같은 XML 파일로 저장됩니다:
dataset bottle_0001.jpg /path/to/dataset/bottle_0001.jpg 640 480 3
간단한 데이터셋 구축
이 수업에서는 시간 제약을 고려하여 2~3종류의 물체(예: 병, 컵, 책)에 대한 간단한 이미지 분류 데이터셋을 구축합니다. 각 클래스별로 다음과 같은 다양성을 확보하는 것이 좋습니다:
다양한 각도
정면, 측면, 45도 등 여러 시점에서 촬영
다양한 조명
밝은 조명, 어두운 조명, 자연광 등
다양한 배경
단색 배경, 복잡한 배경, 실내/실외 등
다양한 거리
가까이서, 중간 거리, 멀리서 촬영
다양한 위치
이미지 중앙, 왼쪽, 오른쪽 등
이미지 전처리 기법
원본 이미지를 AI 모델에 입력하기 전에 다양한 전처리 과정을 거치면 학습 효율과 모델 성능을 높일 수 있습니다.
리사이징
모든 이미지를 동일한 크기로 조정합니다. CNN은 일반적으로 고정된 입력 크기를 요구합니다 (예: 224x224, 299x299).
그레이스케일 변환
컬러 정보가 중요하지 않은 경우, 3채널(RGB)에서 1채널(흑백)로 변환하여 메모리와 계산량을 줄입니다.
정규화
픽셀값을 0~1 또는 -1~1 범위로 스케일링하여 학습 안정성을 높입니다.
데이터 증강
회전, 뒤집기, 밝기 조정 등의 변형을 통해 데이터셋을 인위적으로 확장합니다.
이미지 전처리 코드
import os import cv2 import numpy as np from tensorflow.keras.preprocessing.image import ImageDataGenerator def preprocess_images(input_folder, output_folder, target_size=(224, 224), grayscale=False): # 출력 폴더 생성 os.makedirs(output_folder, exist_ok=True) # 클래스별 폴더 처리 for class_name in os.listdir(input_folder): class_path = os.path.join(input_folder, class_name) output_class_path = os.path.join(output_folder, class_name) # 클래스 폴더가 아닌 경우 건너뛰기 if not os.path.isdir(class_path): continue # 출력 클래스 폴더 생성 os.makedirs(output_class_path, exist_ok=True) # 클래스 내 각 이미지 처리 for img_name in os.listdir(class_path): if not img_name.lower().endswith(('.png', '.jpg', '.jpeg')): continue img_path = os.path.join(class_path, img_name) output_img_path = os.path.join(output_class_path, img_name) # 이미지 로드 if grayscale: img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) else: img = cv2.imread(img_path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR to RGB if img is None: print(f"이미지를 로드할 수 없습니다: {img_path}") continue # 이미지 리사이징 img_resized = cv2.resize(img, target_size) # 정규화 (0-1 범위로) img_normalized = img_resized / 255.0 # 그레이스케일 이미지를 3채널로 확장 (필요시) if grayscale and len(img_normalized.shape) == 2: img_normalized = np.stack([img_normalized] * 3, axis=-1) # 전처리된 이미지 저장 # 정규화된 이미지를 다시 0-255로 변환하여 저장 img_to_save = (img_normalized * 255).astype(np.uint8) if grayscale: cv2.imwrite(output_img_path, img_to_save[:,:,0]) else: cv2.imwrite(output_img_path, cv2.cvtColor(img_to_save, cv2.COLOR_RGB2BGR)) print(f"전처리 완료: {output_img_path}") def create_data_generator(use_augmentation=True): """데이터 증강을 위한 ImageDataGenerator 생성""" if use_augmentation: return ImageDataGenerator( rescale=1./255, # 정규화 rotation_range=20, # 회전 width_shift_range=0.2, # 수평 이동 height_shift_range=0.2, # 수직 이동 shear_range=0.2, # 전단 zoom_range=0.2, # 확대/축소 horizontal_flip=True, # 수평 뒤집기 fill_mode='nearest', # 빈 픽셀 채우기 방식 validation_split=0.2 # 검증 데이터 비율 ) else: return ImageDataGenerator( rescale=1./255, # 정규화만 적용 validation_split=0.2 # 검증 데이터 비율 ) def main(): input_folder = "dataset" output_folder = "preprocessed_dataset" # 이미지 전처리 preprocess_images(input_folder, output_folder, target_size=(224, 224), grayscale=False) print("이미지 전처리가 완료되었습니다.") # 데이터 생성기 예시 datagen = create_data_generator(use_augmentation=True) print("데이터 증강 생성기가 생성되었습니다. 학습 시 사용할 수 있습니다.") if __name__ == "__main__": main()
전처리된 이미지 시각화
전처리 및 데이터 증강 효과를 시각적으로 확인하기 위한 코드입니다:
def visualize_augmentation(image_path, output_folder): """데이터 증강 효과를 시각화하여 저장""" import matplotlib.pyplot as plt # 이미지 로드 img = cv2.imread(image_path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (224, 224)) # 데이터 증강 생성기 datagen = ImageDataGenerator( rotation_range=30, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True, fill_mode='nearest' ) # 배치 크기 1로 이미지 포맷 변경 x = img.reshape((1,) + img.shape) # 증강된 이미지 생성 및 저장 os.makedirs(output_folder, exist_ok=True) plt.figure(figsize=(12, 12)) plt.subplot(3, 3, 1) plt.imshow(img) plt.title('Original Image') plt.axis('off') i = 1 for batch in datagen.flow(x, batch_size=1): plt.subplot(3, 3, i + 1) plt.imshow(batch[0].astype(np.uint8)) plt.title(f'Augmented {i}') plt.axis('off') i += 1 if i > 8: # 8개의 증강된 이미지 생성 break plt.tight_layout() plt.savefig(os.path.join(output_folder, 'augmentation_examples.png')) plt.close() print(f"데이터 증강 시각화가 저장되었습니다: {os.path.join(output_folder, 'augmentation_examples.png')}")

데이터셋 확장: 충분한 데이터를 수집하기 어려운 경우, 공개 데이터셋을 활용하는 방법도 있습니다. COCO, ImageNet 등의 대규모 데이터셋에서 관련 이미지를 선별하여 사용하거나, 전이 학습(Transfer Learning)을 활용할 수도 있습니다.
이 차시에서는 AI 모델 학습을 위한 데이터 수집과 전처리의 중요성을 배웁니다. 실제로 카메라를 통해 데이터를 수집하고, 이를 적절히 가공하는 과정을 통해 AI 개발의 핵심 단계를 경험할 수 있습니다. 수집된 데이터는 다음 차시에서 TensorFlow 모델을 학습시키는 데 사용됩니다.
10차시 — TensorFlow 객체 인식 모델 학습
열 번째 수업에서는 이전 차시에서 수집하고 전처리한 데이터를 사용하여 TensorFlow로 객체 인식 모델을 학습시킵니다. CNN(합성곱 신경망)의 구조를 이해하고, 직접 모델을 설계하여 학습시키는 과정을 경험합니다.
CNN(합성곱 신경망) 구조 이해
CNN은 이미지 처리에 특화된 신경망으로, 인접한 픽셀 간의 관계를 고려하여 특징을 추출합니다. 주요 구성 요소와 작동 원리를 살펴봅시다.
1
합성곱 층 (Convolutional Layer)
필터(커널)가 이미지를 슬라이딩하며 특징 맵(feature map)을 생성합니다. 초기 층에서는 엣지, 텍스처 같은 낮은 수준의 특징을 감지하고, 깊은 층에서는 더 복잡한 패턴을 감지합니다.
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)))
2
풀링 층 (Pooling Layer)
특징 맵의 크기를 줄여 계산량을 감소시키고 위치 불변성을 제공합니다. Max Pooling은 각 영역에서 최댓값만 선택하는 방식입니다.
model.add(MaxPooling2D(pool_size=(2, 2)))
3
드롭아웃 층 (Dropout Layer)
학습 과정에서 일부 뉴런을 무작위로 비활성화하여 과적합을 방지하는 정규화 기법입니다.
model.add(Dropout(0.25))
4
평탄화 층 (Flatten Layer)
다차원 특징 맵을 1차원 벡터로 변환하여 완전 연결 층에 입력할 수 있게 합니다.
model.add(Flatten())
5
완전 연결 층 (Dense Layer)
추출된 특징을 바탕으로 최종 분류를 수행합니다. 마지막 층의 뉴런 수는 분류할 클래스 수와 같습니다.
model.add(Dense(128, activation='relu')) model.add(Dense(num_classes, activation='softmax'))
간단한 이미지 분류 모델 구현
이제 앞서 수집한 데이터셋(병, 컵, 책 등)을 분류하는 CNN 모델을 구현해보겠습니다.
import tensorflow as tf from tensorflow.keras import layers, models from tensorflow.keras.preprocessing.image import ImageDataGenerator import matplotlib.pyplot as plt import numpy as np import os def create_model(input_shape, num_classes): """CNN 모델 생성""" model = models.Sequential([ # 첫 번째 합성곱 블록 layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=input_shape), layers.Conv2D(32, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), layers.Dropout(0.25), # 두 번째 합성곱 블록 layers.Conv2D(64, (3, 3), activation='relu', padding='same'), layers.Conv2D(64, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), layers.Dropout(0.25), # 세 번째 합성곱 블록 layers.Conv2D(128, (3, 3), activation='relu', padding='same'), layers.Conv2D(128, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), layers.Dropout(0.25), # 완전 연결 층 layers.Flatten(), layers.Dense(512, activation='relu'), layers.Dropout(0.5), layers.Dense(num_classes, activation='softmax') ]) # 모델 컴파일 model.compile( optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'] ) return model def train_model(model, train_data, validation_data, epochs=15): """모델 학습 함수""" # 조기 종료 설정 (과적합 방지) early_stopping = tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=5, restore_best_weights=True ) # 모델 학습 history = model.fit( train_data, epochs=epochs, validation_data=validation_data, callbacks=[early_stopping] ) return history def plot_training_history(history, output_folder): """학습 과정 시각화""" # 정확도 그래프 plt.figure(figsize=(12, 4)) plt.subplot(1, 2, 1) plt.plot(history.history['accuracy'], label='Training Accuracy') plt.plot(history.history['val_accuracy'], label='Validation Accuracy') plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.legend() plt.title('Training and Validation Accuracy') # 손실 그래프 plt.subplot(1, 2, 2) plt.plot(history.history['loss'], label='Training Loss') plt.plot(history.history['val_loss'], label='Validation Loss') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.title('Training and Validation Loss') # 그래프 저장 os.makedirs(output_folder, exist_ok=True) plt.tight_layout() plt.savefig(os.path.join(output_folder, 'training_history.png')) plt.close() def main(): # 데이터셋 경로 dataset_path = "preprocessed_dataset" output_folder = "model_output" os.makedirs(output_folder, exist_ok=True) # 이미지 크기 및 배치 크기 설정 img_height, img_width = 224, 224 batch_size = 32 # 데이터 증강 생성기 train_datagen = ImageDataGenerator( rescale=1./255, rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True, validation_split=0.2 # 검증 데이터 비율 ) # 훈련 데이터 생성기 train_generator = train_datagen.flow_from_directory( dataset_path, target_size=(img_height, img_width), batch_size=batch_size, class_mode='categorical', subset='training' ) # 검증 데이터 생성기 validation_generator = train_datagen.flow_from_directory( dataset_path, target_size=(img_height, img_width), batch_size=batch_size, class_mode='categorical', subset='validation' ) # 클래스 정보 출력 class_names = list(train_generator.class_indices.keys()) num_classes = len(class_names) print(f"클래스: {class_names}") print(f"총 클래스 수: {num_classes}") # 모델 생성 model = create_model(input_shape=(img_height, img_width, 3), num_classes=num_classes) model.summary() # 모델 학습 history = train_model(model, train_generator, validation_generator, epochs=15) # 학습 과정 시각화 plot_training_history(history, output_folder) # 모델 저장 model.save(os.path.join(output_folder, 'object_recognition_model.h5')) print(f"모델이 저장되었습니다: {os.path.join(output_folder, 'object_recognition_model.h5')}") # 클래스 이름 저장 with open(os.path.join(output_folder, 'class_names.txt'), 'w') as f: for class_name in class_names: f.write(f"{class_name}\n") print(f"클래스 이름이 저장되었습니다: {os.path.join(output_folder, 'class_names.txt')}") if __name__ == "__main__": main()
모델 평가와 테스트
학습된 모델의 성능을 평가하고, 실제 이미지에서 잘 작동하는지 테스트합니다.
def evaluate_model(model, test_data): """모델 평가 함수""" # 모델 평가 results = model.evaluate(test_data) print(f"테스트 손실: {results[0]:.4f}") print(f"테스트 정확도: {results[1]:.4f}") return results def predict_image(model, image_path, class_names): """단일 이미지에 대한 예측 함수""" # 이미지 로드 및 전처리 img = tf.keras.preprocessing.image.load_img( image_path, target_size=(224, 224) ) img_array = tf.keras.preprocessing.image.img_to_array(img) img_array = img_array / 255.0 # 정규화 img_array = np.expand_dims(img_array, axis=0) # 배치 차원 추가 # 예측 predictions = model.predict(img_array) predicted_class = np.argmax(predictions[0]) confidence = np.max(predictions[0]) return { 'class_name': class_names[predicted_class], 'confidence': confidence, 'predictions': predictions[0] } def visualize_predictions(model, test_data, class_names, num_samples=5): """테스트 데이터에 대한 예측 시각화""" plt.figure(figsize=(15, 10)) # 무작위 샘플 선택 for i, (images, labels) in enumerate(test_data.take(1)): if i >= num_samples: break for j in range(min(num_samples, len(images))): # 예측 predictions = model.predict(np.expand_dims(images[j], axis=0)) predicted_class = np.argmax(predictions[0]) true_class = np.argmax(labels[j]) # 이미지 표시 plt.subplot(1, num_samples, j + 1) plt.imshow(images[j]) color = 'green' if predicted_class == true_class else 'red' title = f"Predicted: {class_names[predicted_class]}\nTrue: {class_names[true_class]}" plt.title(title, color=color) plt.axis('off') plt.tight_layout() plt.savefig('prediction_examples.png') plt.close() print("예측 시각화가 저장되었습니다: prediction_examples.png")
전이 학습(Transfer Learning) 소개
처음부터 모델을 학습시키는 대신, 이미 학습된 모델을 활용하는 전이 학습을 통해 더 적은 데이터로도 좋은 성능을 얻을 수 있습니다.
사전 학습 모델 선택
ImageNet 등으로 학습된 VGG16, ResNet, MobileNet 등 선택
특징 추출기로 활용
기존 모델의 합성곱 층은 고정하고 특징 추출에만 활용
새 분류기 추가
모델 상단에 새로운 완전 연결 층 추가
미세 조정(선택)
학습률을 낮게 설정하고 일부 상위 층도 함께 학습
전이 학습 구현 예시
def create_transfer_learning_model(input_shape, num_classes): """전이 학습을 위한 모델 생성""" # 사전 학습된 MobileNetV2 모델 로드 (가벼운 모델) base_model = tf.keras.applications.MobileNetV2( input_shape=input_shape, include_top=False, # 최상위 분류기 제외 weights='imagenet' # ImageNet으로 사전 학습된 가중치 사용 ) # 기존 층 고정 (학습하지 않음) base_model.trainable = False # 새로운 모델 구성 model = models.Sequential([ base_model, layers.GlobalAveragePooling2D(), layers.Dense(128, activation='relu'), layers.Dropout(0.5), layers.Dense(num_classes, activation='softmax') ]) # 모델 컴파일 model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'] ) return model # 전이 학습 모델 생성 및 학습 transfer_model = create_transfer_learning_model( input_shape=(img_height, img_width, 3), num_classes=num_classes ) transfer_model.summary() # 모델 학습 transfer_history = train_model( transfer_model, train_generator, validation_generator, epochs=10 ) # 모델 저장 transfer_model.save(os.path.join(output_folder, 'transfer_learning_model.h5'))
모델 성능 분석
학습이 완료된 후에는 모델의 성능을 다양한 지표로 분석하여 개선 방향을 파악합니다.
전이 학습을 통해 더 적은 데이터로도 높은 정확도를 얻을 수 있습니다. 사전 학습된 모델이 이미 다양한 이미지에서 유용한 특징을 추출하는 방법을 학습했기 때문입니다.

개선 아이디어: 더 높은 정확도를 위해 데이터 증강 기법을 추가하거나, 더 복잡한 모델 구조를 사용할 수 있습니다. 또한 미세 조정(Fine-tuning)을 통해 사전 학습 모델의 상위 몇 개 층도 함께 학습시키면 성능이 더욱 향상될 수 있습니다.
이 차시에서는 CNN의 기본 구조를 이해하고, 직접 수집한 데이터로 모델을 학습시켜 보았습니다. 전이 학습을 통해 더 효율적인 학습 방법도 경험했습니다. 학습된 모델은 다음 차시에서 실시간 카메라 영상에 적용하여 로봇과 연동하게 됩니다.
11차시 — AI + 로봇 연동
열한 번째 수업에서는 앞서 학습시킨 AI 모델을 실시간 카메라 영상에 적용하고, 인식 결과에 따라 아두이노 로봇에 제어 명령을 전송하는 방법을 학습합니다. 이를 통해 AI와 로봇의 융합적 활용을 경험합니다.
학습된 모델 로드
먼저 이전 차시에서 학습하고 저장한 모델을 로드합니다. 모델과 함께 클래스 이름도 함께 로드해야 예측 결과를 올바르게 해석할 수 있습니다.
import tensorflow as tf import numpy as np import cv2 import serial import time import os def load_model_and_classes(model_path, class_names_path): """학습된 모델과 클래스 이름 로드""" # 모델 로드 model = tf.keras.models.load_model(model_path) # 클래스 이름 로드 with open(class_names_path, 'r') as f: class_names = [line.strip() for line in f.readlines()] print(f"모델을 로드했습니다. 클래스: {class_names}") return model, class_names # 모델과 클래스 이름 로드 model_path = "model_output/object_recognition_model.h5" class_names_path = "model_output/class_names.txt" model, class_names = load_model_and_classes(model_path, class_names_path)
실시간 카메라 영상에 모델 적용
카메라로부터 영상을 입력받아 각 프레임에 대해 모델의 예측을 수행하고, 결과를 시각화합니다.
def preprocess_image(frame, target_size=(224, 224)): """카메라 프레임을 모델 입력에 맞게 전처리""" # 이미지 리사이징 img = cv2.resize(frame, target_size) # BGR을 RGB로 변환 (OpenCV는 BGR, TensorFlow는 RGB 사용) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 정규화 (0-1 범위) img = img / 255.0 # 배치 차원 추가 img = np.expand_dims(img, axis=0) return img def predict_frame(model, frame, class_names): """프레임에 대한 예측 수행""" # 이미지 전처리 processed_img = preprocess_image(frame) # 예측 predictions = model.predict(processed_img) predicted_class_idx = np.argmax(predictions[0]) confidence = predictions[0][predicted_class_idx] return { 'class_idx': predicted_class_idx, 'class_name': class_names[predicted_class_idx], 'confidence': confidence } def run_realtime_detection(model, class_names, confidence_threshold=0.7): """실시간 객체 인식 수행""" # 카메라 열기 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("카메라를 열 수 없습니다.") return print("실시간 객체 인식을 시작합니다. 종료하려면 'q'를 누르세요.") while True: # 프레임 읽기 ret, frame = cap.read() if not ret: break # 예측 수행 result = predict_frame(model, frame, class_names) # 결과 시각화 text = f"{result['class_name']}: {result['confidence']:.2f}" # 신뢰도가 임계값 이상인 경우에만 표시 if result['confidence'] >= confidence_threshold: cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 객체 주변에 박스 표시 (여기서는 전체 화면에 표시) cv2.rectangle(frame, (50, 50), (frame.shape[1]-50, frame.shape[0]-50), (0, 255, 0), 2) else: cv2.putText(frame, "Unknown", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # 결과 표시 cv2.imshow('Object Recognition', frame) # 'q' 키를 누르면 종료 if cv2.waitKey(1) & 0xFF == ord('q'): break # 자원 해제 cap.release() cv2.destroyAllWindows()
Arduino와 통신 설정
Python에서 아두이노로 제어 명령을 전송하기 위한 통신을 설정합니다. 이를 통해 객체 인식 결과에 따라 로봇의 동작을 제어할 수 있습니다.
Python 측 코드
def setup_arduino_communication(port='COM3', baudrate=9600): """아두이노와 시리얼 통신 설정""" try: arduino = serial.Serial(port, baudrate, timeout=1) print(f"아두이노 연결 성공: {port}") time.sleep(2) # 아두이노 리셋 시간 대기 return arduino except Exception as e: print(f"아두이노 연결 실패: {e}") return None def send_command_to_arduino(arduino, command): """아두이노로 명령 전송""" if arduino is None: print("아두이노가 연결되어 있지 않습니다.") return False try: arduino.write(command.encode()) time.sleep(0.05) # 안정적인 전송을 위한 지연 return True except Exception as e: print(f"명령 전송 실패: {e}") return False
Arduino 측 코드
// 블루투스/시리얼로 받은 명령을 처리하는 코드 // (이전 6차시 코드와 유사) void setup() { // 모터 핀 설정 // 이전 차시와 동일... // 시리얼 통신 시작 Serial.begin(9600); } void loop() { // 명령 확인 if (Serial.available()) { char command = Serial.read(); executeCommand(command); } delay(50); } // 명령 실행 함수 void executeCommand(char command) { switch(command) { case 'F': // 전진 forward(200); Serial.println("Moving Forward"); break; case 'B': // 후진 backward(200); Serial.println("Moving Backward"); break; case 'L': // 좌회전 left(150); Serial.println("Turning Left"); break; case 'R': // 우회전 right(150); Serial.println("Turning Right"); break; case 'S': // 정지 stop(); Serial.println("Stopped"); break; // 추가 명령어... } }
객체 인식 기반 로봇 제어
이제 실시간 객체 인식 결과에 따라 로봇의 동작을 제어하는 통합 코드를 구현합니다.
def run_ai_robot_control(model, class_names, arduino, confidence_threshold=0.7): """AI 객체 인식 기반 로봇 제어""" # 카메라 열기 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("카메라를 열 수 없습니다.") return print("AI 기반 로봇 제어를 시작합니다. 종료하려면 'q'를 누르세요.") # 각 클래스에 대한 로봇 동작 정의 class_actions = { 'bottle': 'F', # 병 감지 시 전진 'cup': 'S', # 컵 감지 시 정지 'book': 'B' # 책 감지 시 후진 } # 기본 동작 (아무것도 감지되지 않을 때) default_action = 'S' # 정지 # 마지막 명령 시간 및 내용 추적 last_command_time = time.time() last_command = None command_interval = 1.0 # 명령 간 최소 간격 (초) while True: # 프레임 읽기 ret, frame = cap.read() if not ret: break # 예측 수행 result = predict_frame(model, frame, class_names) current_time = time.time() # 결과 시각화 text = f"{result['class_name']}: {result['confidence']:.2f}" # 신뢰도가 임계값 이상인 경우에만 동작 if result['confidence'] >= confidence_threshold: cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 해당 클래스에 대한 동작이 정의되어 있으면 실행 if result['class_name'] in class_actions: command = class_actions[result['class_name']] # 일정 시간이 지났거나 명령이 변경된 경우에만 새 명령 전송 if (current_time - last_command_time > command_interval or last_command != command): success = send_command_to_arduino(arduino, command) if success: print(f"명령 전송: {command} ({result['class_name']})") last_command_time = current_time last_command = command # 현재 동작 표시 action_text = { 'F': "Moving Forward", 'B': "Moving Backward", 'L': "Turning Left", 'R': "Turning Right", 'S': "Stopped" }.get(command, "Unknown Action") cv2.putText(frame, action_text, (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2) else: cv2.putText(frame, "No object detected", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # 일정 시간 동안 객체가 감지되지 않으면 기본 동작 실행 if current_time - last_command_time > command_interval and last_command != default_action: success = send_command_to_arduino(arduino, default_action) if success: print(f"명령 전송: {default_action} (Default)") last_command_time = current_time last_command = default_action # 결과 표시 cv2.imshow('AI Robot Control', frame) # 'q' 키를 누르면 종료 if cv2.waitKey(1) & 0xFF == ord('q'): # 종료 전 로봇 정지 send_command_to_arduino(arduino, 'S') break # 자원 해제 cap.release() cv2.destroyAllWindows()
클래스별 동작 정의
다양한 인식 객체에 따라 로봇이 서로 다른 동작을 수행하도록 설정할 수 있습니다.
병 (Bottle)
병을 인식하면 로봇이 전진합니다. 예를 들어, 병을 따라가거나 병을 치우는 작업을 수행할 수 있습니다.
컵 (Cup)
컵을 인식하면 로봇이 정지합니다. 컵이 넘어질 수 있는 위험 상황을 방지하는 안전 기능입니다.
책 (Book)
책을 인식하면 로봇이 후진합니다. 책을 피하거나 다른 방향을 탐색하도록 프로그래밍할 수 있습니다.
통합 실행 코드
마지막으로, 모든 기능을 통합하여 AI 기반 로봇 제어 시스템을 실행하는 코드를 작성합니다.
def main(): # 모델과 클래스 이름 로드 model_path = "model_output/object_recognition_model.h5" class_names_path = "model_output/class_names.txt" model, class_names = load_model_and_classes(model_path, class_names_path) # 아두이노 연결 arduino_port = 'COM3' # 실제 포트에 맞게 변경 arduino = setup_arduino_communication(arduino_port) if arduino is None: print("아두이노 연결 없이 객체 인식만 실행합니다.") run_realtime_detection(model, class_names) else: # AI 기반 로봇 제어 실행 run_ai_robot_control(model, class_names, arduino) # 연결 종료 arduino.close() if __name__ == "__main__": main()
통신 프로토콜 확장
더 복잡한 로봇 제어를 위해 통신 프로토콜을 확장할 수 있습니다. 예를 들어, 객체의 위치나 크기 정보도 함께 전송하여 더 정교한 제어가 가능합니다.
기본 명령어 확장
# 기본 동작 + 속도 정보 # 예: 'F150' - 150의 속도로 전진 def send_command_with_speed(arduino, action, speed): command = f"{action}{speed}" return send_command_to_arduino(arduino, command)
JSON 형식 통신
# 복잡한 정보를 JSON 형식으로 전송 import json def send_complex_command(arduino, data_dict): json_str = json.dumps(data_dict) return send_command_to_arduino(arduino, json_str + '\n') # 예: {"action": "F", "speed": 150, "object": "bottle", "confidence": 0.95}

실제 시연을 위한 팁: 실시간 인식은 조명 조건에 민감할 수 있습니다. 충분한 조명을 확보하고, 배경이 복잡하지 않은 환경에서 테스트하세요. 또한, 객체를 카메라 앞에서 천천히 움직이고, 적절한 거리(30-100cm)를 유지하는 것이 좋습니다.
이 차시에서는 AI 모델과 로봇을 연동하여 지능형 로봇 시스템을 구현하는 방법을 학습했습니다. 카메라로 객체를 인식하고, 그 결과에 따라 로봇의 동작을 제어함으로써 AI와 로봇 기술의 융합적 활용을 경험할 수 있었습니다. 다음 차시에서는 지금까지 배운 내용을 종합하여 팀별 프로젝트를 진행합니다.
12차시 — 종합 프로젝트 & 발표
마지막 수업에서는 지금까지 배운 내용을 종합하여 팀별로 AI 자율주행 자동차 프로젝트를 완성하고 발표합니다. 라인트레이싱, 장애물 회피, AI 사물 인식 기능을 통합하여 실제 작동하는 로봇을 시연하고, 개발 과정과 결과를 공유합니다.
종합 프로젝트 개요
이 프로젝트에서는 다음 세 가지 핵심 기능을 통합한 AI 자율주행 자동차를 개발합니다:
라인트레이싱
IR 센서를 사용하여 검은색 라인을 따라 주행
장애물 회피
초음파 센서로 장애물을 감지하고 회피
AI 사물 인식
카메라와 TensorFlow 모델로 객체 인식 및 반응
원격 제어
블루투스를 통한 수동/자율 모드 전환
팀 협업
역할 분담과 통합 작업을 통한 완성
팀 구성 및 역할 분담
학생들을 3~4명씩 팀으로 나누고, 다음과 같이 역할을 분담하여 프로젝트를 진행합니다:
하드웨어 담당
섀시 조립, 센서 배치, 배선 및 전원 관리, 하드웨어 문제해결
아두이노 프로그래밍 담당
라인트레이싱, 장애물 회피, 모터 제어, 블루투스 통신 코드 개발
AI 담당
데이터 수집, 모델 학습, 실시간 인식, Python-Arduino 연동
프로젝트 관리 담당
일정 관리, 문서화, 발표 자료 준비, 시연 시나리오 계획
통합 시스템 아키텍처
전체 시스템은 다음과 같은 구조로 통합됩니다:
센서 입력
IR 센서, 초음파 센서, 카메라를 통한 환경 정보 수집
정보 처리
아두이노와 PC에서 센서 데이터 처리 및 의사결정
통신
블루투스/시리얼 통신으로 PC와 아두이노 간 정보 교환
모터 제어
L298N을 통한 DC 모터 제어로 로봇 이동
모드 통합
자율주행, AI 인식, 수동 제어 모드 간 전환 로직
프로젝트 시연 시나리오
팀별 발표 시간은 약 5분으로, 다음과 같은 시나리오로 시연을 진행합니다:
시연 코스 구성
  • 검은색 라인으로 구성된 트랙
  • 중간에 장애물 배치 (상자, 콘 등)
  • 특정 지점에 인식 대상 객체 배치 (병, 컵, 책)
시연 절차
  1. 수동 모드에서 기본 작동 확인
  1. 라인트레이싱 모드 시연
  1. 장애물 회피 기능 시연
  1. AI 객체 인식 및 반응 시연
  1. 모든 기능을 통합한 자율주행 시연
시연 코스 예시: 검은색 라인으로 구성된 트랙에 장애물과 인식 대상 객체를 배치합니다. 로봇은 라인을 따라 주행하면서 장애물을 회피하고, 특정 객체를 인식하면 프로그래밍된 대로 반응합니다.
발표 내용 구성
팀별 발표는 다음 내용을 포함하여 구성합니다:
1
프로젝트 소개
팀명, 프로젝트 목표, 주요 기능 소개
2
시스템 구성
하드웨어 및 소프트웨어 구성, 아키텍처 설명
3
구현 방법
주요 알고리즘, 코드 구조, 특징적인 해결 방법
4
어려웠던 점
개발 과정에서 마주친 문제와 해결 방법
5
개선 아이디어
추가하고 싶은 기능, 향후 발전 방향
평가 기준
프로젝트 결과는 다음과 같은 기준으로 평가됩니다:
프로젝트 결과물 제출
프로젝트 완료 후 다음 자료를 제출합니다:
소스 코드
Arduino 코드(.ino), Python 코드(.py), 학습된 모델 파일(.h5)
기술 문서
시스템 설계서, 기능 설명, 사용된 알고리즘 설명
발표 자료
발표에 사용한 슬라이드, 시연 영상
팀 활동 기록
역할 분담, 개발 일지, 문제 해결 과정
토론: AI와 로봇의 미래
프로젝트 발표 후, 다음과 같은 주제로 간단한 토론을 진행합니다:
"이번 프로젝트를 통해 경험한 AI와 로봇 기술을 바탕으로, 미래에 이러한 기술이 어떻게 발전하고 우리 사회에 어떤 영향을 미칠지 생각해봅시다. 여러분이 생각하는 AI 로봇의 가능성과 한계, 그리고 이를 활용한 창의적인 아이디어는 무엇인가요?"

생각해볼 질문: 자율주행 기술은 어떤 분야에 적용될 수 있을까요? AI 객체 인식 기술의 한계는 무엇이며, 어떻게 개선할 수 있을까요? 미래 사회에서 AI 로봇과 인간의 관계는 어떻게 될까요?
마무리 및 향후 학습 방향
12차시 교육과정을 마무리하며, 학생들에게 다음과 같은 향후 학습 방향을 제시합니다:
1
심화 로봇공학
보다 복잡한 로봇 시스템 설계, ROS(Robot Operating System) 학습, 다관절 로봇 제어
2
고급 AI 학습
더 복잡한 딥러닝 모델, 자연어 처리, 강화학습을 통한 자율 에이전트 개발
3
경진대회 참가
학내 AI 자율주행 경진대회, 전국 로봇 경진대회, 해커톤 등 참여
4
실제 문제 해결
학교나 지역사회의 실제 문제를 AI와 로봇 기술로 해결하는 프로젝트 수행
이 차시에서는 지금까지 배운 모든 내용을 종합하여 팀별 프로젝트를 완성하고 발표하는 시간을 가졌습니다. 학생들은 하드웨어 조립부터 프로그래밍, AI 모델 적용까지 전 과정을 직접 경험하며 로봇공학과 인공지능의 융합적 활용 능력을 기를 수 있었습니다. 이러한 경험은 미래 기술 발전 방향을 이해하고, 창의적인 문제 해결 능력을 키우는 데 큰 도움이 될 것입니다.
확장 아이디어
12차시 교육과정을 마친 후, 더 깊이 있는 학습과 발전을 위한 확장 아이디어를 소개합니다. 이러한 확장 프로젝트는 학생들의 관심과 능력에 따라 선택적으로 진행할 수 있으며, 동아리 활동이나 심화 학습 과정으로 활용할 수 있습니다.
TensorFlow Lite로 모델 경량화
학습된 AI 모델을 경량화하여 라즈베리파이와 같은 임베디드 장치에서 직접 실행할 수 있게 합니다. 이를 통해 PC 없이도 독립적으로 작동하는 AI 로봇을 구현할 수 있습니다.
01
모델 변환
TensorFlow 모델을 TensorFlow Lite 형식(.tflite)으로 변환
import tensorflow as tf # 저장된 모델 로드 model = tf.keras.models.load_model('object_recognition_model.h5') # TFLite 변환기 생성 converter = tf.lite.TFLiteConverter.from_keras_model(model) # 양자화 적용 (선택사항, 모델 크기 추가 감소) converter.optimizations = [tf.lite.Optimize.DEFAULT] # 변환 실행 tflite_model = converter.convert() # 모델 저장 with open('model.tflite', 'wb') as f: f.write(tflite_model)
02
라즈베리파이 설정
Raspberry Pi OS 설치, 필요한 라이브러리 설치 (TensorFlow Lite, OpenCV 등)
03
하드웨어 연결
라즈베리파이와 아두이노 연결, 카메라 및 기타 센서 연결
04
추론 코드 구현
라즈베리파이에서 TFLite 모델을 사용한 실시간 객체 인식 구현
05
통합 시스템 구축
독립형 AI 로봇 시스템 완성 및 최적화
YOLOv5/YOLOv8 적용
YOLO(You Only Look Once)는 실시간 객체 탐지에 특화된 딥러닝 알고리즘입니다. TensorFlow 대신 YOLO를 적용하여 더 빠르고 정확한 객체 탐지 시스템을 구현할 수 있습니다.
YOLO의 장점
  • 매우 빠른 추론 속도 (실시간 처리에 적합)
  • 높은 정확도와 적은 오탐지
  • 객체의 위치(바운딩 박스)와 클래스를 동시에 예측
  • 다양한 크기의 객체 탐지 가능
  • 활발한 커뮤니티와 지속적인 개선
YOLO 구현 방법
  1. PyTorch 및 YOLO 라이브러리 설치
  1. 사전 학습된 모델 다운로드 또는 커스텀 데이터셋으로 학습
  1. 실시간 영상에 적용 및 로봇 제어와 연동
# YOLOv5 설치 및 실행 예시 !git clone https://github.com/ultralytics/yolov5 %cd yolov5 !pip install -r requirements.txt # 사전 학습된 모델 사용 import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # 이미지에 적용 results = model('path/to/image.jpg') # 결과 표시 results.print() results.show() # 결과 분석 results.pandas().xyxy[0] # 바운딩 박스 좌표와 클래스
YOLOv8은 YOLOv5의 후속 버전으로, 더욱 향상된 성능을 제공합니다. 더 많은 클래스를 더 정확하게 인식할 수 있어 로봇의 환경 인식 능력을 크게 향상시킬 수 있습니다.
ROS2 + Python 연동
ROS(Robot Operating System)는 로봇 소프트웨어 개발을 위한 오픈소스 프레임워크입니다. ROS2를 도입하여 보다 전문적인 로봇 시스템을 구축할 수 있습니다.
노드 기반 아키텍처
센서, 모터, 인식 등 각 기능을 독립적인 노드로 분리하여 모듈화된 시스템 구축
토픽 기반 통신
발행자/구독자 패턴을 통한 효율적인 데이터 공유 및 비동기 통신
서비스 호출
요청/응답 패턴을 통한 동기식 통신으로 명령 실행 및 결과 수신
시각화 도구
RViz, rqt 등의 도구를 통한 로봇 상태 및 센서 데이터 실시간 모니터링
ROS2와 Python을 연동한 간단한 예시 코드:
# ROS2 Python 노드 예시 import rclpy from rclpy.node import Node from std_msgs.msg import String from sensor_msgs.msg import Image from cv_bridge import CvBridge import cv2 class ObjectDetectionNode(Node): def __init__(self): super().__init__('object_detection_node') # 이미지 구독자 생성 self.subscription = self.create_subscription( Image, 'camera/image_raw', self.image_callback, 10) # 명령 발행자 생성 self.command_publisher = self.create_publisher( String, 'robot/command', 10) self.bridge = CvBridge() def image_callback(self, msg): # ROS 이미지 메시지를 OpenCV 형식으로 변환 cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") # 여기에 객체 인식 코드 추가 # ... # 인식 결과에 따라 로봇 명령 발행 command_msg = String() command_msg.data = 'forward' # 예시 명령 self.command_publisher.publish(command_msg) self.get_logger().info(f'Published command: {command_msg.data}') def main(args=None): rclpy.init(args=args) node = ObjectDetectionNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
학교 대회 개최: AI 자율주행 경진대회
학습한 내용을 바탕으로 학교 내 AI 자율주행 경진대회를 개최하여 학생들의 흥미와 도전 의식을 높일 수 있습니다.
1
대회 기획
규칙 수립, 평가 기준 마련, 코스 설계, 일정 계획
2
팀 구성
3~4명으로 팀 구성, 역할 분담, 전략 수립
3
개발 기간
4~6주간 로봇 개발 및 최적화
4
예선
기본 기능 검증 (라인트레이싱, 장애물 회피)
5
본선
복합 코스 주행 및 AI 객체 인식 미션 수행
6
시상 및 평가
우승팀 시상, 기술 공유 세션, 피드백
대회 종목 예시
스피드 레이싱
정해진 트랙을 가장 빠르게 완주하는 경기. 라인 이탈 시 감점.
장애물 코스
다양한 장애물이 배치된 코스를 안전하게 통과하는 경기.
물체 인식 미션
특정 물체를 인식하고 지정된 동작을 수행하는 미션 기반 경기.
종합 챌린지
모든 요소가 복합된 고난도 코스를 완주하는 종합 경기.
추가 확장 프로젝트 아이디어
하드웨어 확장
  • 서보 모터를 활용한 팬-틸트 카메라 시스템 구현
  • 다중 초음파 센서를 이용한 360도 장애물 감지
  • IMU(관성 측정 장치)를 활용한 자세 제어 및 위치 추정
  • GPS 모듈을 통한 실외 내비게이션 구현
  • 솔라 패널을 활용한 에너지 하베스팅 시스템 개발
소프트웨어 확장
  • SLAM(Simultaneous Localization and Mapping) 알고리즘 구현
  • 강화학습을 통한 자율 주행 정책 학습
  • 다중 로봇 간 통신 및 협업 시스템 개발
  • 클라우드 연동을 통한 원격 모니터링 및 제어
  • 음성 인식을 통한 자연어 명령 처리 기능 추가
"지금까지 배운 것은 로봇과 AI의 기초에 불과합니다. 실제 산업 현장에서는 더 복잡하고 정교한 시스템이 사용되지만, 여러분이 경험한 기본 원리는 동일합니다. 이 기초를 바탕으로 더 깊이 탐구하고 창의적인 프로젝트에 도전해보세요."

자기주도 학습: 학생들이 자신의 관심 분야에 따라 확장 프로젝트를 선택하고 자기주도적으로 학습할 수 있도록 지원하세요. 온라인 커뮤니티, 오픈소스 프로젝트, 튜토리얼 등 다양한 자료를 활용하도록 안내하고, 정기적인 멘토링을 통해 발전 방향을 제시해주는 것이 좋습니다.
이러한 확장 아이디어들은 12차시 기본 교육과정을 넘어 학생들의 관심과 역량에 따라 더 깊이 있는 학습을 할 수 있는 기회를 제공합니다. 로봇공학과 인공지능은 빠르게 발전하는 분야이므로, 지속적인 학습과 실험을 통해 최신 기술 트렌드를 따라가고 창의적인 문제 해결 능력을 키울 수 있도록 독려하세요.