Skip to main content
Summary

바퀴 로봇은 두 개의 다리로 움직인다

이제 로봇이 실제로 움직일 차례입니다. 앞 장에서 모터가 로봇의 근육이라면, 이번 장의 바퀴 로봇은 그 근육을 몸체에 붙여 걷게 만드는 단계입니다.

가장 단순한 바퀴 로봇은 좌우에 DC 모터가 하나씩 있고, 앞이나 뒤에 작은 보조 바퀴인 캐스터가 있습니다. 캐스터는 쇼핑카트 바퀴처럼 자유롭게 방향이 바뀌는 바퀴입니다. 힘을 내는 바퀴는 좌우 두 개뿐이고, 캐스터는 차체가 넘어지지 않게 받쳐 줍니다.

이런 구조를 차동 구동이라고 합니다. 어려운 말처럼 보이지만 원리는 간단합니다. 왼쪽 바퀴와 오른쪽 바퀴의 움직임 차이로 방향을 바꾸는 방식입니다.

왼쪽 바퀴오른쪽 바퀴로봇의 움직임
앞으로앞으로전진
뒤로뒤로후진
멈춤 또는 뒤로앞으로왼쪽으로 회전
앞으로멈춤 또는 뒤로오른쪽으로 회전

사람이 왼발과 오른발의 속도를 다르게 해서 몸의 방향을 바꾸는 것과 비슷합니다. 로봇 자동차도 핸들이 없어도 좌우 바퀴의 회전 방향과 속도만 조합하면 원하는 방향으로 움직일 수 있습니다.

모터 드라이버와 바퀴 로봇 조립하기AI 생성 이미지

왜 모터 드라이버가 필요한가

아두이노 핀은 신호를 보내는 데는 좋지만, 모터를 직접 돌릴 만큼 큰 전류를 공급하기에는 약합니다. 모터는 출발할 때 순간적으로 많은 전류를 요구하고, 회전이 멈추거나 방향이 바뀔 때 전기적 충격도 만들 수 있습니다. 그래서 모터를 아두이노 핀에 직접 연결하면 보드가 불안정해지거나 손상될 수 있습니다.

모터 드라이버는 아두이노와 모터 사이에 들어가는 중간 장치입니다. 아두이노가 작은 신호로 "왼쪽 모터를 앞으로 돌려", "오른쪽 모터 속도를 줄여"라고 지시하면, 모터 드라이버가 배터리의 전원을 이용해 실제 모터에 충분한 전류를 흘려줍니다.

대표적인 모터 드라이버로 L298N과 TB6612FNG가 있습니다. 둘 다 두 개의 DC 모터를 제어할 수 있습니다. L298N은 크고 흔히 쓰이는 모듈이며, TB6612FNG는 비교적 작고 효율이 좋은 편입니다. 모양은 달라도 기본 생각은 같습니다.

모터 하나를 제어하려면 보통 세 종류의 신호가 필요합니다.

  • 방향 신호 2개: 모터를 앞으로 돌릴지, 뒤로 돌릴지 정합니다.

  • 속도 신호 1개: PWM으로 모터의 빠르기를 조절합니다.

  • 전원: 모터를 실제로 돌릴 배터리 전원입니다.

방향 신호 두 개가 서로 반대 상태가 되면 모터가 한 방향으로 돌고, 상태를 바꾸면 반대 방향으로 돕니다. 두 신호를 모두 같은 상태로 두면 모터가 멈춥니다. 이 구조를 H-브리지라고 부릅니다. H-브리지는 모터 양쪽에 전원을 어떤 방향으로 걸어 줄지 바꾸는 회로입니다.

차체를 안정적으로 조립하기

먼저 로봇의 몸체를 만듭니다. 아크릴 섀시, 나무판, 두꺼운 플라스틱 판 등 단단한 판이면 사용할 수 있습니다. 중요한 것은 부품을 예쁘게 붙이는 것보다 무게중심과 배선이 안정적인지입니다.

준비할 기본 부품은 다음과 같습니다.

  • 아두이노 우노 1개

  • DC 기어드 모터 2개

  • 바퀴 2개

  • 캐스터 1개

  • 모터 드라이버 1개

  • 배터리 팩 1개

  • 점퍼선

  • 섀시와 나사, 양면테이프 또는 케이블타이

