我使用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 个字节放入缓冲区。
测试已经完成
- 使用 Adafruit 的库和 Arduino 平台:OK - 输出正常
- 使用 Raspberry Pi 2 + python 示例:OK - 输出正常
- 使用树莓派 2 + gobot.io + lsm303DLHC 驱动:错误
- 按照评论中的建议使用 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.