atakan
feat: Initial open-source release of ControlAI
9936912
Raw
History Blame Contribute Delete
2.82 kB
"""Actuator allocation and fault detection tools."""
from __future__ import annotations
from typing import Any
import numpy as np
from controlai_agent.registry import registry
from controlai_agent.verifier import verifier
@registry.register(
name="minimum_norm_control_allocation",
description="Compute minimum 2-norm control allocation for redundant actuators: min ||u||_2 subject to B*u = tau.",
parameters_schema={
"type": "object",
"properties": {
"B": {
"type": "array",
"items": {"type": "number"},
"description": "Actuator effectiveness row vector B (1 x m)",
},
"desired_tau": {
"type": "number",
"description": "Desired virtual control torque/force tau",
},
},
"required": ["B", "desired_tau"],
},
)
def minimum_norm_control_allocation(B: list[float], desired_tau: float) -> dict[str, Any]:
B_vec = np.array(B, dtype=float)
b_norm_sq = float(np.dot(B_vec, B_vec))
u = (desired_tau / b_norm_sq) * B_vec
v_report = verifier.verify_allocation(B_vec, u, desired_tau)
return {
"u": u.tolist(),
"achieved_tau": float(np.dot(B_vec, u)),
"norm_u": float(np.linalg.norm(u)),
"verification": v_report,
}
@registry.register(
name="actuator_fault_isolation",
description="Isolate single actuator effectiveness loss from torque error residual: r = tau_measured - B * u_cmd.",
parameters_schema={
"type": "object",
"properties": {
"B": {"type": "array", "items": {"type": "number"}, "description": "Nominal actuator effectiveness vector"},
"command": {"type": "array", "items": {"type": "number"}, "description": "Commanded actuator vector u_cmd"},
"measured_tau": {"type": "number", "description": "Actual achieved torque tau_meas"},
},
"required": ["B", "command", "measured_tau"],
},
)
def actuator_fault_isolation(B: list[float], command: list[float], measured_tau: float) -> dict[str, Any]:
B_vec = np.array(B, dtype=float)
u_vec = np.array(command, dtype=float)
expected_tau = float(np.dot(B_vec, u_vec))
residual = float(measured_tau - expected_tau)
# Candidate loss fractions assuming actuator i failed
candidate_losses = []
for i in range(len(B_vec)):
denom = B_vec[i] * u_vec[i]
loss_fraction = float(-residual / denom) if abs(denom) > 1e-9 else None
candidate_losses.append(loss_fraction)
return {
"expected_tau": expected_tau,
"measured_tau": measured_tau,
"torque_residual": residual,
"is_fault_detected": abs(residual) > 1e-4,
"candidate_actuator_loss_fractions": candidate_losses,
}