Introducción al Control de Vehículos No Tripulados
El control de vehículos de superficie no tripulados en condiciones marinas complejas presanta desafíos debido a las dinámicas no lineales y las perturbaciones externas. Los métodos de control tradicionales basados en muestreo periódico pueden ser ineficientes computacionalmente. Se propone un enfoque de control predictivo no lineal (NMPC) con mecanismo de disparo por evantos para reducir el cálculo innecesario.
Modelo Dinámico del Vehículo
El modelo considera tres grados de libertad: posición en el plano y orientación. A continuación se muestra una implementación en Python de las ecuaciones dinámicas, con matrices de inercia, Coriolis y amortiguamiento que capturan las no linealidades.
import numpy as np
def modelo_buque(estado, accion):
"""Calcula las derivadas del estado para un vehículo de superficie."""
theta = estado[2] # Ángulo de proa
vel_u, vel_v, vel_r = estado[3], estado[4], estado[5] # Velocidades en marco corporal
# Matriz de inercia (ejemplo simplificado)
matriz_inercia = np.array([[150, 0, 0],
[0, 200, 40],
[0, 40, 80]])
# Término de Coriolis modificado
coriolis = np.array([[0, 0, -80*vel_v - 40*vel_r],
[0, 0, 150*vel_u],
[80*vel_v + 40*vel_r, -150*vel_u, 0]])
# Matriz de amortiguamiento no lineal
amortiguamiento = np.diag([50*vel_u, 70*vel_v, 20*vel_r])
# Cinemática
eta_punto = np.array([vel_u*np.cos(theta) - vel_v*np.sin(theta),
vel_u*np.sin(theta) + vel_v*np.cos(theta),
vel_r])
# Dinámica
nu_punto = np.linalg.inv(matriz_inercia) @ (accion - coriolis @ estado[3:6] - amortiguamiento @ estado[3:6])
return np.concatenate((eta_punto, nu_punto))
Mecanismo de Disparo por Eventos
Para evitar cálculos redundantes, se implementa un disparador basado en el error de estado y un intervalo mínimo. Esto permite actualizar la acción de control solo cuando es necesario, optimizando el uso de recursos.
import time
class DisparadorEventos:
def __init__(self, umbral=0.03, delta_tiempo=0.15):
self.ultima_accion = None
self.umbral_error = umbral
self.intervalo_min = delta_tiempo
self.tiempo_anterior = None
def verificar_disparo(self, estado_actual, trayectoria_referencia):
"""Determina si se debe actualizar el control."""
if self.ultima_accion is None:
return True
error_estado = np.linalg.norm(estado_actual[:3] - trayectoria_referencia[:3])
tiempo_transcurrido = time.time() - self.tiempo_anterior
# Condición combinada: error alto o tiempo mínimo alcanzado
return error_estado > self.umbral_error or tiempo_transcurrido >= self.intervalo_min
Formulación del NMPC
El control predictivo no lineal se formula como un problema de optimización con restricciones. Se utiliza CasADi para modelar y resolver el MPC, definiendo la función de costo con ponderaciones específicas para el seguimiento de trayectoria y el esfuerzo de control.
import casadi as ca
def construir_nmpc(funcion_dinamica, horizonte=8, tiempo_prediccion=4.0):
"""Configura el solucionador NMPC usando CasADi."""
optimizador = ca.Opti()
variables_estado = optimizador.variable(6, horizonte + 1)
variables_control = optimizador.variable(2, horizonte)
# Función de costo: error de seguimiento y penalización de controles
costo_total = 0
for i in range(horizonte):
error_seguimiento = variables_estado[:3, i] - referencia[:, i]
costo_total += 8 * ca.dot(error_seguimiento, error_seguimiento)
costo_total += ca.dot(variables_control[:, i], np.diag([0.2, 0.4]) @ variables_control[:, i])
# Restricciones dinámicas
for i in range(horizonte):
estado_siguiente = funcion_dinamica(variables_estado[:, i], variables_control[:, i])
optimizador.subject_to(variables_estado[:, i+1] == estado_siguiente)
# Límites de las entradas de control
optimizador.subject_to(optimizador.bounded(-25, variables_control[0, :], 25)) # Empuje máximo
optimizador.subject_to(optimizador.bounded(-np.pi/4, variables_control[1, :], np.pi/4)) # Ángulo de timón
optimizador.minimize(costo_total)
return optimizador
Resultados y Desafíos
Las pruebas en un entorno simulado con ROS mostraron una reducción del 30% en el tiempo de cálculo promedio, manteniendo un error de seguimiento de trayectoria dentro de límites aceptables. Sin embargo, la interacción entre el disparo por eventos y el horizonte de predicción puede generar problemas de estabilidad en condiciones dinámicas, como cambios bruscos en el oleaje. Se observó que agregar un término de inercia al mecanismo de disparo mejoró la robustez.
[INFO] 09:15:02 - Disparo por evento: recalculo de control en 65ms
[INFO] 09:15:10 - Estado estable, cálculo omitido
[INFO] 09:15:18 - Perturbación detectada, replanificación activada
El sistema demostró ser eficiente energéticamente en rutas rectas, pero requirió ajustes finos de los parámetros de coste y umbrales para mejorar la precisión en maniobras complejas.