Skip to main content
Summary

로봇은 매 순간 선택한다

지금까지 우리는 로봇을 숫자로 표현하는 방법을 배웠다. 위치는 벡터가 되었고, 방향은 각도와 회전 행렬이 되었고, 센서의 흔들림은 확률분포가 되었다. 이제 한 가지 질문이 남는다.

로봇은 이 숫자들을 보고 무엇을 선택해야 할까?

앞에 목표점이 있다. 로봇은 곧장 가도 되고, 살짝 돌아가도 된다. 장애물이 있다면 더 멀리 돌아가야 할 수도 있다. 센서값이 여러 개 들어왔을 때는 어느 값을 더 믿을지도 정해야 한다. 팔 로봇이라면 같은 위치에 손끝을 보내는 관절 조합이 여러 개일 수 있다. 이때 로봇은 그중 하나를 골라야 한다.

최적화는 바로 이 선택의 기술이다.

최적화란 여러 후보 중에서 가장 좋은 것을 고르는 과정이다. 여기서 좋은이라는 말은 막연한 느낌이 아니라 숫자로 표현된다. 목표에 더 가까운가, 에너지를 덜 쓰는가, 장애물과 충분히 떨어져 있는가, 센서 오차가 작은가 같은 기준을 하나의 점수로 만들고, 그 점수가 가장 좋은 후보를 선택한다.

이 장부터 우리는 로봇 문제를 새로운 관점으로 바라본다. 로봇의 경로, 자세, 위치 추정, 제어 입력은 모두 다음과 같은 질문으로 바꿀 수 있다.

여러 선택지 중에서 비용이 가장 작은 것은 무엇인가?

이 문장이 최적화의 출발점이다.

최적화란 무엇인가

좋은 선택을 숫자로 평가하기

로봇에게 좋은 경로를 고르라고 말하면 로봇은 곤란해한다. 사람에게는 좋은 경로라는 말이 어느 정도 통하지만, 컴퓨터는 좋은이라는 감각을 직접 이해하지 못한다. 컴퓨터에게는 숫자가 필요하다.

예를 들어 로봇이 목표점까지 이동해야 한다고 하자. 후보 경로 A는 짧지만 장애물에 너무 가깝다. 후보 경로 B는 조금 멀지만 안전하다. 후보 경로 C는 안전하지만 너무 많이 빙 돌아간다. 사람은 그림을 보고 대충 판단할 수 있지만, 로봇에게는 판단 기준을 계산식으로 알려 주어야 한다.

이때 사용하는 함수가 목적 함수다. 목적 함수는 어떤 후보를 입력으로 받아 그 후보가 얼마나 좋은지 또는 나쁜지를 숫자로 계산하는 함수다.

로봇 문제에서는 보통 좋은 정도보다 나쁜 정도를 계산하는 편이 많다. 나쁜 정도를 비용이라고 부른다. 그래서 비용이 작을수록 좋은 선택이다. 비용 함수는 후보 선택의 불편함, 오차, 위험, 에너지 소비 등을 숫자로 표현한다.

간단한 예를 보자.

import numpy as np

goal = np.array([5.0, 3.0])

candidate_positions = np.array([
    [4.0, 2.5],
    [5.2, 3.1],
    [6.0, 4.0],
    [3.0, 3.5]
])

for p in candidate_positions:
    cost = np.linalg.norm(goal - p)
    print(p, 'cost =', cost)

여기서 비용은 목표점과 후보 위치 사이의 거리다. 목표에 가까울수록 비용이 작다. 가장 비용이 작은 후보는 목표에 가장 가까운 위치다.

이 예제는 매우 단순하지만 최적화의 핵심을 이미 담고 있다.

cost = np.linalg.norm(goal - p)

이 한 줄은 후보 위치 p가 얼마나 좋은지를 숫자로 평가한다. 이제 로봇은 감이 아니라 계산으로 선택할 수 있다.

목적 함수와 비용 함수

목적 함수와 비용 함수는 비슷하게 쓰이지만, 약간의 뉘앙스 차이가 있다.

목적 함수는 최적화에서 최대로 만들거나 최소로 만들 대상 전체를 말한다. 비용 함수는 그중에서도 작을수록 좋은 값을 표현할 때 자주 쓰는 말이다. 로봇공학에서는 비용을 최소화하는 형태가 아주 흔하다.

