当前位置: 代码迷 >> 综合 >> 【LuatOS-sensor】3三轴罗盘仪GY271
  详细解决方案

【LuatOS-sensor】3三轴罗盘仪GY271

热度:24   发布时间:2023-12-05 20:26:34.0

文章目录

  • 1 前言
  • 2 硬件连接
  • 3 官方驱动
  • 4 准备工作——角度计算
    • 4.1 测试获取与y轴夹角
    • 4.2 映射到lcd
  • 5 代码——结合传感器
  • 6 结果1——计算与北夹角
  • 7 结果2——和手机对比

1 前言

调试三轴罗盘仪,传感器获取磁场强度判定方向。

2 硬件连接

i2c通信,和其他的一样,只用到四根。
在这里插入图片描述

3 官方驱动

罗盘仪:https://doc.openluat.com/wiki/21?wiki_page_id=2750

--- 模块功能:ADC功能测试.
-- ADC测量精度(12bit)
-- 每隔1s读取一次ADC值
-- @author openLuat
-- @module adc.testAdc
-- @license MIT
-- @copyright openLuat
-- @release 2018.12.19module(...,package.seeall)PROJECT = "hmc5883l_demo"
VERSION = "1.0.0"require "log"
require "sys"
require "misc"-- i2c ID
local i2cid = 2-- i2c 速率--打开vlcd电压域
pmd.ldoset(15,pmd.LDO_VLCD)-- GPIO 0、1、2、3、4local addr = 0x1e        --addrlocal speed = 100000      --iic速率local Config_a     = 0x00    --配置寄存器a:设置的数据输出速率和测量配置 0 11 100 00 0X70
local Config_b     = 0x01    --配置寄存器b:设置装置的增益 001 00000 0Xe0
local mode         = 0x02    --模式寄存器: 默认单一测量模式01,连续00 000000 00 0X00/0x01
local Msb_x        = 0x03    --x 高位数据输出
local Lsb_x        = 0x04    --x 低位数据输出
local Msb_y        = 0x07    --x 高位数据输出
local Lsb_y        = 0x08    --x 低位数据输出
local Msb_z        = 0x05    --x 高位数据输出
local Lsb_z        = 0x06    --x 低位数据输出
local status       = 0x09    -- 状态寄存器 0x00
local recogn_a     = 0x0a    -- 识别寄存器a 0x48
local recogn_b     = 0x0b    -- 识别寄存器b 0x34
local recogn_c     = 0x0c    -- 识别寄存器c 0x33--写数据
local function I2C_Write_Byte(regAddress,val,val2)i2c.send(i2cid, addr, {
    regAddress,val,val2})end--读取单个字节
local function I2C_Read_Byte(regAddress)i2c.send(i2cid, addr, regAddress)local rdstr = i2c.recv(i2cid, addr, 1)log.info("rdstr:toHex()",rdstr:toHex())return rdstr:byte(1)--变成10进制数据
end--读取多个字节
local function I2C_Read_Bytes(regAddress,cnt)i2c.send(i2cid, addr, regAddress)local rdstr = i2c.recv(i2cid, addr, cnt)--log.info("rdstr:toHex()-------",rdstr:toHex())return rdstr
end-- 初始化
function init()if  i2c.setup(i2cid, speed, addr) ~= speed  thenlog.error("i2c", "setup fail", addr)i2c.close(i2cid)returnendlog.info("dev i2c init_ok")return true
endfunction hmc5883l_int()I2C_Write_Byte(Config_a,0x70)  --写配置a寄存器数据I2C_Write_Byte(Config_b,0x20)  --写配置b寄存器数据 增益660I2C_Write_Byte(mode,0x00)      --写模式寄存器数据
endfunction hmc5883l_read()local hx=I2C_Read_Byte(Msb_x)local lx=I2C_Read_Byte(Lsb_x)local x_data=hx*256+lxlocal hy=I2C_Read_Byte(Msb_y)local ly=I2C_Read_Byte(Lsb_y)local y_data=hy*256+lylocal hz=I2C_Read_Byte(Msb_z)local lz=I2C_Read_Byte(Lsb_z)local z_data=hz*256+lzif(x_data>32768)  thenx_data= -(0xFFFF - x_data + 1)   endif(y_data>32768)  theny_data = -(0xFFFF - y_data + 1)end if(z_data>32768)  thenz_data = -(0xFFFF - z_data+ 1)endlocal Angle= math.atan2(y_data,x_data)*(180/3.14159265)+180;--单位:角度 (0~360)Angle= Angle log.info("x,y,z-----------", x_data,y_data,z_data )log.info("Angle",string.format("%.1f", Angle))return x_data,y_data,z_data
endsys.taskInit(function()sys.wait(3000)while true dosys.wait(2000)if init() then --初始化hmc588配置hmc5883l_int()--读取x,y,z数值hmc5883l_read()i2c.close(i2cid)endend
end)

