
11. Reward 구현
- date
- 2월 28, 2026
- status
- 완료
- tags
- unrealRL
1. 소개#
강화학습에서 Reward는 에이전트가 어떤 행동을 더 배워야 하는지 알려주는 기준이다. 맨 처음 강화학습을 알게 된 계기였던 그네를 잘타게 하는 법을 학습 시키는 영상에 나오는 것(유전적 알고리즘으로 그네 타는 법을 학습시켰다)이 처음에는 ‘와 저게 바로 강화학습이구나!’ 했는데 둘 다 시도해보고 더 잘한 걸 더 남긴다라는 건 비슷하지만 꽤나 다양한 방면으로 차이가 있는 걸 알게 되었다.
가장 큰 차이점은 유전 알고리즘은 전체 움직임 패턴의 진화라면 강화학습 방식은 하나의 정책이 계속 경험을 쌓는 것의 차이라고 해야할 듯 하다. 보상이라는 것도 유전 알고리즘에서는 개체를 선별하기 위한 Fitness Score 라면, 강화학습에서는 행동을 학습시키기 위한 Reward니 둘의 쓰임이 꽤나 차이가 나는 것을 알 수있다. 차이점을 표로 작성해보면 다음과 같다
| 구분 | 유전 알고리즘 | 강화학습 |
|---|---|---|
| 기본 단위 | 여러 후보 개체 | 하나의 에이전트/정책 |
| 개선 방식 | 잘한 개체를 선택, 교배, 변이 | 행동 후 받은 보상으로 정책 업데이트 |
| 학습 기준 | 전체 결과 점수 | 매 순간의 보상 |
| 대표 흐름 | 세대 단위 진화 | 경험 단위 학습 |
| 예시 | 자동차 100대를 돌려서 잘 달린 자동차의 신경망을 남김 | 자동차가 코너마다 어떤 조향/가속을 해야 보상이 커지는지 학습 |
| 느낌 | “잘한 놈끼리 섞어서 다음 세대 만들기” | “이 상황에서는 이 행동이 좋았구나 배우기” |
1.1. 초기 Reward 구현 목표#
이번 거미 로봇 프로젝트에서는 처음부터 복잡한 Reward를 설계하지 않고, 걷기 학습에 필요한 가장 기본적인 보상 구조부터 구현해보자. 사실 바로 아크 레이더스에 나오는 이 격자형 맵을 만들어서 진행해보고 싶은 마음은 굴뚝 같지만, 이럴 경우 내 로봇이 잘 못 걸을 경우, 어떤 문제로 인해 못 걷는 지 판별을 못하기 때문에 우선은 평지에서 걷는 것 부터 우선 완성되어야 한다