예를 들어 다음과 같은 목표는 모두 비용 최소화 문제로 바꿀 수 있다.

  • 목표점까지의 거리를 줄인다.

  • 센서 측정값과 예측값의 차이를 줄인다.

  • 로봇이 쓰는 에너지를 줄인다.

  • 이동 시간을 줄인다.

  • 장애물과 충돌할 위험을 줄인다.

비용 함수는 보통 여러 항을 더해서 만든다.

전체 비용 = 목표 거리 비용 + 장애물 위험 비용 + 에너지 비용 + 회전 비용

로봇 입장에서는 하나만 잘한다고 좋은 선택이 아니다. 목표에 빨리 도착하더라도 벽에 부딪히면 실패다. 안전하더라도 하루 종일 제자리에서 맴돌면 쓸모가 없다. 그래서 여러 기준을 함께 넣어야 한다.

수식처럼 쓰면 다음과 같은 모양이 된다.

J = w_goal * goal_cost
  + w_obstacle * obstacle_cost
  + w_energy * energy_cost
  + w_smooth * smooth_cost

여기서 J는 전체 비용이다. w_goal, w_obstacle 같은 값은 가중치다. 가중치는 각 기준을 얼마나 중요하게 볼지 정하는 숫자다.

장애물 회피가 매우 중요하면 w_obstacle을 크게 둔다. 배터리를 아끼는 것이 중요하면 w_energy를 크게 둔다. 목표점에 빨리 가까워지는 것이 중요하면 w_goal을 크게 둔다.

가중치를 정하는 일은 로봇에게 성격을 부여하는 일과 비슷하다. 어떤 로봇은 과감하게 움직이고, 어떤 로봇은 조심스럽게 움직인다. 그 차이가 비용 함수 안에 들어간다.

오차도 비용이 된다

이전 부에서 우리는 센서가 항상 정확하지 않다는 것을 배웠다. 센서값에는 노이즈가 있고, 때로는 편향과 드리프트도 있다. 그래서 로봇은 자신의 위치를 정확히 알지 못한다.

위치 추정도 최적화 문제로 볼 수 있다.

예를 들어 로봇이 어떤 위치 x에 있다고 가정해 보자. 센서가 측정한 위치는 z다. 만약 x가 진짜 위치에 가깝다면, x에서 예측한 센서값과 실제 센서값 z의 차이가 작아야 한다. 반대로 x가 엉뚱한 위치라면 센서값과 잘 맞지 않을 것이다.

따라서 다음과 같은 비용을 만들 수 있다.

위치 추정 비용 = 센서 측정값과 예측값의 차이

조금 더 자주 쓰는 형태는 오차의 제곱이다.

비용 = 오차 * 오차

오차를 제곱하면 양수와 음수가 서로 상쇄되지 않는다. 그리고 큰 오차에 더 큰 벌점을 준다. 다음 장에서 배울 최소제곱법은 바로 이 생각을 체계적으로 다루는 방법이다.

Python으로 아주 작은 예를 보자. 로봇이 1차원 직선 위에 있고, 세 개의 센서가 위치를 측정했다고 하자.

import numpy as np

measurements = np.array([2.8, 3.1, 3.0])

candidate_positions = np.linspace(2.0, 4.0, 21)

best_x = None
best_cost = float('inf')

for x in candidate_positions:
    errors = measurements - x
    cost = np.sum(errors ** 2)

    if cost < best_cost:
        best_cost = cost
        best_x = x

print('best position:', best_x)
print('best cost:', best_cost)

이 예제에서 후보 위치 x는 여러 개다. 각 후보에 대해 센서 측정값과의 오차를 계산하고, 오차 제곱합이 가장 작은 위치를 고른다. 이것이 위치 추정을 최적화 문제로 보는 가장 단순한 형태다.

흥미로운 점은 이 구조가 경로 선택과 닮았다는 것이다. 경로 선택에서는 경로 후보를 비교했고, 위치 추정에서는 위치 후보를 비교했다. 최적화의 관점에서는 둘 다 후보를 평가하고 가장 비용이 작은 것을 고르는 문제다.

제어 입력도 선택의 대상이다

로봇은 매 순간 속도 명령을 내려야 한다. 바퀴 로봇이라면 전진 속도 v와 회전 속도 w를 정해야 한다. 드론이라면 각 모터의 출력이나 목표 자세를 정해야 한다. 로봇 팔이라면 각 관절에 줄 속도나 힘을 정해야 한다.