조립은 다음 순서로 진행하면 쉽습니다.

  1. 좌우 모터를 섀시 양쪽에 단단히 고정합니다.

  2. 모터 축에 바퀴를 끼웁니다.

  3. 캐스터를 앞쪽 또는 뒤쪽 중앙에 붙입니다.

  4. 배터리를 차체 가운데 낮은 위치에 고정합니다.

  5. 아두이노와 모터 드라이버를 위쪽에 배치합니다.

  6. 바퀴에 닿지 않도록 전선을 정리합니다.

배터리는 생각보다 무겁습니다. 배터리가 한쪽으로 치우치면 로봇이 직진하지 못하고 한쪽으로 기울 수 있습니다. 가능하면 좌우 가운데, 앞뒤로도 너무 치우치지 않는 위치에 붙입니다.

아두이노는 USB 케이블을 꽂아야 하므로 포트가 막히지 않게 둡니다. 모터 드라이버는 모터와 배터리 선이 모이는 곳이므로 모터 가까이에 두면 배선이 깔끔해집니다.

전원 연결에서 가장 중요한 것

로봇이 움직이지 않는 원인의 상당수는 코드보다 전원 연결에 있습니다. 모터 전원과 아두이노 전원을 구분해서 생각해야 합니다.

아두이노는 USB 케이블이나 별도 전원으로 동작합니다. 모터는 배터리 팩에서 전원을 받습니다. 이때 모터 전원을 아두이노의 5V 핀에서 가져오면 안 됩니다. 모터가 요구하는 전류가 크기 때문입니다.

기본 연결 원칙은 다음과 같습니다.

  • 배터리의 +는 모터 드라이버의 모터 전원 단자에 연결합니다.

  • 배터리의 -는 모터 드라이버의 GND에 연결합니다.

  • 아두이노 GND와 모터 드라이버 GND를 연결합니다.

  • 아두이노의 디지털 핀은 모터 드라이버의 방향 핀과 속도 핀에 연결합니다.

여기서 공통 GND가 중요합니다. 아두이노와 모터 드라이버가 같은 GND를 공유해야 HIGH와 LOW의 기준이 같아집니다. 기준이 다르면 아두이노가 보낸 신호를 모터 드라이버가 정확히 이해하지 못할 수 있습니다.

단, 모터 드라이버 모듈마다 전원 단자 이름이 조금씩 다릅니다. L298N은 ENA, IN1, IN2, IN3, IN4, ENB 같은 이름을 많이 사용합니다. TB6612FNG는 PWMA, AIN1, AIN2, BIN1, BIN2, PWMB, STBY 같은 이름을 사용합니다. 이름은 달라도 역할은 비슷합니다.

역할L298N 예TB6612FNG 예
왼쪽 모터 방향 1IN1AIN1
왼쪽 모터 방향 2IN2AIN2
왼쪽 모터 속도ENAPWMA
오른쪽 모터 방향 1IN3BIN1
오른쪽 모터 방향 2IN4BIN2
오른쪽 모터 속도ENBPWMB
대기 해제없음 또는 점퍼STBY

L298N의 ENA, ENB에 점퍼가 꽂혀 있으면 속도 제어가 항상 켜진 상태일 수 있습니다. PWM으로 속도를 조절하려면 보통 점퍼를 빼고 아두이노의 PWM 핀에 연결합니다. TB6612FNG의 STBY 핀은 모터 드라이버를 깨우는 핀입니다. HIGH로 만들어야 모터가 동작합니다.

기본 연결 예시

다음은 TB6612FNG를 기준으로 한 연결 예시입니다. L298N을 사용한다면 위 표를 보고 같은 역할의 핀으로 바꾸면 됩니다.

아두이노 핀모터 드라이버 핀역할
4AIN1왼쪽 모터 방향 1
5AIN2왼쪽 모터 방향 2
6PWMA왼쪽 모터 속도 PWM
7BIN1오른쪽 모터 방향 1
8BIN2오른쪽 모터 방향 2
9PWMB오른쪽 모터 속도 PWM
10STBY드라이버 동작 허용
GNDGND공통 기준

왼쪽 모터는 모터 드라이버의 A 출력 단자에, 오른쪽 모터는 B 출력 단자에 연결합니다. 모터 전원은 배터리 팩에서 모터 드라이버의 VM 또는 모터 전원 단자로 연결합니다.

