dongqingchan2385 2018-11-29 14:50
浏览 228

i2c总线上LSM303DLHC传感器的磁力计输出不稳定。 问题写作gobot飞行员

I use the Adafruit LSM303DLHC sensor. It is made of 2 sensors, an accelerometer and a magnetometer. I am currently writing a driver for this sensor to work with the gobot.io package through i2c interface on a Raspberry Pi 2.

Problem: The accelerometer part works. The magnetometer sensor part doesn't. I can read the magnetic field registers but I get nonsensical values. Those values are updating between each reading cycle, but they are not varying much and doesn't make sense.

Devices used:

  • LSM303DLHC sensor - Datasheet
  • Raspberry Pi 2
  • Arduino Uno

Details about reading the magnetometer output:

LSM303DLHC output 6 bytes representing 3 magnetic field values along the 3 axis. Each value is made of 2 bytes (16bits) for each axis. The output order is the following:

  • X high byte
  • X low byte
  • Z high byte
  • Z low byte
  • Y high byte
  • Y low byte

In order to set up the sensor we write in the following registers in that order:

  • Reset the magnetometer gain: write 0x00 in CRB_REG_M register(0x01)
  • Set the magnetometer gain: Write 0x60 (+/- 2.5 gauss) to CRB_REG_M register(0x01)
  • Set the output data rate: Write 0x05 (30 Hz) in CRA_REG_M register(0x00)
  • Enable continuous mode: Write 0x00 in MR_REG_M register

After setting up the sensor we can read the output. In order to read it, we write to the 1st of the 6 output registers. Then we read the 6 registers output in one sweep, putting the 6 bytes in a buffer.

Test already done

  1. Using Adafruit's library and Arduino platform: OK - output is normal
  2. Using Raspberry Pi 2 + python example: OK - output is normal
  3. Using Raspberry Pi 2 + gobot.io + lsm303DLHC driver: Error
  4. Using io.ReadFull() instead of io.Read() as suggested in the comment: Error

The first 2 tests (1 & 2) tell me that the sensor work. It's not broken. The i2c speed is not the culprit here because the python program (2) works too.

I suspect something is wrong in my code when it comes to properly form int16 values from the bytes. My driver code part to read the sensor output and form the resulting values

This code live in ~/go/src/gobot.io/x/gobot/drivers/i2c/lsm303DLHC.go (a.k.a the driver)

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
", rawX, rawX, x)
    fmt.Printf("DEBUG rawZ %016b ---> %v \t\t|\t Z %v
", rawZ, rawZ, z)
    fmt.Printf("DEBUG rawY %016b ---> %v \t\t|\t Y %v

", rawY, rawY, y)

    return x, z, y, nil
}

Here is the output of my little program which use this function:

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

You can see on each line the rawX(Y-Z) binary and normal representation then the definitive value in micro-tesla. In all cases those values are way off. They do not vary much even when I turn the device in every direction.

I looked closely to Adafruits C++ library for arduino and I don't see any major difference. Here is the Adafruit code for reading the magnetometer output:

 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));
}

Am I missing something huge? (I hope so...)

Honestly I spend a crazy amount of time on this problem and I am nowhere. I did learn a lot of interesting things about the linux kernel and i2c protocol, ioctl and more... but I am still not able to make the magnetometer work in golang with gobot.io, even if the accelerometer works...

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

  • 写回答

0条回答

    报告相同问题?

    悬赏问题

    • ¥100 Jenkins自动化部署—悬赏100元
    • ¥15 关于#python#的问题:求帮写python代码
    • ¥20 MATLAB画图图形出现上下震荡的线条
    • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
    • ¥15 perl MISA分析p3_in脚本出错
    • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
    • ¥15 ubuntu虚拟机打包apk错误
    • ¥199 rust编程架构设计的方案 有偿
    • ¥15 回答4f系统的像差计算
    • ¥15 java如何提取出pdf里的文字?