问题
在lua5.3上,math.atan2()函数被弃用了,需要自己改。

4 准备工作——角度计算

4.1 测试获取与y轴夹角


-- 交换xy求与y轴的夹角
-- y = 1
-- x = -3^(1/2)y = -1
x = -3^(1/2)-- 获取与y轴的夹角
function get_y_angle(x,y)local temp_atan = 0local pi = 3.1415926if x > 0 thenif y > 0 then-- print("1")temp_atan = math.atan(x,y)/pi*180else if y<0 then-- print("2")temp_atan = math.atan(x,y)/pi*180 endendelse if x < 0 thenif y > 0 then-- print("4")temp_atan = math.atan(x,y)/pi*180 + 360else if y<0 then-- print("3")temp_atan = math.atan(x,y)/pi*180 + 360endendendendreturn temp_atan
endn = get_y_angle(x,y)
-- print(m)
print(n)

4.2 映射到lcd


-- 交换xy求与y轴的夹角
-- y = 1
-- x = -3^(1/2)y = -1
x = -3^(1/2)-- 获取与y轴的夹角
function get_y_angle(x,y)local temp_atan = 0local pi = 3.1415926if x > 0 thenif y > 0 then-- print("1")temp_atan = math.atan(x,y)/pi*180else if y<0 then-- print("2")temp_atan = math.atan(x,y)/pi*180 endif y == 0 thentemp_atan = 90endendelse if x < 0 thenif y > 0 then-- print("4")temp_atan = math.atan(x,y)/pi*180 + 360else if y<0 then-- print("3")temp_atan = math.atan(x,y)/pi*180 + 360endendif y == 0 thentemp_atan = 270endendendreturn temp_atan
endn = get_y_angle(x,y)
-- print(m)
print(n)-- 输入数值范围及当前数值,返回与y轴的夹角
function raw2angle_y(temp_x,temp_y,x_max,x_min,y_max,y_min)local R_x_max = x_maxlocal R_x_min = x_minlocal R_y_max = y_maxlocal R_y_min = y_minlocal R_range_x = R_x_max - R_x_minlocal R_range_y = R_y_max - R_y_minlocal R00_x = R_x_max - (R_range_x)/2local R00_y = R_y_max - (R_range_y)/2print(R00_x,R00_y)local R_temp_x = temp_xlocal R_temp_y = temp_ylocal R_bias_x = R_temp_x - R00_xlocal R_bias_y = R_temp_y - R00_yprint(get_y_angle(R_bias_x,R_bias_y))local lcd_x_max = 128 local lcd_y_max = 128 local R_step_x = lcd_x_max / R_range_xlocal R_step_y = lcd_y_max / R_range_ylocal lcd_x = R_bias_x * R_step_x + 64  -- R00对应(64,64)local lcd_y = R_bias_y * R_step_y + 64print("lcd",lcd_x,lcd_y)endraw2angle_y(300,400,300,-100,400,0)

5 代码——结合传感器

sen_GY271.lua

--- 模块功能:ADC功能测试. GY271 hmc5883l 三轴罗盘
-- ADC测量精度(12bit)
-- 每隔1s读取一次ADC值
-- @author openLuat
-- @module adc.testAdc
-- @license MIT
-- @copyright openLuat
-- @release 2018.12.19--[[ VCC:电源正 GND:电源负 SCL:I2C串行时钟线 SDA:I2C串行数据线 DRDY:中断引脚 -- io11 ]]PROJECT = "hmc5883l_demo"
VERSION = "1.0.0"-- require "log"
-- require "sys"
-- require "misc"-- i2c ID
local GY271_i2c_id = 0-- i2c 地址
local GY271_i2c_addr = 0x1e        --GY271_i2c_addr-- i2c 速率
local GY271_i2c_speed = 100000      --iic速率--打开vlcd电压域
-- pmd.ldoset(15,pmd.LDO_VLCD)-- GPIO 0、1、2、3、4local Config_a     = 0x00    --配置寄存器a:设置的数据输出速率和测量配置 0 11 100 00 0X70
local Config_b     = 0x01    --配置寄存器b:设置装置的增益 001 00000 0Xe0
local mode         = 0x02    --模式寄存器: 默认单一测量模式01,连续00 000000 00 0X00/0x01
local Msb_x        = 0x03    --x 高位数据输出
local Lsb_x        = 0x04    --x 低位数据输出
local Msb_y        = 0x07    --x 高位数据输出
local Lsb_y        = 0x08    --x 低位数据输出
local Msb_z        = 0x05    --x 高位数据输出
local Lsb_z        = 0x06    --x 低位数据输出
local status       = 0x09    -- 状态寄存器 0x00
local recogn_a     = 0x0a    -- 识别寄存器a 0x48
local recogn_b     = 0x0b    -- 识别寄存器b 0x34
local recogn_c     = 0x0c    -- 识别寄存器c 0x33--写数据
local function I2C_Write_Byte(regAddress,val,val2)i2c.send(GY271_i2c_id, GY271_i2c_addr, {
    regAddress,val,val2})end--读取单个字节
