私はCanSatという一種の自律制御ロボットの開発を行っているのですが、ロケットからの分離衝撃、地面への着地衝撃を測定する必要がありました。一般に着地した際には非常に短い時間の間に速度、加速度が変化するのでセンサーの動作周期を短くする必要があります。
マイコンとセンサー間の通信インターフェースにはI2C, SPI, UART等がありますが、今回はその中でも高速にデータの通信を行うことが出来るSPI通信を使って3軸加速度センサーを動かしてみたのでその方法を紹介します。
目次
開発環境
- SBC: Raspberry pi zero w
- 加速度センサー: ADXL345 (秋月電子)
- OS: Debian GNU/Linux 12 (bookworm)
配線
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で動かすためのコードを以下に示します
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()
データシートによると、センサーの出力レートを3200 Hz にするためにはレジスタ0x2Cに0x0Fを設定する必要があります。
コードの13行目
spi.xfer2([0x2C, 0x0F]) # output data rate 3200 Hz
の部分でこの設定を行っています。
参考サイト