이 명령도 최적화의 대상이 된다.

예를 들어 2D 이동 로봇이 있다고 하자. 현재 위치에서 앞으로 0.5초 동안 어떤 속도 명령을 줄지 선택해야 한다. 후보는 여러 개다.

천천히 직진할 수도 있고, 빠르게 직진할 수도 있다. 왼쪽으로 돌 수도 있고, 오른쪽으로 돌 수도 있다. 각 후보 명령을 잠깐 시뮬레이션해 보고, 그 결과가 목표에 가까워지는지, 장애물과 안전한지, 회전이 너무 급하지 않은지를 계산할 수 있다.

이 방식은 매우 로봇답다. 미래를 조금 상상해 보고, 가장 괜찮은 행동을 고르는 것이다.

이제 작은 예제를 만들어 보자.

후보 경로를 비교하는 작은 최적화 예제

이번 예제에서는 로봇이 여러 속도 명령 후보를 시험해 보고 가장 비용이 작은 명령을 선택한다. 로봇은 현재 위치에서 출발해 짧은 시간 동안 움직인다. 각 명령으로 만들어지는 짧은 경로를 후보 경로라고 하자.

비용에는 세 가지를 넣는다. 첫째, 경로 끝점이 목표에 가까워야 한다. 둘째, 장애물과 너무 가까우면 안 된다. 셋째, 너무 급하게 회전하는 명령은 조금 불리하게 한다.

먼저 필요한 함수를 준비한다.

import numpy as np
import matplotlib.pyplot as plt


def normalize_angle(angle):
    return (angle + np.pi) % (2 * np.pi) - np.pi


def simulate_motion(state, v, w, dt=0.1, steps=30):
    x, y, theta = state
    path = []

    for _ in range(steps):
        x += v * np.cos(theta) * dt
        y += v * np.sin(theta) * dt
        theta = normalize_angle(theta + w * dt)
        path.append([x, y])

    return np.array(path), np.array([x, y, theta])

state는 로봇의 현재 상태다. [x, y, theta] 형태로 저장한다. v는 전진 속도, w는 회전 속도다. simulate_motion 함수는 주어진 속도 명령을 일정 시간 동안 적용했을 때 로봇이 어떤 경로를 그리는지 계산한다.

이제 비용 함수를 만든다.


def compute_path_cost(path, final_state, goal, obstacles, v, w):
    final_pos = final_state[:2]

    goal_cost = np.linalg.norm(goal - final_pos)

    diff = path[:, None, :] - obstacles[None, :, :]
    dists = np.linalg.norm(diff, axis=2)
    min_obstacle_dist = np.min(dists)
    obstacle_cost = 1.0 / (min_obstacle_dist + 1e-6)

    turn_cost = abs(w)
    energy_cost = v  2 + 0.3 * (w  2)

    total_cost = (
        2.0 * goal_cost
        + 1.5 * obstacle_cost
        + 0.2 * turn_cost
        + 0.1 * energy_cost
    )

    return total_cost, min_obstacle_dist

이 함수 안에는 여러 종류의 비용이 들어 있다.

goal_cost = np.linalg.norm(goal - final_pos)

이 값은 경로의 끝점이 목표점에서 얼마나 떨어져 있는지를 뜻한다. 작을수록 좋다.

obstacle_cost = 1.0 / (min_obstacle_dist + 1e-6)

이 값은 장애물에 가까울수록 커진다. min_obstacle_dist가 작아지면 1을 작은 수로 나누게 되므로 비용이 커진다. 즉 장애물 가까이 가는 행동에 벌점을 주는 셈이다.

turn_cost = abs(w)
energy_cost = v  2 + 0.3 * (w  2)

이 값들은 너무 급하게 회전하거나 큰 속도를 쓰는 명령에 약간의 비용을 준다. 실제 로봇은 에너지를 무한히 쓸 수 없고, 갑작스러운 움직임은 미끄러짐이나 진동을 만들 수 있다.

이제 여러 후보 명령을 만들어서 비교하자.

state = np.array([0.0, 0.0, 0.0])
goal = np.array([4.0, 2.0])
obstacles = np.array([
    [1.8, 0.4],
    [2.4, 1.2],
    [3.0, 1.6]
])

