Acelerômetro mostra a direção para a qual você aponta seu projeto ou sua placa. Hoje vamos estudar o BMI160, um chip acelerômetro e giroscópio. Vamos comunicar o BMI160 com um ESP32, mais especificamente o SeeedStudio Xiao ESP32-C6.
Já falamos de giroscópio antes, neste artigo. Porém acelerômetro vai ser a primeira vez aqui no blog, então vamos aprofundar um pouco. O projeto que vamos fazer usa três LEDs, um para cada eixo (X, Y e Z). Conforme você girar a protoboard, um dos três LEDs vai acender, indicando que estamos virados naquela direção. Cada orientação da protoboard gera acendimento do LED correspondente.
Comprei o BMI160 no Aliexpress neste link, um ótimo custo benefício. Isso visto pela quantidade de projetos legais que dá pra fazer. Por exemplo controle remoto por movimento (tipo Wii U) e robô equilibrista, ambos usam acelerômetros e giroscópios internamente.
Analisando o datasheet do BMI160, vemos que ele funciona alimentado entre 1,7 e 3,6V, portanto nada de alimenta-lo com 5V. Isto serve para o Arduino UNO, caso você vá usa-lo, coloque conversores de nível lógico nas linhas SDA e SCL.
Vemos também que o sensor lê acelerações até 16g. Isto significa 16 vezes a força da gravidade. Já seu giroscópio lê até 2000º por segundo, é um sensor bem completo!.
O projeto – acelerômetro mostra a direção
Vamos implementar um projeto simples porém muito legal didáticamente. Basicamente teremos três LEDs, um para cada eixo de orientação disponível. Usaremos a força da gravidade, que é 9,81m/s² a nosso favor. Quando qualquer um dos três eixos passar de 95% deste valor (0,95 * valor) nós ligaremos o LED correspondente.
Isto significa que necessariamente o sensor, e consequentemente a protoboard, precisa estar numa posição quase “reta”. Valores intermediários de aceleração, entre +0,95 e -0,95, não acionarão LED algum. Portanto apenas valores acima de +0,95 e abaixo de -0,95 ligarão algum LED.
Você já pode imaginar todo tipo de aplicação para o BMI160, conforme comentado acima. Qualquer projeto que necessite saber orientação ou aceleração em tempo real pode se beneficiar dele. No projeto de hoje, com LEDs o acelerômetro mostra a direção.
Hardware/montagem
Como de costume aqui no blog, as montagens são simples e com poucos componentes. Os projetos que trago para você não são grandes nem complexos. Isto tudo é para proporcionar fácil entendimento e rápida montagem/teste.
Hoje não vai ser diferente, precisaremos de um ESP32 ou qualquer outro microcontrolador com i2c. Como por exemplo Attiny85, Arduino UNO, Arduino Leonardo, etc. Usaremos a placa de giroscópio/acelerômetro BMI160 deste link. Precisaremos ainda de três LEDs de cores diferentes (ou da mesma cor, você escolhe) e três resistores de 680 Ohm. Mas pode ser qualquer valor entre 220 Ohm e 1500 Ohm.
O circuito está abaixo e foi montado em uma protoboard de 400 pontos. Usei esta pequena protoboard pois a placa que fiz para o ESP32-C6 é especial. Ela expões todos os seus 11 pinos em uma única linha, ocupando pouco espaço das protoboards.


