Files
AR-Autopilot/tools/spice/6_bno085_imu.cir
T
alro65 b82ed400bc feat: BNO085 IMU integration — SPICE + simulator yaw rate feed-forward
SPICE (6_bno085_imu.cir):
  - BNO085 power supply with 10uF + 100nF decoupling on VDD
  - Power-on reset RC circuit (R=10K, C=1uF, tau=10ms → deasserts at ~12ms)
  - I2C Fast Mode 400kHz bus: 4.7K pull-ups, 50pF bus capacitance model
  - Full I2C transaction: START + address 0x4A + R/W + BNO085 ACK + STOP
  - INT pin (open-drain, 10K pull-up, 100Hz interrupt simulation)
  - .meas directives: reset timing, SCL rise time, VDD stability

Simulator (esp32_sim.py):
  - SimSnapshot.bno085_yaw_rate_dps field added
  - _bno085_enabled / _bno085_noise_std_dps / _bno085_yaw_rate_dps state
  - enable_bno085(noise_std_dps=0.02) public method
  - disable_bno085() public method
  - _run_physics: samples gyro at 50Hz with Gaussian noise model
  - _run_outer_loop: uses BNO085 yaw rate for rot_ff_term when enabled
    (replaces NMEA-derived ROT — lower latency ~4ms vs ~100-200ms)

Usage:
  sim.enable_bno085()          # activate gyro feed-forward
  sim.enable_bno085(noise_std_dps=0.014)  # with BNO085 spec noise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 22:46:16 -04:00