v_candidates = np.linspace(0.2, 1.0, 5)
w_candidates = np.linspace(-1.2, 1.2, 9)

safe_distance = 0.35

best = None
results = []

for v in v_candidates:
    for w in w_candidates:
        path, final_state = simulate_motion(state, v, w)
        cost, min_dist = compute_path_cost(path, final_state, goal, obstacles, v, w)

        feasible = min_dist >= safe_distance

        results.append({
            'v': v,
            'w': w,
            'path': path,
            'final_state': final_state,
            'cost': cost,
            'min_dist': min_dist,
            'feasible': feasible
        })

        if feasible:
            if best is None or cost < best['cost']:
                best = results[-1]

print('best v:', best['v'])
print('best w:', best['w'])
print('best cost:', best['cost'])
print('minimum obstacle distance:', best['min_dist'])

이 코드는 모든 v, w 조합을 하나씩 시험한다. 각 조합에 대해 짧은 미래 경로를 만들고 비용을 계산한다. 그리고 장애물과 너무 가까운 후보는 제외한다. 남은 후보 중 비용이 가장 작은 명령이 선택된다.

여기서 feasible은 실행 가능한 후보라는 뜻이다. 비용이 아무리 낮아 보여도 안전거리 조건을 만족하지 못하면 선택하지 않는다. 이것이 제약 조건의 첫 번째 모습이다.

결과를 그림으로 확인해 보자.

plt.figure(figsize=(7, 5))

for r in results:
    path = r['path']
    if r['feasible']:
        plt.plot(path[:, 0], path[:, 1], color='lightgray', linewidth=1)
    else:
        plt.plot(path[:, 0], path[:, 1], color='mistyrose', linewidth=1)

best_path = best['path']
plt.plot(best_path[:, 0], best_path[:, 1], color='red', linewidth=3, label='best path')

plt.scatter(state[0], state[1], color='blue', s=80, label='start')
plt.scatter(goal[0], goal[1], color='green', s=80, label='goal')
plt.scatter(obstacles[:, 0], obstacles[:, 1], color='black', s=80, label='obstacle')

for obs in obstacles:
    circle = plt.Circle(obs, safe_distance, color='black', alpha=0.12)
    plt.gca().add_patch(circle)

plt.axis('equal')
plt.grid(True)
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.show()

회색 선은 실행 가능한 후보 경로다. 연한 붉은색 선은 장애물에 너무 가까워 탈락한 후보 경로다. 빨간 선은 비용이 가장 낮은 선택이다.

이 예제는 아직 완벽한 경로 계획기는 아니다. 하지만 중요한 구조는 모두 들어 있다.

  • 후보를 만든다.

  • 후보를 시뮬레이션한다.

  • 비용 함수로 평가한다.

  • 제약 조건을 어기는 후보를 제외한다.

  • 남은 후보 중 비용이 가장 작은 것을 고른다.

이 다섯 단계는 실제 로봇 알고리즘에서도 반복해서 등장한다.

제약 조건은 현실의 벽이다

비용 함수만 있으면 로봇이 모든 문제를 해결할 수 있을 것 같지만, 실제 세계에는 반드시 지켜야 하는 조건이 있다. 이것을 제약 조건이라고 한다.

예를 들어 바퀴 로봇은 무한히 빠르게 달릴 수 없다. 모터의 최대 속도가 있고, 바퀴와 바닥 사이의 마찰 한계도 있다. 로봇 팔의 관절은 아무 각도로나 꺾이지 않는다. 카메라는 볼 수 있는 범위가 정해져 있고, 드론은 배터리와 추력의 한계를 가진다.

로봇에서 자주 만나는 제약 조건은 다음과 같다.

  • 속도 제한: 전진 속도와 회전 속도는 정해진 범위를 넘을 수 없다.

  • 장애물 거리: 로봇은 장애물과 최소 안전거리 이상 떨어져 있어야 한다.

  • 관절 범위: 로봇 팔의 각 관절은 허용된 각도 범위 안에 있어야 한다.

  • 가속도 제한: 속도를 너무 갑자기 바꾸면 안 된다.

  • 작업 공간 제한: 로봇은 정해진 공간 밖으로 나가면 안 된다.

제약 조건은 크게 두 가지 방식으로 다룰 수 있다.

