文章目录
- 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的最值都设置为当前获取值),而且周边干扰较少,否则会影响效果,导致测试到的角度有偏差。