294 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
* =======================================================================
* AR-Autopilot — IMU BNO085: Alimentacion, Reset e I2C
* Archivo: 6_bno085_imu.cir
* Tarjeta: Modulo compacto ESP32+CAN (CIRCUITO GIRO)
*
* CIRCUITO:
*
* 3.3V ──[C=10uF + C=100nF]──── BNO085 VDD (alimentacion principal)
* 3.3V ──[C=100nF]────────────── BNO085 VDDIO (nivel logico I2C = 3.3V)
*
* 3.3V ──[R=10K]──── NRST (BNO085 RESET, activo bajo)
* └── [C=1uF] ── GND → reset POR: NRST sube lento
*
* 3.3V ──[R=4.7K]──── SCL (I2C clock, 400 kHz Fast Mode)
* 3.3V ──[R=4.7K]──── SDA (I2C data, open-drain)
* 3.3V ──[R=10K] ──── INT (interrupcion data-ready, activo bajo OD)
*
* SA0 ── GND → direccion I2C = 0x4A
* BOOT ── GND → modo operacion normal (no bootloader USB)
*
* BNO085 (CEVA/Hillcrest BNO085):
* Alimentacion: VDD = 3.3V, VDDIO = 1.8V a 3.3V
* Corriente tipica: 6.5 mA (todos los sensores activos, 100 Hz)
* Reset: NRST activo bajo, minimo 10 us, startup: 50 ms tipico
* I2C: 100 kHz o 400 kHz (Fast Mode), max 1 MHz (Fast Mode Plus)
* Reportes configurables: Rotation Vector, Gyroscope, Accelerometer...
* Sensor Fusion DSP interno: 500 Hz internal fusion rate
* Giroscopio: ruido ~0.014 deg/s RMS, bias < 1 deg/s
* Magnetometro: compensacion hard/soft iron automatica
* Rango de temperatura operacion: -40 a +85 C (marino OK)
*
* REPORTES USADOS PARA EL AUTOPILOTO:
* ARVR Stabilized Rotation Vector → Heading (0-360°) a 100 Hz
* Gyroscope Calibrated → Yaw rate (°/s) a 250 Hz
* Linear Acceleration → para deteccion de impactos
*
* COMO USAR EN LTSPICE:
* Ver: V(nrst) → curva de reset POR (debe superar 0.7×VDD = 2.31V en ~12ms)
* V(vdd_bno) → tension de alimentacion BNO085 con decoupling
* V(scl) → reloj I2C 400 kHz con tiempos de subida correctos
* V(sda) → datos I2C con open-drain y pull-up
* V(int_pin) → interrupcion data-ready
* =======================================================================
.title AR-Autopilot BNO085 IMU Power, Reset and I2C Interface
* -----------------------------------------------------------------------
* ALIMENTACION 3.3V
* -----------------------------------------------------------------------
V33 V33 GND 3.3V
* -----------------------------------------------------------------------
* DESACOPLO DE ALIMENTACION BNO085
* -----------------------------------------------------------------------
* BNO085 datasheet recomienda: 10uF (bulk) + 100nF (HF) en VDD
* y 100nF adicional en VDDIO, lo mas cerca posible del IC.
* A 22mm del inductor L2 del buck: el ruido de switching es bajo
* pero el decoupling sigue siendo critico para el magnetometro.
Cbulk V33 VDD_BNO 10u ; capacitor bulk 10uF ceramico (X5R)
Cdec1 VDD_BNO GND 100n ; 100nF ceramico junto al pin VDD del BNO085
Cdec2 V33 GND 100n ; 100nF en VDDIO (misma tension 3.3V)
* Inductancia del trace PCB entre condensador bulk y IC (~10mm de traza)
* L_trace a 1.4MHz (MP2338): XL = 2*pi*1.4e6*1e-9 = 8.8mOhm → despreciable
Rtrace V33 VDD_BNO 0.05 ; resistencia de traza PCB (~50mOhm para 10mm)
* Consumo del BNO085 (todos sensores + fusion a 100Hz)
Ibno085 VDD_BNO GND DC 6.5m ; 6.5 mA tipico (datasheet tabla 4.3)
* -----------------------------------------------------------------------
* CIRCUITO DE RESET (Power-On Reset)
* -----------------------------------------------------------------------
* NRST activo bajo: cuando VDD sube, NRST debe permanecer bajo
* hasta que VDD este estable, luego sube lentamente via RC.
* El BNO085 sale de reset cuando NRST > 0.7 * VDDIO = 2.31V
* Con R=10K, C=1uF: τ = 10ms → NRST cruza 2.31V en ~12ms
*
* Simulamos encendido: VDD sube en 1ms (soft-start del buck converter)
* Despues NRST sube lentamente → BNO085 en reset durante ~12ms ✓
* Resistencia de pull-up del RESET
Rrst V33 NRST_NODE 10k
* Condensador de reset (define el tiempo de reset)
Crst NRST_NODE GND 1u IC=0
* Diodo de descarga rapida (para re-reset rapido si VDD cae)
Drst GND NRST_NODE DRST_FAST
.model DRST_FAST D(Is=1e-12 N=1 Rs=1 Cjo=5p)
* Modelo del umbral de reset del BNO085 (schmitt trigger interno)
* NRST < 2.31V → en reset; NRST > 2.31V → operativo
Eres RESET_STATUS GND VALUE={IF(V(NRST_NODE) > 2.31, 3.3, 0)}
* -----------------------------------------------------------------------
* BUS I2C — RESISTENCIAS DE PULL-UP
* -----------------------------------------------------------------------
* Fast Mode (400 kHz): Rpullup maximo = Vcc/(3mA) = 3.3/0.003 = 1.1k
* Rpullup minimo = (Vcc - Voh)/(bus cap × slew rate) ≈ 1k
* Valor estandar: 4.7k (funciona bien hasta 300kHz con Cbus < 100pF)
* Para 400kHz con Cbus=50pF: tr = 0.8473 * 4700 * 50e-12 = 199ns OK (limite es 300ns)
*
* Si necesitas 400kHz garantizado con cable largo (Cbus > 100pF):
* Reducir a 2.2k → tr = 93ns ✓ (pero mayor consumo: 3.3/2.2k = 1.5mA por linea)
Rpull_scl V33 SCL 4.7k ; pull-up SCL
Rpull_sda V33 SDA 4.7k ; pull-up SDA
* Capacidad de bus (trazas PCB ~10cm + pines I2C de ESP32 y BNO085)
* ESP32 I2C input cap: ~5pF, BNO085 I2C input cap: ~5pF, traza: ~10pF/cm × 10cm = 100pF
Cbus_scl SCL GND 50p ; capacidad de bus SCL (solo 10cm de traza en PCB compacto)
Cbus_sda SDA GND 50p ; capacidad de bus SDA
* -----------------------------------------------------------------------
* ESP32 MASTER I2C — Genera transaccion I2C (direccion 0x4A, lectura)
* -----------------------------------------------------------------------
* Protocolo I2C 400kHz (Fast Mode):
* Periodo = 2.5us
* SCL alto = 0.6us min (spec), SCL bajo = 1.3us min
* Usamos: SCL alto = 0.9us, SCL bajo = 1.6us (simétrico aproximado)
*
* Secuencia simulada:
* t=0: Bus idle (SDA=HIGH, SCL=HIGH)
* t=5us: START condition (SDA baja mientras SCL alto)
* t=7us: SCL baja → comienzo de bits de direccion
* t=7-32us: 8 bits: direccion 0x4A + R/W=1 (lectura)
* 0x4A = 1001010, con R/W=1 → byte = 10010101 = 0x95
* t=32us: SCL sube → ACK del esclavo (BNO085 baja SDA)
* t=37us: SCL baja → BNO085 libera SDA (pull-up sube)
* t=40us: BNO085 comienza a enviar dato (primer byte de SHTP)
* t=60us: STOP condition
* SCL: generado por ESP32 (push-pull internamente, vista del bus = open-drain + pull-up)
* Modelamos el SCL como fuente de tension con resistencia baja (driver fuerte)
Vscl_drv SCL_DRV GND PWL(
+ 0 3.3
+ 4.9u 3.3
+ 5.0u 3.3 ; bus idle
+ 6.9u 3.3
+ 7.0u 0 ; SCL baja → START completado, primer bit
+ 8.5u 0
+ 8.6u 3.3 ; bit 7 (MSB): '1'
+ 9.9u 3.3
+ 10.0u 0
+ 11.4u 0
+ 11.5u 3.3 ; bit 6: '0'
+ 12.9u 3.3
+ 13.0u 0
+ 14.4u 0
+ 14.5u 3.3 ; bit 5: '0'
+ 15.9u 3.3
+ 16.0u 0
+ 17.4u 0
+ 17.5u 3.3 ; bit 4: '1'
+ 18.9u 3.3
+ 19.0u 0
+ 20.4u 0
+ 20.5u 3.3 ; bit 3: '0'
+ 21.9u 3.3
+ 22.0u 0
+ 23.4u 0
+ 23.5u 3.3 ; bit 2: '1'
+ 24.9u 3.3
+ 25.0u 0
+ 26.4u 0
+ 26.5u 3.3 ; bit 1: '0'
+ 27.9u 3.3
+ 28.0u 0
+ 29.4u 0
+ 29.5u 3.3 ; bit 0 (R/W=1, lectura)
+ 30.9u 3.3
+ 31.0u 0 ; SCL bajo para ACK
+ 32.4u 0
+ 32.5u 3.3 ; SCL sube: BNO085 debe mantener SDA baja (ACK)
+ 33.9u 3.3
+ 34.0u 0
+ 59.9u 0
+ 60.0u 3.3) ; ultimo SCL bajo → STOP
Rscl_drv SCL_DRV SCL 10 ; impedancia del driver I2C del ESP32
* SDA: ESP32 genera START y los bits de direccion
* BNO085 genera ACK (baja SDA durante ACK clock)
Vsda_drv SDA_DRV GND PWL(
+ 0 3.3
+ 4.9u 3.3
+ 5.0u 0 ; START: SDA baja mientras SCL alto
+ 5.9u 0
+ 6.0u 3.3 ; START completado: SDA sube (SCL ya bajo)
* bits de direccion 0x95 = 10010101 (MSB first)
* bit7=1: SDA alto (pull-up)
+ 6.9u 3.3
+ 7.0u 3.3 ; bit 7 = 1 (recesivo, pull-up mantiene alto)
+ 9.9u 3.3
+ 10.0u 0 ; bit 6 = 0 (ESP32 baja SDA)
+ 11.4u 0
+ 11.5u 0 ; bit 5 = 0
+ 13.9u 0
+ 14.0u 3.3 ; bit 4 = 1
+ 15.9u 3.3
+ 16.0u 0 ; bit 3 = 0
+ 17.9u 0
+ 18.0u 3.3 ; bit 2 = 1
+ 19.9u 3.3
+ 20.0u 0 ; bit 1 = 0
+ 21.9u 0
+ 22.0u 3.3 ; bit 0 = 1 (R/W=1)
+ 29.9u 3.3
+ 30.0u 0 ; ACK slot: ESP32 libera SDA (flota)
* BNO085 baja SDA para ACK → modelado como fuente separada
+ 34.0u 0
+ 34.1u 3.3 ; ESP32 retoma control del bus (post-ACK)
+ 59.9u 3.3
+ 60.0u 3.3) ; STOP: SDA sube mientras SCL alto
Rsda_drv SDA_DRV SDA 10
* ACK del BNO085: baja SDA durante el clock de ACK (t=32.5us a 34us)
Vsda_ack SDA_ACK GND PWL(
+ 0 3.3
+ 31.9u 3.3
+ 32.0u 0 ; BNO085 ACK: baja SDA
+ 33.9u 0
+ 34.0u 3.3) ; BNO085 libera SDA
Rack SDA_ACK SDA 50 ; el driver del BNO085 tiene impedancia finita
* -----------------------------------------------------------------------
* LINEA DE INTERRUPCION INT (data-ready, activo bajo, open-drain)
* -----------------------------------------------------------------------
* El BNO085 baja INT cuando tiene un reporte listo para leer.
* Con heading + yaw rate a 100Hz: INT pulsa cada 10ms
* El ESP32 lee el dato cuando detecta INT bajo (GPIO input con pull-up)
Rpull_int V33 INT_PIN 10k ; pull-up externo (ESP32 tiene pull-up interno tambien)
Cint INT_PIN GND 10p ; capacidad del pin
* Simula INT pulsando periodicamente (100 Hz = 10ms periodo, 100us de pulso bajo)
Vint_bno INT_DRV GND PULSE(3.3 0 5m 100n 100n 100u 10m)
Rint_drv INT_DRV INT_PIN 100 ; open-drain: BNO085 solo puede bajar, no subir
* -----------------------------------------------------------------------
* MEDICIONES AUTOMATICAS
* -----------------------------------------------------------------------
* Tiempo que tarda NRST en superar el umbral de reset (2.31V)
.meas TRAN t_reset_deassert WHEN V(nrst_node)=2.31 RISE=1
* Tension estable de alimentacion del BNO085
.meas TRAN Vvdd_stable AVG V(vdd_bno) FROM 20m TO 50m
* Tiempo de subida de SCL (10% → 90% de 3.3V = 0.33V → 2.97V)
.meas TRAN t_rise_scl TRIG V(scl)=0.33 RISE=1 TARG V(scl)=2.97 RISE=1
* Tension minima en VDD_BNO durante transient de corriente del BNO085
.meas TRAN Vvdd_min MIN V(vdd_bno) FROM 0 TO 50m
* -----------------------------------------------------------------------
* DIRECTIVAS DE SIMULACION
* -----------------------------------------------------------------------
* 50ms total: captura arranque completo + transaccion I2C + varios pulsos INT
.tran 0 50m 0 10n
.options reltol=0.001
* -----------------------------------------------------------------------
* VALORES ESPERADOS
* -----------------------------------------------------------------------
* t_reset_deassert ≈ 12ms → BNO085 sale de reset 12ms despues del arranque
* Vvdd_stable ≈ 3.28-3.30V → caida de tension por Rtrace=50mOhm + Ibno=6.5mA
* ΔV = 6.5mA × 50mOhm = 0.33mV (despreciable) ✓
* t_rise_scl ≈ 150-200ns → con Rpull=4.7k y Cbus=50pF: τ = 235ns
* tr(10%-90%) = 2.2τ × (80%) = 200ns < 300ns OK ✓
* (especificacion I2C Fast Mode: tr < 300ns)
*
* BNO085 en operacion normal:
* Corriente a 3.3V: 6.5mA tipico, 12mA maximo (fusion completa)
* Tiempo de startup tras reset: 50ms tipico (inicializacion DSP)
* Primer reporte disponible: ~100ms tras arranque
*
* CONEXION TIPICA A ESP32:
* GPIO21 → SDA (I2C SDA, con pull-up 4.7k externo)
* GPIO22 → SCL (I2C SCL, con pull-up 4.7k externo)
* GPIO34 → INT (input only, con pull-up 10k, interrupcion falling edge)
* GPIO13 → NRST (output, normalmente alto; pulsa bajo para hard reset)
*
* CONFIGURACION FIRMWARE:
* wire.begin(21, 22) → ESP32 Arduino I2C
* Wire.setClock(400000) → Fast Mode 400kHz
* BNO08x.begin(0x4A, Wire, GPIO34) → libreria SparkFun BNO08x
*
* REPORTES PARA AUTOPILOTO:
* setReports(ARVR_STABILIZED_RV, 0.01) → heading a 100Hz
* setReports(GYROSCOPE_CALIBRATED, 0.004) → yaw rate a 250Hz
* getRVheading() → degrees (0-360) con compensacion tilt
* getGyroZ() → deg/s (eje Z = yaw rate, positivo = estribor)
.backanno
.end