陀螺仪结合Unity姿态孪生Demo演示 硬件使用:MPU6050,MPU9250。 MCU使用:ESP8266。 自备串口TTL读取工具。 固件选择:MicroPython&NodeMCU。 拷贝Assets\ESP8266Program中对应脚本到MCU内存中运行即可,连接串口后,串口收到消息时,打开Unity运行对应程序即可看到陀螺仪模块的姿态孪生(旋转角度会和陀螺仪保持一致)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
7.6 KiB

3 years ago
---------------------------------------------------------
---MPU6050&NodeMCU&ESP8266&姿态融合算法整合脚本---
---读取MPU6050原始数据(三轴加速度,三轴角速度,环境温度)
---融合四元数算法,该程序的输出值为六轴数据融合后的四元数
---四元数转欧拉角需要在其他外接程序上进行实现
---------------------------------------------------------
id = 0 -- always 0
scl = 6 -- set pin 6 as scl
sda = 7 -- set pin 7 as sda
MPU6050SlaveAddress = 0x68
AK8963SlaveAddress = 0x0C
AccelScaleFactor = 16384; -- sensitivity scale factor respective to full scale setting provided in datasheet
GyroScaleFactor = 131;
MPU6050_REGISTER_SMPLRT_DIV = 0x19
MPU6050_REGISTER_USER_CTRL = 0x6A
MPU6050_REGISTER_PWR_MGMT_1 = 0x6B
MPU6050_REGISTER_PWR_MGMT_2 = 0x6C
MPU6050_REGISTER_CONFIG = 0x1A
MPU6050_REGISTER_GYRO_CONFIG = 0x1B
MPU6050_REGISTER_ACCEL_CONFIG = 0x1C
AK_8963_CONFIG = 0x18
MPU6050_REGISTER_FIFO_EN = 0x23
MPU6050_REGISTER_INT_ENABLE = 0x38
MPU6050_REGISTER_ACCEL_XOUT_H = 0x3B
MPU6050_REGISTER_SIGNAL_PATH_RESET = 0x68
function I2C_Write(deviceAddress, regAddress, data)
i2c.start(id) -- send start condition
if (i2c.address(id, deviceAddress, i2c.TRANSMITTER))-- set slave address and transmit direction
then
i2c.write(id, regAddress) -- write address to slave
i2c.write(id, data) -- write data to slave
i2c.stop(id) -- send stop condition
else
print("I2C_Write fails")
end
end
function I2C_Read(deviceAddress, regAddress, SizeOfDataToRead)
response = 0;
i2c.start(id) -- send start condition
if (i2c.address(id, deviceAddress, i2c.TRANSMITTER))-- set slave address and transmit direction
then
i2c.write(id, regAddress) -- write address to slave
i2c.stop(id) -- send stop condition
i2c.start(id) -- send start condition
i2c.address(id, deviceAddress, i2c.RECEIVER)-- set slave address and receive direction
response = i2c.read(id, SizeOfDataToRead) -- read defined length response from slave
i2c.stop(id) -- send stop condition
return response
else
print("I2C_Read fails")
end
return response
end
function unsignTosigned16bit(num) -- convert unsigned 16-bit no. to signed 16-bit no.
if num > 32768 then
num = num - 65536
end
return num
end
function MPU6050_Init() --configure MPU6050
tmr.delay(150000)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SMPLRT_DIV, 0x07)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_1, 0x01)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_2, 0x00)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_CONFIG, 0x00)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_GYRO_CONFIG, 0x00)-- set +/-250 degree/second full scale
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_CONFIG, 0x00)-- set +/- 2g full scale
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_FIFO_EN, 0x00)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_INT_ENABLE, 0x01)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SIGNAL_PATH_RESET, 0x00)
I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_USER_CTRL, 0x00)
end
i2c.setup(id, sda, scl, i2c.SLOW) -- initialize i2c
MPU6050_Init()
data = I2C_Read(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H, 14)
AccelX = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 1), 8), string.byte(data, 2))))
AccelY = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 3), 8), string.byte(data, 4))))
AccelZ = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 5), 8), string.byte(data, 6))))
Temperature = unsignTosigned16bit(bit.bor(bit.lshift(string.byte(data,7), 8), string.byte(data,8)))
GyroX = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 9), 8), string.byte(data, 10))))
GyroY = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 11), 8), string.byte(data, 12))))
GyroZ = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 13), 8), string.byte(data, 14))))
AccelX = AccelX/AccelScaleFactor -- divide each with their sensitivity scale factor
AccelY = AccelY/AccelScaleFactor
AccelZ = AccelZ/AccelScaleFactor
Temperature = Temperature/340+36.53-- temperature formula
--角速度的值会产生偏移,需要校准
GyroX = GyroX/GyroScaleFactor+3
GyroY = GyroY/GyroScaleFactor-0.45
GyroZ = GyroZ/GyroScaleFactor+0.24
--姿态融合算法部分定义
Kp = 100.0
Ki = 0.002
halfT = 0.001
q0 = 1
q1 = 0
q2 = 0
q3 = 0
exInt = 0
eyInt = 0
ezInt = 0
roll = 0.0
pitch = 0.0
yaw = 0.0
function updateHardWareDatas()
data = I2C_Read(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H, 14)
AccelX = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 1), 8), string.byte(data, 2))))
AccelY = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 3), 8), string.byte(data, 4))))
AccelZ = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 5), 8), string.byte(data, 6))))
Temperature = unsignTosigned16bit(bit.bor(bit.lshift(string.byte(data,7), 8), string.byte(data,8)))
GyroX = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 9), 8), string.byte(data, 10))))
GyroY = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 11), 8), string.byte(data, 12))))
GyroZ = unsignTosigned16bit((bit.bor(bit.lshift(string.byte(data, 13), 8), string.byte(data, 14))))
AccelX = AccelX/AccelScaleFactor -- divide each with their sensitivity scale factor
AccelY = AccelY/AccelScaleFactor
AccelZ = AccelZ/AccelScaleFactor
Temperature = Temperature/340+36.53-- temperature formula
GyroX = GyroX/GyroScaleFactor+3
GyroY = GyroY/GyroScaleFactor-0.45
GyroZ = GyroZ/GyroScaleFactor+0.24
end
function IMUupdate(gx,gy,gz,ax,ay,az)
-- body
-- 测量正常化
norm = math.sqrt(ax*ax + ay*ay + az*az)
ax = ax / norm --单位化
ay = ay / norm
az = az / norm
-- 估计方向的重力
vx = 2*(q1*q3 - q0*q2)
vy = 2*(q0*q1 + q2*q3)
vz = q0*q0 - q1*q1 - q2*q2 + q3*q3
-- 错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
ex = (ay*vz - az*vy)
ey = (az*vx - ax*vz)
ez = (ax*vy - ay*vx)
-- 积分误差比例积分增益
exInt = exInt + ex*Ki
eyInt = eyInt + ey*Ki
ezInt = ezInt + ez*Ki
-- 调整后的陀螺仪测量
gx = gx + Kp*ex + exInt
gy = gy + Kp*ey + eyInt
gz = gz + Kp*ez + ezInt
-- 整合四元数率和正常化
q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT
q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT
q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT
q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT
-- 正常化四元
norm = math.sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3)
q0 = q0 / norm
q1 = q1 / norm
q2 = q2 / norm
q3 = q3 / norm
--pitch = math.asin(-2 * q1 * q3 + 2 * q0* q2) * 57.3 -- pitch ,转换为度数
--roll = math.atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1) * 57.3 -- rollv
--yaw = math.atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3
end
while true do --read and print accelero, gyro and temperature value
updateHardWareDatas()
IMUupdate(GyroX,GyroY,GyroZ,AccelX,AccelY,AccelZ)
print(string.format("{'q0':%.3g,'q1':%.3g,'q2':%.3g,'q3':%.3g}",q0,q1,q2,q3))
--输出原始数据
--print(string.format("%.3g,%.3g,%.3g",GyroX,GyroY,GyroZ))
--print(string.format("{'GyroX':%.3g,'GyroY':%.3g,'GyroZ':%.3g,'Temperature':%.3g,'AccelX':%.3g,'AccelY':%.3g,'AccelZ':%.3g}",
--GyroX, GyroY, GyroZ, Temperature, AccelX, AccelY, AccelZ))
tmr.delay(100000) -- 100ms timer delay
end