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

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.19

module(...,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、4


local addr = 0x1e        --addr

local 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  then
        log.error("i2c", "setup fail", addr)
        i2c.close(i2cid)
        return
    end

    log.info("dev i2c init_ok")
    return true
end

function hmc5883l_int()

    I2C_Write_Byte(Config_a,0x70)  --写配置a寄存器数据
    I2C_Write_Byte(Config_b,0x20)  --写配置b寄存器数据  增益660
    I2C_Write_Byte(mode,0x00)      --写模式寄存器数据
end

function hmc5883l_read()

    local hx=I2C_Read_Byte(Msb_x)
    local lx=I2C_Read_Byte(Lsb_x)
    local x_data=hx*256+lx

    local hy=I2C_Read_Byte(Msb_y)
    local ly=I2C_Read_Byte(Lsb_y)
    local y_data=hy*256+ly

    local hz=I2C_Read_Byte(Msb_z)
    local lz=I2C_Read_Byte(Lsb_z)
    local z_data=hz*256+lz

    if(x_data>32768)  then
        x_data= -(0xFFFF - x_data + 1)   
    end

    if(y_data>32768)  then
        y_data = -(0xFFFF - y_data + 1)
    end 

    if(z_data>32768)  then
        z_data = -(0xFFFF - z_data+ 1)
    end

    local 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
end



sys.taskInit(function()
    sys.wait(3000)
    
    while true do
        sys.wait(2000)
        if init() then 

            --初始化hmc588配置
            hmc5883l_int()

            --读取x,y,z数值
            hmc5883l_read()
            
            i2c.close(i2cid)
        end
    end
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 = 0
    local pi = 3.1415926
    if x > 0 then
        if y > 0 then
            -- print("1")
            temp_atan = math.atan(x,y)/pi*180
        else if y<0 then
            -- print("2")
            temp_atan = math.atan(x,y)/pi*180 
        end
        end
    
    else if x < 0 then
        if y > 0 then
            -- print("4")
            temp_atan = math.atan(x,y)/pi*180 + 360
        else if y<0 then
            -- print("3")
            temp_atan = math.atan(x,y)/pi*180 + 360
        end
        end
    end
    end
    return temp_atan
end


n = 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 = 0
    local pi = 3.1415926
    if x > 0 then
        if y > 0 then
            -- print("1")
            temp_atan = math.atan(x,y)/pi*180
        else if y<0 then
            -- print("2")
            temp_atan = math.atan(x,y)/pi*180 
        end

        if y == 0 then
            temp_atan = 90
        end
        end
    else if x < 0 then
        if y > 0 then
            -- print("4")
            temp_atan = math.atan(x,y)/pi*180 + 360
        else if y<0 then
            -- print("3")
            temp_atan = math.atan(x,y)/pi*180 + 360
        end
        end
        if y == 0 then
            temp_atan = 270
        end
    end
    end
    return 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_max
    local R_x_min = x_min
    local R_y_max = y_max
    local R_y_min = y_min
    local R_range_x = R_x_max - R_x_min
    local R_range_y = R_y_max - R_y_min
    local R00_x = R_x_max - (R_range_x)/2
    local R00_y = R_y_max - (R_range_y)/2
    
    print(R00_x,R00_y)
    
    local R_temp_x = temp_x
    local R_temp_y = temp_y

    local R_bias_x = R_temp_x - R00_x
    local R_bias_y = R_temp_y - R00_y
    
    print(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_x
    local R_step_y = lcd_y_max / R_range_y

    local lcd_x = R_bias_x * R_step_x + 64  -- R00对应(64,64)
    local lcd_y = R_bias_y * R_step_y + 64

    print("lcd",lcd_x,lcd_y)

end

raw2angle_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、4


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(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  then
        log.error("i2c", "setup fail", GY271_i2c_addr)
        i2c.close(GY271_i2c_id)
        return
    end

    log.info("dev i2c init_ok")

    sys.wait(1000)
    hmc5883l_int()
    
    hmc5883l_read()

    x_max = x_data
    x_min = x_data
    y_max = y_data
    y_min = y_data
    z_max = z_data
    z_min = z_data

    return true
end

function hmc5883l_int()

    I2C_Write_Byte(Config_a,0x70)  --写配置a寄存器数据
    I2C_Write_Byte(Config_b,0x20)  --写配置b寄存器数据  增益660
    I2C_Write_Byte(mode,0x00)      --写模式寄存器数据
end

function judge_xyz_range()
    
    if x_data > x_max then
        x_max = x_data
    else if x_data < x_min then
        x_min = x_data
    end
    end

    if y_data > y_max then
        y_max = y_data
    else if y_data < y_min then
        y_min = y_data
    end
    end

    if z_data > z_max then
        z_max = z_data
    else if z_data < z_min then
        z_min = z_data
    end
    end

    print("x range: ",x_max,x_min,"y range: ",y_max,y_min,"z range: ",z_max,z_min)
end

function get_angle()

    print("x "..x_data.." | y "..y_data.." | z "..z_data)
    x_p00 = x_max - (x_max - x_min)/2
    y_p00 = y_max - (y_max - y_min)/2
    z_p00 = z_max - (z_max - z_min)/2

    print("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)+180

    print("hmc5883l_angle",hmc5883l_angle)
    
end

function hmc5883l_read()

    local hx=I2C_Read_Byte(Msb_x)
    local lx=I2C_Read_Byte(Lsb_x)
    x_data=hx*256+lx

    local hy=I2C_Read_Byte(Msb_y)
    local ly=I2C_Read_Byte(Lsb_y)
    y_data=hy*256+ly

    local hz=I2C_Read_Byte(Msb_z)
    local lz=I2C_Read_Byte(Lsb_z)
    z_data=hz*256+lz

    if(x_data>32768)  then
        x_data= -(0xFFFF - x_data + 1)   
    end

    if(y_data>32768)  then
        y_data = -(0xFFFF - y_data + 1)
    end 

    if(z_data>32768)  then
        z_data = -(0xFFFF - z_data+ 1)
    end

    log.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
end

function hmc5883l_test()
    sys.wait(3000)
    
    hmc5883l_status = init()
    print("hmc5883l_status",hmc5883l_status)

    while true do
        sys.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)
        end
    end
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 = 0
    local pi = 3.1415926
    if x > 0 then
        if y > 0 then
            -- print("1")
            temp_atan = math.atan(x,y)/pi*180
        else if y<0 then
            -- print("2")
            temp_atan = math.atan(x,y)/pi*180 
        end

        if y == 0 then
            temp_atan = 90
        end
        end
    else if x < 0 then
        if y > 0 then
            -- print("4")
            temp_atan = math.atan(x,y)/pi*180 + 360
        else if y<0 then
            -- print("3")
            temp_atan = math.atan(x,y)/pi*180 + 360
        end
        end
        if y == 0 then
            temp_atan = 270
        end
    end
    end
    return 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_max
    local R_x_min = x_min
    local R_y_max = y_max
    local R_y_min = y_min
    local R_range_x = R_x_max - R_x_min
    local R_range_y = R_y_max - R_y_min
    local R00_x = R_x_max - (R_range_x)/2
    local R00_y = R_y_max - (R_range_y)/2
    
    print("R00",R00_x,R00_y)
    
    local R_temp_x = temp_x
    local R_temp_y = temp_y

    local R_bias_x = R_temp_x - R00_x
    local R_bias_y = R_temp_y - R00_y
    
    N_angle = get_y_angle(R_bias_x,R_bias_y) - 90
    if N_angle < 0 then
        print("N-E")
        N_angle = N_angle+360
    end
    print("get_y_angle",N_angle)
    
    local lcd_x_max = 128 
    local lcd_y_max = 128 
    local R_step_x = lcd_x_max / R_range_x
    local R_step_y = lcd_y_max / R_range_y

    local lcd_x = R_bias_x * R_step_x + 64  -- R00对应(64,64)
    local lcd_y = R_bias_y * R_step_y + 64

    print("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 -- 100000


sys.taskInit(function()
    -- ps:有wait不能放在外面

    if T2_TCS34725 == 1 then
        TCS34725_init(esp32_i2c_id,esp32_i2c_speed) -- TCS34725地址默认为0x29
    end
    
    if T1_BH1750 == 1 then
        BH1750_init(esp32_i2c_id)
    end

    if T3_BMP180 == 1 then
        -- BMP180_test(esp32_i2c_id)
        BMP180_init(esp32_i2c_id)
    end

    if T4_GY271 == 1 then
        
        hmc5883l_test()
    end


    -- sys.wait(1500)

    while 1 do
        
        if T1_BH1750 == 1 then
            BH1750_get()
        end

        if T2_TCS34725 == 1 then
            TCS34725_get() -- TCS34725地址默认为0x29
        end

        if T3_BMP180 == 1 then
            -- BMP180_test(esp32_i2c_id)
            BMP180_get_temp_press()
        end

        sys.wait(100)
    end
end)

sys.run()

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

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

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

7 结果2——和手机对比

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

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

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值