I have had some of these electronic components for a long time, but I never got around to trying them. I want to create an IMU (Inertial Measurement Unit) without any particular need. There are probably already ready-made, simple, and better solutions, so this is just for fun. The sensor is the InvenSense MPU-6050 Six-Axis Gyro + Accelerometer. This sensor is not recommended for use in new projects as it has been replaced by a newer generation. The chip also includes a Digital Motion Processor™ (DMP™), which I do not wish to use, even though I am confident the result would be better.

Here is the block diagram and test setup, but in this case, the compass is missing.

mpu-6000-family-diagram

And here is roughly what the test platform looks like: Wemos S2 Mini ESP32-S2 and GY-521 (MPU6050)

IMU hardware

To start, I’ll at least try to read the RAW data from the sensor. Datasheet for MPU-6050 and register map.

import micropython, esp
from machine import Pin, SoftI2C

key = Pin(0, Pin.IN, Pin.PULL_UP)  # reset button
led = Pin(15, Pin.OUT)  # on-board LED

# MPU registers
ADDRESS = 0x68
ACCEL_RANGE_2G = 0x00
GYRO_RANGE_250DEG = 0x00
PWR_MGMT_1 = 0x6B
PWR_MGMT_2 = 0x6C
ACCEL_XOUT0 = 0x3B
CONFIG = 0x1A
GYRO_CONFIG = 0x1B
ACCEL_CONFIG = 0x1C

i2c = SoftI2C(scl=Pin(36), sda=Pin(38), freq=400000)
i2c.start()
i2c.writeto(ADDRESS, bytearray([PWR_MGMT_1, 0x00]))
i2c.writeto(ADDRESS, bytearray([ACCEL_CONFIG, ACCEL_RANGE_2G]))
i2c.writeto(ADDRESS, bytearray([GYRO_CONFIG, GYRO_RANGE_250DEG]))
i2c.writeto(ADDRESS, bytearray([CONFIG, 0x00]))
i2c.stop()

loop = True
led.value(1)

while loop:
    i2c.start()
    raw = i2c.readfrom_mem(ADDRESS, ACCEL_XOUT0, 14)
    i2c.stop()
    
    print(raw)
    
    if key.value() == 0:
        loop = False

led.value(0)

The result should look something like this. It is not very useful, but at least we know that communication with the sensor works.

b'\xcb\\\x02\x84\xd30\xf8`\xf1\xb5\xfc\xf7\xee\xf6'
b'\xd2\xb4\x01\x9c\xd5T\xf8p\xf0\xd9\xfc\xee\xec_'
b'\xce\xd0\x00\xec\xd3\xc0\xf8\x80\xf0\x9f\xf8\xb6\xea\x8b'
b'\xcdx\xff\\\xd9\x00\xf8\x90\xefH\xfb\x0e\xea '
b'\xcfX\x00\x88\xd5p\xf8`\xef\x8d\xf6|\xe9\x85'
b'\xcet\x00\x08\xd6|\xf8p\xef\xb2\xf3\xbf\xe9\xde'
b'\xd2T\xfe\xc0\xd6P\xf8\x80\xef\xe7\xf3e\xeb\x00'
b'\xd5\xcc\xff\xe8\xd6\xac\xf8\x90\xef\xae\xf6\xa3\xeb\x8b'
b'\xd4\xa4\x00\xd8\xd5\x84\xf8\xa0\xef]\xfa\\\xeb_'
b'\xd6L\x00l\xd6\x00\xf8\x90\xef2\xfek\xeb\\'
b'\xd3\\\x01\x84\xd3,\xf8\x80\xefO\xfe\xaf\xe9\x83'
b'\xd6<\x01\xd8\xd6h\xf8\x90\xed\x73\x05\xcf\xe7\xd9'

Everything together, along with future posts, can be found here.

Now, let’s try to make the MPU6050 generate an interrupt and read sensor data within the interrupt routine. I have removed the print(raw) to measure timing and sampling stability.

INT_ENABLE = 0x38

interrupt_pin = Pin(40, Pin.IN, Pin.PULL_UP)  # Connect INT pin from MPU6050 to GPIO40

# Variable to track interrupt handling
handle_interrupts = True

# Interrupt handler
def handle_interrupt(pin):
    global handle_interrupts
    if handle_interrupts:
        i2c.start()
        raw = i2c.readfrom_mem(ADDRESS, ACCEL_XOUT0, 14)
        i2c.stop()
        # do something

# Attach interrupt
interrupt_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)

while True:
    if key.value() == 0:
        handle_interrupts = False  # Stop handling interrupts
        interrupt_pin.irq(handler=None)  # Detach the interrupt handler
        break

I will attempt to make the ESP32 act as a Wi-Fi access point and broadcast RAW sensor data, then try to use that data to determine orientation on the receiving computer.