지난 글에서 라즈베리 파이와 파이썬 프로그래밍의 기초를 다루며 로봇에 '지능'을 부여하는 첫 단계에 대해 알아보았습니다. 이제 이 지능을 활용하여 로봇이 스스로 주변 환경을 인식하고, 복잡한 지시 없이도 목표를 향해 나아가며, 무엇보다 장애물을 피해서 안전하게 이동하도록 만드는 방법을 배울 차례입니다. 이 글에서는 로봇 자율 주행의 가장 기본적인 단계이자 필수적인 기능인 장애물 회피 알고리즘의 원리를 심층적으로 다룹니다. 초음파 및 적외선 센서를 활용하여 로봇이 장애물을 감지하고, 이를 바탕으로 경로를 변경하는 구체적인 알고리즘과 프로그래밍 예시를 통해 여러분의 로봇이 진정한 '자율 이동체'로 거듭나는 과정을 함께할 것입니다.
로봇 자율 주행이란 무엇인가?
로봇 자율 주행(Autonomous Navigation)은 로봇이 외부의 직접적인 제어 없이 스스로 주변 환경을 인식하고, 경로를 계획하며, 목표 지점까지 이동하는 능력을 의미합니다. 이는 단순한 이동을 넘어, 로봇이 환경에 적응하고 스스로 판단하여 행동하는 지능형 로봇의 핵심 기능입니다. 자율 주행의 가장 기본적인 전제는 바로 장애물 회피입니다.
장애물 회피의 중요성
로봇이 아무리 뛰어난 경로 계획 능력을 가지고 있더라도, 주변에 있는 장애물을 인식하고 피하지 못한다면 임무를 완수할 수 없습니다. 심지어 자신이나 주변 환경에 피해를 줄 수도 있습니다. 따라서 장애물 회피는 로봇의 안전하고 효율적인 자율 주행을 위한 가장 기본적인 기능이자 필수적인 알고리즘입니다.
장애물 감지를 위한 센서 선택
장애물 회피를 위해 가장 일반적으로 사용되는 센서는 다음과 같습니다.
1. 초음파 센서 (Ultrasonic Sensor, 예: HC-SR04)
- 원리: 초음파를 발사하고, 장애물에 부딪혀 반사되어 돌아오는 시간을 측정하여 거리를 계산합니다.
- 장점: 비교적 넓은 범위(2cm ~ 400cm)의 거리 측정이 가능하고, 가격이 저렴합니다.
- 단점: 특정 표면(솜, 곡선형 물체 등)에서 오차가 발생할 수 있고, 측정 주기가 다소 느릴 수 있습니다. 여러 센서 사용 시 간섭이 발생할 수 있습니다.
- 활용: 이동 로봇의 전방, 측면 장애물 감지.
2. 적외선 센서 (Infrared Sensor, IR Sensor, 예: GP2Y0A21, IR 근접 센서)
- 원리: 적외선을 발사하고, 반사된 적외선의 양이나 위상차를 측정하여 거리를 계산합니다. 단순 IR 근접 센서는 특정 거리 내 물체 유무를 감지합니다.
- 장점: 작고 가볍고, 응답 속도가 빠릅니다. 근접한 장애물 감지에 매우 효과적입니다.
- 단점: 측정 거리가 짧고, 밝은 빛이나 검은색/투명한 물체에 약할 수 있습니다.
- 활용: 로봇의 벽 감지, 라인 트레이싱(흑백 대비), 근접 장애물 회피.
3. 범퍼 스위치 (Bumper Switch)
- 원리: 로봇이 물리적으로 장애물에 부딪혔을 때 스위치가 눌려 접촉을 감지합니다.
- 장점: 매우 간단하고 확실한 감지 방법입니다. 가격이 매우 저렴합니다.
- 단점: 장애물과 충돌해야만 감지할 수 있으므로, 충돌을 피하는 고급 회피에는 적합하지 않습니다.
- 활용: 보조적인 안전 장치, 로봇 청소기 등.
기본적인 장애물 회피 알고리즘 (Pseudo Code)
가장 간단한 형태의 장애물 회피 알고리즘은 다음과 같은 논리 흐름을 가집니다.
1. 센서로 전방의 거리(또는 장애물 유무)를 측정한다.
2. 만약 측정된 거리가 '위험 거리'보다 작으면 (즉, 장애물이 너무 가까이 있으면):
a. 로봇을 정지시키거나 후진시킨다.
b. 주변 센서를 다시 측정하거나, 임의의 방향(예: 오른쪽)으로 회전한다.
c. 회전 후 다시 전방을 측정하여 안전하다고 판단되면 전진한다.
3. 만약 '위험 거리'보다 크면 (즉, 장애물이 없으면):
a. 로봇을 전진시킨다.
4. 이 과정을 무한히 반복한다.
아두이노 기반 장애물 회피 로봇 구현 예시
지난 7편에서 조립했던 아두이노 기반 이동 로봇에 초음파 센서(HC-SR04)를 추가하여 장애물 회피 기능을 구현해 보겠습니다.
추가 부품:
- HC-SR04 초음파 센서: 1개 (전방 감지용)
- 점퍼선: (센서 연결용)
배선 (아두이노 우노 기준):
- HC-SR04:
- VCC 핀 -> 아두이노 5V
- GND 핀 -> 아두이노 GND
- Trig 핀 -> 아두이노 디지털 핀 (예: D7)
- Echo 핀 -> 아두이노 디지털 핀 (예: D6)
- L298N 모터 드라이버 및 모터: 7편의 배선과 동일하게 연결합니다. (IN1/IN2/ENA, IN3/IN4/ENB)
아두이노 스케치 (코드):
// L298N 모터 드라이버 핀 설정 (7편 코드 참고)
int motor1_in1 = 2;
int motor1_in2 = 3;
int motor1_ena = 9; // PWM 핀
int motor2_in3 = 4;
int motor2_in4 = 5;
int motor2_enb = 10; // PWM 핀
// HC-SR04 초음파 센서 핀 설정
int trigPin = 7;
int echoPin = 6;
// 상수 정의
const long DURATION_TIMEOUT = 23200; // 400cm (200cm 왕복)에 대한 타임아웃 마이크로초 (소리 속도 약 343m/s)
const int OBSTACLE_DISTANCE_CM = 25; // 장애물 회피를 시작할 거리 (cm)
void setup() {
// 모터 핀 모드 설정
pinMode(motor1_in1, OUTPUT);
pinMode(motor1_in2, OUTPUT);
pinMode(motor1_ena, OUTPUT);
pinMode(motor2_in3, OUTPUT);
pinMode(motor2_in4, OUTPUT);
pinMode(motor2_enb, OUTPUT);
// 초음파 센서 핀 모드 설정
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600); // 시리얼 통신 시작 (디버깅용)
Serial.println("Obstacle Avoidance Robot Ready!");
}
void loop() {
long duration, distanceCm;
// 1. 초음파 센서로 거리 측정
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Echo 핀으로부터 펄스 지속 시간을 읽습니다. (최대 DURATION_TIMEOUT까지 기다림)
duration = pulseIn(echoPin, HIGH, DURATION_TIMEOUT);
// 거리를 cm로 변환 (소리의 속도: 343m/s = 0.0343cm/us. 왕복 거리이므로 2로 나눔)
distanceCm = duration * 0.0343 / 2;
Serial.print("Distance: ");
Serial.print(distanceCm);
Serial.println(" cm");
// 2. 장애물 감지 및 회피 로직
if (distanceCm < OBSTACLE_DISTANCE_CM && distanceCm > 0) { // 장애물이 너무 가까이 있다면
Serial.println("Obstacle detected! Avoiding...");
stopMotors(); // 일단 정지
delay(500); // 잠시 대기
moveBackward(100); // 잠시 후진
delay(700);
stopMotors();
delay(300);
// 오른쪽으로 회전 (로봇마다 회전 방향은 다를 수 있음)
// 한쪽 바퀴만 돌리거나, 양쪽 바퀴를 반대 방향으로 돌립니다.
turnRight(150); // 예: 오른쪽 바퀴는 정지, 왼쪽 바퀴만 전진
delay(1000); // 1초간 회전
stopMotors();
delay(300);
// 회전 후 다시 전방 확인을 위해 loop()가 다시 시작됨
} else { // 장애물이 없다면 전진
moveForward(150);
Serial.println("Moving forward...");
}
delay(50); // 짧은 지연 (센서 안정화 및 루프 속도 조절)
}
// === 로봇 움직임 제어 함수 ===
void moveForward(int speed) {
digitalWrite(motor1_in1, HIGH);
digitalWrite(motor1_in2, LOW);
analogWrite(motor1_ena, speed);
digitalWrite(motor2_in3, HIGH);
digitalWrite(motor2_in4, LOW);
analogWrite(motor2_enb, speed);
}
void moveBackward(int speed) {
digitalWrite(motor1_in1, LOW);
digitalWrite(motor1_in2, HIGH);
analogWrite(motor1_ena, speed);
digitalWrite(motor2_in3, LOW);
digitalWrite(motor2_in4, HIGH);
analogWrite(motor2_enb, speed);
}
void turnLeft(int speed) {
digitalWrite(motor1_in1, LOW); // 왼쪽 바퀴 후진
digitalWrite(motor1_in2, HIGH);
analogWrite(motor1_ena, speed);
digitalWrite(motor2_in3, HIGH); // 오른쪽 바퀴 전진
digitalWrite(motor2_in4, LOW);
analogWrite(motor2_enb, speed);
}
void turnRight(int speed) {
digitalWrite(motor1_in1, HIGH); // 왼쪽 바퀴 전진
digitalWrite(motor1_in2, LOW);
analogWrite(motor1_ena, speed);
digitalWrite(motor2_in3, LOW); // 오른쪽 바퀴 후진
digitalWrite(motor2_in4, HIGH);
analogWrite(motor2_enb, speed);
}
void stopMotors() {
analogWrite(motor1_ena, 0);
analogWrite(motor2_enb, 0);
}
코드 설명:
- 핀 설정: 초음파 센서와 모터 드라이버 핀을 정의하고 OUTPUT/INPUT으로 설정합니다.
loop()
함수:digitalWrite(trigPin, ...)
: 짧은 펄스를 트리거 핀에 보내 초음파를 발사합니다.pulseIn(echoPin, HIGH, DURATION_TIMEOUT)
: 에코 핀이 HIGH 신호를 유지하는 시간(초음파가 돌아오는 시간)을 측정합니다.DURATION_TIMEOUT
은 너무 멀리 있거나 센서가 응답하지 않을 때 무한 대기하는 것을 방지합니다.distanceCm = duration * 0.0343 / 2;
: 측정된 시간(duration)을 바탕으로 거리를 계산합니다. 소리의 속도와 왕복 시간을 고려한 공식입니다.- 조건문
if (distanceCm < OBSTACLE_DISTANCE_CM && distanceCm > 0)
: 측정된 거리가 미리 정의된OBSTACLE_DISTANCE_CM
(예: 25cm)보다 작고, 유효한 값일 때 (0보다 클 때) 장애물 회피 동작을 시작합니다. - 회피 동작: 로봇을 정지시키고, 잠시 후진한 다음, 특정 방향(예: 오른쪽)으로 회전하여 장애물을 벗어납니다. 회전 후 다시
loop()
의 시작으로 돌아가 전방을 확인합니다. - 정상 동작: 장애물이 없으면
moveForward()
함수를 호출하여 로봇을 전진시킵니다.
- 움직임 제어 함수:
moveForward
,moveBackward
,turnLeft
,turnRight
,stopMotors
함수는 로봇의 움직임을 추상화하여 코드를 더 읽기 쉽게 만듭니다. (7편 코드에서 가져옴)
장애물 회피 알고리즘의 개선 및 확장
이 예제는 가장 기본적인 장애물 회피 알고리즘입니다. 더 똑똑한 로봇을 만들려면 다음과 같은 방법으로 알고리즘을 개선할 수 있습니다.
- 다중 센서 사용:
- 전방뿐만 아니라 좌/우/후방에 추가 센서를 장착하여 로봇 주변의 360도 환경을 더 정확하게 파악합니다.
- 측면 센서 값을 기반으로 가장 안전한 회피 방향을 결정할 수 있습니다.
- (그림 삽입 예정: 다중 센서 배치 예시)
- 랜덤 회전 또는 스마트 회전:
- 단순히 한 방향으로만 회전하는 대신, 좌/우측 센서 값을 비교하여 더 넓은 공간이 있는 방향으로 회전하거나, 무작위로 회전하여 예상치 못한 상황을 돌파할 수 있습니다.
- 미로 탐색 알고리즘(예: 벽면 추적, 트레모(Tremaux) 알고리즘)과 결합하여 더욱 효율적인 탐색이 가능합니다.
- 속도 제어:
- 장애물과의 거리에 따라 로봇의 속도를 조절하여 부드러운 회피 동작을 구현할 수 있습니다. (예: 멀리 있으면 빠르게, 가까워지면 느리게)
- 센서 융합 (Sensor Fusion):
- 카메라, Lidar 등 다른 종류의 센서 데이터를 함께 사용하여 더 정확한 환경 인식과 장애물 분류를 수행할 수 있습니다. (예: 카메라로 장애물의 종류를 파악하여 사람인지, 벽인지 구분)
- 예외 처리:
- 센서 오류, 데이터 이상치 등을 처리하는 코드를 추가하여 로봇의 안정성을 높입니다.
실제 환경 적용 시 고려사항
- 센서 배치: 센서의 시야각과 사각지대를 고려하여 최적의 위치에 배치해야 합니다.
- 환경 영향: 초음파 센서는 소리, 적외선 센서는 빛에 영향을 받을 수 있으므로, 실제 작동 환경에서의 성능을 테스트해야 합니다.
- 로봇의 크기와 속도: 로봇의 크기와 이동 속도에 따라 '위험 거리'와 회피 동작의 크기를 조절해야 합니다. 빠른 로봇은 더 긴 제동 거리와 더 큰 회피 공간이 필요합니다.
- 배터리 소모: 센서와 모터의 작동은 배터리 소모를 증가시키므로, 효율적인 전원 관리도 중요합니다.
마무리하며...
이번 글에서는 로봇 자율 주행의 가장 기본적인 단계인 장애물 회피 알고리즘의 원리와 아두이노를 이용한 구현 예시를 살펴보았습니다. 초음파 센서를 활용하여 장애물을 감지하고, 로봇이 스스로 경로를 변경하여 안전하게 이동하도록 만드는 것이 얼마나 중요한지 이해하셨을 겁니다. 이 기본적인 알고리즘을 바탕으로 다중 센서 활용, 스마트 회전, 속도 제어 등 다양한 방식으로 로봇의 지능을 더욱 향상시킬 수 있습니다.
다음 편에서는 좀 더 정교하고 복잡한 움직임을 제어하는 로봇 팔 만들기에 도전해 보겠습니다. 서보 모터와 키네마틱스 기초를 통해 로봇 팔의 각 관절을 제어하는 방법을 배우게 될 것입니다. 이제 여러분의 로봇에 초음파 센서를 장착하고, 위 예제 코드를 수정하여 자신만의 장애물 회피 로봇을 만들어 실제 환경에서 테스트해 보세요!
0 댓글