diff --git a/.canon.yaml b/.canon.yaml
index 798511f..78246ba 100644
--- a/.canon.yaml
+++ b/.canon.yaml
@@ -1,5 +1,5 @@
# This file provides project-level configuration for the canon dev environment utility. https://github.com/viamrobotics/canon
-MODULE:
+tdk-invensense:
default: true
image_amd64: ghcr.io/viamrobotics/rdk-devenv:amd64-cache
image_arm64: ghcr.io/viamrobotics/rdk-devenv:arm64-cache
@@ -9,7 +9,7 @@ MODULE:
group: testbot
persistent: true
-MODULE-antique:
+tdk-invensense-antique:
image_amd64: ghcr.io/viamrobotics/antique2:amd64-cache
image_arm64: ghcr.io/viamrobotics/antique2:arm64-cache
minimum_date: 2023-10-26T20:00:00.0Z
diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml
index 3a6d0dd..80704b6 100644
--- a/.github/workflows/pr-labeler.yml
+++ b/.github/workflows/pr-labeler.yml
@@ -21,14 +21,14 @@ jobs:
script: |
let prNumber = context.payload.pull_request && context.payload.pull_request.number;
try {
- await github.rest.issues.removeLabel({owner: "viam-modules", repo: "MODULE", issue_number: prNumber, name: "safe to test"});
+ await github.rest.issues.removeLabel({owner: "viam-modules", repo: "tdk-invensense", issue_number: prNumber, name: "safe to test"});
} catch (err) {
core.info(`Non-fatal error ${err}, while trying to remove 'safe to test' label.`);
}
let orgResp = await github.rest.orgs.checkMembershipForUser({org: "viam-modules", username: context.payload.sender.login});
if (orgResp.status === 204) {
// order of labeling events must be preserved, so two seperate calls
- await github.rest.issues.addLabels({owner: "viam-modules", repo: "MODULE", issue_number: prNumber, labels: ["safe to test"]});
+ await github.rest.issues.addLabels({owner: "viam-modules", repo: "tdk-invensense", issue_number: prNumber, labels: ["safe to test"]});
return true;
}
return false;
diff --git a/.github/workflows/pullrequest-trusted.yml b/.github/workflows/pullrequest-trusted.yml
index cbde6c8..325dd76 100644
--- a/.github/workflows/pullrequest-trusted.yml
+++ b/.github/workflows/pullrequest-trusted.yml
@@ -12,10 +12,10 @@ on:
jobs:
test:
if: (github.event.label.name == 'safe to test' || github.event.label.name == 'appimage')
- uses: viam-modules/MODULE/.github/workflows/test.yml@main
+ uses: viam-modules/tdk-invensense/.github/workflows/test.yml@main
secrets:
MONGODB_TEST_OUTPUT_URI: ${{ secrets.MONGODB_TEST_OUTPUT_URI }}
DOCKER_PUBLIC_READONLY_PAT: ${{ secrets.DOCKER_PUBLIC_READONLY_PAT }}
license_finder:
- uses: viam-modules/MODULE/.github/workflows/license_finder.yml@main
+ uses: viam-modules/tdk-invensense/.github/workflows/license_finder.yml@main
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d7598d2..ba4bd9f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -46,10 +46,10 @@ jobs:
- name: Build and package
run: |
- canon --profile MODULE
+ canon --profile tdk-invensense
TARGET_OS=${{ matrix.platform }} TARGET_ARCH=${{ matrix.arch }} make module
- - name: Upload MODULE module to registry
+ - name: Upload tdk-invensense module to registry
uses: viamrobotics/upload-module@main
with:
meta-path: meta.json
diff --git a/MODEL/MODEL.go b/MODEL/MODEL.go
deleted file mode 100644
index e69de29..0000000
diff --git a/Makefile b/Makefile
index a348bb3..a333bbf 100644
--- a/Makefile
+++ b/Makefile
@@ -9,13 +9,13 @@ endif
module: build
rm -f $(BIN_OUTPUT_PATH)/module.tar.gz
- tar czf $(BIN_OUTPUT_PATH)/module.tar.gz $(BIN_OUTPUT_PATH)/MODULE meta.json
+ tar czf $(BIN_OUTPUT_PATH)/module.tar.gz $(BIN_OUTPUT_PATH)/tdk-invensense meta.json
build: build-go
build-go:
- rm -f $(BIN_OUTPUT_PATH)/MODULE
- go build -tags no_cgo,osusergo,netgo -ldflags="-extldflags=-static $(COMMON_LDFLAGS)" -o $(BIN_OUTPUT_PATH)/MODULE main.go
+ rm -f $(BIN_OUTPUT_PATH)/tdk-invensense
+ go build -tags no_cgo,osusergo,netgo -ldflags="-extldflags=-static $(COMMON_LDFLAGS)" -o $(BIN_OUTPUT_PATH)/tdk-invensense main.go
tool-install:
GOBIN=`pwd`/$(TOOL_BIN) go install \
diff --git a/README.md b/README.md
index ac25dd7..56ce650 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
-# [`MODULE` module](https://github.com/viam-modules/MODULE)
+# [`tdk-invensense` module](https://github.com/viam-modules/tdk-invensense)
-This [MODULE module](https://app.viam.com/module/viam/MODULE) implements a MODULE [MODEL COMPONENT](), used for using the [`rdk:component:COMPONENT` API](https://docs.viam.com/appendix/apis/components/COMPONENT/).
+This [tdk-invensense module](https://app.viam.com/module/viam/tdk-invensense) implements a tdk-invensense [mpu6050 movement_sensor](), used for using the [`rdk:component:movement_sensor` API](https://docs.viam.com/appendix/apis/components/movement_sensor/).
> [!NOTE]
-> Before configuring your COMPONENT, you must [create a machine](https://docs.viam.com/cloud/machines/#add-a-new-machine).
+> Before configuring your movement_sensor, you must [create a machine](https://docs.viam.com/cloud/machines/#add-a-new-machine).
-## Configure your MODEL COMPONENT
+## Configure your mpu6050 movement_sensor
Navigate to the [**CONFIGURE** tab](https://docs.viam.com/configure/) of your [machine](https://docs.viam.com/fleet/machines/) in the [Viam app](https://app.viam.com/).
-[Add COMPONENT / MODULE:MODEL to your machine](https://docs.viam.com/configure/#components).
+[Add movement_sensor / tdk-invensense:mpu6050 to your machine](https://docs.viam.com/configure/#components).
-On the new component panel, copy and paste the following attribute template into your COMPONENT's attributes field:
+On the new component panel, copy and paste the following attribute template into your movement_sensor's attributes field:
```json
{
@@ -20,22 +20,22 @@ On the new component panel, copy and paste the following attribute template into
### Attributes
-The following attributes are available for `viam:MODULE:MODEL` COMPONENTs:
+The following attributes are available for `viam:tdk-invensense:mpu6050` movement_sensors:
| Attribute | Type | Required? | Description |
| --------- | ---- | --------- | ---------- |
-| `i2c_bus` | string | **Required** | The index of the I2C bus on the board that the COMPONENT is wired to. |
-| `i2c_address` | string | Optional | Default: `0x77`. The [I2C device address](https://learn.adafruit.com/i2c-addresses/overview) of the COMPONENT. |
+| `i2c_bus` | string | **Required** | The index of the I2C bus on the board that the movement_sensor is wired to. |
+| `i2c_address` | string | Optional | Default: `0x77`. The [I2C device address](https://learn.adafruit.com/i2c-addresses/overview) of the movement_sensor. |
## Example configuration
-### `viam:MODULE:MODEL`
+### `viam:tdk-invensense:mpu6050`
```json
{
- "name": "",
- "model": "viam:MODULE:MODEL",
- "type": "COMPONENT",
+ "name": "",
+ "model": "viam:tdk-invensense:mpu6050",
+ "type": "movement_sensor",
"namespace": "rdk",
"attributes": {
},
@@ -44,6 +44,6 @@ The following attributes are available for `viam:MODULE:MODEL` COMPONENTs:
```
### Next Steps
-- To test your COMPONENT, expand the **TEST** section of its configuration pane or go to the [**CONTROL** tab](https://docs.viam.com/fleet/control/).
-- To write code against your COMPONENT, use one of the [available SDKs](https://docs.viam.com/sdks/).
-- To view examples using a COMPONENT component, explore [these tutorials](https://docs.viam.com/tutorials/).
\ No newline at end of file
+- To test your movement_sensor, expand the **TEST** section of its configuration pane or go to the [**CONTROL** tab](https://docs.viam.com/fleet/control/).
+- To write code against your movement_sensor, use one of the [available SDKs](https://docs.viam.com/sdks/).
+- To view examples using a movement_sensor component, explore [these tutorials](https://docs.viam.com/tutorials/).
\ No newline at end of file
diff --git a/go.mod b/go.mod
index d903c1e..4acce2a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module MODULE
+module tdk-invensense
go 1.23.0
@@ -7,9 +7,13 @@ require (
github.com/axw/gocov v1.1.0
github.com/edaniels/golinters v0.0.5-0.20220906153528-641155550742
github.com/fullstorydev/grpcurl v1.8.6
+ github.com/golang/geo v0.0.0-20210211234256-740aa86cb551
github.com/golangci/golangci-lint v1.61.0
+ github.com/kellydunn/golang-geo v0.7.0
+ github.com/pkg/errors v0.9.1
github.com/rhysd/actionlint v1.6.24
go.viam.com/rdk v0.48.2
+ go.viam.com/test v1.1.1-0.20220913152726-5da9916c08a2
go.viam.com/utils v0.1.110
gotest.tools/gotestsum v1.10.0
)
@@ -42,11 +46,15 @@ require (
github.com/alexkohler/nakedret/v2 v2.0.4 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
+ github.com/apache/arrow/go/arrow v0.0.0-20201229220542-30ce2eb5d4dc // indirect
github.com/ashanbrown/forbidigo v1.6.0 // indirect
github.com/ashanbrown/makezero v1.1.1 // indirect
+ github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect
+ github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bep/debounce v1.2.1 // indirect
github.com/bkielbasa/cyclop v1.2.1 // indirect
+ github.com/blackjack/webcam v0.6.1 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bluenviron/gortsplib/v4 v4.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.4.1 // indirect
@@ -65,6 +73,8 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/chavacava/garif v0.1.0 // indirect
+ github.com/chewxy/hm v1.0.0 // indirect
+ github.com/chewxy/math32 v1.0.8 // indirect
github.com/ckaznocha/intrange v0.2.0 // indirect
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect
@@ -73,6 +83,7 @@ require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
+ github.com/disintegration/imaging v1.6.2 // indirect
github.com/dnephin/pflag v1.0.7 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/edaniels/golog v0.0.0-20230215213219-28954395e8d0 // indirect
@@ -87,15 +98,22 @@ require (
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
+ github.com/fogleman/gg v1.3.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
+ github.com/gen2brain/malgo v0.11.21 // indirect
github.com/ghostiam/protogetter v0.3.6 // indirect
+ github.com/go-audio/audio v1.0.0 // indirect
+ github.com/go-audio/riff v1.0.0 // indirect
+ github.com/go-audio/transforms v0.0.0-20180121090939-51830ccc35a5 // indirect
+ github.com/go-audio/wav v1.1.0 // indirect
github.com/go-critic/go-critic v0.11.4 // indirect
github.com/go-fonts/liberation v0.3.0 // indirect
github.com/go-gl/mathgl v1.0.0 // indirect
github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-nlopt/nlopt v0.0.0-20230219125344-443d3362dcb5 // indirect
github.com/go-pdf/fpdf v0.6.0 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
@@ -109,9 +127,9 @@ require (
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/flock v0.12.1 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
- github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
@@ -123,6 +141,7 @@ require (
github.com/golangci/revgrep v0.5.3 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
github.com/gonuts/binary v0.2.0 // indirect
+ github.com/google/flatbuffers v2.0.6+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
@@ -150,7 +169,6 @@ require (
github.com/jjti/go-spancheck v0.6.2 // indirect
github.com/julz/importas v0.1.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
- github.com/kellydunn/golang-geo v0.7.0 // indirect
github.com/kisielk/errcheck v1.7.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
github.com/klauspost/compress v1.16.5 // indirect
@@ -169,6 +187,7 @@ require (
github.com/lestrrat-go/jwx v1.2.29 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lib/pq v1.10.9 // indirect
+ github.com/lmittmann/ppm v1.0.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufeee/execinquery v1.2.1 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
@@ -186,6 +205,8 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/montanaflynn/stats v0.7.0 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
+ github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect
+ github.com/muesli/kmeans v0.3.1 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
@@ -199,6 +220,7 @@ require (
github.com/pion/interceptor v0.1.29 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.12 // indirect
+ github.com/pion/mediadevices v0.6.4 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.14 // indirect
github.com/pion/rtp v1.8.7 // indirect
@@ -208,7 +230,7 @@ require (
github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.10 // indirect
github.com/pion/turn/v2 v2.1.6 // indirect
- github.com/pkg/errors v0.9.1 // indirect
+ github.com/pion/webrtc/v3 v3.2.36 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.6.0 // indirect
@@ -266,6 +288,8 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect
+ github.com/xfmoulet/qoi v0.2.0 // indirect
+ github.com/xtgo/set v1.0.0 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
@@ -288,7 +312,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.viam.com/api v0.1.350 // indirect
- go.viam.com/test v1.1.1-0.20220913152726-5da9916c08a2 // indirect
+ go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect
@@ -302,6 +326,7 @@ require (
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0 // indirect
+ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gonum.org/v1/gonum v0.12.0 // indirect
gonum.org/v1/plot v0.12.0 // indirect
google.golang.org/api v0.196.0 // indirect
@@ -312,10 +337,16 @@ require (
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
+ gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ gorgonia.org/tensor v0.9.24 // indirect
+ gorgonia.org/vecf32 v0.9.0 // indirect
+ gorgonia.org/vecf64 v0.9.0 // indirect
honnef.co/go/tools v0.5.1 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
nhooyr.io/websocket v1.8.7 // indirect
+ periph.io/x/conn/v3 v3.7.0 // indirect
+ periph.io/x/host/v3 v3.8.1-0.20230331112814-9f0d9f7d76db // indirect
)
diff --git a/go.sum b/go.sum
index 2d19bd2..56a6cd1 100644
--- a/go.sum
+++ b/go.sum
@@ -233,6 +233,7 @@ github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/chewxy/hm v1.0.0 h1:zy/TSv3LV2nD3dwUEQL2VhXeoXbb9QkpmdRAVUFiA6k=
github.com/chewxy/hm v1.0.0/go.mod h1:qg9YI4q6Fkj/whwHR1D+bOGeF7SniIP40VweVepLjg0=
+github.com/chewxy/math32 v1.0.0/go.mod h1:Miac6hA1ohdDUTagnvJy/q+aNnEk16qWUdb8ZVhvCN0=
github.com/chewxy/math32 v1.0.8 h1:fU5E4Ec4Z+5RtRAi3TovSxUjQPkgRh+HbP7tKB2OFbM=
github.com/chewxy/math32 v1.0.8/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -583,6 +584,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs=
+github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.6+incompatible h1:XHFReMv7nFFusa+CEokzWbzaYocKXI6C7hdU5Kgh9Lw=
github.com/google/flatbuffers v2.0.6+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -761,6 +763,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
+github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg=
+github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -813,6 +817,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -968,6 +973,7 @@ github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGq
github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8=
github.com/mozilla/tls-observatory v0.0.0-20201209171846-0547674fceff/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/mozilla/tls-observatory v0.0.0-20210209181001-cf43108d6880/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s=
+github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 h1:p4A2Jx7Lm3NV98VRMKlyWd3nqf8obft8NfXlAUmqd3I=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/kmeans v0.3.1 h1:KshLQ8wAETfLWOJKMuDCVYHnafddSa1kwGh/IypGIzY=
@@ -1312,6 +1318,7 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -1391,6 +1398,7 @@ github.com/viamrobotics/evdev v0.1.3/go.mod h1:N6nuZmPz7HEIpM7esNWwLxbYzqWqLSZkf
github.com/viamrobotics/webrtc/v3 v3.99.10 h1:ykE14wm+HkqMD5Ozq4rvhzzfvnXAu14ak/HzA1OCzfY=
github.com/viamrobotics/webrtc/v3 v3.99.10/go.mod h1:ziH7/S52IyYAeDdwUUl5ZTbuyKe47fWorAz+0z5w6NA=
github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE=
+github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg=
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@@ -1556,6 +1564,8 @@ golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMx
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
@@ -1628,6 +1638,7 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -1728,6 +1739,7 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1994,6 +2006,7 @@ google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4=
@@ -2028,6 +2041,7 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200910201057-6591123024b3/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff --git a/main.go b/main.go
index 9e7afc2..aa82a00 100644
--- a/main.go
+++ b/main.go
@@ -4,13 +4,16 @@ package main
import (
"context"
+ "tdk-invensense/mpu6050"
+
+ "go.viam.com/rdk/components/movementsensor"
"go.viam.com/rdk/logging"
"go.viam.com/rdk/module"
"go.viam.com/utils"
)
func main() {
- utils.ContextualMain(mainWithArgs, module.NewLoggerFromArgs("MODULE"))
+ utils.ContextualMain(mainWithArgs, module.NewLoggerFromArgs("tdk-invensense"))
}
func mainWithArgs(ctx context.Context, args []string, logger logging.Logger) error {
@@ -19,7 +22,7 @@ func mainWithArgs(ctx context.Context, args []string, logger logging.Logger) err
return err
}
- if err = module.AddModelFromRegistry(ctx, COMPONENT.API, MODEL.Model); err != nil {
+ if err = module.AddModelFromRegistry(ctx, movementsensor.API, mpu6050.Model); err != nil {
return err
}
diff --git a/meta.json b/meta.json
index f8d7db0..910036e 100644
--- a/meta.json
+++ b/meta.json
@@ -1,13 +1,13 @@
{
"$schema": "https://dl.viam.dev/module.schema.json",
- "module_id": "viam:MODULE",
+ "module_id": "viam:tdk-invensense",
"visibility": "public",
- "url": "https://github.com/viam-modules/MODULE",
- "description": "Go module for MODULE MODEL COMPONENT, compatible with Viam",
+ "url": "https://github.com/viam-modules/tdk-invensense",
+ "description": "Go module for tdk-invensense mpu6050 movement_sensor, compatible with Viam",
"models": [
{
- "api": "rdk:component:COMPONENT",
- "model": "viam:MODULE:MODEL"
+ "api": "rdk:component:movement_sensor",
+ "model": "viam:tdk-invensense:mpu6050"
}
],
"build": {
@@ -15,5 +15,5 @@
"path": "bin/module.tar.gz",
"arch" : ["linux/arm64", "linux/amd64", "darwin/arm64"]
},
- "entrypoint": "bin/MODULE"
+ "entrypoint": "bin/tdk-invensense"
}
\ No newline at end of file
diff --git a/mpu6050/mpu6050.go b/mpu6050/mpu6050.go
new file mode 100644
index 0000000..4e4c1c0
--- /dev/null
+++ b/mpu6050/mpu6050.go
@@ -0,0 +1,350 @@
+//go:build linux
+
+// Package mpu6050 implements the movementsensor interface for an MPU-6050 6-axis accelerometer. A
+// datasheet for this chip is at
+// https://components101.com/sites/default/files/component_datasheet/MPU6050-DataSheet.pdf and a
+// description of the I2C registers is at
+// https://download.datasheets.com/pdfs/2015/3/19/8/3/59/59/invse_/manual/5rm-mpu-6000a-00v4.2.pdf
+//
+// We support reading the accelerometer, gyroscope, and thermometer data off of the chip. We do not
+// yet support using the digital interrupt pin to notify on events (freefall, collision, etc.),
+// nor do we yet support using the secondary I2C connection to add an external clock or
+// magnetometer.
+//
+// The chip has two possible I2C addresses, which can be selected by wiring the AD0 pin to either
+// hot or ground:
+// - if AD0 is wired to ground, it uses the default I2C address of 0x68
+// - if AD0 is wired to hot, it uses the alternate I2C address of 0x69
+//
+// If you use the alternate address, your config file for this component must set its
+// "use_alternate_i2c_address" boolean to true.
+package mpu6050
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/golang/geo/r3"
+ geo "github.com/kellydunn/golang-geo"
+ "github.com/pkg/errors"
+ "go.viam.com/rdk/components/board/genericlinux/buses"
+ "go.viam.com/rdk/components/movementsensor"
+ "go.viam.com/rdk/logging"
+ "go.viam.com/rdk/resource"
+ "go.viam.com/rdk/spatialmath"
+ "go.viam.com/rdk/utils"
+ goutils "go.viam.com/utils"
+)
+
+// Model for viam supported tdk-invensense mpu6050 movement sensor.
+var Model = resource.NewModel("viam", "tdk-invensense", "mpu6050")
+
+const (
+ defaultAddressRegister = 117
+ expectedDefaultAddress = 0x68
+ alternateAddress = 0x69
+)
+
+// Config is used to configure the attributes of the chip.
+type Config struct {
+ I2cBus string `json:"i2c_bus"`
+ UseAlternateI2CAddress bool `json:"use_alt_i2c_address,omitempty"`
+}
+
+// Validate ensures all parts of the config are valid, and then returns the list of things we
+// depend on.
+func (conf *Config) Validate(path string) ([]string, error) {
+ if conf.I2cBus == "" {
+ return nil, resource.NewConfigValidationFieldRequiredError(path, "i2c_bus")
+ }
+
+ var deps []string
+ return deps, nil
+}
+
+func init() {
+ resource.RegisterComponent(movementsensor.API, Model, resource.Registration[movementsensor.MovementSensor, *Config]{
+ Constructor: newMpu6050,
+ })
+}
+
+type mpu6050 struct {
+ resource.Named
+ resource.AlwaysRebuild
+ bus buses.I2C
+ i2cAddress byte
+ mu sync.Mutex
+
+ // The 3 things we can measure: lock the mutex before reading or writing these.
+ angularVelocity spatialmath.AngularVelocity
+ temperature float64
+ linearAcceleration r3.Vector
+ // Stores the most recent error from the background goroutine
+ err movementsensor.LastError
+
+ workers *goutils.StoppableWorkers
+ logger logging.Logger
+}
+
+func addressReadError(err error, address byte, bus string) error {
+ msg := fmt.Sprintf("can't read from I2C address %d on bus %s", address, bus)
+ return errors.Wrap(err, msg)
+}
+
+func unexpectedDeviceError(address, defaultAddress byte) error {
+ return errors.Errorf("unexpected non-MPU6050 device at address %d: response '%d'",
+ address, defaultAddress)
+}
+
+// newMpu6050 constructs a new Mpu6050 object.
+func newMpu6050(
+ ctx context.Context,
+ deps resource.Dependencies,
+ conf resource.Config,
+ logger logging.Logger,
+) (movementsensor.MovementSensor, error) {
+ newConf, err := resource.NativeConfig[*Config](conf)
+ if err != nil {
+ return nil, err
+ }
+
+ bus, err := buses.NewI2cBus(newConf.I2cBus)
+ if err != nil {
+ return nil, err
+ }
+ return makeMpu6050(ctx, deps, conf, logger, bus)
+}
+
+// This function is separated from NewMpu6050 solely so you can inject a mock I2C bus in tests.
+func makeMpu6050(
+ ctx context.Context,
+ _ resource.Dependencies,
+ conf resource.Config,
+ logger logging.Logger,
+ bus buses.I2C,
+) (movementsensor.MovementSensor, error) {
+ newConf, err := resource.NativeConfig[*Config](conf)
+ if err != nil {
+ return nil, err
+ }
+
+ var address byte
+ if newConf.UseAlternateI2CAddress {
+ address = alternateAddress
+ } else {
+ address = expectedDefaultAddress
+ }
+ logger.CDebugf(ctx, "Using address %d for MPU6050 sensor", address)
+
+ sensor := &mpu6050{
+ Named: conf.ResourceName().AsNamed(),
+ bus: bus,
+ i2cAddress: address,
+ logger: logger,
+ // On overloaded boards, the I2C bus can become flaky. Only report errors if at least 5 of
+ // the last 10 attempts to talk to the device have failed.
+ err: movementsensor.NewLastError(10, 5),
+ }
+
+ // To check that we're able to talk to the chip, we should be able to read register 117 and get
+ // back the device's non-alternative address (0x68)
+ defaultAddress, err := sensor.readByte(ctx, defaultAddressRegister)
+ if err != nil {
+ return nil, addressReadError(err, address, newConf.I2cBus)
+ }
+ if defaultAddress != expectedDefaultAddress {
+ return nil, unexpectedDeviceError(address, defaultAddress)
+ }
+
+ // The chip starts out in standby mode (the Sleep bit in the power management register defaults
+ // to 1). Set it to measurement mode (by turning off the Sleep bit) so we can get data from it.
+ // To do this, we set register 107 to 0.
+ err = sensor.writeByte(ctx, 107, 0)
+ if err != nil {
+ return nil, errors.Errorf("Unable to wake up MPU6050: '%s'", err.Error())
+ }
+
+ // Now, turn on the background goroutine that constantly reads from the chip and stores data in
+ // the object we created.
+ sensor.workers = goutils.NewBackgroundStoppableWorkers(func(cancelCtx context.Context) {
+ // Reading data a thousand times per second is probably fast enough.
+ timer := time.NewTicker(time.Millisecond)
+ defer timer.Stop()
+
+ for {
+ select {
+ case <-timer.C:
+ rawData, err := sensor.readBlock(cancelCtx, 59, 14)
+ // Record `err` no matter what: even if it's nil, that's useful information.
+ sensor.err.Set(err)
+ if err != nil {
+ sensor.logger.CErrorf(ctx, "error reading MPU6050 sensor: '%s'", err)
+ continue
+ }
+
+ linearAcceleration := toLinearAcceleration(rawData[0:6])
+ // Taken straight from the MPU6050 register map. Yes, these are weird constants.
+ temperature := float64(utils.Int16FromBytesBE(rawData[6:8]))/340.0 + 36.53
+ angularVelocity := toAngularVelocity(rawData[8:14])
+
+ // Lock the mutex before modifying the state within the object. By keeping the mutex
+ // unlocked for everything else, we maximize the time when another thread can read the
+ // values.
+ sensor.mu.Lock()
+ sensor.linearAcceleration = linearAcceleration
+ sensor.temperature = temperature
+ sensor.angularVelocity = angularVelocity
+ sensor.mu.Unlock()
+ case <-cancelCtx.Done():
+ return
+ }
+ }
+ })
+
+ return sensor, nil
+}
+
+func (mpu *mpu6050) readByte(ctx context.Context, register byte) (byte, error) {
+ result, err := mpu.readBlock(ctx, register, 1)
+ if err != nil {
+ return 0, err
+ }
+ return result[0], err
+}
+
+func (mpu *mpu6050) readBlock(ctx context.Context, register byte, length uint8) ([]byte, error) {
+ handle, err := mpu.bus.OpenHandle(mpu.i2cAddress)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ err := handle.Close()
+ if err != nil {
+ mpu.logger.CError(ctx, err)
+ }
+ }()
+
+ results, err := handle.ReadBlockData(ctx, register, length)
+ return results, err
+}
+
+func (mpu *mpu6050) writeByte(ctx context.Context, register, value byte) error {
+ handle, err := mpu.bus.OpenHandle(mpu.i2cAddress)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ err := handle.Close()
+ if err != nil {
+ mpu.logger.CError(ctx, err)
+ }
+ }()
+
+ return handle.WriteByteData(ctx, register, value)
+}
+
+// Given a value, scales it so that the range of int16s becomes the range of +/- maxValue.
+func setScale(value int, maxValue float64) float64 {
+ return float64(value) * maxValue / (1 << 15)
+}
+
+// A helper function to abstract out shared code: takes 6 bytes and gives back AngularVelocity, in
+// radians per second.
+func toAngularVelocity(data []byte) spatialmath.AngularVelocity {
+ gx := int(utils.Int16FromBytesBE(data[0:2]))
+ gy := int(utils.Int16FromBytesBE(data[2:4]))
+ gz := int(utils.Int16FromBytesBE(data[4:6]))
+
+ maxRotation := 250.0 // Maximum degrees per second measurable in the default configuration
+ return spatialmath.AngularVelocity{
+ X: setScale(gx, maxRotation),
+ Y: setScale(gy, maxRotation),
+ Z: setScale(gz, maxRotation),
+ }
+}
+
+// A helper function that takes 6 bytes and gives back linear acceleration.
+func toLinearAcceleration(data []byte) r3.Vector {
+ x := int(utils.Int16FromBytesBE(data[0:2]))
+ y := int(utils.Int16FromBytesBE(data[2:4]))
+ z := int(utils.Int16FromBytesBE(data[4:6]))
+
+ // The scale is +/- 2G's, but our units should be m/sec/sec.
+ maxAcceleration := 2.0 * 9.81 /* m/sec/sec */
+ return r3.Vector{
+ X: setScale(x, maxAcceleration),
+ Y: setScale(y, maxAcceleration),
+ Z: setScale(z, maxAcceleration),
+ }
+}
+
+func (mpu *mpu6050) AngularVelocity(ctx context.Context, extra map[string]interface{}) (spatialmath.AngularVelocity, error) {
+ mpu.mu.Lock()
+ defer mpu.mu.Unlock()
+ return mpu.angularVelocity, mpu.err.Get()
+}
+
+func (mpu *mpu6050) LinearVelocity(ctx context.Context, extra map[string]interface{}) (r3.Vector, error) {
+ return r3.Vector{}, movementsensor.ErrMethodUnimplementedLinearVelocity
+}
+
+func (mpu *mpu6050) LinearAcceleration(ctx context.Context, exta map[string]interface{}) (r3.Vector, error) {
+ mpu.mu.Lock()
+ defer mpu.mu.Unlock()
+
+ lastError := mpu.err.Get()
+ if lastError != nil {
+ return r3.Vector{}, lastError
+ }
+ return mpu.linearAcceleration, nil
+}
+
+func (mpu *mpu6050) Orientation(ctx context.Context, extra map[string]interface{}) (spatialmath.Orientation, error) {
+ return spatialmath.NewOrientationVector(), movementsensor.ErrMethodUnimplementedOrientation
+}
+
+func (mpu *mpu6050) CompassHeading(ctx context.Context, extra map[string]interface{}) (float64, error) {
+ return 0, movementsensor.ErrMethodUnimplementedCompassHeading
+}
+
+func (mpu *mpu6050) Position(ctx context.Context, extra map[string]interface{}) (*geo.Point, float64, error) {
+ return geo.NewPoint(0, 0), 0, movementsensor.ErrMethodUnimplementedPosition
+}
+
+func (mpu *mpu6050) Accuracy(ctx context.Context, extra map[string]interface{}) (*movementsensor.Accuracy, error) {
+ return movementsensor.UnimplementedOptionalAccuracies(), nil
+}
+
+func (mpu *mpu6050) Readings(ctx context.Context, extra map[string]interface{}) (map[string]interface{}, error) {
+ mpu.mu.Lock()
+ defer mpu.mu.Unlock()
+
+ readings := make(map[string]interface{})
+ readings["linear_acceleration"] = mpu.linearAcceleration
+ readings["temperature_celsius"] = mpu.temperature
+ readings["angular_velocity"] = mpu.angularVelocity
+
+ return readings, mpu.err.Get()
+}
+
+func (mpu *mpu6050) Properties(ctx context.Context, extra map[string]interface{}) (*movementsensor.Properties, error) {
+ return &movementsensor.Properties{
+ AngularVelocitySupported: true,
+ LinearAccelerationSupported: true,
+ }, nil
+}
+
+func (mpu *mpu6050) Close(ctx context.Context) error {
+ mpu.workers.Stop()
+
+ mpu.mu.Lock()
+ defer mpu.mu.Unlock()
+ // Set the Sleep bit (bit 6) in the power control register (register 107).
+ err := mpu.writeByte(ctx, 107, 1<<6)
+ if err != nil {
+ mpu.logger.CError(ctx, err)
+ }
+ return err
+}
diff --git a/mpu6050/mpu6050_nonlinux.go b/mpu6050/mpu6050_nonlinux.go
new file mode 100644
index 0000000..9087d5a
--- /dev/null
+++ b/mpu6050/mpu6050_nonlinux.go
@@ -0,0 +1,2 @@
+// Package mpu6050 is only implemented for Linux systems.
+package mpu6050
diff --git a/mpu6050/mpu6050_test.go b/mpu6050/mpu6050_test.go
new file mode 100644
index 0000000..561d70a
--- /dev/null
+++ b/mpu6050/mpu6050_test.go
@@ -0,0 +1,262 @@
+//go:build linux
+
+package mpu6050
+
+import (
+ "context"
+ "testing"
+
+ "github.com/pkg/errors"
+ "go.viam.com/rdk/components/board/genericlinux/buses"
+ "go.viam.com/rdk/components/movementsensor"
+ "go.viam.com/rdk/logging"
+ "go.viam.com/rdk/resource"
+ "go.viam.com/rdk/testutils/inject"
+ "go.viam.com/test"
+ "go.viam.com/utils/testutils"
+)
+
+func TestValidateConfig(t *testing.T) {
+ cfg := Config{}
+ deps, err := cfg.Validate("path")
+ expectedErr := resource.NewConfigValidationFieldRequiredError("path", "i2c_bus")
+ test.That(t, err, test.ShouldBeError, expectedErr)
+ test.That(t, deps, test.ShouldBeEmpty)
+}
+
+func TestInitializationFailureOnChipCommunication(t *testing.T) {
+ logger := logging.NewTestLogger(t)
+ i2cName := "i2c"
+
+ t.Run("fails on read error", func(t *testing.T) {
+ cfg := resource.Config{
+ Name: "movementsensor",
+ Model: Model,
+ API: movementsensor.API,
+ ConvertedAttributes: &Config{
+ I2cBus: i2cName,
+ },
+ }
+ i2cHandle := &inject.I2CHandle{}
+ readErr := errors.New("read error")
+ i2cHandle.ReadBlockDataFunc = func(ctx context.Context, register byte, numBytes uint8) ([]byte, error) {
+ if register == defaultAddressRegister {
+ return nil, readErr
+ }
+ return []byte{}, nil
+ }
+ i2cHandle.CloseFunc = func() error { return nil }
+ i2c := &inject.I2C{}
+ i2c.OpenHandleFunc = func(addr byte) (buses.I2CHandle, error) {
+ return i2cHandle, nil
+ }
+
+ deps := resource.Dependencies{}
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldNotBeNil)
+ test.That(t, err, test.ShouldBeError, addressReadError(readErr, expectedDefaultAddress, i2cName))
+ test.That(t, sensor, test.ShouldBeNil)
+ })
+
+ t.Run("fails on unexpected address", func(t *testing.T) {
+ cfg := resource.Config{
+ Name: "movementsensor",
+ Model: Model,
+ API: movementsensor.API,
+ ConvertedAttributes: &Config{
+ I2cBus: i2cName,
+ UseAlternateI2CAddress: true,
+ },
+ }
+ i2cHandle := &inject.I2CHandle{}
+ i2cHandle.ReadBlockDataFunc = func(ctx context.Context, register byte, numBytes uint8) ([]byte, error) {
+ if register == defaultAddressRegister {
+ return []byte{0x64}, nil
+ }
+ return nil, errors.New("unexpected register")
+ }
+ i2cHandle.CloseFunc = func() error { return nil }
+ i2c := &inject.I2C{}
+ i2c.OpenHandleFunc = func(addr byte) (buses.I2CHandle, error) {
+ return i2cHandle, nil
+ }
+
+ deps := resource.Dependencies{}
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldNotBeNil)
+ test.That(t, err, test.ShouldBeError, unexpectedDeviceError(alternateAddress, 0x64))
+ test.That(t, sensor, test.ShouldBeNil)
+ })
+}
+
+func TestSuccessfulInitializationAndClose(t *testing.T) {
+ logger := logging.NewTestLogger(t)
+ i2cName := "i2c"
+
+ cfg := resource.Config{
+ Name: "movementsensor",
+ Model: Model,
+ API: movementsensor.API,
+ ConvertedAttributes: &Config{
+ I2cBus: i2cName,
+ UseAlternateI2CAddress: true,
+ },
+ }
+ i2cHandle := &inject.I2CHandle{}
+ i2cHandle.ReadBlockDataFunc = func(ctx context.Context, register byte, numBytes uint8) ([]byte, error) {
+ return []byte{expectedDefaultAddress}, nil
+ }
+ // the only write operations that the sensor implementation performs is
+ // the command to put it into either measurement mode or sleep mode,
+ // and measurement mode results from a write of 0, so if is closeWasCalled is toggled
+ // we know Close() was successfully called
+ closeWasCalled := false
+ i2cHandle.WriteByteDataFunc = func(ctx context.Context, register, data byte) error {
+ if data == 1<<6 {
+ closeWasCalled = true
+ }
+ return nil
+ }
+ i2cHandle.CloseFunc = func() error { return nil }
+ i2c := &inject.I2C{}
+ i2c.OpenHandleFunc = func(addr byte) (buses.I2CHandle, error) {
+ return i2cHandle, nil
+ }
+
+ deps := resource.Dependencies{}
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldBeNil)
+ err = sensor.Close(context.Background())
+ test.That(t, err, test.ShouldBeNil)
+ test.That(t, closeWasCalled, test.ShouldBeTrue)
+}
+
+func setupDependencies(mockData []byte) (resource.Config, buses.I2C) {
+ i2cName := "i2c"
+
+ cfg := resource.Config{
+ Name: "movementsensor",
+ Model: Model,
+ API: movementsensor.API,
+ ConvertedAttributes: &Config{
+ I2cBus: i2cName,
+ UseAlternateI2CAddress: true,
+ },
+ }
+
+ i2cHandle := &inject.I2CHandle{}
+ i2cHandle.ReadBlockDataFunc = func(ctx context.Context, register byte, numBytes uint8) ([]byte, error) {
+ if register == defaultAddressRegister {
+ return []byte{expectedDefaultAddress}, nil
+ }
+ return mockData, nil
+ }
+ i2cHandle.WriteByteDataFunc = func(ctx context.Context, b1, b2 byte) error {
+ return nil
+ }
+ i2cHandle.CloseFunc = func() error { return nil }
+ i2c := &inject.I2C{}
+ i2c.OpenHandleFunc = func(addr byte) (buses.I2CHandle, error) {
+ return i2cHandle, nil
+ }
+ return cfg, i2c
+}
+
+//nolint:dupl
+func TestLinearAcceleration(t *testing.T) {
+ // linear acceleration, temperature, and angular velocity are all read
+ // sequentially from the same series of 16-bytes, so we need to fill in
+ // the mock data at the appropriate portion of the sequence
+ linearAccelMockData := make([]byte, 16)
+ // x-accel
+ linearAccelMockData[0] = 64
+ linearAccelMockData[1] = 0
+ expectedAccelX := 9.81
+ // y-accel
+ linearAccelMockData[2] = 32
+ linearAccelMockData[3] = 0
+ expectedAccelY := 4.905
+ // z-accel
+ linearAccelMockData[4] = 16
+ linearAccelMockData[5] = 0
+ expectedAccelZ := 2.4525
+
+ logger := logging.NewTestLogger(t)
+ deps := resource.Dependencies{}
+ cfg, i2c := setupDependencies(linearAccelMockData)
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldBeNil)
+ defer sensor.Close(context.Background())
+ testutils.WaitForAssertion(t, func(tb testing.TB) {
+ linAcc, err := sensor.LinearAcceleration(context.Background(), nil)
+ test.That(tb, err, test.ShouldBeNil)
+ test.That(tb, linAcc, test.ShouldNotBeZeroValue)
+ })
+ accel, err := sensor.LinearAcceleration(context.Background(), nil)
+ test.That(t, err, test.ShouldBeNil)
+ test.That(t, accel.X, test.ShouldEqual, expectedAccelX)
+ test.That(t, accel.Y, test.ShouldEqual, expectedAccelY)
+ test.That(t, accel.Z, test.ShouldEqual, expectedAccelZ)
+}
+
+//nolint:dupl
+func TestAngularVelocity(t *testing.T) {
+ // linear acceleration, temperature, and angular velocity are all read
+ // sequentially from the same series of 16-bytes, so we need to fill in
+ // the mock data at the appropriate portion of the sequence
+ angVelMockData := make([]byte, 16)
+ // x-vel
+ angVelMockData[8] = 64
+ angVelMockData[9] = 0
+ expectedAngVelX := 125.0
+ // y-accel
+ angVelMockData[10] = 32
+ angVelMockData[11] = 0
+ expectedAngVelY := 62.5
+ // z-accel
+ angVelMockData[12] = 16
+ angVelMockData[13] = 0
+ expectedAngVelZ := 31.25
+
+ logger := logging.NewTestLogger(t)
+ deps := resource.Dependencies{}
+ cfg, i2c := setupDependencies(angVelMockData)
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldBeNil)
+ defer sensor.Close(context.Background())
+ testutils.WaitForAssertion(t, func(tb testing.TB) {
+ angVel, err := sensor.AngularVelocity(context.Background(), nil)
+ test.That(tb, err, test.ShouldBeNil)
+ test.That(tb, angVel, test.ShouldNotBeZeroValue)
+ })
+ angVel, err := sensor.AngularVelocity(context.Background(), nil)
+ test.That(t, err, test.ShouldBeNil)
+ test.That(t, angVel.X, test.ShouldEqual, expectedAngVelX)
+ test.That(t, angVel.Y, test.ShouldEqual, expectedAngVelY)
+ test.That(t, angVel.Z, test.ShouldEqual, expectedAngVelZ)
+}
+
+func TestTemperature(t *testing.T) {
+ // linear acceleration, temperature, and angular velocity are all read
+ // sequentially from the same series of 16-bytes, so we need to fill in
+ // the mock data at the appropriate portion of the sequence
+ temperatureMockData := make([]byte, 16)
+ temperatureMockData[6] = 231
+ temperatureMockData[7] = 202
+ expectedTemp := 18.3
+
+ logger := logging.NewTestLogger(t)
+ deps := resource.Dependencies{}
+ cfg, i2c := setupDependencies(temperatureMockData)
+ sensor, err := makeMpu6050(context.Background(), deps, cfg, logger, i2c)
+ test.That(t, err, test.ShouldBeNil)
+ defer sensor.Close(context.Background())
+ testutils.WaitForAssertion(t, func(tb testing.TB) {
+ readings, err := sensor.Readings(context.Background(), nil)
+ test.That(tb, err, test.ShouldBeNil)
+ test.That(tb, readings["temperature_celsius"], test.ShouldNotBeZeroValue)
+ })
+ readings, err := sensor.Readings(context.Background(), nil)
+ test.That(t, err, test.ShouldBeNil)
+ test.That(t, readings["temperature_celsius"], test.ShouldAlmostEqual, expectedTemp, 0.001)
+}