초기 목표는 완벽한 보행이 아니라, 로봇이 다음 세 가지를 먼저 학습하게 만드는 것이다.
| 목표 | 의미 | Reward 방향 |
|---|---|---|
| 앞으로 이동 | 제자리에서 버둥거리지 않고 목표 방향으로 이동 | 전방 이동 시 보상 |
| 균형 유지 | 몸체가 과하게 기울거나 넘어지는 행동 방지 | Pitch/Roll이 커지면 패널티 |
| 엎드려 미끄러지기 방지 | 바닥에 붙어서 앞으로 가는 편법 행동 방지 | 몸체 높이가 낮아지면 패널티 |
여기서 중요한 점은 Reward를 처음부터 많이 넣지 않는 것이다. 발 접지, 관절 에너지, 지형 Raycast, 장애물 회피 보상까지 한 번에 넣으면 학습이 실패했을 때 원인을 파악하기 어렵다. 따라서 현재 단계에서는 평지에서 앞으로 이동하려는 경향이 생기는지를 먼저 확인하고, 이후 단계에서 지형 정보와 장애물 대응을 추가한다.
2. Reward 설계#
우선적으로 실제 보상을 줄 항목을 하나하나 작성해보면,
2.1. 전방 이동 보상#
전방 이동 보상은 로봇이 목표 방향으로 이동할수록 증가하는 보상
로봇이 아무 움직임 없이 서 있거나 제자리에서 다리만 흔들면 학습이 진행되지 않기 때문에, 가장 먼저 “앞으로 이동하는 행동”에 보상을 줘야 한다.
Forward Reward = 전방 속도 × 보상 가중치이 보상은 로봇이 앞으로 움직이는 행동을 찾도록 유도한다.
2.2. 몸체 기울기 패널티#
로봇이 앞으로 이동하더라도 몸체가 심하게 기울거나 넘어지면 보행이라고 보기 어렵다.
따라서 몸체의 Pitch와 Roll 값을 확인해서, 기울기가 커질수록 패널티를 부여한다.
Tilt Penalty = (Pitch 절댓값 + Roll 절댓값) × 패널티 가중치Yaw는 방향 회전에 해당하므로, 초기 단계에서는 기울기 패널티에 포함하지 않는다.
2.3. 낮은 높이 패널티#
강화학습에서는 에이전트가 사람이 의도하지 않은 방식으로 Reward를 얻는 경우가 많다.
예를 들어 앞으로 이동 보상만 주면, 로봇이 정상적으로 걷는 대신 몸체를 바닥에 붙이고 미끄러져 이동하는 방법을 찾을 수도 있다. 이를 막기 위해 몸체 높이가 일정 기준보다 낮아지면 패널티를 준다.
Low Height Penalty = 몸체 높이가 기준 이하이면 감점이 항목은 로봇이 최소한의 자세를 유지한 상태로 이동하도록 유도한다.
3. 구현#
공식 문서 기준으로 보면 Reward는
BP_SpiderTrainingManagerActor 자체가 아니라LearningAgentsTrainingEnvironment계열에서 구현해야 한다.Epic 문서에서
ULearningAgentsTrainingEnvironment::GatherAgentRewards는 Agent들의 reward 값을 모으는 콜백이고, 기본적으로 각 Agent에 대해GatherAgentReward를 호출한다고 되어 있다.또
GatherRewards는 학습 루프 중 행동을 적용한 뒤 다음 상태에서 reward를 평가할 때 호출하는 함수라고 설명이 되어있다(ULearningAgentsTrainingEnvironment::GatherRewards | Unreal Engine 5.7 Documentation | Epic Developer Community)
3.1. BP_SpiderTrainingEnvironment 생성#
콘텐츠 브라우저에서 우클릭 → Blueprint Class → All Classes 검색(LearningAgentsTrainingEnvironment) 이름은 BP_SpiderTrainingEnvironment

3.1 Gather Agent Reward 오버라이딩#
1. Gather Agent Reward 함수 오버라이딩#
풀 블루프린트 에디터 열기→왼쪽에함수,오버라이드목록에서 Gather Agent Reward 선택
입력 변수 추가
변수명 타입 기본값 ForwardRewardScaleFloat 0.01TiltPenaltyScaleFloat -0.005MinBodyHeightFloat 50.0LowHeightPenaltyFloat -1.0Agent Id → Get Agent 노드 연결 후, Agent Class→BP_SpiderRobot

Get Agent의 Return Value에서 드래그 → Spider Mesh 노드 추가(실제 컴포넌트 참조)Spider Mesh/Spider Mesh → Get Physics Linear Velocity 노드 추가
여기까지하면 현재 학습 중인 BP_SpiderRobot을 찾아서 해당 로봇의 스파이더 매쉬를 가져와서 실제 물리 속도를 가져올 수 있다.
2. Spider Mesh에서 Get Forward Vector 만들기#
Spider Mesh파란 핀에서 한 번 더 드래그 → Get Forward Vector 노드 생성속도만 보면 로봇이 어느 방향으로 움직이는지 알 수는 있지만, 그게 앞으로 간 건지, 옆으로 미끄러진 건지, 뒤로 간 건지 구분이 안 되기 때문에,
Forward Vector로 로봇이 바라보는 방향을 가져온다.
3. Dot Product 만들기#
빈 곳 우클릭해서 검색 →Dot Product, Vector용 Dot Product 노드를 생성
연결은 이렇게.
Get Physics Linear Velocity Return Value → Dot Product A Get Forward Vector Return Value → Dot Product B
왜
Dot Product를 쓰냐면, 이게 속도 방향이 전방 방향과 얼마나 같은지 계산해주기 때문이다.상황 Dot Product 결과 앞으로 이동 양수 정지 0 근처 옆으로 이동 0 근처 뒤로 이동 음수 즉, “앞으로 잘 갔는가?”를 숫자로 바꾸는 노드
4. ForwardRewardScale 곱하기#
Dot Product 결과에서 드래그 → Multiply 노드를 생성 ,
ForwardRewardScale 가져와서 두번째 핀에 연결