local function I2C_Read_Byte(regAddress)i2c.send(GY271_i2c_id, GY271_i2c_addr, regAddress)local rdstr = i2c.recv(GY271_i2c_id, GY271_i2c_addr, 1)-- log.info("rdstr:toHex()",rdstr:toHex()) -- 打印原始数据return rdstr:byte(1)--变成10进制数据
end--读取多个字节
local function I2C_Read_Bytes(regAddress,cnt)i2c.send(GY271_i2c_id, GY271_i2c_addr, regAddress)local rdstr = i2c.recv(GY271_i2c_id, GY271_i2c_addr, cnt)--log.info("rdstr:toHex()-------",rdstr:toHex())return rdstr
end-- 初始化
function init()if  i2c.setup(GY271_i2c_id, GY271_i2c_speed, GY271_i2c_addr) ~= GY271_i2c_speed  thenlog.error("i2c", "setup fail", GY271_i2c_addr)i2c.close(GY271_i2c_id)returnendlog.info("dev i2c init_ok")sys.wait(1000)hmc5883l_int()hmc5883l_read()x_max = x_datax_min = x_datay_max = y_datay_min = y_dataz_max = z_dataz_min = z_datareturn true
endfunction hmc5883l_int()I2C_Write_Byte(Config_a,0x70)  --写配置a寄存器数据I2C_Write_Byte(Config_b,0x20)  --写配置b寄存器数据 增益660I2C_Write_Byte(mode,0x00)      --写模式寄存器数据
endfunction judge_xyz_range()if x_data > x_max thenx_max = x_dataelse if x_data < x_min thenx_min = x_dataendendif y_data > y_max theny_max = y_dataelse if y_data < y_min theny_min = y_dataendendif z_data > z_max thenz_max = z_dataelse if z_data < z_min thenz_min = z_dataendendprint("x range: ",x_max,x_min,"y range: ",y_max,y_min,"z range: ",z_max,z_min)
endfunction get_angle()print("x "..x_data.." | y "..y_data.." | z "..z_data)x_p00 = x_max - (x_max - x_min)/2y_p00 = y_max - (y_max - y_min)/2z_p00 = z_max - (z_max - z_min)/2print("p00",x_p00,y_p00,z_p00)hmc5883l_angle = math.atan((y_data - y_p00)/(x_data - x_p00))*(180/3.14159265)+180-- hmc5883l_angle = math.atan((x_data - x_p00)/(y_data - y_p00))*(180/3.14159265)+180print("hmc5883l_angle",hmc5883l_angle)endfunction hmc5883l_read()local hx=I2C_Read_Byte(Msb_x)local lx=I2C_Read_Byte(Lsb_x)x_data=hx*256+lxlocal hy=I2C_Read_Byte(Msb_y)local ly=I2C_Read_Byte(Lsb_y)y_data=hy*256+lylocal hz=I2C_Read_Byte(Msb_z)local lz=I2C_Read_Byte(Lsb_z)z_data=hz*256+lzif(x_data>32768)  thenx_data= -(0xFFFF - x_data + 1)   endif(y_data>32768)  theny_data = -(0xFFFF - y_data + 1)end if(z_data>32768)  thenz_data = -(0xFFFF - z_data+ 1)endlog.info("x,y,z-----------", x_data,y_data,z_data )-- local Angle= math.atan(x_data,y_data)*(180/3.14159265)+180 --单位:角度 (0~360)-- Angle= Angle -- log.info("Angle",string.format("%.1f", Angle))return x_data,y_data,z_data
endfunction hmc5883l_test()sys.wait(3000)hmc5883l_status = init()print("hmc5883l_status",hmc5883l_status)while true dosys.wait(1000)if hmc5883l_status then --初始化hmc588配置-- hmc5883l_int()--读取x,y,z数值hmc5883l_read()judge_xyz_range()-- get_angle()raw2angle_y(x_data,y_data,x_max,x_min,y_max,y_min)-- i2c.close(GY271_i2c_id)endend
end-- test-- 交换xy求与y轴的夹角
-- y = 1
-- x = -3^(1/2)-- y = -1
-- x = -3^(1/2)-- 获取与y轴的夹角
function get_y_angle(x,y)local temp_atan = 0local pi = 3.1415926if x > 0 thenif y > 0 then-- print("1")temp_atan = math.atan(x,y)/pi*180else if y<0 then-- print("2")temp_atan = math.atan(x,y)/pi*180 endif y == 0 thentemp_atan = 90endendelse if x < 0 thenif y > 0 then-- print("4")temp_atan = math.atan(x,y)/pi*180 + 360else if y<0 then-- print("3")temp_atan = math.atan(x,y)/pi*180 + 360endendif y == 0 thentemp_atan = 270endendendreturn temp_atan
end-- n = get_y_angle(x,y)
-- -- print(m)
-- print(n)-- 输入数值范围及当前数值,返回与y轴的夹角
function raw2angle_y(temp_x,temp_y,x_max,x_min,y_max,y_min)local R_x_max = x_maxlocal R_x_min = x_minlocal R_y_max = y_maxlocal R_y_min = y_minlocal R_range_x = R_x_max - R_x_minlocal R_range_y = R_y_max - R_y_minlocal R00_x = R_x_max - (R_range_x)/2local R00_y = R_y_max - (R_range_y)/2print("R00",R00_x,R00_y)local R_temp_x = temp_xlocal R_temp_y = temp_ylocal R_bias_x = R_temp_x - R00_xlocal R_bias_y = R_temp_y - R00_yN_angle = get_y_angle(R_bias_x,R_bias_y) - 90if N_angle < 0 thenprint("N-E")N_angle = N_angle+360endprint("get_y_angle",N_angle)local lcd_x_max = 128 local lcd_y_max = 128 local R_step_x = lcd_x_max / R_range_xlocal R_step_y = lcd_y_max / R_range_ylocal lcd_x = R_bias_x * R_step_x + 64  -- R00对应(64,64)local lcd_y = R_bias_y * R_step_y + 64print("lcd",lcd_x,lcd_y)end-- raw2angle_y(300,400,300,-100,400,0)

