0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラズパイで3軸加速度センサー (AE-ADXL367) を使う方法

Posted at

目次

販売リンク、データシート

秋月電子で買いました、以下リンクです

3軸加速度センサーモジュール AE-ADXL367

ADXL367 データシート (日本語)

開発環境

Raspberry Pi 4 Model B
OS : 2024-10-22-raspios-bullseye-armhf
python 3.10

ラズパイへの接続方法

Raspberry PiはI2C通信用のピンを備えています
I2Cとは、マイコン間で主に使用される通信方式の一つです
ADXL367はI2C通信で情報をやり取りできるので、Raspberry PiとADXL367をI2C通信できるように接続します

ADXL367.jpg

I2Cの有効化

Raspberry PiのI2Cはデフォルトでは無効になっているので、設定を変更して有効にします
以下のコマンドを使用してラズパイの設定を変更します

raspi-config

Screenshot from 2018-04-29 11-56-31.png

Interfacing Options -> I2C -> Yes を選択してI2Cを有効化します
設定できたら、左右矢印でFinishを選択して、エンターキーを押して、raspi-configを終わります

コードを動かすための前準備

PythonからI2Cをコントロールするためのライブラリ「smbus」のインストール
$ sudo apt install python-smbus
もろもろの計算用にnumpyのインストール
$ sudo apt install python-numpy

コード

ADXL367を動かして加速度のデータを取得するためのコードは以下の通りです

adxl367.py
# -*- coding: utf-8 -*-
# 使用センサー: ADXL367
import math
import time

import numpy as np
import smbus


class LowGAcc3:
    def __init__(self, calibrated=False, offset_list = [[0 for _ in range(10)] for _ in range(3)]):
        self.calibrated = calibrated
        self.offset_list = offset_list
        self.acc_x = 0
        self.acc_y = 0
        self.acc_z = 0
        self.acc_norm = 0

        # self.ADDR = 0x1d
        self.ADDR = 0x53
        self.i2c = smbus.SMBus(1)

        # センサーの諸設定
        self.i2c.write_byte_data(self.ADDR, 0x2C, 0x03) # output data rate 100 Hz
        self.i2c.write_byte_data(self.ADDR, 0x2D, 0x02)

        time.sleep(0.5)

    def apply_offset_list(offset_list, x, y, z):
        xyz_array = np.array([x, y, z])
        for i, offset in enumerate(offset_list):
            offset_array = np.array(offset)
            xyz_array[i] -= np.mean(offset_array)

        return tuple(xyz_array)
    
    def get_calibration_data(self):
        calibration_iter = 10
        for _ in range(calibration_iter):
            x, y, z = self.get_acc_raw()
            self.offset_list[0].append(x)
            self.offset_list[1].append(y)
            self.offset_list[2].append(z-1.0)
        
        print(self.offset_list)

        self.calibrated = True
    
    def get_acc_raw(self):
        # 単位はGです
        try:
            #データ読み込み
            xh = self.i2c.read_byte_data(self.ADDR, 0x0E)
            xl = self.i2c.read_byte_data(self.ADDR, 0x0F)
            yh = self.i2c.read_byte_data(self.ADDR, 0x10)
            yl = self.i2c.read_byte_data(self.ADDR, 0x11)
            zh = self.i2c.read_byte_data(self.ADDR, 0x12)
            zl = self.i2c.read_byte_data(self.ADDR, 0x13)
        
            #データ変換
            x = (xh << 6) | (xl >> 2)
            y = (yh << 6) | (yl >> 2)
            z = (zh << 6) | (zl >> 2)
        
            #極性判断
            if x >= 8192:
                x = x - 16384
        
            if y >= 8192:
                y = y - 16384
        
            if z >= 8192:
                z = z - 16384
        
            #物理量(加速度[g])に変換
            x = x * 2 / 8191 # 2g設定
            y = y * 2 / 8191
            z = z * 2 / 8191

            self.acc_x = x
            self.acc_y = y
            self.acc_z = z
            self.acc_norm = math.sqrt(x**2 + y**2 + z**2)
            
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        
        return x, y, z, math.sqrt(x**2+y**2+z**2)

    def get_acc_calibrated(self):
        if not self.calibrated:
            print("set calibration data!")
            return
        
        x, y, z = self.get_acc_raw()
        x, y, z = self.apply_offset_list(self.offset_list, x, y, z)

        self.acc_x = x
        self.acc_y = y
        self.acc_z = z
        self.acc_norm = math.sqrt(x**2 + y**2 + z**2)

        return x, y, z, math.sqrt(x**2 + y**2 + z**2)

def main():
    low_g_acc = LowGAcc3()
    
    while True:
        out_x, out_y, out_z, norm = low_g_acc.get_acc_raw()
        print(f"{out_x}, {out_y}, {out_z}, {norm}")
        time.sleep(0.1)

def test_calib():
    low_g_acc = LowGAcc3()
    low_g_acc.get_calibration_data()

    out_x, out_y, out_z, norm = low_g_acc.get_acc_calibrated()
    print(f"{out_x}, {out_y}, {out_z}, {norm}")
    print("offset_list:")
    print(low_g_acc.offset_list)


if __name__ == "__main__":
    main()

起こりやすいエラーとその対処

このコードを実行したときにこんな I/O error が表示されることがあります

$ python adxl367.py
Traceback (most recent call last):
  File "/home/pi/adxl367.py", line 124, in <module>
    main()
  File "/home/pond/adxl367.py", line 106, in main
    low_g_acc = LowGAcc3()
                ^^^^^^^^^^
  File "/home/pi/adxl367.py", line 24, in __init__
    self.i2c.write_byte_data(self.ADDR, 0x2C, 0x03) # output data rate 100 Hz
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 5] Input/output error

この場合はソースコードの次の部分

        # self.ADDR = 0x1d
        self.ADDR = 0x53

        self.ADDR = 0x1d
        # self.ADDR = 0x53

とI2Cアドレスを変更することで解決する場合があります
こうなる理由としては、この加速度センサー ADXL367 は2つのI2Cアドレスを使用することが出来、ASEL pinをGNDに接続することで 0x1d のアドレスを使用するように出来るようになっているのですが、このピンをGNDに接続していないときでも 0x1d のアドレスを使用する場合があるためです(なぜこのようなことが起こるのかは不明)

コードの簡単な解説

  • classを使ってオブジェクト指向風に書きました
  • __init__ メソッドで初期化設定を行い、データの範囲を ±2 g 、出力レートを 100 Hz に設定しました (データシート 44 ページ目)
  • get_acc_raw メソッドでデータの取得を行い、x, y, z, norm の順で加速度のデータを返します (データシート 34, 35, 36 ページ目)
  • その他メソッドはキャリブレーションに使用する目的で書きました

応用

 加速度センサーは衝撃検知や自由落下検知、速度測定に使用できます
 自由落下検知は単に加速度の値が 0 になったことを検知すれば実現できます。センサーの機能としても実装されているので興味があればデータシートを読んでみるのも面白いと思います
 また、加速度の値を積分すれば物体の速度を測ることも出来ます。数値積分の方法については台形積分やシンプソンの公式などがあるのでこれも調べてみると面白いと思います

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?