왜
0.01을 곱하냐면, Unreal 속도는 보통 cm/s 단위라 값이 너무 크게 나올 수 있기 때문에, 예를 들어 속도가100이면 Reward가100이 되어버리니까,0.01을 곱해서1.0정도로 줄이는 것이 좋다. 가능하면 나중에는 이0.01도ForwardRewardScale변수로 빼주도록 하자.
5. Return Node의 OutReward 에 연결#
마지막으로 곱한 값을
Return Node의Out Reward에 연결최종 흐름

flowchart LR A[Agent Id] --> B[Get Agent] B --> C[Spider Mesh] C --> D[Get Physics Linear Velocity] C --> E[Get Forward Vector] D --> F[Dot Product] E --> F F --> G[* 0.01] G --> H[Out Reward]
3.2. 몸체 기울기 패널티 추가#
현재 Reward는 로봇이 앞으로 이동하면 보상을 주는 구조이다. 하지만 이 상태만으로는 로봇이 정상적으로 걷는 것이 아니라, 몸체를 굴리거나 바닥에 비비면서 앞으로 이동하는 방식도 보상받을 수 있기 때문에, 다음 단계에서는 몸체가 과하게 기울어질 경우 감점하는 Tilt Penalty를 추가해서 해당 방식을 방지해보도록 하자.
Tilt Penalty = (Pitch 절댓값 + Roll 절댓값) × TiltPenaltyScale여기서
Pitch는 앞뒤 기울기,Roll은 좌우 기울기이다.Yaw는 방향 회전에 해당하므로, 넘어짐 판단에는 사용하지 않는다.
1. Spider Mesh에서 Get World Rotation 생성#
기존에 사용한
Spider Mesh핀에서 드래그 →Get World Rotation노드 생성이 노드는 Spider Mesh가 현재 월드에서 어떤 방향으로 회전되어 있는지 가져온다.
2. Break Rotator 생성#
Get World Rotation의 Return Value에서 드래그 →Break Rotator생성Break Rotator는 회전값을Pitch,Yaw,Roll로 나누기 위해 사용한다.
3. Pitch와 Roll에 Absolute 적용#
Pitch에서 드래그 →Absolute (Float)생성Roll에서 드래그 →Absolute (Float)생성
기울기는 방향보다 크기가 중요하다. 왼쪽으로 기울었는지 오른쪽으로 기울었는지가 아니라, 얼마나 많이 기울었는지가 중요하므로 절댓값을 사용한다.
4. Pitch와 Roll 더하기#
Abs(Pitch)와Abs(Roll)을Float + Float으로 더한다.TiltAmount = Abs(Pitch) + Abs(Roll)이 값이 클수록 로봇 몸체가 많이 기울어진 상태이다.

5. TiltPenaltyScale 곱하기#
이제 이 합산 값을 패널티 값으로 변경해야 한다
TiltAmount에TiltPenaltyScale변수를 곱하도록 하자
TiltPenalty = TiltAmount × TiltPenaltyScaleTiltPenaltyScale이 음수인 이유는 기울기가 커질수록 Reward를 줄이기 위해서이다.예를 들어 Pitch가 10도, Roll이 5도라면
TiltAmount = 10 + 5 = 15 TiltPenalty = 15 × -0.005 = -0.075즉, 약간 기울어진 정도는 작은 감점만 주고, 심하게 기울어질수록 감점이 커진다.
6. 기존 Forward Reward와 더하기#
현재 만들어둔 전방 이동 Reward 결과와 Tilt Penalty를 더하도록 하자
TotalReward = ForwardReward + TiltPenalty블루프린트에서는 기존
ForwardRewardScale곱하기 결과와TiltPenalty결과를Float + Float으로 더한 뒤, 그 값을Return Node의Out Reward에 연결한다.이는 총 보상 = 앞으로 간 보상 + 기울기 패널티의 뜻이다.
7. 최종 연결 형태#

