agrobot_base/Python/mpc/test6.py

124 lines
4.0 KiB
Python

# MPC híbrido com controle de pontos visitados via limiar de distância
import numpy as np
import matplotlib.pyplot as plt
import json
# Carrega o mapa
with open("CidadeJardimTerreno2_Corrigido.json", "r", encoding="utf-8") as f:
data = json.load(f)
traj_gps = []
for feature in data["features"]:
coords = feature["geometry"]["coordinates"]
for lon, lat in coords:
traj_gps.append((lat, lon))
def latlon_to_xy(lat, lon, lat0, lon0):
R = 6371000
dlat = np.radians(lat - lat0)
dlon = np.radians(lon - lon0)
x = R * dlon * np.cos(np.radians((lat + lat0) / 2))
y = R * dlat
return x, y
lat0, lon0 = traj_gps[0]
traj_xy = np.array([latlon_to_xy(lat, lon, lat0, lon0) for lat, lon in traj_gps])
# Parâmetros
distancia_entre_eixos = 0.92
angulo_max_graus = 30.0
angulo_max_rad = np.radians(angulo_max_graus)
dt = 0.2
horizonte = 250
velocidade_param = 1.0
limiar_entrada = 0.7 # distância para considerar ponto como visitado
def calcular_orientacao(p1, p2):
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
return np.arctan2(dy, dx)
def calcular_omega_fisico(v, angulo_rad, tipo_movimento):
L = distancia_entre_eixos
tan_delta = np.tan(angulo_rad)
if tipo_movimento == "rodasFrontais":
return (v * tan_delta) / L
elif tipo_movimento == "movimentoArco":
return (2 * v * tan_delta) / L
return 0.0
def proximo_nao_visitado(visitados):
for i, v in enumerate(visitados):
if not v:
return i
return len(visitados) - 1 # fallback para o último ponto
def simular_trajetoria_com_limiar(x0, y0, theta0, v, traj_xy):
x, y, theta = x0, y0, theta0
pontos = [(x, y)]
custo_total = 0.0
tipos_usados = []
visitados = [False] * len(traj_xy)
for step in range(horizonte):
idx_alvo = proximo_nao_visitado(visitados)
if idx_alvo >= len(traj_xy):
break
ponto_alvo = traj_xy[idx_alvo]
pos_atual = np.array([x, y])
# Verifica se o ponto foi alcançado
if np.linalg.norm(pos_atual - ponto_alvo) < limiar_entrada:
visitados[idx_alvo] = True
idx_alvo = proximo_nao_visitado(visitados)
if idx_alvo >= len(traj_xy):
break
ponto_alvo = traj_xy[idx_alvo]
orient_alvo = calcular_orientacao(pos_atual, ponto_alvo)
delta_theta = (orient_alvo - theta + np.pi) % (2 * np.pi) - np.pi
angulo_direcional = np.clip(delta_theta, -angulo_max_rad, angulo_max_rad)
melhor_tipo = None
melhor_estado = None
menor_custo = float('inf')
for tipo in ["rodasFrontais", "movimentoArco"]:
omega = calcular_omega_fisico(v, angulo_direcional, tipo)
x_sim = x + v * np.cos(theta) * dt
y_sim = y + v * np.sin(theta) * dt
theta_sim = theta + omega * dt
erro_dist = np.linalg.norm([x_sim - ponto_alvo[0], y_sim - ponto_alvo[1]])
orient_sim = calcular_orientacao((x_sim, y_sim), ponto_alvo)
erro_orient = np.abs((orient_sim - theta_sim + np.pi) % (2 * np.pi) - np.pi)
custo = erro_dist * 2.0 + erro_orient * 1.5
if custo < menor_custo:
menor_custo = custo
melhor_tipo = tipo
melhor_estado = (x_sim, y_sim, theta_sim)
x, y, theta = melhor_estado
pontos.append((x, y))
tipos_usados.append(melhor_tipo)
custo_total += menor_custo
return np.array(pontos), custo_total, tipos_usados
# Simular com lógica de ponto visitado
x0, y0, theta0 = traj_xy[0][0] - 0.5, traj_xy[0][1] - 0.5, 0.0
traj_melhor, custo_final, tipos_melhor = simular_trajetoria_com_limiar(x0, y0, theta0, velocidade_param, traj_xy)
# Plot
plt.plot(traj_melhor[:,0], traj_melhor[:,1], 'b-', linewidth=2.5, label='MPC com visitação')
plt.plot(traj_xy[:,0], traj_xy[:,1], 'ro--', label='Trajetória alvo')
plt.xlabel("X (m)")
plt.ylabel("Y (m)")
plt.title(f"MPC com visitação de pontos (vel {velocidade_param} m/s)")
plt.grid(True)
plt.axis("equal")
plt.legend()
plt.show()