Continuando a nossa série de artigos sobre a Raspberry Pi Pico, trazemos neste aqui o uso do integrado MPU6050 através do módulo GY-521, que é um acelerômetro muito comum no mercado e que pode ser utilizado em diversos projetos que precisam de estabilidade através de dados como velocidade e posição.
O MPU6050
O Circuito Integrado MPU6050 foi desenvolvido pela InvenSense (atual TDK) para equipar smartphones, pois ele possui 6 eixos de rastreamento, o acelerômetro nos 3 eixos e um giroscópio de 3 eixos, tudo num único integrado. A TDK já tem atualmente uma versão mais moderna deste CI, é o ICM-4270-P, mas é fácil encontrar no mercado o MPU-6050.
O GY-521
Este é o módulo que auxilia o uso do MPU6050 para quem está na fase de protótipo ou em trabalhos makers. Como é fabricada por diversas empresas, as diferenças aparecem, mas na maioria dos casos respeitam a disposição dos pinos como apresentado na figura 1.

Por ser uma placa que utiliza o protocolo I2C, ela já vem com um endereço padrão, o 0x68HEX, mas é possível usar um outro acelerômetro ou módulo com o endereço 0x69HEX (pino AD0 ao VCC), ou outros sensores usando os pinos XDA e XCL como auxiliares na comunicação I2C. A seguir temos as especificações de cada pino do módulo.
Alimentação e Terra
VCC: É o pino de entrada de energia. O módulo GY-521 possui um regulador de tensão interno, o que permite alimentá-lo com 3.3V ou 5V com segurança.
GND: Pino de aterramento (0V). Deve ser conectado ao GND do seu microcontrolador.
Comunicação I2C (Principal)
SCL (Serial Clock): Fornece o sinal de clock para a comunicação I2C. Ele sincroniza a transferência de dados entre o sensor e o processador.
SDA (Serial Data): É a linha por onde os dados de movimento (aceleração e rotação) são enviados de fato.
I2C Auxiliar (Master)
Estes pinos permitem que o MPU-6050 atue como um "mestre" para outros sensores externos, como um magnetômetro (bússola), sem sobrecarregar o processador principal:
XDA (Auxiliary Data): Linha de dados para o barramento I2C auxiliar.
XCL (Auxiliary Clock): Linha de clock para o barramento I2C auxiliar.
Configuração e Controle
AD0 (Address Select): Define o endereço I2C do módulo.
Se estiver desconectado ou no GND, o endereço padrão será 0x68.
Se estiver conectado ao VCC, o endereço muda para 0x69. Isso permite usar dois módulos MPU-6050 no mesmo projeto.
INT (Interrupt): Pino de interrupção. Ele avisa ao seu microcontrolador quando novos dados estão prontos para serem lidos ou quando um evento específico (como uma queda livre ou movimento brusco) foi detectado.
O Funcionamento do Módulo
Quando o MPU 6050 é inicializado , ele começa a detectar qualquer tipo de movimento e converter tanto o deslocamento entre os eixos X, Y e Z, como também a velocidade que este movimento é feito, convertendo essas informações em dados e transmitindo para a Pi Pico quando estes dados são solicitados.
Na figura 2 temos um gráfico de como funciona fisicamente estes movimentos.

Conectando na Pi Pico 2
Na figura 3 temos o esquema de ligação do módulo com a Pi Pico, lembrando aqui que a fonte de energia vem via USB o qual estamos subindo o código. Em caso de funcionamento fora do ambiente de desenvolvimento , uma fonte externa é necessária.