ForwardReward = Dot(Velocity, ForwardVector) * ForwardRewardScale
TiltPenalty = (Abs(Roll) + Abs(Pitch)) * TiltPenaltyScale
OutReward = ForwardReward + TiltPenalty- 이제 Reward는 단순히 앞으로 이동하는 것만 평가하지 않고, 앞으로 이동하면서도 몸체를 안정적으로 유지하는 행동을 더 선호하게 된다.
3.3. Gather Agent Completion 오버라이딩#
- Reward는 “좋은 행동/나쁜 행동 점수”이고, Completion은 “이번 에피소드를 끝낼지”를 판단하는 역할이다. 만약 넘어졌는데도 에피소드가 계속 진행되면, 로봇이 넘어진 상태에서 이상한 행동까지 계속 학습하기 때문이다.
BP_SpiderTrainingEnvironment에서 오버라이드 목록 열고 → Gather Agent Completion 선택
1. Completion 조건 입력#
일단 생각날만한 종료 조건은 기울기가 너무 기울어서 로봇이 정상적으로 못 움직이는 경우가 있다. 그러니 우선 기울기를 입력받도록 하자
변수 추가
변수명 타입 기본값 MaxTiltAngleForCompletionFloat 70.0노드 흐름 생성

flowchart LR A[Agent Id] --> B[Get Agent] B --> C[Spider Mesh] C --> D[Get World Rotation] D --> E[Break Rotator] E --> F[Abs Roll] E --> G[Abs Pitch] F --> H[Roll > MaxTiltAngle] G --> I[Pitch > MaxTiltAngle] H --> J[OR] I --> J J --> K[Out Completion]
3.4. Reset Agent Episode 오버라이딩#
이제 넘어지면 종료 후에 종료된 로봇을 처음 위치/자세로 되돌리는 과정을 만들어야 한다. Reset이 없으면 episode가 끝나도 다음 학습을 할 수 없기 때문.
reset_agent_episode(agent_id)는 특정 Agent의 episode를 리셋하는 콜백이다.reset_agent_episodes는 여러 Agent에 대해 기본적으로 단수형 reset을 호출하는 구조. 그리고 reward/completion은 action 이후 다음 상태에서 평가된다.unreal.LearningAgentsTrainingEnvironment — Unreal Python 5.5 (Experimental) documentation
즉 여기서 할 일은 간단하다.
1. Agent Id로 BP_SpiderRobot 가져오기 2. 로봇 위치를 시작 위치로 이동 3. 회전을 초기 회전으로 복구 4. Physics Linear Velocity = 0 5. Physics Angular Velocity = 0트레이닝 환경 → 함수 →
Reset Agent Episode오버라이드이제 마찬가지로 Agent 를 가져와서 작업을 수행하도록 하자
Reset Agent Episode/Agent id → Get Agent
Get Agent/Return Value → Get Spider Mesh → Set Physics Linear Velocity
Set Physics Linear Velocity → Set Physics Angular Velocity in Degrees
변수 생성
변수명 타입 기본값 예시 의미 ResetLocationVector (0, 0, 150)에피소드 시작 위치 ResetRotationRotator (0, 0, 0)에피소드 시작 회전 각각을
Set Actor Location And Rotation연결Set Actor Location And Rotation/Teleport 체크
Set Actor Location And Rotation/실행핀 → Set Physics Linear Velocity
Set Physics Linear Velocity/실행핀 → Set Physics Angular Velocity in Degrees
Set Physics Angular Velocity in Degrees/실행핀 → Wake All Rigid Bodies

