8. 첫 번째 프로젝트: 장애물을 피하는 작은 이동 로봇
8. 첫 번째 프로젝트: 장애물을 피하는 작은 이동 로봇

가장 먼저 만드는 이유
이제부터는 진짜 로봇을 만들어 볼 차례다. 첫 프로젝트로 장애물을 피하는 작은 이동 로봇을 선택한 이유는 단순하다. 이 로봇 안에는 로봇 제작의 핵심이 거의 다 들어 있기 때문이다. 몸체가 있고, 바퀴로 움직이며, 센서로 앞을 보고, 판단을 내리고, 모터를 제어한다. 크기는 작지만 로봇의 기본 구조가 한 번에 보인다.
무엇보다 이 프로젝트는 개인 개발자에게 아주 좋은 출발점이다. 너무 복잡하지 않으면서도 "내가 만든 기계가 스스로 움직인다"는 강한 성공 경험을 준다. 책상 위의 코드를 실제 세계의 움직임으로 바꾸는 순간, 로봇 개발이 왜 재미있는지 몸으로 이해하게 된다.
이 장의 목표는 화려한 자율주행을 만드는 것이 아니다. 가장 작은 성공 경험으로 로봇 제작의 전체 흐름을 손에 익히는 것이다. 센서를 읽고, 조건을 판단하고, 모터를 움직여 회피하는 것. 이 단순한 흐름이 이후의 카메라 로봇, 음성 로봇, ROS 2 기반 로봇으로 자연스럽게 이어진다.
이번 프로젝트에서 만들 것
이번에 만들 로봇은 바퀴형 이동 로봇이다. 평소에는 앞으로 전진하다가, 앞에 벽이나 물체가 가까이 오면 멈춘다. 그리고 뒤로 조금 물러난 뒤 한쪽으로 회전해서 다시 전진한다. 사람 입장에서는 매우 단순한 행동처럼 보이지만, 로봇 입장에서는 감지, 판단, 제어가 모두 필요한 꽤 그럴듯한 자율 행동이다.
이 프로젝트를 끝내면 다음과 같은 감각을 얻게 된다.
센서 값이 현실에서 얼마나 흔들리는지 이해하게 된다.
모터 두 개를 제어하는 것만으로도 방향 전환이 가능하다는 것을 체감한다.
자율주행은 거대한 AI가 아니라 작은 규칙의 조합에서도 시작할 수 있다는 것을 알게 된다.
로봇 개발에서 조립, 배선, 코드, 테스트, 튜닝이 모두 중요하다는 사실을 배우게 된다.
준비물: 가능한 한 단순하게 시작하자
처음부터 비싸고 복잡한 부품을 고를 필요는 없다. 이번 프로젝트의 핵심은 완성도보다 학습 속도다. 가장 흔한 2륜 또는 4륜 로봇 키트로도 충분하다.
준비물은 다음 정도면 된다.
바퀴형 로봇 키트 또는 간단한 섀시
DC 기어드 모터 2개 이상
모터 드라이버 보드
초음파 거리 센서 1개
마이크로컨트롤러 보드(예: 아두이노 계열)
배터리 팩과 전원 스위치
점퍼 케이블, 나사, 스페이서 같은 기본 조립 부품
여기서 가장 중요한 것은 세 가지다. 몸체, 움직임, 거리 감지다. 카메라가 없어도 되고, Wi-Fi가 없어도 된다. 오히려 처음에는 없는 편이 좋다. 요소가 적을수록 문제를 찾기 쉽기 때문이다.
로봇의 구조를 먼저 머릿속에 그리기
조립하기 전에 이 로봇이 어떻게 움직일지 그림처럼 떠올려 보자.
초음파 센서가 앞쪽 거리를 읽는다. 마이크로컨트롤러는 그 값을 계속 확인한다. 거리가 충분하면 모터 두 개를 모두 앞으로 돌린다. 거리가 너무 가까우면 정지한다. 그다음 잠깐 후진하고, 왼쪽 또는 오른쪽으로 돈다. 그리고 다시 앞으로 나아간다.
구조로 쓰면 아주 간단하다.
센서 입력 → 거리 판단 → 모터 제어
이 한 줄이 로봇의 기본이다. 이후 더 복잡한 로봇을 만들게 되어도 결국 이 구조는 계속 남아 있다. 센서가 카메라로 바뀌고, 판단이 AI 모델로 바뀌고, 모터 제어가 ROS 2 노드로 바뀔 뿐이다.
바퀴형 이동 로봇은 어떻게 방향을 바꿀까
사람은 몸을 비틀거나 발을 다르게 움직여 방향을 바꾼다. 바퀴형 로봇은 왼쪽 바퀴와 오른쪽 바퀴의 속도를 다르게 해서 방향을 바꾼다. 이것이 가장 기본적인 차동 구동 방식이다.
왼쪽과 오른쪽 바퀴가 같은 속도로 앞으로 돌면 로봇은 직진한다. 왼쪽 바퀴가 느리고 오른쪽 바퀴가 빠르면 왼쪽으로 휘어진다. 한쪽은 앞으로, 한쪽은 뒤로 돌리면 제자리 회전도 가능하다.
처음 프로젝트에서 이 원리를 체감하는 것이 매우 중요하다. 나중에 자율주행, 경로 계획, SLAM을 배우더라도 실제 로봇을 움직이는 기초는 결국 이런 바퀴 제어에서 시작하기 때문이다.
조립: 완벽함보다 안정성이 먼저다
조립할 때는 멋있게 보이는 것보다 중심이 안정적인 구성이 좋다. 배터리는 가능한 낮고 가운데에 두는 편이 좋다. 초음파 센서는 로봇의 앞쪽 중앙에 달면 이해하기 쉽다. 보드를 너무 위에 올리면 무게 중심이 높아져 흔들릴 수 있다.
처음 조립에서는 다음 원칙만 기억하면 된다.
센서는 앞을 잘 보게 배치한다.
바퀴는 좌우가 균형 있게 굴러가야 한다.
케이블은 바퀴에 닿지 않게 정리한다.
배터리는 단단히 고정한다.
전원 스위치는 손이 쉽게 닿는 위치에 둔다.
로봇 프로젝트에서 사소해 보이는 이런 부분이 실제로는 매우 중요하다. 배선이 바퀴에 걸리면 코드는 멀쩡한데 로봇이 이상하게 움직인다. 센서가 너무 위를 보면 책상 위에서는 잘 되는데 바닥에서는 오작동한다. 로봇은 소프트웨어와 하드웨어가 함께 문제를 만든다.
배선: 전원과 신호를 구분해서 생각하자
초보자가 가장 많이 막히는 곳이 배선이다. 하지만 원리는 단순하다. 전원은 부품을 움직이게 하고, 신호는 부품에게 무엇을 하라고 알려 준다.
모터는 전류를 꽤 먹기 때문에 보드 핀에 직접 연결하지 않고 모터 드라이버를 거친다. 마이크로컨트롤러는 모터 드라이버에 방향과 속도 신호를 보내고, 실제 모터를 움직이는 전력은 드라이버와 배터리가 담당한다. 초음파 센서는 비교적 단순하다. 전원, 접지, 그리고 거리 측정을 위한 신호 핀만 연결하면 된다.
처음 배선할 때는 반드시 종이에 간단한 연결도를 그려 보자. 머리로만 연결하면 한두 개쯤은 꼭 바뀐다. 특히 모터 좌우 방향이 바뀌면 "앞으로 가라"는 코드가 실제로는 회전으로 나타날 수 있다.
가장 단순한 동작 로직
첫 버전의 로직은 아주 단순하게 시작하는 것이 좋다. 복잡하게 만들수록 고장 원인이 늘어난다.
기본 로직은 이렇다.
앞쪽 거리를 읽는다.
거리가 안전 기준보다 멀면 앞으로 간다.
거리가 너무 가까우면 멈춘다.
잠깐 뒤로 간다.
왼쪽 또는 오른쪽으로 일정 시간 회전한다.
다시 앞으로 간다.
이 규칙만 있어도 로봇은 꽤 그럴듯하게 움직인다. 사람 눈에는 "생각하는 것처럼" 보이기도 한다. 사실은 복잡한 생각이 아니라 조건문 몇 개일 뿐이지만, 로봇 개발의 재미는 바로 여기에 있다. 단순한 규칙이 현실 세계에서 예상보다 생동감 있게 보인다는 점이다.
거리 기준값은 왜 중요한가
거리 센서를 달았다고 해서 바로 잘 움직이지는 않는다. 어느 거리에서 장애물이라고 판단할지를 정해야 한다. 예를 들어 20cm보다 가까우면 회피하도록 설정할 수 있다. 하지만 이 값은 로봇 크기, 속도, 센서 위치, 바닥 상태에 따라 달라진다.
너무 짧게 잡으면 벽 가까이 다가간 뒤 허둥대며 멈춘다. 너무 길게 잡으면 아무것도 없는데도 자꾸 겁먹고 회전한다. 그래서 로봇 개발에서는 이론만큼 튜닝이 중요하다. 숫자 하나를 바꾸는 것만으로 로봇 성격이 달라진다.
초보자에게 추천하는 방법은 딱 하나다. 처음에는 보수적으로, 즉 넉넉하게 잡아라. 조금 겁 많은 로봇이 벽에 부딪히는 로봇보다 훨씬 낫다.
첫 번째 버전 코드 예시
이번 장에서는 아두이노 스타일의 가장 단순한 예시를 보자. 실제 핀 번호는 사용하는 보드와 모터 드라이버에 따라 달라질 수 있으니, 개념을 중심으로 읽으면 된다.
const int trigPin = 9;
const int echoPin = 10;
const int leftMotorA = 2;
const int leftMotorB = 3;
const int rightMotorA = 4;
const int rightMotorB = 5;
long readDistanceCM() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 30000);
long distance = duration * 0.034 / 2;
return distance;
}
void forward() {
digitalWrite(leftMotorA, HIGH);
digitalWrite(leftMotorB, LOW);
digitalWrite(rightMotorA, HIGH);
digitalWrite(rightMotorB, LOW);
}
void backward() {
digitalWrite(leftMotorA, LOW);
digitalWrite(leftMotorB, HIGH);
digitalWrite(rightMotorA, LOW);
digitalWrite(rightMotorB, HIGH);
}
void turnLeft() {
digitalWrite(leftMotorA, LOW);
digitalWrite(leftMotorB, HIGH);
digitalWrite(rightMotorA, HIGH);
digitalWrite(rightMotorB, LOW);
}
void stopMotor() {
digitalWrite(leftMotorA, LOW);
digitalWrite(leftMotorB, LOW);
digitalWrite(rightMotorA, LOW);
digitalWrite(rightMotorB, LOW);
}
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(leftMotorA, OUTPUT);
pinMode(leftMotorB, OUTPUT);
pinMode(rightMotorA, OUTPUT);
pinMode(rightMotorB, OUTPUT);
}
void loop() {
long distance = readDistanceCM();
if (distance > 0 && distance < 20) {
stopMotor();
delay(200);
backward();
delay(400);
turnLeft();
delay(500);
} else {
forward();
}
}이 코드는 아주 투박하지만 첫 프로젝트에는 오히려 좋다. 왜냐하면 로봇의 동작 구조가 한눈에 보이기 때문이다. 앞으로 갈지, 멈출지, 뒤로 갈지, 돌지를 모두 직접 읽을 수 있다.
이 코드에서 꼭 이해해야 할 포인트
이 예시에서 중요한 것은 문법보다 흐름이다. loop()는 로봇의 심장박동 같은 역할을 한다. 계속 반복되며 센서를 읽고 행동을 결정한다. 로봇 개발에서 이 반복 루프는 거의 모든 시스템의 출발점이다.
또 하나 중요한 점은, 지금 로봇은 세상을 아주 단순하게 본다는 것이다. "가깝다" 또는 "가깝지 않다" 정도로만 판단한다. 하지만 이것만으로도 실제 회피 행동이 가능하다. 여기서부터 점점 더 정교하게 만들면 된다.
마지막으로 delay()가 많이 들어가 있다는 것도 눈여겨볼 만하다. 첫 프로젝트에서는 이해를 돕기 위해 시간 지연을 쓰는 편이 쉽다. 다만 나중에는 이런 방식이 로봇을 둔하게 만들 수 있다. 앞으로 더 발전시키면서 논블로킹 방식, 상태 머신, 더 세밀한 제어로 넘어가게 된다.
테스트는 바닥보다 넓은 테이블에서 먼저 하지 말자
처음 테스트할 때 많은 사람이 책상 위에 로봇을 올려놓고 코드를 실행한다. 그런데 이동 로봇은 의외로 빨리 떨어질 수 있다. 첫 테스트는 바닥에서, 주변이 넓고 안전한 공간에서 하는 것이 좋다.
처음 전원을 켜기 전에는 다음을 꼭 확인하자.
바퀴가 공회전 없이 잘 고정되어 있는지
센서가 정면을 향하고 있는지
배터리 전압이 충분한지
좌우 모터 방향이 의도와 맞는지
전원 케이블이 빠질 위험이 없는지
테스트는 한 번에 모든 것을 보지 말고 나눠서 해야 한다. 센서 읽기만 확인하고, 그다음 모터만 돌려 보고, 마지막에 합치는 식이 좋다. 로봇 개발에서 문제를 빨리 찾는 사람은 천재라서가 아니라, 테스트를 잘게 나누기 때문이다.
잘 안 움직일 때 가장 흔한 문제
첫 프로젝트는 거의 반드시 한 번쯤 말썽을 부린다. 그런데 그 과정이 오히려 실력을 빨리 키운다. 자주 만나는 문제는 생각보다 비슷하다.
로봇이 한쪽으로만 돈다면 좌우 모터 속도가 다르거나, 바퀴 마찰이 다르거나, 섀시 조립이 비뚤어졌을 가능성이 있다. 모터는 같은 부품처럼 보여도 실제 성능 차이가 조금씩 있다. 그래서 완벽한 직진은 생각보다 어렵다.
센서 값이 이상하면 배선 문제, 전원 불안정, 센서 각도 문제를 먼저 의심해 보자. 특히 초음파 센서는 부드러운 천, 비스듬한 표면, 아주 좁은 물체 앞에서 예상보다 불안정할 수 있다.
전원을 넣으면 재부팅되거나 멈춘다면 배터리 공급이 부족할 수 있다. 모터가 출발할 때 순간적으로 더 많은 전류를 요구하기 때문이다. 이럴 때는 코드보다 전원 구성이 원인일 가능성이 높다.
로봇을 조금 더 똑똑하게 만드는 쉬운 개선
첫 버전이 성공했다면, 이제부터가 진짜 재미다. 같은 하드웨어로도 로봇을 꽤 더 똑똑하게 만들 수 있다.
가장 쉬운 개선은 회전 방향을 매번 바꾸는 것이다. 항상 왼쪽으로만 돌면 특정 구석에 갇힐 수 있다. 왼쪽, 오른쪽을 번갈아 시도하거나, 센서 값을 여러 번 읽어 더 먼 쪽으로 도는 방식도 생각해 볼 수 있다.
두 번째 개선은 센서 값을 한 번만 보지 않고 여러 번 평균 내는 것이다. 거리 값이 튀는 문제를 줄일 수 있다. 로봇이 덜 예민해지고, 더 차분하게 행동한다.
세 번째 개선은 속도 조절이다. 평소에는 천천히 움직이다가, 공간이 넓으면 조금 더 빠르게 갈 수 있다. 반대로 장애물에 가까워질수록 감속하게 만들 수도 있다. 이렇게 하면 로봇이 훨씬 자연스럽게 보인다.
상태를 나누면 로봇이 더 이해하기 쉬워진다
처음에는 조건문 몇 개로 충분하지만, 조금만 기능이 늘어나면 코드가 금방 복잡해진다. 이때 도움이 되는 개념이 상태다. 상태란 지금 로봇이 무엇을 하고 있는지를 이름으로 구분하는 것이다.
예를 들어 이 로봇은 전진, 정지, 후진, 회전 같은 상태를 가질 수 있다. 그러면 코드가 "센서를 읽고 바로 이것저것 실행"하는 방식에서 "현재 상태에 따라 행동"하는 방식으로 바뀐다. 이 구조는 훨씬 읽기 쉽고 확장하기도 좋다.
나중에 음성 명령, 카메라 인식, 원격 제어가 추가되면 이런 상태 개념이 더 중요해진다. 첫 프로젝트에서 상태를 미리 맛보는 것만으로도 이후 장들이 훨씬 쉬워진다.
단순한 회피와 진짜 자율주행의 차이
이 로봇은 장애물을 피하지만, 아직 지도를 이해하지는 못한다. 목적지를 기억하지도 않고, 자신이 어디에 있는지도 모른다. 단지 눈앞 상황에 반응할 뿐이다. 그래도 이것은 분명 자율 행동이다. 누군가 매번 조종하지 않아도 스스로 감지하고 움직이기 때문이다.
이 차이를 이해하는 것이 중요하다. 로봇 개발은 갑자기 완전한 자율주행으로 뛰어오르지 않는다. 이런 반응형 로봇에서 출발해, 점점 더 많은 감각과 기억과 계획을 더해 간다. 지금 만드는 작은 회피 로봇은 그 출발점이다.
이번 프로젝트에서 배운 것
이 장을 끝냈다면 사실상 첫 번째 로봇 개발 사이클을 경험한 것이다. 부품을 고르고, 몸체를 조립하고, 배선하고, 코드를 올리고, 테스트하고, 숫자를 조정했다. 이것이 로봇 제작의 기본 흐름이다.
이번 프로젝트를 통해 얻은 핵심은 다음과 같다.
로봇은 센서 입력, 판단, 모터 출력의 반복으로 움직인다.
단순한 규칙 기반 제어만으로도 자율 행동의 기초를 만들 수 있다.
실제 로봇에서는 조립과 배선, 전원, 튜닝이 코드만큼 중요하다.
작은 성공 경험 하나가 다음 프로젝트의 자신감을 크게 높여 준다.
다음 프로젝트로 이어지는 다리
이번 장의 로봇은 거리만 본다. 다음 단계에서는 여기에 카메라를 더해 사물을 보기 시작할 수 있다. 그러면 로봇은 단순히 "앞에 뭔가 있다"를 넘어서 "앞에 사람, 컵, 책, 문이 있다"처럼 해석하게 된다. 그 순간부터 로봇은 단순 기계에서 AI 로봇으로 한 걸음 더 나아간다.
하지만 잊지 말자. 카메라를 달기 전에 이미 가장 중요한 것을 배웠다. 로봇은 결국 현실 세계에서 움직여야 한다는 사실이다. 그리고 현실 세계에서 움직이는 로봇은 언제나 센서, 판단, 제어, 테스트의 반복 위에 서 있다.
작고 서툰 이 첫 이동 로봇은 앞으로 만들 모든 로봇의 조상 같은 존재다. 귀엽고, 단순하고, 가끔 벽 앞에서 버벅거리겠지만, 바로 그런 모습 덕분에 우리는 로봇을 가장 빠르게 배운다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.