첫 번째는 단단한 제약이다. 반드시 지켜야 하는 조건이다. 예를 들어 장애물과 충돌하는 경로는 아무리 목표에 가까워도 선택하면 안 된다. 이런 후보는 아예 버린다.

두 번째는 부드러운 제약이다. 가능하면 지키고 싶지만, 상황에 따라 비용으로 조절할 수 있는 조건이다. 예를 들어 회전을 조금 덜 했으면 좋겠다는 기준은 비용 항으로 넣을 수 있다. 회전이 커질수록 비용을 올리면 로봇은 자연스럽게 부드러운 움직임을 선호한다.

앞의 코드에서 safe_distance는 단단한 제약으로 처리했다.

feasible = min_dist >= safe_distance

장애물과의 최소 거리가 안전거리보다 작으면 그 후보는 탈락한다. 반면 turn_cost와 energy_cost는 부드러운 제약에 가깝다. 급회전이나 높은 속도를 완전히 금지하지는 않지만, 비용을 높여 덜 선호하게 만든다.

이 구분은 실제 로봇 설계에서 매우 중요하다. 절대 어기면 안 되는 조건은 제약으로 두고, 선호의 문제는 비용으로 넣는 것이 일반적이다.

비용 함수는 로봇의 가치관이다

같은 상황에서도 비용 함수를 어떻게 만들었느냐에 따라 로봇의 행동이 달라진다.

장애물 비용의 가중치를 크게 만들면 로봇은 장애물에서 멀리 떨어져 움직인다. 안전하지만 경로가 길어질 수 있다. 목표 거리 비용의 가중치를 크게 만들면 로봇은 목표로 더 적극적으로 접근한다. 빠를 수 있지만 장애물 근처를 아슬아슬하게 지나갈 수도 있다.

다음 코드에서 가중치를 바꾸면 로봇의 선택도 바뀐다.

total_cost = (
    2.0 * goal_cost
    + 1.5 * obstacle_cost
    + 0.2 * turn_cost
    + 0.1 * energy_cost
)

만약 장애물 회피를 더 중요하게 만들고 싶다면 이렇게 바꿀 수 있다.

total_cost = (
    2.0 * goal_cost
    + 5.0 * obstacle_cost
    + 0.2 * turn_cost
    + 0.1 * energy_cost
)

반대로 목표점에 더 빨리 다가가게 만들고 싶다면 goal_cost의 가중치를 키울 수 있다.

total_cost = (
    5.0 * goal_cost
    + 1.5 * obstacle_cost
    + 0.2 * turn_cost
    + 0.1 * energy_cost
)

이처럼 비용 함수는 단순한 계산식이 아니라 로봇의 행동 방식을 결정하는 설계도다. 비용 함수를 바꾸면 로봇의 성격이 바뀐다. 신중한 로봇, 빠른 로봇, 에너지를 아끼는 로봇, 부드럽게 움직이는 로봇을 모두 비용 함수로 표현할 수 있다.

그래서 최적화에서 가장 어려운 부분은 계산 자체가 아닐 때가 많다. 무엇을 비용으로 삼을지, 어떤 제약을 반드시 지켜야 할지, 각 항의 가중치를 어떻게 정할지를 결정하는 일이 더 어렵다.

좋은 비용 함수의 조건

비용 함수는 아무렇게나 만들 수 있지만, 좋은 비용 함수에는 몇 가지 특징이 있다.

첫째, 로봇이 원하는 행동과 비용이 잘 연결되어야 한다. 목표에 가까워질수록 비용이 줄어야 하고, 위험해질수록 비용이 커져야 한다. 비용이 실제 의도와 어긋나면 로봇은 이상한 선택을 한다.

둘째, 너무 많은 기준을 한꺼번에 넣기보다 중요한 기준부터 시작하는 것이 좋다. 처음부터 목표 거리, 시간, 에너지, 진동, 안전성, 센서 시야, 통신 품질까지 모두 넣으면 무엇이 문제인지 알기 어렵다. 먼저 단순한 비용 함수로 움직임을 확인한 뒤 조금씩 추가하는 편이 안전하다.

셋째, 비용의 크기 단위를 조심해야 한다. 목표 거리 비용이 0에서 5 사이인데 장애물 비용이 0에서 10000 사이로 튄다면, 장애물 비용이 모든 것을 지배할 수 있다. 그래서 가중치 조정과 값의 스케일 확인이 중요하다.