3.5. BP_SpiderTrainingEnvironment 등록#
앞에서 BP_SpiderTrainingEnvironment를 생성하고, 그 안에 Gather Agent Reward, Gather Agent Completion, Reset Agent Episode를 구현하였다.
하지만 여기까지는 Training Environment 안에 필요한 함수들을 만든 것일 뿐, 아직 실제 학습 루프에 연결된 상태는 아니다.
Learning Agents에서는 Learning Manager가 Agent를 직접 관리하고, Interactor와 Training Environment 같은 Listener를 통해 학습에 필요한 기능들을 호출한다.
즉, BP_SpiderTrainingEnvironment를 만들었다고 해서 Gather Agent Reward, Gather Agent Completion, Reset Agent Episode가 자동으로 실행되는 것은 아니다.
따라서 BP_SpiderTrainingManager의 BeginPlay에서 BP_SpiderTrainingEnvironment를 생성하고, 이를 BP_SpiderLearningManager에 Listener로 등록하는 과정이 필요하다.
1. 기존 BeginPlay 흐름#
기존 BP_SpiderTrainingManager의 BeginPlay에서는 먼저 BP_SpiderInteractor를 생성하고, 이를 BP_SpiderLearningManager에 Listener로 등록하는 흐름이 구성되어 있었다.
flowchart LR
A[Event BeginPlay] --> B[Construct BP Spider Interactor]
B --> C[Set Spider Interactor]
C --> D[Setup Interactor]
D --> E[Add Listener]여기서 BP_SpiderInteractor는 Observation 수집과 Action 적용을 담당한다.
- Observation 수집: 로봇의 현재 상태를 학습 입력값으로 전달
- Action 적용: Policy가 출력한 관절 제어값을 실제 로봇에 적용
즉, Interactor는 로봇과 Policy 사이에서 상태와 행동을 주고받는 역할을 한다.
하지만 Reward, Completion, Reset은 Interactor가 담당하는 기능이 아니다.
이 기능들은 앞에서 만든 BP_SpiderTrainingEnvironment가 담당하므로, Training Environment도 별도의 Listener로 등록해야 한다.
2. Make Training Environment 추가#
Interactor를 등록한 뒤, Make Training Environment 노드를 추가하였다.
이 노드는 Learning Agents에서 사용할 Training Environment 인스턴스를 생성하는 역할을 한다.
여기서는 Class에 앞에서 만든 BP_SpiderTrainingEnvironment를 지정하였다.
설정은 다음과 같다.
| 항목 | 설정 |
|---|---|
In Manager | BP_SpiderLearningManager |
Class | BP_SpiderTrainingEnvironment |
Name | TrainingEnvironment |
In Manager에 BP_SpiderLearningManager를 연결하는 이유는, 이 Training Environment가 어떤 Learning Manager에 소속되어 동작할지 지정하기 위해서이다.
Class에는 직접 만든 BP_SpiderTrainingEnvironment를 넣는다.

그래야 앞에서 오버라이드한 Reward, Completion, Reset 함수들이 학습 과정에서 사용될 수 있다.
3. Spider Training Environment 변수 저장#
Make Training Environment의 Return Value는 Spider Training Environment 변수에 저장하였다.
flowchart LR
A[Make Training Environment] --> B[Set Spider Training Environment]이렇게 변수로 저장하는 이유는 생성된 Training Environment를 이후에도 참조할 수 있도록 하기 위해서이다.
단순히 노드에서 한 번 생성하고 끝내는 것이 아니라, BP_SpiderTrainingManager가 현재 사용하는 Training Environment를 변수로 가지고 있게 만드는 구조이다.
이렇게 해두면 이후 디버깅을 하거나, Training Environment 관련 값을 확인해야 할 때 같은 인스턴스를 다시 참조할 수 있다.
4. Training Environment를 Listener로 등록#
Training Environment를 생성하고 변수에 저장한 뒤에는, Add Listener 노드를 한 번 더 사용해서 BP_SpiderLearningManager에 등록해야 한다.

