lsm303

package module
v0.0.0-...-4f69292 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2022 License: Apache-2.0 Imports: 7 Imported by: 1

README

go-lsm303

Adafruit LSM303 accelerometer and magnetometer via I2C-bus from Raspberry PI

Usage

Acceleroometer
accelerometer, err := NewAccelerometer()
xa, ya, za, err := accelerometer.Sense()
// Configuration
accelerometer.SetRange(ACCELEROMETER_RANGE_16G)
accelerometer.SetMode(ACCELEROMETER_MODE_LOW_POWER)
Magnetometer
// The periph.io has units defined for many things, but not for
// magnetometer flux, so we only have SenseRaw
xm, ym, zm, err := magnetometer.SenseRaw()

// Configuration
magnetometer.SetGain(MAGNETOMETER_GAIN_5_6)
magnetometer.SetRate(MAGNETOMETER_RATE_75)

// The magnetometer also has a relative temperature sensor. It's not
// calibrated, but adding 20 should give the approximate temperature.
temp, err := magnetometer.SenseRelativeTemperature()
Computing heading

With these sensors, you can compute the tilt-compensated heading. Note that the magnetometer will have some hard interference from locally mounted metal objects. To compensate, you will need to log the maximum and minimum magnetometer readings while moving the object through all orientations.

type Axes struct {
    Pitch Radians
    Roll  Radians
    Yaw   Radians
}

xa, ya, za, err := accelerometer.Sense()
xm, ym, zm, err := magnetometer.SenseRaw()
axes := computeAxes(xa, ya, za, xm, ym, zm)

func computeAxes(xRawA, yRawA, zRawA, xRawM, yRawM, zRawM int16) Axes {
    // Avoid divide by zero problems
    if zRawA == 0 {
        zRawA = 1
    }
    // The roll calculation assumes that +y is forward, x is right, and
    // +z is up
    x2 := int32(xRawA) * int32(xRawA)
    z2 := int32(zRawA) * int32(zRawA)

    // Tilt compensated compass readings
    pitch_r := math.Atan2(float64(yRawA), math.Sqrt(float64(x2+z2)))
    roll_r := -math.Atan2(float64(xRawA), float64(zRawA))

    pitch_r -= configuration.PitchOffset
    for pitch_r < ToRadians(-180.0) {
        pitch_r += ToRadians(360.0)
    }
    for pitch_r > ToRadians(180.0) {
        pitch_r -= ToRadians(360.0)
    }

    roll_r -= configuration.RollOffset
    for roll_r < ToRadians(-180.0) {
        roll_r += ToRadians(360.0)
    }
    for roll_r > ToRadians(180.0) {
        roll_r -= ToRadians(360.0)
    }

    temp_m.x -= ((int32_t)m_min.x + m_max.x) / 2;
    temp_m.y -= ((int32_t)m_min.y + m_max.y) / 2;

    // Here you will need to set the maximum and minimum magnetometer
    // readings from calibration as described above
    const int16 maxXM = 0
    const int16 maxYM = 0
    const int16 maxZM = 0
    const int16 minXM = 0
    const int16 minYM = 0
    const int16 minZM = 0

    xM := float64(xRawM - (maxXM - minXM) / 2)
    yM := float64(yRawM - (maxYM - minYM) / 2)
    zM := float64(zRawM - (maxZM - minZM) / 2)
    xHorizontal := xM*math.Cos(-pitch_r) + yM*math.Sin(roll_r)*math.Sin(-pitch_r) - zM*math.Cos(roll_r)*math.Sin(-pitch_r)
    yHorizontal := yM*math.Cos(roll_r) + zM*math.Sin(roll_r)
    yaw_r := math.Atan2(yHorizontal, xHorizontal)
    return Axes{
        Pitch: pitch_r,
        Roll:  roll_r,
        Yaw:   yaw_r,
    }
}

Caveats