main.lua

PROJECT = "sensor"
VERSION = "1.0.0"_G.sys = require("sys")require("sen_BH1750")       -- 光感
require("sen_TCS34725")     -- 色彩
require("sen_BMP180")       -- 气压
require("sen_GY271")-- 加载I?C功能测试模块
T1_BH1750 = 0
T2_TCS34725 = 0
T3_BMP180 = 0
T4_GY271 = 1-- i2c ID
esp32_i2c_id = 0        -- esp32只支持一路i2c, id为0
esp32_spi_id = 2        -- esp32只支持一路spi, id为2-- i2c 速率
esp32_i2c_speed = i2c.SLOW -- 100000sys.taskInit(function()-- ps:有wait不能放在外面if T2_TCS34725 == 1 thenTCS34725_init(esp32_i2c_id,esp32_i2c_speed) -- TCS34725地址默认为0x29endif T1_BH1750 == 1 thenBH1750_init(esp32_i2c_id)endif T3_BMP180 == 1 then-- BMP180_test(esp32_i2c_id)BMP180_init(esp32_i2c_id)endif T4_GY271 == 1 thenhmc5883l_test()end-- sys.wait(1500)while 1 doif T1_BH1750 == 1 thenBH1750_get()endif T2_TCS34725 == 1 thenTCS34725_get() -- TCS34725地址默认为0x29endif T3_BMP180 == 1 then-- BMP180_test(esp32_i2c_id)BMP180_get_temp_press()endsys.wait(100)end
end)sys.run()

6 结果1——计算与北夹角

在这里插入图片描述
这里的get_y_angle就是N,数值为0时指向正北。

和手机有一点偏差,后续再结合lcd屏幕显示数值吧。

7 结果2——和手机对比

lcd绘制出来成一根直线,看起来像是y=ymax - x 。

如图,以手机作为参考的话,还是相对符合的。
不过需要注意的是,在测试是需要校正(将xy的最值都设置为当前获取值),而且周边干扰较少,否则会影响效果,导致测试到的角度有偏差。

在这里插入图片描述
在这里插入图片描述

  相关解决方案