처음 테스트할 때는 반드시 로봇을 책이나 상자 위에 올려 바퀴가 바닥에 닿지 않게 하세요. 코드가 예상과 다르게 동작해도 로봇이 책상 밖으로 떨어지는 일을 막을 수 있습니다.

주행 함수를 만들기

이제 코드를 작성합니다. 이번 코드의 목표는 단순히 한 번 움직이는 것이 아닙니다. 앞으로 장애물 회피 로봇이나 라인트레이서 로봇에서도 다시 사용할 수 있는 주행 함수를 만드는 것입니다.

함수 이름은 동작이 바로 떠오르도록 정합니다.

  • forward(): 전진

  • backward(): 후진

  • turnLeft(): 왼쪽 제자리 회전

  • turnRight(): 오른쪽 제자리 회전

  • stopMotors(): 정지

아래 코드는 TB6612FNG 기준입니다. L298N 사용자는 STBY_PIN 관련 줄을 제거하거나 사용하지 않아도 됩니다.

const int LEFT_IN1 = 4;
const int LEFT_IN2 = 5;
const int LEFT_PWM = 6;

const int RIGHT_IN1 = 7;
const int RIGHT_IN2 = 8;
const int RIGHT_PWM = 9;

const int STBY_PIN = 10;

const int BASIC_SPEED = 160;

void setup() {
  pinMode(LEFT_IN1, OUTPUT);
  pinMode(LEFT_IN2, OUTPUT);
  pinMode(LEFT_PWM, OUTPUT);

  pinMode(RIGHT_IN1, OUTPUT);
  pinMode(RIGHT_IN2, OUTPUT);
  pinMode(RIGHT_PWM, OUTPUT);

  pinMode(STBY_PIN, OUTPUT);
  digitalWrite(STBY_PIN, HIGH);

  stopMotors();
}

void loop() {
  forward(BASIC_SPEED);
  delay(1000);

  stopMotors();
  delay(500);

  backward(BASIC_SPEED);
  delay(1000);

  stopMotors();
  delay(500);

  turnLeft(BASIC_SPEED);
  delay(700);

  stopMotors();
  delay(500);

  turnRight(BASIC_SPEED);
  delay(700);

  stopMotors();
  delay(1500);
}

void driveLeftMotor(int speed) {
  if (speed > 0) {
    digitalWrite(LEFT_IN1, HIGH);
    digitalWrite(LEFT_IN2, LOW);
    analogWrite(LEFT_PWM, speed);
  } else if (speed < 0) {
    digitalWrite(LEFT_IN1, LOW);
    digitalWrite(LEFT_IN2, HIGH);
    analogWrite(LEFT_PWM, -speed);
  } else {
    digitalWrite(LEFT_IN1, LOW);
    digitalWrite(LEFT_IN2, LOW);
    analogWrite(LEFT_PWM, 0);
  }
}

void driveRightMotor(int speed) {
  if (speed > 0) {
    digitalWrite(RIGHT_IN1, HIGH);
    digitalWrite(RIGHT_IN2, LOW);
    analogWrite(RIGHT_PWM, speed);
  } else if (speed < 0) {
    digitalWrite(RIGHT_IN1, LOW);
    digitalWrite(RIGHT_IN2, HIGH);
    analogWrite(RIGHT_PWM, -speed);
  } else {
    digitalWrite(RIGHT_IN1, LOW);
    digitalWrite(RIGHT_IN2, LOW);
    analogWrite(RIGHT_PWM, 0);
  }
}

void forward(int speed) {
  driveLeftMotor(speed);
  driveRightMotor(speed);
}

void backward(int speed) {
  driveLeftMotor(-speed);
  driveRightMotor(-speed);
}

void turnLeft(int speed) {
  driveLeftMotor(-speed);
  driveRightMotor(speed);
}

void turnRight(int speed) {
  driveLeftMotor(speed);
  driveRightMotor(-speed);
}

void stopMotors() {
  driveLeftMotor(0);
  driveRightMotor(0);
}

