本次的任务是:实现MPU6050-GY-521系列的简单使用。
- 在arduino中读取数据,并显示数据。
- 使用Python进行三维渲染,显示三维的平衡。
主机系统:Ubuntu19.04 (桌面版)
Python:3.71
arduino IDE: 2:1.0.5
arduino 板子:Arduino uno R3
测试板子:MPU6050-GY-512(淘宝都有买)
MPU6050-GY-512
https://playground.arduino.cc/Main/MPU-6050/
https://github.com/makelove/Pi_Self_Driving_Car/tree/master/ROS/Kinetic/IMU/mpu6050
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include
const int MPU_addr=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
Serial.begin(9600);
}
void loop(){
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
Serial.print("AcX = ");Serial.print(AcX);
Serial.print(" | AcY = ");Serial.print(AcY);
Serial.print(" | AcZ = ");Serial.print(AcZ);
Serial.print(" | Tmp = ");Serial.print(Tmp/340.00+36.53); //equation for temperature in degrees C from datasheet
Serial.print(" | GyX = ");Serial.print(GyX);
Serial.print(" | GyY = ");Serial.print(GyY);
Serial.print(" | GyZ = ");Serial.println(GyZ);
delay(333);
}
提示:使用串口接收器查看(arduino IDE 右上角处)
<1>. arduino的代码参考:
https://www.basemu.com/3d-opengl-visualisation-of-the-data-from-an-mpu-6050.html
https://www.basemu.com/reading-data-from-the-mpu-6050-on-the-raspberry-pi-for-python.html
<2>pyhton的代码参考:
arduino向python传送数据:https://www.bilibili.com/video/av64658484/?p=2
python显示三维数据:https://www.basemu.com/3d-opengl-visualisation-of-the-data-from-an-mpu-6050.html
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include
const int MPU_addr=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
Serial.begin(9600);
}
void loop(){
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
Serial.print(AcX);
Serial.print(",");
Serial.print(AcY);
Serial.print(",");
Serial.print(AcZ);
Serial.print(",");
Serial.print(Tmp/340.00+36.53); //equation for temperature in degrees C from datasheet
Serial.print(",");
Serial.print(GyX);
Serial.print(",");
Serial.print(GyY);
Serial.print(",");
Serial.println(GyZ);
delay(333);
}
以逗号为分隔符来输出数据,使用串口接收器查看(arduino IDE 右上角处)
这个也是arduino给电脑(Python)的角度数据。
安装通信模块:serial库,
在命令行:pip install pyserial
# 导入通信的模块
import serial
# 创建串口通信
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5)
# 不断搜索是否有信息传入
while 1:
# 读取串口的信息
val = ser.readline().decode('utf-8')
# 以逗号来分割传入的数据
parsed = val.split(',')
# 去除末尾的数据
parsed = [ x.rstrip() for x in parsed]
# 把数据转化为数字类型
parsed = [ eval(x) for x in parsed]
print(parsed)
在Python里使数据变为列表类型,列表里又是浮点数类型,便于后面的计算。
显示三维的原理:是根据上面的代码先获取数据,再根于数据来显示模型。
所需要到的库:pygame , OpenGL
安装第三方库:pip install pygame ,pip install PyOpenGL
完整python代码:
"""
成功运行
"""
#!/usr/bin/python
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from math import radians
from pygame.locals import *
# 导入通信的模块
import serial
# 创建串口通信
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5)
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():
# 读取串口的信息
val = ser.readline().decode('utf-8')
# 以逗号来分割传入的数据
parsed = val.split(',')
# 去除末尾的数据
parsed = [x.rstrip() for x in parsed]
if(len(parsed) > 2):
# 把数据转化为数字类型
parsed = [eval(x) for x in parsed]
return parsed
else:
return [0,0,0,0,0]
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]/ 131
print(x_angle)
y_angle = values[1]/ 131
print(y_angle)
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 range(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()
显示效果如下:当我们转动一定角度时,在模型里,也对应转动一定的角度。
先运行arduino 代码,在运行pyhton的完整代码,两者在共同一个电脑运行。
作者:张一根
日期:2019/10/4