This uses periph.io to access peripherals. periph.io made some major updates in 2020, (see Periph's blog post) but I haven't had a chance to test the new version yet. Pull requests welcome!

For best results, you will need to calibrate the magnetometer as described above.

Documentation

Index

Constants

View Source
const (
	// Copied from the data sheet. Unused values are commented out.
	ACCELEROMETER_IDENTIFY    = 0x0F
	ACCELEROMETER_CTRL_REG1_A = 0x20
	//ACCELEROMETER_CTRL_REG2_A     = 0x21
	//ACCELEROMETER_CTRL_REG3_A     = 0x22
	ACCELEROMETER_CTRL_REG4_A = 0x23
	//ACCELEROMETER_CTRL_REG5_A     = 0x24
	//ACCELEROMETER_CTRL_REG6_A     = 0x25
	//ACCELEROMETER_REFERENCE_A     = 0x26
	//ACCELEROMETER_STATUS_REG_A    = 0x27
	ACCELEROMETER_OUT_X_L_A = 0x28
	ACCELEROMETER_OUT_X_H_A = 0x29
	ACCELEROMETER_OUT_Y_L_A = 0x2A
	ACCELEROMETER_OUT_Y_H_A = 0x2B
	ACCELEROMETER_OUT_Z_L_A = 0x2C
	ACCELEROMETER_OUT_Z_H_A = 0x2D
)
View Source
const (
	// Copied from the data sheet. Unused values are commented out.
	MAGNETOMETER_CRA_REG_M = 0x00
	MAGNETOMETER_CRB_REG_M = 0x01
	MAGNETOMETER_MR_REG_M  = 0x02
	MAGNETOMETER_OUT_X_H_M = 0x03
	MAGNETOMETER_OUT_X_L_M = 0x04
	MAGNETOMETER_OUT_Z_H_M = 0x05
	MAGNETOMETER_OUT_Z_L_M = 0x06
	MAGNETOMETER_OUT_Y_H_M = 0x07
	MAGNETOMETER_OUT_Y_L_M = 0x08
	//MAGNETOMETER_SR_REG_M  = 0x09
	MAGNETOMETER_IRA_REG_M = 0x0A
	//MAGNETOMETER_IRB_REG_M = 0x0B
	//MAGNETOMETER_IRC_REG_M = 0x0C
	MAGNETOMETER_TEMP_OUT_H_M = 0x31
	MAGNETOMETER_TEMP_OUT_L_M = 0x32
)
View Source
const ACCELEROMETER_ADDRESS = 0x19
View Source
const MAGNETOMETER_ADDRESS = 0x1E

Variables

View Source
var DefaultAccelerometerOpts = AccelerometerOpts{
	Range: ACCELEROMETER_RANGE_4G,
	Mode:  ACCELEROMETER_MODE_NORMAL,
}

DefaultAccelerometerOpts is the recommended default options.

View Source
var DefaultMagnetometerOpts = MagnetometerOpts{
	Gain: MAGNETOMETER_GAIN_4_0,
	Rate: MAGNETOMETER_RATE_30,
}

DefaultMagnetometerOpts is the recommended default options.

Functions

This section is empty.

Types

type Accelerometer

type Accelerometer struct {
	// contains filtered or unexported fields
}

This is a handle to the LSM303 accelerometer sensor.

func NewAccelerometer

func NewAccelerometer(bus i2c.Bus, opts *AccelerometerOpts) (*Accelerometer, error)

New accelerometer opens a handle to an LSM303 accelerometer sensor.

func (*Accelerometer) GetMode

func (accelerometer *Accelerometer) GetMode() (AccelerometerMode, error)

func (*Accelerometer) GetRange

func (accelerometer *Accelerometer) GetRange() (AccelerometerRange, error)

func (*Accelerometer) Sense

func (accelerometer *Accelerometer) Sense() (physic.Force, physic.Force, physic.Force, error)

func (*Accelerometer) SenseRaw

func (accelerometer *Accelerometer) SenseRaw() (int16, int16, int16, error)

func (*Accelerometer) SetMode

func (accelerometer *Accelerometer) SetMode(mode AccelerometerMode) error

func (*Accelerometer) SetRange

func (accelerometer *Accelerometer) SetRange(range_ AccelerometerRange) error

func (*Accelerometer) String

func (accelerometer *Accelerometer) String() string

type AccelerometerMode

type AccelerometerMode int
const (
	ACCELEROMETER_MODE_NORMAL AccelerometerMode = iota
	ACCELEROMETER_MODE_HIGH_RESOLUTION
	ACCELEROMETER_MODE_LOW_POWER
)

func (AccelerometerMode) String

func (mode AccelerometerMode) String() string

type AccelerometerOpts

type AccelerometerOpts struct {
	Range AccelerometerRange
	Mode  AccelerometerMode
}

Opts holds the configuration options.

type AccelerometerRange

type AccelerometerRange int
const (
	ACCELEROMETER_RANGE_2G AccelerometerRange = iota
	ACCELEROMETER_RANGE_4G
	ACCELEROMETER_RANGE_8G
	ACCELEROMETER_RANGE_16G
)

func (AccelerometerRange) String

func (range_ AccelerometerRange) String() string

type Magnetometer

type Magnetometer struct {
	// contains filtered or unexported fields
}

This is a handle to the LSM303 magnetometer sensor.

func NewMagnetometer

func NewMagnetometer(bus i2c.Bus, opts *MagnetometerOpts) (*Magnetometer, error)

New magnetometer opens a handle to an LSM303 magnetometer sensor.

func (*Magnetometer) GetGain

func (magnetometer *Magnetometer) GetGain() (MagnetometerGain, error)

func (*Magnetometer) GetRate

func (magnetometer *Magnetometer) GetRate() (MagnetometerRate, error)

func (*Magnetometer) SenseRaw

func (magnetometer *Magnetometer) SenseRaw() (int16, int16, int16, error)

func (*Magnetometer) SenseRelativeTemperature

func (magnetometer *Magnetometer) SenseRelativeTemperature() (physic.Temperature, error)

The temperature sensor is technically on the same line as the magnetometer, so that's why I'm putting as a Magnetometer method. Note that the sensor is uncalibrated, so it can't return an absolute temperature, but from what I've read online, adding about 20 degrees C should get you close.

func (*Magnetometer) SetGain

func (magnetometer *Magnetometer) SetGain(gain MagnetometerGain) error

func (*Magnetometer) SetRate

func (magnetometer *Magnetometer) SetRate(mode MagnetometerRate) error

type MagnetometerGain

type MagnetometerGain int
const (
	MAGNETOMETER_GAIN_1_3 MagnetometerGain = iota
	MAGNETOMETER_GAIN_1_9
	MAGNETOMETER_GAIN_2_5
	MAGNETOMETER_GAIN_4_0
	MAGNETOMETER_GAIN_4_7
	MAGNETOMETER_GAIN_5_6
	MAGNETOMETER_GAIN_8_1
)

func (MagnetometerGain) String

func (mode MagnetometerGain) String() string

type MagnetometerOpts

type MagnetometerOpts struct {
	Gain MagnetometerGain
	Rate MagnetometerRate
}

Opts holds the configuration options.

type MagnetometerRate

type MagnetometerRate int
const (
	MAGNETOMETER_RATE_0_75 MagnetometerRate = iota
	MAGNETOMETER_RATE_1_5
	MAGNETOMETER_RATE_3_0
	MAGNETOMETER_RATE_7_5
	MAGNETOMETER_RATE_15
	MAGNETOMETER_RATE_30
	MAGNETOMETER_RATE_75
	MAGNETOMETER_RATE_220
)

func (MagnetometerRate) String

func (range_ MagnetometerRate) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL