i2c Interfacing

How it’s implemented

Two modules define classes which interface with the sensor. mpu9250_i2c collects the raw data. joystick_reader stores and averages sensor data over time and makes it available to the Blender addon when needed.

The sensor uses inter-integrated circuit, or “i squared c” to communicate with the Raspberry Pi. I2C consists of two wires; the SDA (Serial data line) and SCL (Serial clock line) and pull up resistors which keep those lines high until pulled low. The SCL switches between high and low at a fixed rate. Based on the offset between the highs and lows of the SCL line and highs and lows of the SDA line, I2C devices can interpret bit data. i2C transfers data grouped into 8 bits (1 byte). The first byte of the transfer is always the address of the receiving device so more than one device can be connected at a time, except for the last bit, which indicates whether the master device should write (0) or read (1) bits from the slave device.

The next address of a transfer is the address of the internal register of the receiving I2C device. This is generally followed with data to write starting at that location.

mpu9250_i2c handles the I2C communication in this project. It initializes the accelerometer by transmitting bytes to appropriate registers to reset it to a standard mode with the mpu9250_i2c.MPU6050_start() function. This tells the sensor, among other things, to sample the gyroscope at 250 degrees per second.

As the blender addon thread loops, mpu9250_i2c.mpu6050_conv() is called regularly. This function uses mpu9250_i2c.read_raw_bits() to extract bits from the registers in the mpu9250 where sensor readings are stored. It actually extracts one byte from the specified register and then extracts the byte from the subsequent register. Those two bytes, the high byte and the low byte, together form the reading for that sensor. Each reading is converted to degrees and adjusted based on the sensitivity setting of the sensor (250 degrees per second).

The JoystickReader class is used to interface between the blender addon and the mpu9250 conversion module. JoystickReader contains an instance of Axis for each of the 3 acceleration sensors and each of the 3 gyroscope sensors, 6 total. JoystickReader collects values from mpu6050_conv and passes them to the Axis objects. The Axis objects keep running averages of recently read values based on their settings. JoystickReader also tracks what GPIO pins the trigger button and the top button of the Joystick are wired to. It sets up the GPIO system using the RPi.GPIO library.

When JoystickReader.get_averages is called by the blender addon, JoystickReader retrieves the current average (or the last read, if that setting is selected) from each Axis. JoystickReader also determines whether the GPIO lines that the trigger and top are wired to are high or low. JoystickReader then assembles that in a dictionary and returns it for use by the Blender addon.

Example return dictionary from JoystickReader.get_averages
return {
 'ax':self.acceleration_x.average,
 'ay':self.acceleration_y.average,
 'az':self.acceleration_z.average,
 'wx':self.gyro_x.average,
 'wy':self.gyro_y.average,
 'wz':self.gyro_z.average,
 'top': GPIO.input(self.top_pin),
 'trigger': GPIO.input(self.trigger_pin)
}

MPU9250_i2c

This module interfaces directly with the sensor.

This code was largely taken from this article by Joshua Hrisko.

mpu9250_i2c.MPU6050_start()[source]

This function initializes the sensor in the following manner:

  1. Set the sample rate div to zero (no change in the sample rate.)

  2. Set the power management register to all zeros, with the following effects:

    • Set to not sleep mode.

    • Set to normal sample mode.

    • Set to normal gyro power mode.

    • Set to normal voltage generator mode.

    • Set to default clock speed.

  3. Write the power management register again, to reset internal registers.

  4. Write the config register with all zeros, with the following effects:

    • Set FIFO mode to normal.

    • Set FSYNC to normal.

    • Set DLPF_CFG to normal.

  5. Write all zeros to the GYRO_CONFIG register with the following effects:

    • Set sample rate to 250 degrees/second

    • Do not bypass DPLF

  6. Write all zeros to the ACCEL_CONFIG register, setting the accel sample rate to +- 2g/second.

  7. Write a 1 to INT_ENABLE register, to enable interrupt when sensor gets any reading.

Returns

A tuple of (gyro sample rate, acceleration sample rate)

Return type

tuple

mpu9250_i2c.read_raw_bits(register)[source]

This reads the raw bits at a high sensor register and the raw bits at the subsequent register (the low byte). It combines those value to get the total read for the sensor.

Parameters

register (byte) – The high byte of a sensor read register.

Returns

The sensor reading, 16 bits.

Return type

int

mpu9250_i2c.mpu6050_conv()[source]

Gets the sensor readings for each register by calling read_raw_bits() for each sensor register.

Converts those readings to floats of the appropriate magnitude by multiplying by the quantity per second that the sensor is set to.

Returns

A tuple of (ax, ay, az, wx, wy, wz)

Return type

tuple

mpu9250_i2c.MPU6050_ADDR = 104

The i2c address of the sensor, which is 104.

mpu9250_i2c.PWR_MGMT_1 = 107

Power management register

Bit Mapping

Bit

Name

Description

7

H_RESET

1 resets internal registers and restores default. Auto clears.

6

SLEEP

Sets chip to sleep mode.

5

CYCLE

Sets chip to a single sample mode. (Not used)

4

GYRO_STANDBY

Lower power mode for Gyros.

3

PD_PTAT

Power done internal PTAT voltage generator. (Not used)

2-0

CLKSEL

Selects clock speed.

mpu9250_i2c.SMPLRT_DIV = 25

Sample Rate Divider register.

Internal sample rate divided by this number to generate the final sample rate.

Bit Mapping

Bit

Name

Description

7-0

SMPLRT_DIV

Sample Rate Divider

Final Sample Rate = Internal_Sample_Rate / (1 + SMPLRT_DIV)

mpu9250_i2c.CONFIG = 26

Configuration.

Bit Mapping

Bit

Name

Description

7

reserved

6

FIFO_MODE