Independente de como você vai fazer a montagem, siga o diagrama esquemático acima e terá sucesso. O acelerômetro/giroscópio BMI160 tem duas fileiras de pinos para conexão. Apenas uma é necessária, aquela com o SDA e SCL além do 3V3 e GND.
Firmware/código
Eu usei o software IDE do Arduino para programar este exemplo. Precisei instalar uma biblioteca chamada “DFRobot_BMI160”. Ela está disponível para buscar e instalação dentro da própria IDE do Arduino.
Usei como base para meu código o exemplo “Calibrated_sensor_Output” em “File > Examples > FastIMU > Calibrated_sensor_Output”. Modifiquei o exemplo para inserir minha lógica de acendimentos dos LEDs.
O código completo está abaixo. Veja que o endereço do BMI160 é “0x69”, segundo seu próprio datasheet. Observe também que usamos a biblioteca “wire” para comunicação i2c, em 400kHz.
#include "FastIMU.h"
#include <Wire.h>
#define IMU_ADDRESS 0x69 //Change to the address of the IMU
#define PERFORM_CALIBRATION //Comment to disable startup calibration
BMI160 IMU; //Change to the name of any supported IMU!
// Currently supported IMUS: MPU9255 MPU9250 MPU6886 MPU6500 MPU6050 ICM20689 ICM20690 BMI055 BMX055 BMI160 LSM6DS3 LSM6DSL QMI8658
calData calib = { 0 }; //Calibration data
AccelData accelData; //Sensor data
GyroData gyroData;
MagData magData;
long sensorTime= 0;
void setup() {
Wire.begin();
Wire.setClock(400000); //400khz clock
Serial.begin(115200);
pinMode(D0, OUTPUT);
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
int err = IMU.init(calib, IMU_ADDRESS);
if (err != 0) {
Serial.print("Error initializing IMU: ");
Serial.println(err);
while (true) {
;
}
}
#ifdef PERFORM_CALIBRATION
Serial.println("FastIMU calibration & data example");
if (IMU.hasMagnetometer()) {
delay(1000);
Serial.println("Move IMU in figure 8 pattern until done.");
delay(3000);
IMU.calibrateMag(&calib);
Serial.println("Magnetic calibration done!");
}
else {
delay(5000);
}
delay(5000);
Serial.println("Keep IMU level.");
delay(5000);
IMU.calibrateAccelGyro(&calib);
Serial.println("Calibration done!");
Serial.println("Accel biases X/Y/Z: ");
Serial.print(calib.accelBias[0]);
Serial.print(", ");
Serial.print(calib.accelBias[1]);
Serial.print(", ");
Serial.println(calib.accelBias[2]);
Serial.println("Gyro biases X/Y/Z: ");
Serial.print(calib.gyroBias[0]);
Serial.print(", ");
Serial.print(calib.gyroBias[1]);
Serial.print(", ");
Serial.println(calib.gyroBias[2]);
if (IMU.hasMagnetometer()) {
Serial.println("Mag biases X/Y/Z: ");
Serial.print(calib.magBias[0]);
Serial.print(", ");
Serial.print(calib.magBias[1]);
Serial.print(", ");
Serial.println(calib.magBias[2]);
Serial.println("Mag Scale X/Y/Z: ");
Serial.print(calib.magScale[0]);
Serial.print(", ");
Serial.print(calib.magScale[1]);
Serial.print(", ");
Serial.println(calib.magScale[2]);
}
delay(5000);
IMU.init(calib, IMU_ADDRESS);
#endif
//err = IMU.setGyroRange(500); //USE THESE TO SET THE RANGE, IF AN INVALID RANGE IS SET IT WILL RETURN -1
//err = IMU.setAccelRange(2); //THESE TWO SET THE GYRO RANGE TO ±500 DPS AND THE ACCELEROMETER RANGE TO ±2g
if (err != 0) {
Serial.print("Error Setting range: ");
Serial.println(err);
while (true) {
;
}
}
}
void loop() {
if(millis() - sensorTime > 50){
sensorTime= millis();
IMU.update();
IMU.getAccel(&accelData);
float x= accelData.accelX;
float y= accelData.accelY;
float z= accelData.accelZ;
Serial.print(x);
Serial.print("\t");
Serial.print(y);
Serial.print("\t");
Serial.print(z);
Serial.print("\t");
IMU.getGyro(&gyroData);
Serial.print(gyroData.gyroX);
Serial.print("\t");
Serial.print(gyroData.gyroY);
Serial.print("\t");
Serial.print(gyroData.gyroZ);
if (IMU.hasMagnetometer()) {
IMU.getMag(&magData);
Serial.print("\t");
Serial.print(magData.magX);
Serial.print("\t");
Serial.print(magData.magY);
Serial.print("\t");
Serial.print(magData.magZ);
}
if (IMU.hasTemperature()) {
Serial.print("\t");
Serial.println(IMU.getTemp());
}
else {
Serial.println();
}
if(x > 0.95 || x < -0.95){
digitalWrite(D0, HIGH);
digitalWrite(D1, LOW);
digitalWrite(D2, LOW);
}else if(y > 0.95 || y < -0.95){
digitalWrite(D0, LOW);
digitalWrite(D1, HIGH);
digitalWrite(D2, LOW);
}else if(z > 0.95 || z < -0.95){
digitalWrite(D0, LOW);
digitalWrite(D1, LOW);
digitalWrite(D2, HIGH);
}else{
digitalWrite(D0, LOW);
digitalWrite(D1, LOW);
digitalWrite(D2, LOW);
}
}
}
A parte que eu adicionei ao código está abaixo. Veja que eu usei condicionais IF() comparando os eixos X, Y e Z com valores “> 0.95” e “< -0.95”. Isso garante uma faixa de 5% de tolerância/inclinação na detecção da orientação da placa.
if(x > 0.95 || x < -0.95){
digitalWrite(D0, HIGH);
digitalWrite(D1, LOW);
digitalWrite(D2, LOW);
}else if(y > 0.95 || y < -0.95){
digitalWrite(D0, LOW);
digitalWrite(D1, HIGH);
digitalWrite(D2, LOW);
}else if(z > 0.95 || z < -0.95){
digitalWrite(D0, LOW);
digitalWrite(D1, LOW);
digitalWrite(D2, HIGH);
}else{
digitalWrite(D0, LOW);
digitalWrite(D1, LOW);
digitalWrite(D2, LOW);
}
Colocando para funcionar
Após copiar o código acima e colar na sua IDE do Arduino, clique no botão “>” upload que está no canto superior esquerdo. Após alguns segundos o código será gravado no seu ESP32 ou Arduino. Aguarde então mais alguns segundos e um dos LEDs deve acender.
Movimente a placa nos três eixos e observer os LEDs acendendo um após o outro. Eu fiz um vídeo ilustrando o funcionamento do código no circuito, veja bem no início do artigo.



Caso tenha comentários ou informações a acrescentar, comente no campo abaixo ou lá no Youtube do blog FritzenLab. Até a próxima.





