前面的文章:在树莓派上通过Python读取MPU-6050的数据,文章中介绍了如何通过Python读取MPU6050的位置状态,今天我们讨论如何用读取的状态值来进行三维可视化,通过http协议实现在OpenGL模式下显示3D图像。下面进入主题:
创建简单的WEB服务器
首先基于web.py(它是Python的web框架,它非常简单但功能强大,同时它是开源程序。)创建一个简单的WEB服务器,这里需要通过 apt-get 进行安装
sudo apt-get install python-webpy
然后再创建一个目录,用于存放代码,同时我们将创建一个简单的测试程序。
mkdir webpy cd webpy vi server.py
测试代码如下:
#!/usr/bin/python import web urls = ( '/', 'index' ) class index: def GET(self): return "Hello, world!" if __name__ == "__main__": app = web.application(urls, globals()) app.run()
保存代码server.py并将它设置为可执行文件
chmod +x server.py
然后运行代码
./server.py
你将看到下面的内容,表明服务器在等待请求
http://0.0.0.0:8080/
现在在你的浏览器地址栏中输入:http://树莓派的IP地址:8080,比如:http://192.168.1.65:8080,浏览器将会显示一个包含“Hello,world!”的网页,这样我们就可以利用这个WEB服务器来读取远程数据了。
在服务器中添加传感器的代码
使用下面的代码替换server.py的内容
#!/usr/bin/python import web import smbus import math urls = ( '/', 'index' ) # Power management registers power_mgmt_1 = 0x6b power_mgmt_2 = 0x6c bus = smbus.SMBus(0) # or bus = smbus.SMBus(1) for 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 = 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 return str(get_x_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled))+" "+str(get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)) 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()
服务器端以sudo运行文件,这样可以获取从I2C读取数据的权限。
sudo ./server.py
这样通过你的浏览器将得到X轴和Y轴的值。我的X轴和Y轴的当前值如下:
-28.7291281627 -39.4833542336
数据的三维可视化
因为使用的是Linux系统,因此不知道以下代码是否适用于Windows或mac系统,但需要说明的是代码并不是在树莓派上运行的,那样就不需要http协议了。下面是本次测试的代码。
首先安装OpenGL和pygame
sudo apt-get install python-opengl sudo apt-get install python-pygame
然后将下列代码保存为level.py文件,运行它
#!/usr/bin/python import pygame import urllib from OpenGL.GL import * from OpenGL.GLU import * from math import radians from pygame.locals import * SCREEN_SIZE = (800, 600) SCALAR = .5 SCALAR2 = 0.2 def resize(width, height): glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, float(width) / height, 0.001, 10.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(0.0, 1.0, -5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) def init(): glEnable(GL_DEPTH_TEST) glClearColor(0.0, 0.0, 0.0, 0.0) glShadeModel(GL_SMOOTH) glEnable(GL_BLEND) glEnable(GL_POLYGON_SMOOTH) glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST) glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glLightfv(GL_LIGHT0, GL_AMBIENT, (0.3, 0.3, 0.3, 1.0)); def read_values(): link = "http://192.168.1.65:8080" # Change this address to your settings f = urllib.urlopen(link) myfile = f.read() return myfile.split(" ") def run(): pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE | OPENGL | DOUBLEBUF) resize(*SCREEN_SIZE) init() clock = pygame.time.Clock() cube = Cube((0.0, 0.0, 0.0), (.5, .5, .7)) angle = 0 while True: then = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == QUIT: return if event.type == KEYUP and event.key == K_ESCAPE: return values = read_values() x_angle = values[0] y_angle = values[1] glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glColor((1.,1.,1.)) glLineWidth(1) glBegin(GL_LINES) for x in range(-20, 22, 2): glVertex3f(x/10.,-1,-1) glVertex3f(x/10.,-1,1) for x in range(-20, 22, 2): glVertex3f(x/10.,-1, 1) glVertex3f(x/10., 1, 1) for z in range(-10, 12, 2): glVertex3f(-2, -1, z/10.) glVertex3f( 2, -1, z/10.) for z in range(-10, 12, 2): glVertex3f(-2, -1, z/10.) glVertex3f(-2, 1, z/10.) for z in range(-10, 12, 2): glVertex3f( 2, -1, z/10.) glVertex3f( 2, 1, z/10.) for y in range(-10, 12, 2): glVertex3f(-2, y/10., 1) glVertex3f( 2, y/10., 1) for y in range(-10, 12, 2): glVertex3f(-2, y/10., 1) glVertex3f(-2, y/10., -1) for y in range(-10, 12, 2): glVertex3f(2, y/10., 1) glVertex3f(2, y/10., -1) glEnd() glPushMatrix() glRotate(float(x_angle), 1, 0, 0) glRotate(-float(y_angle), 0, 0, 1) cube.render() glPopMatrix() pygame.display.flip() class Cube(object): def __init__(self, position, color): self.position = position self.color = color # Cube information num_faces = 6 vertices = [ (-1.0, -0.05, 0.5), (1.0, -0.05, 0.5), (1.0, 0.05, 0.5), (-1.0, 0.05, 0.5), (-1.0, -0.05, -0.5), (1.0, -0.05, -0.5), (1.0, 0.05, -0.5), (-1.0, 0.05, -0.5) ] normals = [ (0.0, 0.0, +1.0), # front (0.0, 0.0, -1.0), # back (+1.0, 0.0, 0.0), # right (-1.0, 0.0, 0.0), # left (0.0, +1.0, 0.0), # top (0.0, -1.0, 0.0) ] # bottom vertex_indices = [ (0, 1, 2, 3), # front (4, 5, 6, 7), # back (1, 5, 6, 2), # right (0, 4, 7, 3), # left (3, 2, 6, 7), # top (0, 1, 5, 4) ] # bottom def render(self): then = pygame.time.get_ticks() glColor(self.color) vertices = self.vertices # Draw all 6 faces of the cube glBegin(GL_QUADS) for face_no in xrange(self.num_faces): glNormal3dv(self.normals[face_no]) v1, v2, v3, v4 = self.vertex_indices[face_no] glVertex(vertices[v1]) glVertex(vertices[v2]) glVertex(vertices[v3]) glVertex(vertices[v4]) glEnd() if __name__ == "__main__": run()
请把上面代码中IP地址:http://192.168.1.65:8080 改为您的树莓派IP地址。这样,当您运行level.py时,将会显示MPU6050传感器的当前的三维位置模型,当我们旋转传感器时3D图像将进行实时变化。
你可能会注意到,当传感器静止时图像会发生抖动,这是噪声数据导致的。