이때 연결은 다음과 같이 구성한다.
| Add Listener 핀 | 연결 대상 |
|---|---|
Target | BP_SpiderLearningManager |
Listener | Spider Training Environment |
여기서 중요한 점은 Add Listener가 두 번 사용된다는 것이다.
첫 번째 Add Listener는 BP_SpiderInteractor를 등록하기 위한 것이고,
두 번째 Add Listener는 BP_SpiderTrainingEnvironment를 등록하기 위한 것이다.
두 Listener의 역할은 다음과 같이 다르다.
| Listener | 역할 |
|---|---|
BP_SpiderInteractor | Observation 수집, Action 적용 |
BP_SpiderTrainingEnvironment | Reward 계산, Completion 판단, Episode Reset |
따라서 Training Environment를 만들기만 하고 Add Listener에 연결하지 않으면, Reward와 Completion, Reset 함수가 학습 루프에서 호출되지 않을 수 있다.
5. Agent 등록#
Training Environment까지 Listener로 등록한 뒤에는, 월드에 배치된 BP_SpiderRobot을 찾아 Agent로 등록한다.
이를 위해 Get Actor Of Class 노드에서 BP_SpiderRobot을 찾고, 그 Return Value를 Add Agent의 Agent 핀에 연결하였다.
Add Agent의 연결은 다음과 같다.

| Add Agent 핀 | 연결 대상 |
|---|---|
Target | BP_SpiderLearningManager |
Agent | Get Actor Of Class의 Return Value |
여기서 Target은 반드시 BP_SpiderLearningManager가 되어야 한다.
Add Agent는 Training Environment에 Agent를 넣는 노드가 아니라, Learning Manager가 관리할 학습 대상 Agent를 등록하는 노드이기 때문이다.
6. 최종 BeginPlay 구성#
최종적으로 BP_SpiderTrainingManager의 BeginPlay 흐름은 다음과 같이 구성된다.

이 구조에서 BP_SpiderLearningManager는 학습에 참여하는 Agent와 Listener들을 관리하는 중심 역할을 한다.
BP_SpiderInteractor는 Observation과 Action을 담당하고,
BP_SpiderTrainingEnvironment는 Reward, Completion, Reset을 담당한다.
마지막으로 BP_SpiderRobot은 실제 학습 대상 Agent로 등록된다.
정리하면 다음과 같다.
| 구성 요소 | 역할 |
|---|---|
BP_SpiderLearningManager | Agent와 Listener를 관리하는 중심 객체 |
BP_SpiderInteractor | Observation 수집 및 Action 적용 |
BP_SpiderTrainingEnvironment | Reward, Completion, Reset 처리 |
BP_SpiderRobot | 실제 학습 대상 Agent |
7. 현재 단계의 의미#
이번 단계에서 중요한 점은 BP_SpiderTrainingEnvironment를 단순히 생성한 것이 아니라, 실제 Learning Agents 학습 루프에 연결했다는 것이다.
앞에서 만든 Reward, Completion, Reset은 이제 다음 흐름 안에서 사용될 수 있다.
flowchart TD
A[Observation 수집] --> B[Policy가 Action 출력]
B --> C[Interactor가 Action 적용]
C --> D[로봇 물리 시뮬레이션 진행]
D --> E[Training Environment가 Reward 계산]
E --> F[Training Environment가 Completion 판단]
F --> G{Episode 종료 여부}
G -- 계속 진행 --> A
G -- 종료 --> H[Reset Agent Episode]
H --> A즉, 로봇은 이제 단순히 관절 Action만 받는 상태가 아니라, 행동 결과에 따라 보상을 받고, 넘어졌을 경우 에피소드가 종료되며, 다시 초기 상태에서 다음 에피소드를 시작할 수 있는 구조가 되었다.
이를 통해 강화학습에 필요한 기본 루프가 다음과 같이 연결된다.
Observation → Action → Physics Simulation → Reward → Completion → Reset이 구조가 완성되어야 PPO Trainer를 사용한 실제 학습을 시작할 수 있다.