HS-S75-L 电子指南针罗盘模块

HS-S75-L 电子指南针罗盘模块

1、介绍

电子指南针罗盘模块是基于磁传感与姿态解算技术的高精度感知组件,核心功能为精准输出航向角(精度士0.5°~士2)与设备姿态数据,广泛适配消费电子、智能穿戴、无人机、车载设备等场景。模块集成高灵敏度传感器与抗干扰校准算法,支持I2C/SPI等主流通信协议,具备宽电压适配、高低温稳定工作(-40°C~85°C)及低功耗特性,可快速与各类智能设备集成,为其提供可靠的方向定位与姿态反馈能力,是实现设备“空间感知”的核心组件。

2、原理图

3、模块参数

引脚名称

描述

G

GND(电源输入负极)

V

VCC(电源输入正极)

SDA

数据引脚

SCL

时钟引脚

  • 供电电压: 3.3V-5V

  • 连接方式:PH2.0 4P端子线

  • 安装方式:乐高搭建

4、电路板尺寸

5、添加Arduino库文件

不会使用库文件的参考这里:参考链接

库文件下载:点击下载

米思齐库文件下载步骤(使用代码前前下载米思齐库文件):

不会安装库文件的请点击这里:参考链接

6、添加MicroPython环境库文件

米思齐库文件下载步骤(使用代码前前下载米思齐库文件):

不会安装库文件的请点击这里:参考链接

7、Arduino IDE示例程序

示例程序(UNO开发板):点击下载

#include <QMC5883LCompassSoft.h>
#include <SoftwareWire.h>

SoftwareWire softWire6_5(6, 5);
QMC5883LCompassSoft compass(&softWire6_5);

void setup(){
  compass.init();
  Serial.begin(9600);
}

void loop(){
  compass.read();Serial.println(String("方位角:") + String(compass.getAzimuth()));
  delay(100);

}

示例程序(ESP32开发板——python代码不适用Arduino环境):

import time
import math
from machine import I2C, Pin
import sys


QMC5883L_ADDR = 0x0D
QMC5883L_REG_OUT_X_L = 0x00
QMC5883L_REG_CTRL1 = 0x09
QMC5883L_REG_CTRL2 = 0x0A
QMC5883L_REG_FBR = 0x0B

QMC5883L_MODE_CONTINUOUS = 0b00000001
QMC5883L_ODR_200HZ = 0b00001100
QMC5883L_RNG_8G = 0b00010000
QMC5883L_OSR_512 = 0b00000000

_BEARINGS = (
    (' ', ' ', 'N'), ('N', 'N', 'E'), (' ', 'N', 'E'), ('E', 'N', 'E'),
    (' ', ' ', 'E'), ('E', 'S', 'E'), (' ', 'S', 'E'), ('S', 'S', 'E'),
    (' ', ' ', 'S'), ('S', 'S', 'W'), (' ', 'S', 'W'), ('W', 'S', 'W'),
    (' ', ' ', 'W'), ('W', 'N', 'W'), (' ', 'N', 'W'), ('N', 'N', 'W'),
)

def _to_signed_16bit(val):
    if val > 32767:
        return val - 65536
    return val


