Friday, December 12, 2014

58. Exploring the Pi B+'s Ports IV - Reading the MPU-6050 using Python

26,000 page views!!
The last post described the 3D wireframe demonstration of the MPU-6050's rotations (ie the GY-521 breakout board) about the x-, y- and z-axes, and other scripts which displayed the readout of quaternions etc.  Those test programs were written in the C++ programming language. 

This time test programs are written in Python, giving me a better chance of understanding what's going on!  The circuitry is identical to that used in the last post, and of course, the I2C interface has previously been enabled.

smbus is a Python module which allows SMBus (system management bus - a sub-set of the I2C protocol) access through the I2C interface on Linux hosts. This is the key module for Python access.

Reading Accelerometer Data


In this first program, in addition to reading the data from the accelerometer, the output values are sent to a web page, just for fun!  The address of the web page depends on the Pi's IP address, which can be found using the terminal command

ifconfig

and appending :8080 to the end.   For example,

http://ip-address-of-your-pi:8080

Here's the Python code for server.py:

#!/usr/bin/python
#This python program serves a web page which can be accessed via
#local wifi network, giving x and y rotations of the MPU-6050
# Written by Andrew Birkett
# (http://blog.bitify.co.uk/2013/11/3d-opengl-visualisation-of-data-from.html)
# and modified by S&S Dec 2014
import web
import smbus
import math
urls = (
'/', 'index'
)
# Power management registers
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c
bus = smbus.SMBus(1) # or bus = smbus.SMBus(0) for pre-Revision 2 boards
address = 0x68 # This is the address value read via the i2cdetect command
def read_byte(adr):
return bus.read_byte_data(address, adr)
def read_word(adr):
high = bus.read_byte_data(address, adr)
low = bus.read_byte_data(address, adr+1)
val = (high << 8) + low
return val
def read_word_2c(adr):
val = read_word(adr)
if (val >= 0x8000):
return -((65535 - val) + 1)
else:
return val
def dist(a,b):
return math.sqrt((a*a)+(b*b))
def get_y_rotation(x,y,z):
radians = math.atan2(x, dist(y,z))
return -math.degrees(radians)
def get_x_rotation(x,y,z):
radians = math.atan2(y, dist(x,z))
return math.degrees(radians)
class index:
def GET(self):
accel_xout = read_word_2c(0x3b)
accel_yout = read_word_2c(0x3d)
accel_zout = read_word_2c(0x3f)
accel_xout_scaled = accel_xout / 16384.0
accel_yout_scaled = accel_yout / 16384.0
accel_zout_scaled = accel_zout / 16384.0
xrot = get_x_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
yrot = get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
# Return angle values to 1 decimal place
return "x-rotation: %.1f" %xrot+" degrees. y-rotation: %.1f" %yrot+" degrees"
if __name__ == "__main__":
# Now wake the 6050 up as it starts in sleep mode
bus.write_byte_data(address, power_mgmt_1, 0)
app = web.application(urls, globals())
app.run()
view raw server.py hosted with ❤ by GitHub
Andrew Birkett's really neat code reads the accelerometer part of the MPU-6050 and prints out the x- and y-axis rotations which are calculated by the program.  The output via the web page looks like this:
x-rotation: 0.2 degrees.   y-rotation: -2.2 degrees.

The values of course change as the MPU-6050 is rotated about its x- and y-axes. for example:
x-rotation: 50.8 degrees.   y-rotation: 18.4 degrees.
The web page has to be refreshed to see new values.

Reading Gyro & Accelerometer Data

This program, Reading6050.py, also written by Andrew Birkett, looks like this:
#!/usr/bin/python
import smbus
import math
# Power management registers
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c
def read_byte(adr):
return bus.read_byte_data(address, adr)
def read_word(adr):
high = bus.read_byte_data(address, adr)
low = bus.read_byte_data(address, adr+1)
val = (high << 8) + low
return val
def read_word_2c(adr):
val = read_word(adr)
if (val >= 0x8000):
return -((65535 - val) + 1)
else:
return val
def dist(a,b):
return math.sqrt((a*a)+(b*b))
def get_y_rotation(x,y,z):
radians = math.atan2(x, dist(y,z))
return -math.degrees(radians)
def get_x_rotation(x,y,z):
radians = math.atan2(y, dist(x,z))
return math.degrees(radians)
bus = smbus.SMBus(1) # or bus = smbus.SMBus(1) for Revision 2 boards
address = 0x68 # This is the address value read via the i2cdetect command
# Now wake the 6050 up as it starts in sleep mode
bus.write_byte_data(address, power_mgmt_1, 0)
print "gyro data"
print "---------"
gyro_xout = read_word_2c(0x43)
gyro_yout = read_word_2c(0x45)
gyro_zout = read_word_2c(0x47)
print "gyro_xout: ", gyro_xout, " scaled: ", (gyro_xout / 131)
print "gyro_yout: ", gyro_yout, " scaled: ", (gyro_yout / 131)
print "gyro_zout: ", gyro_zout, " scaled: ", (gyro_zout / 131)
print
print "accelerometer data"
print "------------------"
accel_xout = read_word_2c(0x3b)
accel_yout = read_word_2c(0x3d)
accel_zout = read_word_2c(0x3f)
accel_xout_scaled = accel_xout / 16384.0
accel_yout_scaled = accel_yout / 16384.0
accel_zout_scaled = accel_zout / 16384.0
print "accel_xout: ", accel_xout, " scaled: ", accel_xout_scaled
print "accel_yout: ", accel_yout, " scaled: ", accel_yout_scaled
print "accel_zout: ", accel_zout, " scaled: ", accel_zout_scaled
print "x rotation: " , get_x_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
print "y rotation: " , get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
view raw Reading6050.py hosted with ❤ by GitHub

The program produces results like this:
pi@raspberrypi ~ $ sudo python Reading6050.py
gyro data
---------
gyro_xout:  -202  scaled:  -2
gyro_yout:  -191  scaled:  -2
gyro_zout:  11  scaled:  0

accelerometer data
------------------
accel_xout:  176  scaled:  0.0107421875
accel_yout:  160  scaled:  0.009765625
accel_zout:  15364  scaled:  0.937744140625
x rotation:  0.596614942501
y rotation:  -0.656278927449
pi@raspberrypi ~ $ 
So what does the program do and what do these results mean?

No comments:

Post a Comment