Código-Fonte
Vamos começar com um código de teste, uma função que captura os dados sem tratamento nenhum e mostrá-lo no shell da IDE do Thonny.
from machine import Pin, I2C
from time import sleep
MPU_ADDR = 0x68
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
# Acorda o MPU6050
i2c.writeto_mem(MPU_ADDR, 0x6B, b'\x00')
def read_raw(reg):
high = i2c.readfrom_mem(MPU_ADDR, reg, 1)[0]
low = i2c.readfrom_mem(MPU_ADDR, reg+1, 1)[0]
value = (high << 8) | low
if value > 32767:
value -= 65536
return value
while True:
ax = read_raw(0x3B) / 16384
ay = read_raw(0x3D) / 16384
az = read_raw(0x3F) / 16384
gx = read_raw(0x43) / 131
gy = read_raw(0x45) / 131
gz = read_raw(0x47) / 131
print("Aceleração (g):", ax, ay, az)
print("Giroscópio (°/s):", gx, gy, gz)
print("-----")
sleep(0.5)
Agora vamos utilizar o módulo para detectarmos o movimento de algo onde ele é aplicado.
from machine import Pin, I2C
from time import sleep
import math
# I2C nos pinos 4 (SDA) e 5 (SCL)
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=100000)
addr = 0x68
# Acorda o MPU6050
i2c.writeto_mem(addr, 0x6B, b'\x00')
def read_raw(reg):
high = i2c.readfrom_mem(addr, reg, 1)[0]
low = i2c.readfrom_mem(addr, reg+1, 1)[0]
value = (high << 8) | low
if value > 32767:
value -= 65536
return value
def get_angles():
ax = read_raw(0x3B) / 16384
ay = read_raw(0x3D) / 16384
az = read_raw(0x3F) / 16384
# Cálculo dos ângulos
pitch = math.degrees(math.atan2(ax, math.sqrt(ay*ay + az*az)))
roll = math.degrees(math.atan2(ay, math.sqrt(ax*ax + az*az)))
return pitch, roll
def detect_gesture(pitch, roll):
# Ajuste fino dos limites conforme seu uso
if roll > 25:
return "Inclinado para a direita"
elif roll < -25:
return "Inclinado para a esquerda"
elif pitch > 25:
return "Levantando a mão"
elif pitch < -25:
return "Baixando a mão"
else:
return "Neutro"
print("Controle gestual iniciado...")
while True:
pitch, roll = get_angles()
gesto = detect_gesture(pitch, roll)
print(f"Pitch={pitch:.1f} Roll={roll:.1f} -> Gesto: {gesto}")
sleep(0.2)
E para finalizar, vamos utilizar o sensor como uma ferramenta, o “nível”.
from machine import Pin, I2C
from time import sleep
import math
# I2C0 nos pinos 4 (SDA) e 5 (SCL)
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=100000)
addr = 0x68
# Acorda o MPU6050
i2c.writeto_mem(addr, 0x6B, b'\x00')
def read_raw(reg):
high = i2c.readfrom_mem(addr, reg, 1)[0]
low = i2c.readfrom_mem(addr, reg+1, 1)[0]
value = (high << 8) | low
if value > 32767:
value -= 65536
return value
def get_angles():
ax = read_raw(0x3B) / 16384
ay = read_raw(0x3D) / 16384
az = read_raw(0x3F) / 16384
pitch = math.degrees(math.atan2(ax, math.sqrt(ay*ay + az*az)))
roll = math.degrees(math.atan2(ay, math.sqrt(ax*ax + az*az)))
return pitch, roll
def nivel_status(pitch, roll, limite=3):
# limite = tolerância em graus para considerar "nivelado"
if abs(pitch) < limite and abs(roll) < limite:
return "NIVELADO"
status = []
if pitch > limite:
status.append("Frente Alta")
elif pitch < -limite:
status.append("Frente Baixa")
if roll > limite:
status.append("Direita Alta")
elif roll < -limite:
status.append("Esquerda Alta")
return " | ".join(status)
print("Nível digital iniciado...")
while True:
pitch, roll = get_angles()
estado = nivel_status(pitch, roll)
print(f"Pitch={pitch:6.2f}° Roll={roll:6.2f}° -> {estado}")
sleep(0.2)
Conclusão
Atualmente o uso de giroscópio e acelerômetro é comum em aplicações onde manter o alinhamento é muito importante, desde de máquinas de precisão como drones, patinetes , aplicações médicas, entre outras. Existem diversos tipos de sensores, e o preço aumenta conforme a velocidade de processamento e a precisão aumentam. Mas para começar este módulo é bem acessível e com ele é possível cometer alguns erros sem grandes prejuízos.
Referências
ICM-42670
https://invensense.tdk.com/download-pdf/icm-42670-p-datasheet/
Série - A Saga de Usar a Pi Pico
https://www.youtube.com/watch?v=YUYZi53PirM&list=PLUg1G7GdWdJxOumCzW3H2cqWJY3a1-kVM
Usando o MPU-6050