1 means additional writes will not be added to fifo

5-3

EXT_SYNC_SET

Enables FSYNC pin data to be sampled for short strobes

2-0

DLPF_CFG”

Not used

mpu9250_i2c.GYRO_CONFIG = 27

Gyroscope configuration

Bit Mapping

Bit

Name

Description

7

XGYRO_Cten

X Gyro Self Test

6

YGYRO_Cten

Y Gyro Self Test

5

ZGYRO_Cten

Z Gyro Self Test

4-3

GYRO_FS_SEL

Sets Gyro sample rate

2

reserved

1

Fchoice_b

Bypass dplf - not used

GYRO_FS_SEL sample rates are:
  • 00 = +250 degrees/second

  • 01 = +500 degrees/second

  • 10 = +1000 degrees/second

  • 11 = +2000 degrees/second

mpu9250_i2c.ACCEL_CONFIG = 28

Accelerometer configuration

Bit Mapping

Bit

Name

Description

7

ax_st_en

X Accel Self Test

6

ay_st_en

Y Accel Self Test

5

az_st_en

Z Accel Self Test

4-3

ACCEL_FS_SEL

Sets Accel Sample rate

2-0

reserved

ACCEL_FS_SEL sample rates are:
  • 00 = +-2 g/second

  • 01 = +-4 g/second

  • 10 = +-8 g/second

  • 11 = +-16 g/second

mpu9250_i2c.INT_ENABLE = 56

Interrupt Enable

Bit Mapping

Bit

Name

Description

7

WOM_EN

1 - enable interrupt for wake on motion

6

reserved

5

FIFO_OVERFLOW_EN

1 - enable interrupt fifo overflow

4

FSYNC_INT_EN

1 - enable fsync interrupt

3

reserved

2

reserved

1

RAW_RDY_EN

1 - enable raw sensor data ready interrupt

mpu9250_i2c.ACCEL_XOUT_H = 59

X-Accelerometer High Byte

mpu9250_i2c.ACCEL_YOUT_H = 61

Y-Accelerometer High Byte

mpu9250_i2c.ACCEL_ZOUT_H = 63

Z-Accelerometer High Byte

mpu9250_i2c.GYRO_XOUT_H = 67

X-Gyro High Byte

mpu9250_i2c.GYRO_YOUT_H = 69

Y-Gyro High Byte

mpu9250_i2c.GYRO_ZOUT_H = 71

Z-Gyro High Byte

mpu9250_i2c.bus = None

bus is initialized to smbus

Type

smbus2.SMBus

mpu9250_i2c.gyro_sens = 250

set to returned value from MPU6050_start(), which is 250 degrees per second

mpu9250_i2c.accel_sens = 2

set to returned value from MPU6050_start(), which is 2 Gs per second

joystick_reader

Interfaces with the mpu9250_i2c.py script. JoystickReader retrieves values from that script, and stores them in Axis objects.

The Axis objects average values as they come in based on their parameters.

When the Blender addon needs readings, JoystickReader collects the averages from each Axis and returns them as a dictionary.

class joystick_reader.Axis(name, keep_vals=10, weight=0)[source]

Stores rolling average of recorded values for an axis.

Parameters
  • name (str) – name of the axis, e.g. ‘ax’,’wy’,etc.

  • keep_vals (int) – number of recently read values to keep for averaging.

  • weight (float) – factor to weigh last-read value

name

name of the axis

vals

last few values recorded

average

current average

keep_vals

number of values to keep

weight

weights the last reading

add_val(val)[source]

Append value to recently-read values and update average based on weighting.

Parameters

val (number) – value to add

get_last_val()[source]

Get the last read value of this axis.

Returns

last value

Return type

number

class joystick_reader.JoystickReader(trigger_pin, top_pin, keepvals=10, weight=0)[source]

Interfaces with sensor and updates axis objects with readings.

Parameters
  • trigger_pin (int) – The raspberry Pi GPIO pin that the trigger button is wired to.

  • top_pin (int) – The raspberry Pi GPIO pin that the top button is wired to.

  • keep_vals (int) – The number of sensor readings each axes will store for averaging.

  • weight (float) – The factor by which each axis will weight the last-read sensor value.

axes

A list of the used axes.

Includes self.acceleration_x, self.acceleration_y, self.acceleration_z, self.gyro_x, self.gyro_y, and self.gyro_z

Ref

joystick_reader.Axis

Type

Axis

load_pins(trigger_pin, top_pin)[source]

Change the RPi.GPIO pins for the top and trigger line.

Turns off input detection for previously active pins.

Parameters
  • trigger_pin (int) – The raspberry Pi GPIO pin that the trigger button is wired to.

  • top_pin (int) – The raspberry Pi GPIO pin that the top button is wired to.

load_keep_vals_and_weight(new_keep_vals, new_weight)[source]

Changes retained values length and last value weighting for all axes.

Parameters
  • keep_vals (int) – The number of sensor readings each axes will store for averaging.

  • weight (float) – The factor by which each axis will weight the last-read sensor value.

end()[source]

Turns off detection for currently active RPi.GPIO pins.

get_round_of_random_values()[source]

Adds a value between -5 and 5 to each Axis.

Used for debugging Blender addon outside of Raspberry Pi environment.

zero_gyro()[source]

Zeros gyroscopes.

get_vals_from_sensor()[source]

Gets values from mpu9250_i2c.py , which interfaces with the sensor.

Passes sensor reads to appropriate Axis object.

If sensor fails to read, sets global error flag.

get_averages()[source]

Returns average readings for each Axis object as a dictionary.

Returns

Axis averages and GPIO pin reads.

Return type

dict

get_last()[source]

Returns last readings for each Axis object as a dictionary.

Returns

Axis last-reads and GPIO pin reads.

Return type

dict