넷째, 그림으로 확인해야 한다. 숫자만 보면 비용 함수가 잘 작동하는지 알기 어렵다. 후보 경로, 장애물, 선택된 경로를 그려 보면 로봇이 왜 그런 선택을 했는지 훨씬 쉽게 이해할 수 있다.

지금까지 이 책에서 계속 그림을 그려 온 이유도 여기에 있다. 로봇 수학은 머릿속 공식으로만 이해하기 어렵다. 숫자가 어떤 움직임이 되는지 눈으로 확인해야 감각이 생긴다.

최적화 문제의 기본 형태

최적화 문제는 보통 다음과 같은 형태로 정리할 수 있다.

변수: 로봇이 선택해야 하는 값
목적: 비용 함수를 최소화하기
제약: 반드시 만족해야 하는 조건

앞의 속도 명령 예제에서는 다음과 같이 볼 수 있다.

변수: 전진 속도 v, 회전 속도 w
목적: 목표 거리 비용 + 장애물 비용 + 회전 비용 + 에너지 비용을 최소화
제약: 장애물과 안전거리 이상 떨어지기

위치 추정 예제에서는 다음과 같다.

변수: 로봇의 위치 x
목적: 센서 측정값과 예측값의 오차 제곱합을 최소화
제약: 필요하다면 가능한 위치 범위 안에 있기

경로 계획 문제에서는 이렇게 된다.

변수: 여러 웨이포인트 또는 경로 전체
목적: 짧고 부드러우며 안전한 경로의 비용을 최소화
제약: 장애물과 충돌하지 않고 작업 공간 안에 있기

로봇 팔의 자세 문제에서는 다음과 같다.

변수: 각 관절의 각도
목적: 손끝이 목표 자세에 가까워지도록 오차를 최소화
제약: 관절 각도 범위와 충돌 회피 조건을 만족하기

문제는 달라 보여도 구조는 비슷하다. 무엇을 고를지 정하고, 그 선택을 평가하는 비용을 만들고, 현실적인 제한을 추가한다. 그러면 로봇 문제는 최적화 문제로 바뀐다.

모든 후보를 다 볼 수 있을까

앞의 예제에서는 후보 v, w를 격자로 만들어 모두 비교했다. 이런 방법을 전수 조사라고 부를 수 있다. 가능한 후보를 하나씩 다 계산해 보고 가장 좋은 것을 고르는 방식이다.

전수 조사는 이해하기 쉽고 구현도 간단하다. 후보가 적을 때는 매우 좋은 출발점이다. 하지만 후보가 많아지면 문제가 생긴다.

v 후보가 10개이고 w 후보가 10개라면 조합은 100개다. 여기에 가속도 후보까지 10개를 넣으면 1000개가 된다. 경로를 20개의 웨이포인트로 표현하고 각 웨이포인트가 여러 위치 후보를 가진다면 경우의 수는 순식간에 폭발한다.

이것이 최적화 알고리즘이 필요한 이유다. 모든 후보를 다 보지 않고도 좋은 답을 찾아야 한다. 다음 장들에서 배울 최소제곱법과 경사하강법은 이런 문제를 해결하기 위한 대표적인 도구다.

하지만 복잡한 알고리즘을 배우기 전에 지금의 감각이 가장 중요하다.

최적화는 마법이 아니다. 후보를 평가하는 비용 함수가 있고, 그 비용을 줄이는 방향으로 답을 찾는 과정이다. 어려운 알고리즘도 결국 이 구조 위에서 움직인다.

최적화는 이전 내용들을 연결한다

이 장에서 배운 최적화는 갑자기 등장한 새로운 주제가 아니다. 사실 우리는 이미 여러 번 최적화의 그림자를 보았다.

목표 추종 로봇을 만들 때는 목표점까지의 거리와 방향 오차를 줄이려고 했다. 센서 퓨전에서는 더 믿을 만한 추정을 얻기 위해 불확실성이 작은 센서에 더 큰 가중치를 주었다. 칼만 필터에서는 예측과 측정을 조합해 추정 오차를 줄였다. 경로를 따라 움직일 때는 급격한 회전을 피하고 부드럽게 이동하려 했다.

이 모든 생각은 최적화 언어로 다시 말할 수 있다.

