加速度センサー ADXL345を3200 Hzで動かしてみた

私はCanSatという一種の自律制御ロボットの開発を行っているのですが、ロケットからの分離衝撃、地面への着地衝撃を測定する必要がありました。一般に着地した際には非常に短い時間の間に速度、加速度が変化するのでセンサーの動作周期を短くする必要があります。

マイコンとセンサー間の通信インターフェースにはI2C, SPI, UART等がありますが、今回はその中でも高速にデータの通信を行うことが出来るSPI通信を使って3軸加速度センサーを動かしてみたのでその方法を紹介します。

# 目次
- [開発環境](#開発環境)
- [配線](#配線)
- [SPIを使うための設定](#spiを使うための設定)
- [SPI通信用ライブラリのインストール](#spi通信用ライブラリのインストール)
- [コード](#コード)

# 開発環境
- SBC: Raspberry pi zero w
- 加速度センサー: ADXL345 (秋月電子)
- OS: Debian GNU/Linux 12 (bookworm)

# 配線

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550181/a0b5adaf-85c9-62e0-7d63-dc4042f61542.jpeg" width="310mm">

3軸加速度センサー ADXL345は上の画像のようなピン配置をしているので下の表のようにRaspberry piと接続します

| Raspberry pi pin | ADXL345 |
|:-----------|------------:|
| 1 pin 3V3       | VDD        |
| 6 pin GND    | GND      |
| 21 pin MISO       | SDO        |
| 19 pin MOSI         | SDA(SDI)         |
| 23 pin SCLK       | SCL       |
| 24 pin CE0#    | CS     |

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

`raspi-config`

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

# SPI通信用ライブラリのインストール
ラズパイのpythonでSPI通信を行うにはpi-spidevライブラリを使用します
pipコマンドでインストールします

```
$ pip3 install spidev
```

# コード
ADXL345をPython 3で動かすためのコードを以下に示します
```python:spi_3200hz_adxl345.py
import spidev
import time
import datetime
import codecs
import math

#初期設定
spi = spidev.SpiDev()
spi.open(0,0)
spi.mode = 3  #このデバイスはSPI mode3で動作
spi.max_speed_hz = 1000000

spi.xfer2([0x2C, 0x0F]) # output data rate 3200 Hz
spi.xfer2([0x31, 0x09])
spi.xfer2([0x2D, 0x08]) #測定スタート

def hosuu_to_normal(num):
    if num > 32768:
        num -= 65536
    return num

def avg_offset_list(offset_list):
    res = 0
    for offset_list_ele in offset_list:
        res += offset_list_ele
    return res/len(offset_list)

offset_count = 10
offset_x = []
offset_y = []
offset_z = []

fmt_name = "record/acc_logs_ADXL_test_4g_{0:%Y%m%d-%H%M%S}.csv".format(datetime.datetime.now())
f_acc_logs = codecs.open(fmt_name, mode='w', encoding="utf-8")

header_value = u"yyyy-mm-dd hh:mm:ss.mmmmmm,x[g],y[g],z[g],norm[g]"
f_acc_logs.write(header_value+"\n")

max_value = 0

try:
    while True:
        #x,y,z方向の加速度を取得(2の補数表現)
        x_data_list = spi.xfer2([0xc0|0x32, 0x00, 0x00])
        y_data_list = spi.xfer2([0xc0|0x34, 0x00, 0x00])
        z_data_list = spi.xfer2([0xc0|0x36, 0x00, 0x00])
        x_data = x_data_list[1] | (x_data_list[2] << 8)
        y_data = y_data_list[1] | (y_data_list[2] << 8)
        z_data = z_data_list[1] | (z_data_list[2] << 8)
        #2の補数を10進に変換
        x_data = hosuu_to_normal(x_data)
        y_data = hosuu_to_normal(y_data)
        z_data = hosuu_to_normal(z_data)
        #加速度に変換（Dレンジ ±4g）
        x_data = x_data * 4 / 0x3FF
        y_data = y_data * 4 / 0x3FF
        z_data = z_data * 4 / 0x3FF

        if offset_count >= 0 :
            offset_count -= 1
            offset_x.append(x_data)
            offset_y.append(y_data)
            offset_z.append(z_data-(+1)) # z軸方向に重力があるように
            continue

        x_data -= avg_offset_list(offset_x)
        y_data -= avg_offset_list(offset_y)
        z_data -= avg_offset_list(offset_z)

        # write log file
        now = datetime.datetime.now()
        f_acc_logs.write(f'{now},{x_data},{y_data},{z_data},{math.sqrt(x_data**2+y_data**2+z_data**2)}\n')
        if math.sqrt(x_data**2+y_data**2+z_data**2) > max_value:
            max_value = math.sqrt(x_data**2+y_data**2+z_data**2)
            print(max_value)
        # print('x: {:4.2f}, y: {:4.2f}, z: {:4.2f} [G]'.format(x_data, y_data, z_data))
        # time.sleep(0.1)

except KeyboardInterrupt:
    print('!FINISH!')
    f_acc_logs.close()
```

[データシート](https://www.analog.com/media/jp/technical-documentation/data-sheets/adxl345_jp.pdf)によると、センサーの出力レートを3200 Hz にするためにはレジスタ0x2Cに0x0Fを設定する必要があります。
コードの13行目
```python
spi.xfer2([0x2C, 0x0F]) # output data rate 3200 Hz
```
の部分でこの設定を行っています。

# 参考サイト
https://masaeng.hatenablog.com/entry/2020/05/10/234342