Módulo 2.3: Introdução a Aprendizado por Reforço
Módulo 2.3: Introdução a Aprendizado por Reforço
Duração estimada: 13-18 horas Nível: Intermediário Pré-requisito: Módulos 2.1 e 2.2 concluídos
Objetivos de Aprendizado
Ao final deste módulo, você será capaz de:
- Compreender conceitos fundamentais de Aprendizado por Reforço
- Diferenciar RL de outros tipos de aprendizado de máquina
- Instalar e configurar Stable-Baselines3
- Criar ambientes Gym personalizados
- Treinar robôs usando algoritmo PPO
- Avaliar e visualizar curvas de aprendizado
- Testar modelos treinados em simulação
- Entender limitações e desafios do RL
Parte 1: O que é Aprendizado por Reforço? (3-4h)
1.1 Aprendizado por Tentativa e Erro
Imagine aprender a andar de bicicleta:
- Você tenta pedalar (ação)
- Você cai ou fica equilibrado (feedback do ambiente)
- Você ajusta seu comportamento baseado no resultado
- Você repete até aprender
Isso é Aprendizado por Reforço (RL)!
┌─────────────────────────────┐
│ │
│ APRENDIZADO POR │
│ REFORÇO │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Agente │ │Ambiente │ │
│ │ (Robô) │◄──┤ (Mundo) │ │
│ └────┬────┘ └────▲────┘ │
│ │ │ │
│ │ Estado │ │
│ └─────────────┘ │
│ │ │
│ │ Ação │
│ └──────► │
│ │
│ ◄────── │
│ Recompensa │
└─────────────────────────────┘
1.2 Componentes do RL
1. Agente
O “aprendiz” que toma decisões (o robô humanoide).
2. Ambiente
O mundo onde o agente atua (simulador, mundo real).
3. Estado (State)
Informação atual do ambiente. Exemplos:
- Posição do robô:
[x=0.5, y=1.2, z=0.0] - Velocidade:
[vx=0.3, vy=0.0] - Orientação:
[roll=0, pitch=5°, yaw=90°] - Leituras de sensores:
[lidar=[0.8, 1.2, ...], camera=[pixels]]
4. Ação (Action)
Decisão que o agente toma. Exemplos:
- Discreta: “Andar frente”, “Girar esquerda”, “Parar”
- Contínua: Velocidade linear = 0.5 m/s, Angular = 0.2 rad/s
5. Recompensa (Reward)
Feedback numérico que diz se ação foi boa ou ruim.
Exemplos:
# Bom: robô andou para frente
recompensa = +1.0
# Ruim: robô bateu em obstáculo
recompensa = -10.0
# Neutro: robô parado
recompensa = 0.0
6. Política (Policy)
Estratégia do agente: mapeamento de estados para ações.
# Política simples (regra)
if distancia_obstaculo < 0.5:
acao = "girar"
else:
acao = "andar_frente"
# Política RL (rede neural)
acao = rede_neural.prever(estado)
1.3 RL vs Outras Técnicas
| Característica | RL | Aprendizado Supervisionado | Controle Tradicional |
|---|---|---|---|
| Dados | Aprende por tentativa | Precisa de dataset rotulado | Precisa de modelo matemático |
| Feedback | Recompensa (tarde) | Labels (imediato) | Erro de controle |
| Exploração | Explora novas ações | Não explora | Não explora |
| Adaptação | Adapta-se a mudanças | Fixo após treino | Fixo (tunning manual) |
| Exemplo | Robô aprende a andar | Classificar imagens | PID controller |
1.4 Algoritmos de RL
Existem dezenas de algoritmos. Os principais para robótica:
Q-Learning (clássico)
- Aprende valor de cada ação em cada estado
- Funciona bem em ambientes simples
- Difícil escalar para robôs complexos
Deep Q-Network (DQN)
- Q-Learning com redes neurais
- Usado em jogos Atari
- Melhor para ações discretas
Proximal Policy Optimization (PPO)
- MUITO USADO EM ROBÓTICA
- Aprende política diretamente
- Funciona com ações contínuas
- Estável e eficiente
Soft Actor-Critic (SAC)
- State-of-the-art para controle contínuo
- Mais complexo que PPO
- Muito eficiente em amostragem
Neste módulo usaremos PPO!
1.5 Exemplo Conceitual
Treinar robô para alcançar objetivo:
EPISÓDIO 1 (robô novato)
─────────────────────────
t=0: Estado: [x=0, y=0, meta=[x=5, y=0]]
Ação: andar_frente (velocidade aleatória)
Recompensa: +0.1 (moveu na direção certa)
t=1: Estado: [x=0.2, y=0]
Ação: girar_esquerda (exploração)
Recompensa: -0.1 (moveu na direção errada)
t=2: Estado: [x=0.2, y=0.1]
Ação: andar_frente
Recompensa: +0.1
...
t=50: Estado: [x=2.3, y=1.5]
Ação: parar (não chegou)
Recompensa: -5.0 (não alcançou meta)
RECOMPENSA TOTAL: -10.3
─────────────────────────
EPISÓDIO 100 (robô aprendeu!)
─────────────────────────
t=0: Estado: [x=0, y=0, meta=[x=5, y=0]]
Ação: andar_frente (rede neural decidiu)
Recompensa: +0.5
t=1: Estado: [x=0.8, y=0]
Ação: andar_frente
Recompensa: +0.5
...
t=10: Estado: [x=5.0, y=0.0]
Ação: parar (chegou!)
Recompensa: +100.0 (ALCANÇOU META!)
RECOMPENSA TOTAL: +150.0
─────────────────────────
Parte 2: Instalação e Setup (1-2h)
2.1 Instalando Stable-Baselines3
Stable-Baselines3 (SB3) é a biblioteca mais popular de RL para Python.
# Ative seu ambiente virtual
source ~/robotica/robo_env/bin/activate # Linux/Mac
# ou
robo_env\Scripts\activate # Windows
# Instale SB3 e dependências
pip install stable-baselines3[extra]
pip install gymnasium
pip install tensorboard
# Para visualização
pip install matplotlib
2.2 Primeiro Código RL - Cartpole
CartPole: balançar uma vara em um carrinho (ambiente clássico).
import gymnasium as gym
from stable_baselines3 import PPO
# Cria ambiente
env = gym.make("CartPole-v1", render_mode="human")
# Cria agente PPO
model = PPO("MlpPolicy", env, verbose=1)
# Treina por 10.000 timesteps
print("Treinando...")
model.fit(total_timesteps=10000)
# Salva modelo
model.save("ppo_cartpole")
print("Modelo salvo!")
# Testa modelo treinado
print("Testando modelo...")
obs, info = env.reset()
for i in range(1000):
action, _states = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(action)
env.render()
if terminated or truncated:
obs, info = env.reset()
env.close()
Execute:
python primeiro_rl.py
Você verá o CartPole aprendendo a se equilibrar!
2.3 Entendendo o Código
# 1. Criar ambiente
env = gym.make("CartPole-v1")
# 2. Criar agente
model = PPO(
"MlpPolicy", # Política: Multi-Layer Perceptron (rede neural)
env, # Ambiente
verbose=1 # Mostra progresso
)
# 3. Treinar
model.fit(total_timesteps=10000)
# 4. Prever ação
action, _states = model.predict(obs, deterministic=True)
# 5. Executar ação no ambiente
obs, reward, terminated, truncated, info = env.step(action)
2.4 Visualizando Aprendizado com TensorBoard
from stable_baselines3 import PPO
import gymnasium as gym
# Cria ambiente
env = gym.make("CartPole-v1")
# Cria modelo com logging
model = PPO("MlpPolicy", env, verbose=1, tensorboard_log="./tensorboard_logs/")
# Treina
model.fit(total_timesteps=50000)
Visualize no navegador:
tensorboard --logdir ./tensorboard_logs/
# Abra http://localhost:6006
Você verá gráficos de:
- Recompensa ao longo do tempo
- Loss da rede neural
- Valor estimado
Parte 3: Criando Ambiente Gym Personalizado (4-5h)
3.1 Estrutura de um Ambiente Gym
Todo ambiente Gym precisa de:
import gymnasium as gym
from gymnasium import spaces
import numpy as np
class MeuAmbiente(gym.Env):
"""Ambiente personalizado seguindo interface gym.Env"""
def __init__(self):
super(MeuAmbiente, self).__init__()
# Define espaço de ações
# Exemplo: 2 ações contínuas (velocidade linear e angular)
self.action_space = spaces.Box(
low=np.array([-1.0, -1.0]),
high=np.array([1.0, 1.0]),
dtype=np.float32
)
# Define espaço de observações
# Exemplo: posição x, y, ângulo
self.observation_space = spaces.Box(
low=np.array([-10, -10, -np.pi]),
high=np.array([10, 10, np.pi]),
dtype=np.float32
)
def reset(self, seed=None, options=None):
"""
Reseta ambiente para estado inicial
Returns:
observation: Estado inicial
info: Dict com informações extras
"""
super().reset(seed=seed)
# Inicializa estado
self.state = np.array([0.0, 0.0, 0.0]) # [x, y, theta]
return self.state, {}
def step(self, action):
"""
Executa ação e retorna resultado
Args:
action: Ação a ser executada
Returns:
observation: Novo estado
reward: Recompensa
terminated: Se episódio terminou
truncated: Se episódio foi truncado (timeout)
info: Dict com informações extras
"""
# Executa ação (simula movimento)
vel_linear = action[0]
vel_angular = action[1]
# Atualiza estado (simplificado)
dt = 0.1
self.state[0] += vel_linear * np.cos(self.state[2]) * dt # x
self.state[1] += vel_linear * np.sin(self.state[2]) * dt # y
self.state[2] += vel_angular * dt # theta
# Calcula recompensa
reward = self._calcular_recompensa()
# Verifica se terminou
terminated = self._check_terminado()
truncated = False
return self.state, reward, terminated, truncated, {}
def _calcular_recompensa(self):
"""Implementa lógica de recompensa"""
# Exemplo simples
return -0.1 # Penalidade por timestep
def _check_terminado(self):
"""Verifica se episódio terminou"""
# Exemplo: termina se sair de limites
x, y, _ = self.state
if abs(x) > 10 or abs(y) > 10:
return True
return False
def render(self, mode='human'):
"""Renderiza ambiente (opcional)"""
print(f"Estado: x={self.state[0]:.2f}, y={self.state[1]:.2f}, theta={self.state[2]:.2f}")
3.2 Ambiente: Robô Alcança Objetivo
Vamos criar um ambiente onde robô precisa alcançar um ponto no espaço 2D:
import gymnasium as gym
from gymnasium import spaces
import numpy as np
import matplotlib.pyplot as plt
class RoboAlcancaObjetivo(gym.Env):
"""
Ambiente: Robô 2D precisa alcançar objetivo
Observação:
- Posição robô [x, y]
- Posição objetivo [goal_x, goal_y]
- Distância até objetivo
Ação:
- Velocidade linear [-1, 1]
- Velocidade angular [-1, 1]
Recompensa:
- +100 se alcançar objetivo
- -distancia_até_objetivo a cada step
- -0.1 por timestep (incentiva eficiência)
"""
def __init__(self, render_mode=None):
super(RoboAlcancaObjetivo, self).__init__()
# Ações: [vel_linear, vel_angular]
self.action_space = spaces.Box(
low=np.array([-1.0, -1.0]),
high=np.array([1.0, 1.0]),
dtype=np.float32
)
# Observações: [x, y, theta, goal_x, goal_y]
self.observation_space = spaces.Box(
low=np.array([-10, -10, -np.pi, -10, -10]),
high=np.array([10, 10, np.pi, 10, 10]),
dtype=np.float32
)
self.render_mode = render_mode
# Parâmetros
self.max_steps = 200
self.goal_threshold = 0.3 # Distância para considerar "alcançado"
# Estado
self.pos = np.array([0.0, 0.0]) # [x, y]
self.theta = 0.0
self.goal = np.array([5.0, 5.0])
self.steps = 0
# Para render
if render_mode == "human":
self.fig, self.ax = plt.subplots()
plt.ion()
def reset(self, seed=None, options=None):
super().reset(seed=seed)
# Posição inicial aleatória
self.pos = np.random.uniform(-2, 2, size=2)
self.theta = np.random.uniform(-np.pi, np.pi)
# Objetivo aleatório
self.goal = np.random.uniform(3, 7, size=2)
self.steps = 0
return self._get_obs(), {}
def _get_obs(self):
"""Retorna observação atual"""
return np.array([
self.pos[0],
self.pos[1],
self.theta,
self.goal[0],
self.goal[1]
], dtype=np.float32)
def step(self, action):
# Extrai ações
vel_linear = action[0] * 0.5 # Max 0.5 m/s
vel_angular = action[1] * 1.0 # Max 1.0 rad/s
# Atualiza posição (cinemática diferencial)
dt = 0.1
self.pos[0] += vel_linear * np.cos(self.theta) * dt
self.pos[1] += vel_linear * np.sin(self.theta) * dt
self.theta += vel_angular * dt
# Normaliza theta para [-pi, pi]
self.theta = np.arctan2(np.sin(self.theta), np.cos(self.theta))
self.steps += 1
# Calcula distância até objetivo
distancia = np.linalg.norm(self.pos - self.goal)
# Calcula recompensa
reward = -distancia # Quanto mais longe, pior
# Bônus se alcançou
terminated = False
if distancia < self.goal_threshold:
reward += 100.0
terminated = True
# Penalidade se saiu do mapa
if np.any(np.abs(self.pos) > 10):
reward -= 50.0
terminated = True
# Trunca se passou do limite de steps
truncated = self.steps >= self.max_steps
# Pequena penalidade por timestep (incentiva velocidade)
reward -= 0.1
if self.render_mode == "human":
self.render()
return self._get_obs(), reward, terminated, truncated, {}
def render(self):
"""Renderiza ambiente"""
if self.render_mode == "human":
self.ax.clear()
# Desenha robô
self.ax.plot(self.pos[0], self.pos[1], 'bo', markersize=10, label='Robô')
# Desenha direção
dx = 0.3 * np.cos(self.theta)
dy = 0.3 * np.sin(self.theta)
self.ax.arrow(self.pos[0], self.pos[1], dx, dy, head_width=0.2, color='b')
# Desenha objetivo
self.ax.plot(self.goal[0], self.goal[1], 'r*', markersize=20, label='Objetivo')
# Desenha círculo de alcance
circle = plt.Circle(self.goal, self.goal_threshold, color='r', fill=False, linestyle='--')
self.ax.add_patch(circle)
# Configurações
self.ax.set_xlim(-10, 10)
self.ax.set_ylim(-10, 10)
self.ax.set_aspect('equal')
self.ax.grid(True)
self.ax.legend()
self.ax.set_title(f'Step: {self.steps}')
plt.pause(0.01)
def close(self):
if self.render_mode == "human":
plt.close()
3.3 Treinando o Ambiente Personalizado
from stable_baselines3 import PPO
from stable_baselines3.common.env_checker import check_env
# Verifica se ambiente está correto
env = RoboAlcancaObjetivo()
check_env(env)
print("Ambiente válido!")
# Cria modelo
model = PPO(
"MlpPolicy",
env,
verbose=1,
tensorboard_log="./logs_robo_objetivo/",
learning_rate=0.0003,
n_steps=2048,
batch_size=64,
n_epochs=10,
gamma=0.99,
gae_lambda=0.95
)
# Treina
print("Iniciando treinamento...")
model.fit(total_timesteps=100000)
# Salva
model.save("ppo_robo_alcanca_objetivo")
print("Modelo treinado e salvo!")
# Testa
print("\nTestando modelo...")
env_teste = RoboAlcancaObjetivo(render_mode="human")
obs, info = env_teste.reset()
for _ in range(500):
action, _states = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env_teste.step(action)
if terminated or truncated:
print("Episódio terminou!")
obs, info = env_teste.reset()
env_teste.close()
Parte 4: Entendendo e Visualizando Resultados (2-3h)
4.1 Curvas de Aprendizado
Durante o treinamento, monitore:
┌─────────────────────────────────────┐
│ RECOMPENSA MÉDIA vs TIMESTEPS │
│ │
│ 100│ ╱──────── │
│ │ ╱ │
│ 50│ ╱ │
│ │ ╱ │
│ 0├────────────────────── │
│ 0 25k 50k 75k 100k │
│ Timesteps │
└─────────────────────────────────────┘
Interpretação:
- Subindo: Aprendendo ✅
- Platô: Convergiu ✅
- Descendo: Problema ❌
- Muito ruidoso: Aumentar batch_size
4.2 Avaliando Modelo
from stable_baselines3.common.evaluation import evaluate_policy
# Carrega modelo
model = PPO.load("ppo_robo_alcanca_objetivo")
# Cria ambiente
env = RoboAlcancaObjetivo()
# Avalia por 10 episódios
mean_reward, std_reward = evaluate_policy(
model,
env,
n_eval_episodes=10,
deterministic=True
)
print(f"Recompensa média: {mean_reward:.2f} +/- {std_reward:.2f}")
# Análise
if mean_reward > 80:
print("Modelo EXCELENTE! ✅")
elif mean_reward > 50:
print("Modelo BOM! Pode melhorar.")
elif mean_reward > 0:
print("Modelo MEDIANO. Precisa mais treino.")
else:
print("Modelo RUIM. Revise recompensas e hiperparâmetros.")
4.3 Visualizando Trajetórias
import matplotlib.pyplot as plt
def visualizar_trajetorias(model, env, num_episodios=5):
"""Plota trajetórias de múltiplos episódios"""
plt.figure(figsize=(10, 10))
for ep in range(num_episodios):
obs, info = env.reset()
trajetoria = [obs[:2]] # Guarda [x, y]
for _ in range(200):
action, _ = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(action)
trajetoria.append(obs[:2])
if terminated or truncated:
break
trajetoria = np.array(trajetoria)
# Plota trajetória
plt.plot(trajetoria[:, 0], trajetoria[:, 1], '-o', alpha=0.6, label=f'Ep {ep+1}')
# Plota início e fim
plt.plot(trajetoria[0, 0], trajetoria[0, 1], 'go', markersize=10)
plt.plot(trajetoria[-1, 0], trajetoria[-1, 1], 'ro', markersize=10)
# Plota objetivo
goal = obs[3:5]
plt.plot(goal[0], goal[1], 'r*', markersize=20)
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.title('Trajetórias do Robô')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()
# Uso
model = PPO.load("ppo_robo_alcanca_objetivo")
env = RoboAlcancaObjetivo()
visualizar_trajetorias(model, env, num_episodios=5)
4.4 Comparando Antes e Depois do Treino
def comparar_desempenho():
"""Compara robô aleatório vs treinado"""
env = RoboAlcancaObjetivo()
model = PPO.load("ppo_robo_alcanca_objetivo")
# Testa robô aleatório
print("=== ROBÔ ALEATÓRIO ===")
recompensas_aleatorio = []
for _ in range(10):
obs, info = env.reset()
recompensa_total = 0
for _ in range(200):
action = env.action_space.sample() # Ação aleatória
obs, reward, terminated, truncated, info = env.step(action)
recompensa_total += reward
if terminated or truncated:
break
recompensas_aleatorio.append(recompensa_total)
# Testa robô treinado
print("=== ROBÔ TREINADO ===")
recompensas_treinado = []
for _ in range(10):
obs, info = env.reset()
recompensa_total = 0
for _ in range(200):
action, _ = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(action)
recompensa_total += reward
if terminated or truncated:
break
recompensas_treinado.append(recompensa_total)
# Resultados
print(f"\nAleatório: {np.mean(recompensas_aleatorio):.2f} +/- {np.std(recompensas_aleatorio):.2f}")
print(f"Treinado: {np.mean(recompensas_treinado):.2f} +/- {np.std(recompensas_treinado):.2f}")
melhoria = np.mean(recompensas_treinado) - np.mean(recompensas_aleatorio)
print(f"\nMelhoria: +{melhoria:.2f} ({melhoria/abs(np.mean(recompensas_aleatorio))*100:.1f}%)")
comparar_desempenho()
Parte 5: Integração com ROS 2 e Simulador (3-4h)
5.1 Ambiente Gym com ROS 2
Integre ambiente Gym com robô real no ROS 2:
import gymnasium as gym
from gymnasium import spaces
import numpy as np
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
from nav_msgs.msg import Odometry
class RoboROS2Env(gym.Env, Node):
"""
Ambiente Gym que controla robô real via ROS 2
"""
def __init__(self):
# Inicializa Gym Env
super(RoboROS2Env, self).__init__()
# Inicializa ROS 2 Node
rclpy.init()
Node.__init__(self, 'robo_rl_env')
# Espaços
self.action_space = spaces.Box(
low=np.array([-1.0, -1.0]),
high=np.array([1.0, 1.0]),
dtype=np.float32
)
# Observação: [dist_frente, dist_esq, dist_dir, vel_x, vel_angular]
self.observation_space = spaces.Box(
low=np.array([0, 0, 0, -2, -2]),
high=np.array([10, 10, 10, 2, 2]),
dtype=np.float32
)
# Publishers e Subscribers
self.cmd_vel_pub = self.create_publisher(Twist, '/cmd_vel', 10)
self.scan_sub = self.create_subscription(LaserScan, '/scan', self.callback_scan, 10)
self.odom_sub = self.create_subscription(Odometry, '/odom', self.callback_odom, 10)
# Estado
self.scan_data = None
self.odom_data = None
self.get_logger().info('Ambiente RL-ROS2 iniciado!')
def callback_scan(self, msg):
"""Recebe dados LIDAR"""
ranges = np.array(msg.ranges)
ranges = np.clip(ranges, msg.range_min, msg.range_max)
# Extrai 3 regiões: frente, esquerda, direita
num_readings = len(ranges)
self.dist_frente = np.min(ranges[num_readings//2-10:num_readings//2+10])
self.dist_esq = np.min(ranges[3*num_readings//4:num_readings])
self.dist_dir = np.min(ranges[0:num_readings//4])
def callback_odom(self, msg):
"""Recebe odometria"""
self.vel_x = msg.twist.twist.linear.x
self.vel_angular = msg.twist.twist.angular.z
def reset(self, seed=None, options=None):
super().reset(seed=seed)
# Para robô
msg = Twist()
self.cmd_vel_pub.publish(msg)
# Aguarda dados dos sensores
while self.scan_data is None or self.odom_data is None:
rclpy.spin_once(self, timeout_sec=0.1)
return self._get_obs(), {}
def _get_obs(self):
"""Retorna observação atual"""
return np.array([
self.dist_frente,
self.dist_esq,
self.dist_dir,
self.vel_x,
self.vel_angular
], dtype=np.float32)
def step(self, action):
# Publica ação
msg = Twist()
msg.linear.x = float(action[0]) * 0.5 # Max 0.5 m/s
msg.angular.z = float(action[1]) * 1.0 # Max 1.0 rad/s
self.cmd_vel_pub.publish(msg)
# Aguarda próximo estado
rclpy.spin_once(self, timeout_sec=0.1)
# Calcula recompensa
reward = 0.0
# Recompensa por andar para frente
if self.dist_frente > 1.0:
reward += self.vel_x # Quanto mais rápido, melhor
# Penalidade por colidir
if self.dist_frente < 0.3:
reward -= 10.0
terminated = True
else:
terminated = False
truncated = False
return self._get_obs(), reward, terminated, truncated, {}
def close(self):
# Para robô
msg = Twist()
self.cmd_vel_pub.publish(msg)
rclpy.shutdown()
5.2 Treinando com Robô Real
from stable_baselines3 import PPO
# Cria ambiente ROS 2
env = RoboROS2Env()
# Treina
model = PPO("MlpPolicy", env, verbose=1)
model.fit(total_timesteps=50000)
# Salva
model.save("ppo_robo_ros2")
ATENÇÃO: Treinar com robô real é LENTO e pode danificar hardware. Sempre:
- Treine primeiro em simulação
- Teste em ambiente seguro
- Tenha botão de emergência
Parte 6: Hiperparâmetros e Troubleshooting (1-2h)
6.1 Principais Hiperparâmetros PPO
model = PPO(
"MlpPolicy",
env,
# Taxa de aprendizado
learning_rate=3e-4, # Padrão. Reduza se instável (1e-4), aumente se lento (1e-3)
# Quantos steps coletar antes de atualizar
n_steps=2048, # Maior = mais estável, mas mais lento
# Tamanho do batch para treino
batch_size=64, # Múltiplo de n_steps. Maior = mais estável
# Quantas épocas treinar com dados coletados
n_epochs=10, # Padrão. Mais épocas = mais treino por dados
# Discount factor (quanto valoriza recompensas futuras)
gamma=0.99, # 0.9-0.999. Maior = valoriza mais o futuro
# Generalized Advantage Estimation
gae_lambda=0.95, # 0.9-0.99. Controla viés vs variância
# Clip range para atualização de política
clip_range=0.2, # Padrão. Previne mudanças drásticas
verbose=1
)
6.2 Problemas Comuns
Problema 1: Recompensa não sobe
Causas:
- Recompensas mal projetadas
- Learning rate muito alto
- Ações não têm efeito real no ambiente
Soluções:
# 1. Verifique recompensas
print(f"Recompensa mínima possível: {min_reward}")
print(f"Recompensa máxima possível: {max_reward}")
print(f"Recompensa de ações aleatórias: {random_reward}")
# 2. Reduza learning rate
model = PPO("MlpPolicy", env, learning_rate=1e-4)
# 3. Simplifique ambiente
# Torne mais fácil obter recompensas positivas
Problema 2: Aprendizado muito lento
Soluções:
# 1. Aumente paralelização
from stable_baselines3.common.vec_env import SubprocVecEnv
# Cria 4 ambientes em paralelo
env = SubprocVecEnv([lambda: RoboAlcancaObjetivo() for _ in range(4)])
model = PPO("MlpPolicy", env, verbose=1)
model.fit(total_timesteps=100000) # 4x mais rápido!
# 2. Aumente learning rate
model = PPO("MlpPolicy", env, learning_rate=1e-3)
# 3. Aumente n_steps
model = PPO("MlpPolicy", env, n_steps=4096)
Problema 3: Modelo instável (performance cai)
Soluções:
# 1. Reduza learning rate
model = PPO("MlpPolicy", env, learning_rate=1e-5)
# 2. Aumente clip_range
model = PPO("MlpPolicy", env, clip_range=0.1)
# 3. Salve checkpoints frequentemente
from stable_baselines3.common.callbacks import CheckpointCallback
checkpoint_callback = CheckpointCallback(
save_freq=10000,
save_path='./checkpoints/',
name_prefix='ppo_model'
)
model.fit(total_timesteps=100000, callback=checkpoint_callback)
6.3 Design de Recompensas
Princípios:
- Recompensa deve refletir objetivo
# BOM: Recompensa pela distância ao objetivo reward = -distancia_objetivo # RUIM: Recompensa fixa por timestep reward = 1.0 - Use recompensas densas, não esparsas
# RUIM (esparsa): Só recompensa no final reward = 100 if alcançou_objetivo else 0 # BOM (densa): Recompensa contínua reward = -distancia_objetivo # Quanto mais perto, melhor if alcançou_objetivo: reward += 100 - Normalize recompensas
# Mantenha recompensas em [-1, 1] ou [-100, 100] reward = np.clip(reward, -100, 100) - Penalize comportamentos ruins
# Colidiu reward -= 50 # Ficou parado if velocidade < 0.1: reward -= 1
Mini-Projeto Final: Robô Desvio de Obstáculos com RL
Objetivo: Criar ambiente e treinar robô para:
- Navegar em ambiente com obstáculos
- Alcançar objetivo o mais rápido possível
- Não colidir
Checklist:
- Criar ambiente Gym com obstáculos
- Definir observações (LIDAR + posição + objetivo)
- Definir ações (velocidades)
- Projetar função de recompensa
- Treinar com PPO por 200k timesteps
- Avaliar desempenho
- Visualizar trajetórias
- Comparar com controle reativo (Módulo 2.2)
- Documentar resultados
Recursos Adicionais
Documentação
Cursos
Papers
Troubleshooting
Erro: “Box bound precision lowered by casting to float32”
Ignore - é só um aviso. Ou use dtype=np.float32 explicitamente.
Erro: “AssertionError: The action space must be Box”
Você está tentando usar espaço de ações discreto com algoritmo que requer contínuo. Use DQN para discreto ou Box action_space para PPO.
Treinamento não converge
- Simplifique ambiente (menos observações, menos ações)
- Verifique se recompensas fazem sentido
- Teste com CartPole primeiro para validar código
- Aumente total_timesteps
Checklist de Conclusão
- Compreender conceitos de RL (agente, ambiente, recompensa)
- Instalar Stable-Baselines3
- Treinar CartPole
- Criar ambiente Gym personalizado
- Treinar “Robô Alcança Objetivo”
- Avaliar modelo com evaluate_policy
- Visualizar curvas de aprendizado (TensorBoard)
- Visualizar trajetórias
- Integrar Gym com ROS 2 (conceitual)
- Fazer tunning de hiperparâmetros
- Mini-projeto “Desvio de Obstáculos” concluído
Próximo Nível
Parabéns! Você completou o Nível 2: Criador.
Você agora sabe:
- Programar em Python e ROS 2
- Trabalhar com sensores e controle
- Implementar Aprendizado por Reforço
No Nível 3: Desenvolvedor, você vai:
- Algoritmos avançados (SAC, TD3)
- Visão computacional profunda
- Large Behavior Models (LBMs)
- Sim-to-Real transfer
Certificado Nível 2
Ao concluir todos os módulos e o projeto final, você receberá:
Certificado Digital: “Criador em Robótica Humanoide”
- Validado pela comunidade FTH
- Compartilhável no LinkedIn
- Acesso ao Nível 3 desbloqueado
Dúvidas? Participe da comunidade FTH no Discord ou abra uma issue no GitHub.
Última atualização: 2025-10-29