거리 오차를 줄인다. 방향 오차를 줄인다. 추정 오차를 줄인다. 위험을 줄인다. 에너지 사용을 줄인다. 시간 낭비를 줄인다.

줄이고 싶은 것이 있으면 비용 함수가 된다. 반드시 지켜야 하는 것이 있으면 제약 조건이 된다. 선택해야 하는 값이 있으면 최적화 변수가 된다.

이렇게 보면 로봇공학의 많은 문제는 서로 다른 이름을 가진 같은 질문처럼 보인다.

어떤 선택이 가장 좋은가?

작은 실험: 가중치를 바꾸며 로봇 성격 관찰하기

앞의 예제를 그대로 실행한 뒤, compute_path_cost 함수 안의 가중치를 바꿔 보자. 예를 들어 장애물 비용을 크게 만들면 로봇이 장애물을 더 멀리 피하는지 확인할 수 있다. 회전 비용을 크게 만들면 로봇이 급하게 꺾는 경로를 덜 선택하는지 볼 수 있다.

다음처럼 비용 함수의 가중치를 함수 인자로 빼면 실험하기 쉽다.


def compute_path_cost_with_weights(
    path,
    final_state,
    goal,
    obstacles,
    v,
    w,
    weights
):
    final_pos = final_state[:2]

    goal_cost = np.linalg.norm(goal - final_pos)

    diff = path[:, None, :] - obstacles[None, :, :]
    dists = np.linalg.norm(diff, axis=2)
    min_obstacle_dist = np.min(dists)
    obstacle_cost = 1.0 / (min_obstacle_dist + 1e-6)

    turn_cost = abs(w)
    energy_cost = v  2 + 0.3 * (w  2)

    total_cost = (
        weights['goal'] * goal_cost
        + weights['obstacle'] * obstacle_cost
        + weights['turn'] * turn_cost
        + weights['energy'] * energy_cost
    )

    return total_cost, min_obstacle_dist

이제 로봇의 성격을 딕셔너리로 표현할 수 있다.

careful_robot = {
    'goal': 2.0,
    'obstacle': 5.0,
    'turn': 0.2,
    'energy': 0.1
}

fast_robot = {
    'goal': 5.0,
    'obstacle': 1.5,
    'turn': 0.1,
    'energy': 0.05
}

smooth_robot = {
    'goal': 2.0,
    'obstacle': 1.5,
    'turn': 2.0,
    'energy': 0.2
}

같은 시작점, 같은 목표점, 같은 장애물을 두고도 이 세 로봇은 서로 다른 경로를 고를 수 있다. 이것은 최적화의 재미있는 부분이다. 수학은 딱딱해 보이지만, 비용 함수를 어떻게 설계하느냐에 따라 로봇의 행동은 꽤 개성 있게 달라진다.

이번 장에서 기억할 것

최적화는 로봇공학의 여러 문제를 하나의 언어로 묶어 준다. 경로 계획, 제어, 위치 추정, 센서 보정, 로봇 팔 자세 계산은 모두 후보 중에서 더 좋은 선택을 찾는 문제로 볼 수 있다.

목적 함수는 선택을 평가하는 함수다. 비용 함수는 작을수록 좋은 값을 만든다. 오차, 에너지, 시간, 위험도는 모두 비용으로 표현할 수 있다. 제약 조건은 로봇이 반드시 지켜야 하는 현실의 한계다. 속도 제한, 장애물 거리, 관절 범위, 작업 공간 제한 같은 조건이 여기에 들어간다.

가장 중요한 감각은 이것이다.

로봇이 똑똑해 보이는 이유는 막연한 직감 때문이 아니다. 좋은 선택을 숫자로 평가하고, 그 숫자가 가장 좋아지는 방향을 찾기 때문이다.

다음 장에서는 이 생각을 위치 추정과 데이터 보정 문제로 가져간다. 여러 측정값이 있을 때 가장 그럴듯한 직선이나 위치를 찾는 방법, 즉 최소제곱법을 배울 것이다. 최소제곱법은 오차의 제곱합을 비용으로 두고 그 비용이 가장 작아지는 답을 찾는 최적화의 가장 중요한 출발점 중 하나다.

책 목록

로봇을 위한 수학과 Python: 좌표에서 시뮬레이터까지

전체 목차 보기

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

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

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

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

참여하기