3

我使用Adafruit LSM303DLHC传感器。它由 2 个传感器、一个加速度计和一个磁力计组成。我目前正在为此传感器编写一个驱动程序,以通过Raspberry Pi 2 上的i2c接口与gobot.io包一起使用。

问题:加速度计部分工作。磁力计传感器部分没有。我可以读取磁场寄存器,但我得到了无意义的值。这些值在每个阅读周期之间都会更新,但它们变化不大并且没有意义。

使用的设备:

  • LSM303DLHC 传感器 -数据表
  • 树莓派 2
  • 阿杜诺

有关读取磁力计输出的详细信息:

LSM303DLHC 输出 6 个字节,代表沿 3 轴的 3 个磁场值。每个轴的每个值由 2 个字节(16 位)组成。输出顺序如下:

  • X 高字节
  • X 低字节
  • Z 高字节
  • Z 低字节
  • Y 高字节
  • Y 低字节

为了设置传感器,我们按顺序写入以下寄存器:

  • 重置磁力计增益:在 CRB_REG_M 寄存器(0x01)中写入 0x00
  • 设置磁力计增益:将 0x60(+/- 2.5 高斯)写入 CRB_REG_M 寄存器(0x01)
  • 设置输出数据速率:在 CRA_REG_M 寄存器 (0x00) 中写入 0x05 (30 Hz)
  • 启用连续模式:在 MR_REG_M 寄存器中写入 0x00

设置传感器后,我们可以读取输出。为了读取它,我们写入 6 个输出寄存器中的第一个。然后我们在一次扫描中读取 6 个寄存器输出,将 6 个字节放入缓冲区。

测试已经完成

  1. 使用 Adafruit 的库和 Arduino 平台:OK - 输出正常
  2. 使用 Raspberry Pi 2 + python 示例:OK - 输出正常
  3. 使用树莓派 2 + gobot.io + lsm303DLHC 驱动:错误
  4. 按照评论中的建议使用 io.ReadFull() 而不是 io.Read() :错误

前 2 次测试(1 和 2)告诉我传感器工作正常。它没有坏。i2c 速度不是这里的罪魁祸首,因为 python 程序 (2) 也可以。

当从字节正确形成 int16 值时,我怀疑我的代码有问题。 我的驱动程序代码部分用于读取传感器输出并形成结果值

此代码位于 ~/go/src/gobot.io/x/gobot/drivers/i2c/lsm303DLHC.go (又名驱动程序)

func (d *LSM303Driver) MagneticField() (x, z, y float32, err error) {
    // Write to the first output register to start the reading procedure
    if _, err = d.Magnetometer.connection.Write([]byte{lsm303RegisterMagOutXLSB}); err != nil {
        return 0, 0, 0, err
    }

    // create a buffer to put the output bytes
    measurements := make([]byte, 6)
    // read the 6 output bytes
    if _, err = d.Magnetometer.connection.Read(measurements); err != nil {
        return 0, 0, 0, err
    }

    var rawXh uint8
    var rawXl uint8
    var rawZh uint8
    var rawZl uint8
    var rawYh uint8
    var rawYl uint8

    buf := bytes.NewBuffer(measurements)

    binary.Read(buf, binary.BigEndian, &rawXh)
    binary.Read(buf, binary.BigEndian, &rawXl)
    binary.Read(buf, binary.BigEndian, &rawZh)
    binary.Read(buf, binary.BigEndian, &rawZl)
    binary.Read(buf, binary.BigEndian, &rawYh)
    binary.Read(buf, binary.BigEndian, &rawYl)

    rawX := int16((uint16(rawXh) << 8) | uint16(rawXl))
    rawZ := int16((uint16(rawZh) << 8) | uint16(rawZl))
    rawY := int16((uint16(rawYh) << 8) | uint16(rawYl))

    // Gain is set to +/- 2.5 LSB/Gauss (Least Significant Byte)
    // Datasheet page 38
    // Unit convertion: gaussToMicroTesla = 100
    gainXY, gainZ := d.getGainXYZ()

    x = float32(rawX) / float32(gainXY) * float32(gaussToMicroTesla)
    z = float32(rawZ) / float32(gainZ) * float32(gaussToMicroTesla)
    y = float32(rawY) / float32(gainXY) * float32(gaussToMicroTesla)

    fmt.Printf("DEBUG rawX %016b ---> %v \t\t|\t X %v\n", rawX, rawX, x)
    fmt.Printf("DEBUG rawZ %016b ---> %v \t\t|\t Z %v\n", rawZ, rawZ, z)
    fmt.Printf("DEBUG rawY %016b ---> %v \t\t|\t Y %v\n\n", rawY, rawY, y)

    return x, z, y, nil
}

这是我使用此功能的小程序的输出:

...
DEBUG rawX 0000001100101011 ---> 811        |    X 121.04478
DEBUG rawZ 0000001011110111 ---> 759        |    Z 126.5
DEBUG rawY 0000001100110000 ---> 816        |    Y 121.79104

DEBUG rawX 0000001100101011 ---> 811        |    X 121.04478
DEBUG rawZ 0000001011110111 ---> 759        |    Z 126.5
DEBUG rawY 0000001100110000 ---> 816        |    Y 121.79104

DEBUG rawX 0000001100100111 ---> 807        |    X 120.44777
DEBUG rawZ 0000001011110110 ---> 758        |    Z 126.33333
DEBUG rawY 0000001100101100 ---> 812        |    Y 121.19403
...

您可以在每一行看到 rawX(YZ) 二进制和正常表示,然后是微特斯拉的最终值。在所有情况下,这些值都偏离了。即使我向各个方向转动设备,它们也没有太大变化。

我仔细查看了用于 arduino 的Adafruits C++ 库,但没有发现任何重大差异。这是读取磁力计输出的 Adafruit 代码:

 void Adafruit_LSM303_Mag_Unified::read()
 {
   // Read the magnetometer
      Wire.beginTransmission((byte)LSM303_ADDRESS_MAG);

  Wire.send(LSM303_REGISTER_MAG_OUT_X_H_M);

   Wire.endTransmission();
   Wire.requestFrom((byte)LSM303_ADDRESS_MAG, (byte)6);

  // Wait around until enough data is available
   while (Wire.available() < 6);

  // Note high before low (different than accel)
    uint8_t xhi = Wire.receive();
    uint8_t xlo = Wire.receive();
    uint8_t zhi = Wire.receive();
    uint8_t zlo = Wire.receive();
    uint8_t yhi = Wire.receive();
    uint8_t ylo = Wire.receive();

  // Shift values to create properly formed integer (low byte first)
  raw.x = (int16_t)(xlo | ((int16_t)xhi << 8));
  raw.y = (int16_t)(ylo | ((int16_t)yhi << 8));
  raw.z = (int16_t)(zlo | ((int16_t)zhi << 8));
}

我错过了什么巨大的东西吗?(但愿如此...)

老实说,我在这个问题上花了很多时间,但我无处可去。我确实学到了很多关于 linux 内核和 i2c 协议、ioctl 等等的有趣的东西……但我仍然无法使用 gobot.io 使磁力计在 golang 中工作,即使加速度计工作……

I thanks in advance those who will spend the time to read me.

4

0 回答 0