由于接触陀螺仪比较长时间了,一直有一个念想,就是做一个自己的陀螺仪3D模型显示,功夫不负有心人,终于某个早晨在一个技术群里发现了有processing这个软件可以比较简单的实现(虽然之前也知道C#等这些传统意义上的上位机豪强可以实现,但总归有些生疏隔阂一般,再一个也是基于时间成本考虑)。于是乎花了一天的时间将这个3D模型做了出来,效果还不错,嘻嘻🤭~
视频链接:https://www.bilibili.com/video/BV11y4y1m7t1
在这期间遇到了一个问题,在学长的帮助下成功解决,现在来描述一下这个具体过程:
首先有些东西必须描述清楚:
- 陀螺仪得出来得角度是有正有负
- 串口每次只能发1byte,也就是8bits
问题
在这两个大前提下,问题就慢慢显露了出来。首先1byte最大能表示2^8=255,难道还要我陀螺仪转的角度不超过255°不成,那显然是byte太刁蛮了,你byte表示不了这么多关我陀螺仪什么事对吧。这里就是第一个问题,陀螺仪得角度超过255时导致byte溢出又直接回到0,试着想一下3D模型上转了200多度了再继续转直接给你回到到0度,就像向日葵跟着太阳自东向西,第二天一个猛回头从西边甩到东边,这谁受得了?
第二个问题也呼应了标题,串口不能发负数的问题。这里要来一波小定义:byte数据类型(字节型)用一个字节(byte)储存,可区别256个数字,取值范围:0-255。byte是0-255的 无符号类型,所以不能表示负数。这也就是为什么串口发送数据发不过去的原因了。在3D的现象就是顺时针模型跟着动,逆时针就不动了。
解决
直接上代码吧,有缘人就看着🆗,反正笔记也是我自己看🐕
arduino的代码:
#include <MPU6050_tockn.h>
#include <Wire.h>
MPU6050 mpu6050(Wire);
int inByte = 0; // incoming serial byte
int pit,rol,yaw; //角度值
int pit_h,rol_h,yaw_h; //角度高八位
int pit_l,rol_l,yaw_l; //角度低八位
int pit_flag=0,rol_flag=0,yaw_flag=0; //角度正负标志位
void setup()
{
Serial.begin(115200);
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(true);
establishContact(); // send a byte to establish contact until Processing responds
}
void loop()
{
mpu6050.update();
pit = mpu6050.getAngleX();
rol = mpu6050.getAngleY();
yaw = mpu6050.getAngleZ();
/**********************************/
if(pit > 255-1){
pit_h = 255;
pit_l = pit - 255;
pit_flag = 0;
}
else if(pit>0 && pit<=255-1){
pit_h = pit;
pit_l = 0;
pit_flag = 0;
}
else if(pit < -255+1){
pit_h = abs(-255);
pit_l = abs(pit + 255);
pit_flag = 1;
}
else{
pit_h = abs(pit);
pit_l = 0;
pit_flag = 1;
}
/**********************************/
if(rol > 255-1){
rol_h = 255;
rol_l = rol - 255;
rol_flag = 0;
}
else if(rol>0 && rol<=255-1){
rol_h = rol;
rol_l = 0;
rol_flag = 0;
}
else if(rol < -255+1){
rol_h = abs(-255);
rol_l = abs(rol + 255);
rol_flag = 1;
}
else{
rol_h = abs(rol);
rol_l = 0;
rol_flag = 1;
}
/**********************************/
if(yaw > 255-1){
yaw_h = 255;
yaw_l = yaw - 255;
yaw_flag = 0;
}
else if(yaw>0 && yaw<=255-1){
yaw_h = yaw;
yaw_l = 0;
yaw_flag = 0;
}
else if(yaw<-255+1){
yaw_h = abs(-255);
yaw_l = abs(yaw + 255);
yaw_flag = 1;
}
else{
yaw_h = abs(yaw);
yaw_l = 0;
yaw_flag = 1;
}
Serial.write(pit_h);
Serial.write(pit_l);
Serial.write(rol_h);
Serial.write(rol_l);
Serial.write(yaw_h);
Serial.write(yaw_l);
Serial.write(pit_flag);
Serial.write(rol_flag);
Serial.write(yaw_flag);
/**************这里注释的供调试时看数据用*******************/
/*
Serial.print("pit:");
Serial.print(pit);
Serial.print(" rol:");
Serial.print(rol);
Serial.print(" yaw:");
Serial.println(yaw);
*/
}
/***************与processing确认连接*********************/
void establishContact() {
while (Serial.available() <= 0) {
Serial.write('A'); // send a capital A
delay(20);
}
}
processing的代码:
import processing.serial.*;
Serial myPort;
int[] serialInArray = new int[9];
int serialCount = 0;
int pit,rol,yaw;
int pit_last,rol_last,yaw_last;
boolean firstContact = false;
void setup() {
size(640, 360, P3D);
noStroke();
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 115200);
}
float i = 0,j = 0,k = 0;
void draw() {
lights();
background(0);
float cameraY = height/2.0;
float fov = 0.12 * PI/2;
float cameraZ = cameraY / tan(fov / 2.0);
float aspect = float(width)/float(height);
perspective(fov, aspect, cameraZ/10.0, cameraZ*10.0);
translate(width/2, height/2, 0);
rotateX(-rol*(PI/180));
rotateY(yaw*(PI/180));
rotateZ(-pit*(PI/180));
fill(50,205,50);
box(80, 10, 40);
}
void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear();
firstContact = true;
myPort.write('A');
}
}
else {
serialInArray[serialCount] = inByte;
serialCount++;
if (serialCount > 9-1 ) {
if(serialInArray[6] == 0)
pit = serialInArray[0] +serialInArray[1];
else
pit = -(serialInArray[0] +serialInArray[1]);
if(serialInArray[7] == 0)
rol = serialInArray[2] +serialInArray[3];
else
rol = -(serialInArray[2] +serialInArray[3]);
if(serialInArray[8] == 0)
yaw = serialInArray[4] +serialInArray[5];
else
yaw = -(serialInArray[4] +serialInArray[5]) ;
serialCount = 0;
}
}
}