MCU & FPGA Sensores BNO055: Guia Completo de Orientação Absoluta, I2C, Calibração e Driver Robusto em C

BNO055: Guia Completo de Orientação Absoluta, I2C, Calibração e Driver Robusto em C


5. Driver Robusto em C para o BNO055 com Tratamento de Timeout e Recuperação de Barramento

Agora vamos estruturar uma implementação em C pensada para uso profissional em microcontroladores como STM32, RP2040, nRF52 ou similares, considerando os problemas reais de clock stretching e timeout discutidos anteriormente.

O objetivo aqui não é apenas “ler o sensor”, mas construir uma camada confiável, com retry automático, verificação de CHIP_ID e recuperação do barramento quando necessário.

Assumiremos que exista uma camada HAL mínima com as funções:

int I2C_Write(uint8_t addr, uint8_t *data, uint16_t len);
int I2C_Read(uint8_t addr, uint8_t *data, uint16_t len);
void delay_ms(uint32_t ms);
void I2C_RecoverBus(void);

Onde:

  • Retorno 0 = sucesso
  • Retorno diferente de 0 = erro

5.1 Endereço I2C

O BNO055 possui dois possíveis endereços:

  • 0x28 (ADR = GND)
  • 0x29 (ADR = VDDIO)

Definimos:

#define BNO055_ADDR 0x28

5.2 Escrita com Retry

int BNO055_WriteReg(uint8_t reg, uint8_t value)
{
    uint8_t buffer[2];
    buffer[0] = reg;
    buffer[1] = value;

    for(int retry = 0; retry < 3; retry++)
    {
        if(I2C_Write(BNO055_ADDR, buffer, 2) == 0)
            return 0;

        I2C_RecoverBus();
        delay_ms(2);
    }

    return -1;
}

Aqui usamos três tentativas antes de declarar falha. Isso aumenta drasticamente robustez em ambientes ruidosos.


5.3 Leitura com Retry

int BNO055_ReadReg(uint8_t reg, uint8_t *data, uint16_t len)
{
    for(int retry = 0; retry < 3; retry++)
    {
        if(I2C_Write(BNO055_ADDR, ®, 1) == 0)
        {
            if(I2C_Read(BNO055_ADDR, data, len) == 0)
                return 0;
        }

        I2C_RecoverBus();
        delay_ms(2);
    }

    return -1;
}

Esse padrão é essencial porque muitos travamentos ocorrem entre o envio do registrador e a leitura subsequente.


5.4 Inicialização Segura Completa

int BNO055_Init(void)
{
    uint8_t id;

    if(BNO055_ReadReg(0x00, &id, 1) != 0)
        return -1;

    if(id != 0xA0)
        return -2;

    // CONFIG MODE
    if(BNO055_WriteReg(0x3D, 0x00) != 0)
        return -3;

    delay_ms(25);

    // RESET
    if(BNO055_WriteReg(0x3F, 0x20) != 0)
        return -4;

    delay_ms(650);

    // NDOF MODE
    if(BNO055_WriteReg(0x3D, 0x0C) != 0)
        return -5;

    delay_ms(25);

    return 0;
}

Note que usamos delays conservadores. Em sistemas críticos, prefira robustez à velocidade.


5.5 Leitura de Quaternion

int BNO055_ReadQuaternion(float *qw, float *qx,
                           float *qy, float *qz)
{
    uint8_t buffer[8];

    if(BNO055_ReadReg(0x20, buffer, 8) != 0)
        return -1;

    int16_t raw_w = (buffer[1] << 8) | buffer[0];
    int16_t raw_x = (buffer[3] << 8) | buffer[2];
    int16_t raw_y = (buffer[5] << 8) | buffer[4];
    int16_t raw_z = (buffer[7] << 8) | buffer[6];

    *qw = raw_w / 16384.0f;
    *qx = raw_x / 16384.0f;
    *qy = raw_y / 16384.0f;
    *qz = raw_z / 16384.0f;

    return 0;
}

Observe a ordem LSB primeiro, conforme especificado no datasheet.


5.6 Conversão para Ângulos

void Quaternion_ToEuler(float qw, float qx,
                        float qy, float qz,
                        float *roll,
                        float *pitch,
                        float *yaw)
{
    *roll = atan2f(2.0f*(qw*qx + qy*qz),
                   1.0f - 2.0f*(qx*qx + qy*qy));

    *pitch = asinf(2.0f*(qw*qy - qz*qx));

    *yaw = atan2f(2.0f*(qw*qz + qx*qy),
                  1.0f - 2.0f*(qy*qy + qz*qz));
}

5.7 Estrutura de Aplicação Principal

int main(void)
{
    if(BNO055_Init() != 0)
    {
        // tratar erro
        while(1);
    }

    while(1)
    {
        float qw, qx, qy, qz;
        float roll, pitch, yaw;

        if(BNO055_ReadQuaternion(&qw, &qx, &qy, &qz) == 0)
        {
            Quaternion_ToEuler(qw, qx, qy, qz,
                               &roll, &pitch, &yaw);
        }

        delay_ms(10);
    }
}

Isso produz orientação estável a 100 Hz aproximadamente.


5.8 Considerações Profissionais Importantes

  1. Nunca mudar modo operacional durante leitura contínua.
  2. Sempre verificar calibração antes de usar dados críticos.
  3. Em aplicações industriais, implementar watchdog para I2C.
  4. Considerar uso de RTOS separando:
    • Task I2C
    • Task processamento
    • Task aplicação

Na próxima seção vamos abordar:

  • Salvamento e restauração de calibração
  • Leitura de vetores de aceleração linear
  • Uso para estimativa de movimento
  • Limitações do BNO055 comparado a fusão externa (Madgwick/Mahony)
  • Considerações para projetos críticos como robótica e navegação
0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x