speed 값은 0부터 255까지 사용할 수 있습니다. 0은 정지이고 255는 가장 빠른 속도입니다. 너무 낮은 값에서는 모터가 힘을 내지 못하고 윙 소리만 날 수 있습니다. 작은 DC 기어드 모터는 보통 120 이상에서 안정적으로 돌기 시작하는 경우가 많습니다. 로봇마다 다르므로 직접 시험해 보아야 합니다.

모터 방향이 반대로 돌 때

코드를 올렸는데 전진 명령에서 로봇이 뒤로 가거나 제자리에서 빙글빙글 돌 수 있습니다. 고장이 아닙니다. 좌우 모터가 섀시에 서로 반대 방향으로 붙어 있기 때문에 자주 생기는 일입니다.

해결 방법은 두 가지입니다.

첫째, 반대로 도는 모터의 두 선을 서로 바꿔 꽂습니다. 가장 직관적인 방법입니다.

둘째, 코드에서 해당 모터의 방향을 반대로 바꿉니다. 예를 들어 오른쪽 모터만 반대로 돈다면 driveRightMotor() 함수 안의 HIGH와 LOW를 서로 바꾸면 됩니다.

중요한 것은 코드에서 "양수 속도는 앞으로"라는 약속을 맞추는 것입니다. 이 약속만 맞춰 두면 이후 장에서 센서값에 따라 forward(), turnLeft(), stopMotors() 같은 함수를 편하게 사용할 수 있습니다.

직진이 삐뚤어질 때

두 모터에 같은 속도 값을 줘도 로봇이 완벽히 직진하지 않을 수 있습니다. 모터의 힘이 조금씩 다르고, 바퀴 마찰이나 차체 무게도 다르기 때문입니다.

이럴 때는 빠른 쪽 모터의 속도를 조금 낮춥니다.

void forward(int speed) {
  driveLeftMotor(speed);
  driveRightMotor(speed - 10);
}

위 예시는 오른쪽 모터가 더 빠를 때 오른쪽 속도를 10 줄이는 방식입니다. 단, speed - 10이 0보다 작아지지 않도록 너무 낮은 속도에서는 주의해야 합니다. 처음에는 5나 10 정도씩 바꾸며 로봇이 얼마나 곧게 가는지 확인합니다.

확인 순서와 자주 생기는 문제

로봇이 움직이지 않을 때는 한 번에 모든 것을 의심하지 말고 순서대로 확인합니다.

  1. 배터리가 충분히 충전되어 있는가?

  2. 모터 전원이 모터 드라이버의 전원 단자에 연결되어 있는가?

  3. 아두이노 GND와 모터 드라이버 GND가 연결되어 있는가?

  4. PWM 핀이 실제 PWM 가능한 핀에 연결되어 있는가?

  5. TB6612FNG의 STBY 핀이 HIGH인가?

  6. L298N의 ENA, ENB 점퍼 상태가 의도와 맞는가?

  7. 모터 선이 빠지거나 바퀴에 전선이 걸리지 않았는가?

모터가 순간적으로 돌다가 아두이노가 재시작된다면 전원이 부족할 가능성이 큽니다. 모터가 출발할 때 전압이 떨어지면 아두이노도 같이 흔들립니다. 이때는 모터 전원과 아두이노 전원을 분리하거나, 더 안정적인 배터리를 사용해야 합니다. 그래도 GND는 반드시 서로 연결해야 합니다.

다음 프로젝트를 위한 몸체 완성

이번 장에서 만든 바퀴 로봇은 아직 스스로 판단하지 않습니다. 정해진 순서대로 앞으로 가고, 뒤로 가고, 회전할 뿐입니다. 하지만 중요한 기반은 완성되었습니다.

이제 로봇에는 몸체가 있고, 좌우 바퀴가 있고, 전원 구조가 있으며, 주행 함수도 있습니다. 다음 단계에서는 이 함수들을 센서값과 연결합니다. 장애물이 가까우면 stopMotors()를 실행하고, 왼쪽으로 피해야 하면 turnLeft()를 실행할 수 있습니다.

로봇의 기본 구조를 다시 떠올려 봅시다. 센서는 입력, 아두이노 코드는 처리, 모터는 출력입니다. 이번 장에서는 출력 부분을 실제 바퀴 움직임으로 완성했습니다. 이제 로봇은 판단만 더해지면 스스로 움직이는 기계에 가까워집니다.

책 목록

아두이노로 배우는 로봇의 기본

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기