1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-04-24 13:48:49 +08:00

Adding support for hmc8553l compass

This commit is contained in:
Yuri Gorokhov 2021-02-01 18:07:18 -08:00 committed by Ron Evans
parent 97d23a5aec
commit 979379d765
6 changed files with 240 additions and 1 deletions

View File

@ -275,6 +275,7 @@ drivers provided using the `gobot/drivers/i2c` package:
- GrovePi Expansion Board
- Grove RGB LCD
- HMC6352 Compass
- HMC8553L 3-Axis Digital Compass
- INA3221 Voltage Monitor
- JHD1313M1 LCD Display w/RGB Backlight
- L3GD20H 3-Axis Gyroscope

View File

@ -36,7 +36,6 @@ https://github.com/hybridgroup/gobot/issues
- ensure that SMBUS operations are working as expected.
- add support for the following i2c devices:
- HMC5883L
- LSM303DLHC
- MAG3110
- MMA8452

View File

@ -27,6 +27,7 @@ Gobot has a extensible system for connecting to hardware devices. The following
- GrovePi Expansion Board
- Grove RGB LCD
- HMC6352 Compass
- HMC8553L 3-Axis Digital Compass
- INA3221 Voltage Monitor
- JHD1313M1 LCD Display w/RGB Backlight
- L3GD20H 3-Axis Gyroscope

View File

@ -0,0 +1,120 @@
package i2c
import (
"math"
"gobot.io/x/gobot"
)
const (
defaultAddress = 0x1e // default I2C Address
registerA = 0x0 // Address of Configuration register A
registerB = 0x01 // Address of Configuration register B
registerMode = 0x02 // Address of node register
xAxisH = 0x03 // Address of X-axis MSB data register
zAxisH = 0x05 // Address of Z-axis MSB data register
yAxisH = 0x07 // Address of Y-axis MSB data register
)
// HMC8553LDriver is a Driver for a HMC6352 digital compass
type HMC8553LDriver struct {
name string
connector Connector
connection Connection
Config
}
// NewHMC8553LDriver creates a new driver with specified i2c interface
// Params:
// conn Connector - the Adaptor to use with this Driver
//
// Optional params:
// i2c.WithBus(int): bus to use with this driver
// i2c.WithAddress(int): address to use with this driver
//
func NewHMC8553LDriver(a Connector, options ...func(Config)) *HMC8553LDriver {
hmc := &HMC8553LDriver{
name: gobot.DefaultName("HMC8553L"),
connector: a,
Config: NewConfig(),
}
for _, option := range options {
option(hmc)
}
return hmc
}
// Name returns the name for this Driver
func (h *HMC8553LDriver) Name() string { return h.name }
// SetName sets the name for this Driver
func (h *HMC8553LDriver) SetName(n string) { h.name = n }
// Connection returns the connection for this Driver
func (h *HMC8553LDriver) Connection() gobot.Connection { return h.connector.(gobot.Connection) }
// Start initializes the HMC8553L
func (h *HMC8553LDriver) Start() (err error) {
bus := h.GetBusOrDefault(h.connector.GetDefaultBus())
address := h.GetAddressOrDefault(defaultAddress)
h.connection, err = h.connector.GetConnection(address, bus)
if err != nil {
return err
}
if err := h.connection.WriteByteData(registerA, 0x70); err != nil {
return err
}
if err := h.connection.WriteByteData(registerB, 0xa0); err != nil {
return err
}
if err := h.connection.WriteByteData(registerMode, 0); err != nil {
return err
}
return
}
// Halt returns true if devices is halted successfully
func (h *HMC8553LDriver) Halt() (err error) { return }
// ReadRawData reads the raw values from the X, Y, and Z registers
func (h *HMC8553LDriver) ReadRawData() (x int16, y int16, z int16, err error) {
unsignedX, err := h.connection.ReadWordData(xAxisH)
if err != nil {
return
}
unsignedY, err := h.connection.ReadWordData(yAxisH)
if err != nil {
return
}
unsignedZ, err := h.connection.ReadWordData(zAxisH)
if err != nil {
return
}
return unsignedToSigned(unsignedX), unsignedToSigned(unsignedY), unsignedToSigned(unsignedZ), nil
}
// Heading returns the current heading in radians
func (h *HMC8553LDriver) Heading() (heading float64, err error) {
var x, y int16
x, y, _, err = h.ReadRawData()
if err != nil {
return
}
heading = math.Atan2(float64(y), float64(x))
if heading > 2*math.Pi {
heading -= 2 * math.Pi
}
if heading < 0 {
heading += 2 * math.Pi
}
return
}
func unsignedToSigned(unsignedValue uint16) int16 {
if unsignedValue > 32768 {
return int16(unsignedValue) - ^int16(0) - ^int16(0) - 2
}
return int16(unsignedValue)
}

