Medidas cercanas, respuesta en dirección opuesta
Imaginemos dos estimaciones de orientación de una pieza en una mesa giratoria: +179° y −179°. Sus flechas casi se superponen hacia la izquierda, a un grado de 180°. La media aritmética suma y divide entre dos: 0°, hacia la derecha. Un programa puede convertir observaciones casi coincidentes en orientación opuesta aun sumando y dividiendo correctamente.
No solo preguntamos cómo evitarlo, sino qué media calculamos, qué minimiza y cuándo no hay dirección media fiable. Construimos el método desde vectores del círculo, resolvemos los números y comparamos dos distancias. El título describe un riesgo matemático, no un incidente ni un ensayo de robot EL-AI. Todas las observaciones son sintéticas y reproducibles.
Un ángulo no es un punto de una recta
Para longitudes 179 y −179 están lejos. En direcciones sumar una vuelta no cambia la flecha: −179° y 181° representan lo mismo. Reescribir la segunda medida como 181° hace que la media sea 180°. Solo cambió el representante numérico. Una media direccional debería ser equivalente al sumar o restar 360° a cualquier observación; el promedio aritmético no lo es.
Estudiamos dirección plana, no vueltas acumuladas del eje. Tras tres revoluciones un articulación puede apuntar igual que sin ellas, pero posición desenrollada, límites y cables difieren. Eliminar vueltas perdería información. Primero se define qué representa el dato. El artículo trata direcciones circulares, no todas las variables articulares.
Convertir medidas en flechas
Asociamos theta al vector unitario u(theta)=(cos theta, sin theta). Su longitud uno representa dirección sin magnitud arbitraria. Las funciones trigonométricas usan radianes: grados por pi/180. Promediamos componentes horizontal y vertical con pesos w_i no negativos y total W positivo, obteniendo c y s. Pesos iguales dan la media sin ponderar.
atan2 usa ambas componentes y reconoce el cuadrante; arctan(s/c) pierde esa información y divide por c. rho es la longitud del vector medio, entre cero y uno: flechas concordantes refuerzan y opuestas cancelan. mu tiene dirección solo con resultante no nula. El código usa un umbral numérico para residuos flotantes, distinto de un umbral de calidad física.
El ejemplo, número por número
Para +179° y −179° ambos cosenos son aproximadamente −0,9998476952. Los senos +0,0174524064 y −0,0174524064 se cancelan. Con pesos iguales c≈−0,9998476952, s≈0 y rho≈0,9998476952. La resultante larga apunta a la izquierda: atan2 da 180°, equivalente a −180°. Las observaciones distan solo 2° por el arco corto. Saltar entre −180° y +180° cambia etiqueta, no implica una vuelta física.
Sumar 360° a la primera observación conserva dirección, comprobado por el código. Con triple peso para la primera obtenemos unos 179,4999619°, más cerca de ella. Ponderar es una elección del modelo de fusión, no se justifica llamando “confianza” a un número. Interpretar fiabilidad exige modelar errores y dependencias. Dos sensores con sesgo compartido pueden tener rho próximo a uno y apuntar ambos mal.
¿Qué error minimiza esta media?
¿Por qué es una media y no solo una receta? Medimos distancia recta entre puntas de flechas unitarias, una cuerda del círculo, y buscamos mu que minimice la suma ponderada de cuadrados. El objetivo es adimensional: ni error posicional en metros ni distancia angular cuadrática. Elegir distancia forma parte del problema estadístico.
La primera identidad usa productos escalares unitarios: cada norma cuadrada vale uno y el producto es coseno de la diferencia. Expandir cos(theta−mu) reúne c y s. Con rho positivo minimizamos cuando el último coseno vale uno, mu=alpha módulo vuelta. Con rho=0 el coste es 2W para cualquier mu. Quedan derivados fórmula y caso indeterminado.
Con +179°/−179° y pesos unitarios el coste cordal es unos 7,99939078 en 0° y 0,0006092194 en 180°. Son valores del objetivo definido, no porcentajes de éxito robótico. El contraste muestra el error de representación del caso, no distancia de colisión ni calidad de visión.
Cuando desaparece la resultante
Las direcciones 0° y 180° con pesos iguales cancelan exactamente: c=s=0. Los datos no prefieren media cordal. El 90° aritmético no descubre información, elige un número dependiente de representación. sin(pi) flotante puede dejar un residuo cercano a 10⁻¹⁶ y atan2 devolver un número sin resolver la ambigüedad matemática.
Nuestra implementación devuelve None con rho≤10⁻¹², política experimental explícita, no umbral certificado ni de confianza estadística. La aplicación necesita criterios basados en ruido y comportamiento al no estimar. SciPy circmean documenta resultado dependiente de implementación con resultante cero. Nuestro comportamiento difiere explícitamente; no ejecutamos SciPy ni inventamos comparación.
Un resultado definido puede ser muy sensible
Sustituimos 180° por 179,999°: rho≈8,72665×10⁻⁶ y media +89,9995°. Usar −179,999°, físicamente a solo 0,002°, da −89,9995°. Las medias casi se oponen. No es solo salto de etiqueta: también difieren las flechas. Cerca de cancelarse direcciones opuestas, una perturbación mínima elige entre muchos mínimos casi equivalentes.
La derivada de atan2 explica sensibilidad: pequeños dc, ds dan dmu=(c ds−s dc)/rho² en radianes al primer orden. La norma del gradiente respecto a (c, s) es 1/rho: resultantes cortas amplifican errores angulares. Es local, para perturbaciones pequeñas y rho positivo, no intervalo de confianza. El código recorre epsilon desde 1° hasta 0,001°.

La distancia por el círculo da otra media
Una cuerda une puntos en recta; un arco sigue el círculo. Son cercanos con desviaciones pequeñas, distintos con grandes. Una media intrínseca minimiza cuadrados de diferencias angulares cortas, ajustadas a una vuelta. No coincide en general con la cordal. Llamar un método “circular” no identifica su objetivo: importa la distancia.
Con 0°,0°,180° dos flechas derechas superan a una izquierda: rho=1/3 y media cordal 0°. Para distancia angular en 0°≤mu≤180° el coste es 2mu²+(180°−mu)². Derivar da 6mu−360°=0, luego 60°; el semicírculo negativo da otro mínimo −60°. El coste es 21.600 grados² en ambos, frente a 32.400 en cero. El cordal vale 4 en cero y unos 5 en ±60°. No contradicción, sino objetivos distintos.
Usamos grados para leer; pasar a radianes multiplica costes por (pi/180)² sin cambiar mínimos. El código compara valores y la derivación por semicírculos establece mínimos. Ninguna media es universalmente más “verdadera”: se elige el error que interesa reducir. Datos multimodales pueden necesitar varias hipótesis, no un resumen único.
| Caso, grados | Media aritmética | Media circular cordal | rho |
|---|---|---|---|
| 179, -179 | 0 | 180 | 0.9998476952 |
| 179, 181 | 180 | -180 | 0.9998476952 |
| 0, 180 | 90 | — | ~0 |
| 0, 179.999 | 89.9995 | 89.9995 | 0.00000872665 |
| 0, 0, 180 | 60 | ~0 | 1/3 |
El guion indica que no devolvemos dirección bajo el umbral; +180° y −180° equivalen. La media ordinaria depende del corte del intervalo; una circular puede optimizar su objetivo y ser poco informativa o sensible. Conservar rho y observaciones ayuda a distinguirlo; rho solo no reconstruye la distribución.
Desenrollar ángulos es otra operación
Desenrollar añade vueltas para hacer continua una secuencia. Si el eje avanza poco de 179° a −179°, el segundo dato puede ser 181°. Eso usa tiempo o información previa. Medidas simultáneas sin referencia pueden no tener asignación única de vueltas. Si entre muestras se supera media vuelta, el salto mínimo puede elegir mal. No ejecutamos desenrollado ni simulamos trayectorias; distinguimos sus supuestos.
También deben coincidir referencias geométricas. Ángulos de cámara y base robótica no se fusionan solo por usar grados: ejes, signos y transformaciones deben ser coherentes. La media circular no corrige calibración ni timestamps. Nuestra pregunta supone direcciones planas comparables y estudia cómo resumirlas.
Qué ejecuta el código y qué queda fuera
experiment.py usa Python 3.14.0 y math, guardando observaciones, pesos, componentes, rho, medias y costes. Es determinista, sin seed. fsum acumula y se rechazan entradas vacías, pesos negativos o no finitos y total cero. Los assert usan tolerancias explícitas y la cancelación se explica exactamente. El listado breve aísla el ejemplo; el archivo añade casos y objetivos. plot.py genera cuatro figuras Matplotlib con instrucciones de fuente china.
Una pasada requiere trabajo proporcional a observaciones y estado agregado constante: suma de pesos, cosenos y senos. El script guarda más datos para inspección, por lo que no describe toda su memoria. No medimos tiempo en microcontroladores, precisión de encoder ni controladores. Tres sumas no establecen latencia robótica completa.
La documentación primaria SciPy 1.18.0 distingue circmean basada en resultante de Rotation.mean con pérdida cordal matricial. Evita confundir direcciones planas con rotaciones 3D generales; no justificamos promediar por separado ángulos de Euler. No ejecutamos esas API ni atribuimos resultados a SciPy. No afirmamos leer libros o papers listados allí. Es análisis didáctico, no investigación nueva revisada por pares.
Respuesta al problema inicial
El robot puede recibir dirección opuesta al tratar coordenadas circulares como números lineales. Flechas unitarias y media circular corrigen +179°/−179° dando 180°. Pero resultantes pequeñas, grupos opuestos, distancia, referencias y vueltas limitan la interpretación. Se trata de elegir geometría y reconocer cuándo una orientación resume mal los datos, no de confiar en una fórmula mágica.
La robótica industrial y colaborativa es una dirección de exploración indicada para EL-AI. El vínculo aplicativo es hipotético: no son ensayos, demostración de seguridad ni evidencia de productos, clientes o instalaciones. La evidencia son identidades y casos sintéticos ejecutados. Una célula real requiere protocolos, calibración y validación dinámica y de seguridad específica fuera del artículo.
Fuentes y materiales reproducibles
SciPy 1.18.0 — scipy.stats.circmean, definition and zero-resultant behaviour.
SciPy 1.18.0 — Rotation.mean, chordal objective.
import math
angles=[179,-179]
c=math.fsum(math.cos(math.radians(a)) for a in angles)/len(angles)
s=math.fsum(math.sin(math.radians(a)) for a in angles)/len(angles)
rho=math.hypot(c,s)
mean=math.degrees(math.atan2(s,c)) if rho>1e-12 else None
assert abs(abs(mean)-180)<1e-10
print(sum(angles)/len(angles),mean,rho)
Código, datos e instrucciones · JSON. Cálculos didácticos ejecutados con Python 3.14.0; figuras con Matplotlib 3.11.2. Análisis asistido por IA, sin afirmar revisión por pares ni humana. Portada original ImageGen ilustrativa: no documenta personas, sedes ni instalaciones de EL-AI. Fuentes consultadas el 24 de octubre de 2026.