class QMC5883LCompassSoft:


    def __init__(self, i2c: I2C):
        self._i2c = i2c
        self._ADDR = QMC5883L_ADDR

        self._smooth_use = False
        self._smooth_steps = 5
        self._smooth_advanced = False
        self._vRaw = [0, 0, 0]
        self._vHistory = [[0, 0, 0] for _ in range(10)]
        self._vScan = 0
        self._vTotals = [0.0, 0.0, 0.0]
        self._vSmooth = [0, 0, 0]
        self._calibration_use = False
        self._vCalibration = [[0, 0], [0, 0], [0, 0]]
        self._vCalibrated = [0, 0, 0]


    def _write_reg(self, reg, val):
        try:
            self._i2c.writeto(self._ADDR, bytes([reg, val]))
        except Exception as e:
            print(f"I2C Write Error to {reg}: {e}")

    def _read_raw(self):

        try:

            data = self._i2c.readfrom_mem(self._ADDR, QMC5883L_REG_OUT_X_L, 6)


            x_raw_unsigned = int.from_bytes(data[0:2], 'little', False)
            y_raw_unsigned = int.from_bytes(data[2:4], 'little', False)
            z_raw_unsigned = int.from_bytes(data[4:6], 'little', False)

            self._vRaw[0] = _to_signed_16bit(x_raw_unsigned)
            self._vRaw[1] = _to_signed_16bit(y_raw_unsigned)
            self._vRaw[2] = _to_signed_16bit(z_raw_unsigned)

            return True
        except Exception as e:

            return False


    def init(self):

        self._write_reg(QMC5883L_REG_FBR, 0x01)

        self.setMode(QMC5883L_MODE_CONTINUOUS, QMC5883L_ODR_200HZ, QMC5883L_RNG_8G, QMC5883L_OSR_512)

    def setMode(self, mode, odr, rng, osr):
        """Set the chip mode, ODR, RNG, and OSR."""
        control_val = mode | odr | rng | osr
        self._write_reg(QMC5883L_REG_CTRL1, control_val)

    def setSmoothing(self, steps: int, adv: bool):
        """Set smoothing parameters (steps 1-10)."""
        self._smooth_use = True
        self._smooth_steps = min(max(1, steps), 10)
        self._smooth_advanced = adv

    def setCalibration(self, x_min, x_max, y_min, y_max, z_min, z_max):
        """Set calibration values (Hard and Soft Iron Compensation)."""
        self._calibration_use = True
        self._vCalibration[0] = [x_min, x_max]
        self._vCalibration[1] = [y_min, y_max]
        self._vCalibration[2] = [z_min, z_max]


    def _applyCalibration(self):
        """Applies hard-iron offset and soft-iron scaling."""
        x_min, x_max = self._vCalibration[0]
        y_min, y_max = self._vCalibration[1]
        z_min, z_max = self._vCalibration[2]

        x_offset = (x_min + x_max) / 2
        y_offset = (y_min + y_max) / 2
        z_offset = (z_min + z_max) / 2

        x_avg_delta = (x_max - x_min) / 2
        y_avg_delta = (y_max - y_min) / 2
        z_avg_delta = (z_max - z_min) / 2


        x_avg_delta = x_avg_delta if x_avg_delta != 0 else 1.0
        y_avg_delta = y_avg_delta if y_avg_delta != 0 else 1.0
        z_avg_delta = z_avg_delta if z_avg_delta != 0 else 1.0

        avg_delta = (x_avg_delta + y_avg_delta + z_avg_delta) / 3

        x_scale = avg_delta / x_avg_delta
        y_scale = avg_delta / y_avg_delta
        z_scale = avg_delta / z_avg_delta

        self._vCalibrated[0] = int((self._vRaw[0] - x_offset) * x_scale)
        self._vCalibrated[1] = int((self._vRaw[1] - y_offset) * y_scale)
        self._vCalibrated[2] = int((self._vRaw[2] - z_offset) * z_scale)

    def _smoothing(self):
        """Rolling average and optional min/max removal."""
        if self._vScan >= self._smooth_steps:
            self._vScan = 0

        current_data = self._vCalibrated if self._calibration_use else self._vRaw

        for i in range(3):
            old_val = self._vHistory[self._vScan][i]
            new_val = current_data[i]

            self._vTotals[i] -= old_val # Safe even if old_val is 0 initially
            self._vHistory[self._vScan][i] = new_val
            self._vTotals[i] += new_val

            current_window = [self._vHistory[j][i] for j in range(self._smooth_steps)]

            if self._smooth_advanced:
                max_val = max(current_window)
                min_val = min(current_window)

                divisor = self._smooth_steps - 2
                if divisor > 0:
                    self._vSmooth[i] = int((sum(current_window) - max_val - min_val) / divisor)
                else: # steps <= 2
                    self._vSmooth[i] = int(sum(current_window) / self._smooth_steps)
            else:
                self._vSmooth[i] = int(self._vTotals[i] / self._smooth_steps)

        self._vScan += 1


    def read(self):
        """Reads the sensor and applies calibration/smoothing."""
        if self._read_raw():
            if self._calibration_use:
                self._applyCalibration()

            if self._smooth_use:
                self._smoothing()
            return True
        return False

    def _get_axis_value(self, i):
        """Get the final value (smoothed, calibrated, or raw)."""
        if self._smooth_use:
            return self._vSmooth[i]

        if self._calibration_use:
            return self._vCalibrated[i]

        return self._vRaw[i]

    def getX(self):
        return self._get_axis_value(0)

    def getY(self):
        return self._get_axis_value(1)

    def getZ(self):
        return self._get_axis_value(2)



    def getAzimuth(self):

        x = self.getX()
        y = self.getY()

        if x == 0 and y == 0:
            return 0

        a = math.atan2(y, x) * 180.0 / math.pi

        return int(360 + a) if a < 0 else int(a)

    def getBearing(self, azimuth: int):
        return int(round(azimuth / 22.5)) % 16

    def getDirection(self, azimuth: int):
        d = self.getBearing(azimuth)
        return _BEARINGS[d]


i2c = I2C(1, scl=Pin(22), sda=Pin(21), freq=400000)
compass = QMC5883LCompassSoft(i2c)
compass.init()
compass.setSmoothing(5, False)

import machine
import time


while True:
    compass.read()
    value = compass.getAzimuth()
    print(value)
    time.sleep(1)

8、米思齐 Mixly 示例程序(图形化语言)

示例程序(UNO开发板):点击下载

示例程序(ESP32开发板):点击下载

9、测试环境搭建

Arduino UNO 测试环境搭建

准备配件:

  • UNO-R3 开发板 *1

  • UNO-R3 EXP 扩展板 *1

  • USB type-c 数据线 *1

  • HS-S75-L 电子罗盘模块*1

  • PH2.0 4P双头端子线 *1

电路接线图:

ESP32 Python 测试环境搭建

10、视频教程

Arduino UNO视频教程

ESP32 Python视频教程:

11、测试结论

Arduino UNO测试结论:

上传代码后根据串口打印的数值来判断方向。