View File

@ -0,0 +1,72 @@
package i2c
import (
"errors"
"testing"
"gobot.io/x/gobot"
"gobot.io/x/gobot/gobottest"
)
var _ gobot.Driver = (*HMC8553LDriver)(nil)
// --------- HELPERS
func initTestHMC8553LDriver() (driver *HMC8553LDriver) {
driver, _ = initTestHMC8553LDriverWithStubbedAdaptor()
return
}
func initTestHMC8553LDriverWithStubbedAdaptor() (*HMC8553LDriver, *i2cTestAdaptor) {
adaptor := newI2cTestAdaptor()
return NewHMC8553LDriver(adaptor), adaptor
}
// --------- TESTS
func TestNewHMC8553LDriver(t *testing.T) {
// Does it return a pointer to an instance of HMC8553LDriver?
var bm interface{} = NewHMC8553LDriver(newI2cTestAdaptor())
_, ok := bm.(*HMC8553LDriver)
if !ok {
t.Errorf("NewHMC8553LDriver() should have returned a *HMC8553LDriver")
}
b := NewHMC8553LDriver(newI2cTestAdaptor())
gobottest.Refute(t, b.Connection(), nil)
}
// Methods
func TestHMC8553LDriverStart(t *testing.T) {
hmc, adaptor := initTestHMC8553LDriverWithStubbedAdaptor()
gobottest.Assert(t, hmc.Start(), nil)
adaptor.i2cWriteImpl = func([]byte) (int, error) {
return 0, errors.New("write error")
}
err := hmc.Start()
gobottest.Assert(t, err, errors.New("write error"))
}
func Test8553LStartConnectError(t *testing.T) {
d, adaptor := initTestHMC8553LDriverWithStubbedAdaptor()
adaptor.Testi2cConnectErr(true)
gobottest.Assert(t, d.Start(), errors.New("Invalid i2c connection"))
}
func TestHMC8553LDriverHalt(t *testing.T) {
hmc := initTestHMC8553LDriver()
gobottest.Assert(t, hmc.Halt(), nil)
}
func TestHMC8553LDriverSetName(t *testing.T) {
d := initTestHMC8553LDriver()
d.SetName("TESTME")
gobottest.Assert(t, d.Name(), "TESTME")
}
func TestHMC8553LDriverOptions(t *testing.T) {
d := NewHMC8553LDriver(newI2cTestAdaptor(), WithBus(2))
gobottest.Assert(t, d.GetBusOrDefault(1), 2)
}

View File

@ -0,0 +1,46 @@
// +build example
//
// Do not build by default.
/*
How to run
go run examples/firmata_hmc8553l.go
*/
package main
import (
"fmt"
"time"
"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/i2c"
"gobot.io/x/gobot/platforms/raspi"
)
func main() {
raspi := raspi.NewAdaptor()
hmc8553l := i2c.NewHMC8553LDriver(raspi)
work := func() {
gobot.Every(200*time.Millisecond, func() {
// get heading in radians, to convert to degrees multiply by 180/math.Pi
heading, _ := hmc8553l.Heading()
fmt.Println("Heading", heading)
// read the raw data from the device, this is useful for calibration
x, y, z, _ := hmc8553l.ReadRawData()
fmt.Println(x, y, z)
})
}
robot := gobot.NewRobot("hmc8553LBot",
[]gobot.Connection{raspi},
[]gobot.Device{hmc8553l},
work,
)
robot.Start()
}