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.

 

 

Figura 1 - O MPU6050 no módulo.
Figura 1 - O MPU6050 no módulo.

 

 

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.

 

 

Figura 2 - Os movimentos aplicados no módulo.
Figura 2 - Os movimentos aplicados no módulo.

 

 

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.

 

 

Figura 3 - Esquema Elétrico.
Figura 3 - Esquema Elétrico.

 

 

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

https://youtu.be/BdE6Sk9MgbI 

 

NO YOUTUBE


NOSSO PODCAST