メモ

調べたり思いついたりしたことをメモします

加速度センサ(ADXL343)を Raspberry Pi 4 で使う

f:id:uenoshin:20190720150540j:plain

Analog Devices の3軸加速度センサ ADXL343 を £5 ぐらいで購入できましたので Raspberry Pi 4 で動かしてみました。 9pinの足を全部はんだ付けしてブレッドボード上に実装しています。ちなみにはんだ付けする前の写真はこちらです。あんまり上手じゃないですけど、とりあえず繋がりさえすればOKです。

f:id:uenoshin:20190720151311j:plain

I2Cでの接続になります。ADXL343 上の VIN を Pi 4 の 3v3 へ接続、GND,SDA,SCL はそれぞれ同名のクチにジャンパ線で接続しています。

正しく接続できたか i2cdetect で確認します。 先日遊んでいた BME680 も接続していますのでアドレスは 0x53 と 0x76 の両方が見えていますが ADXL343 は 0x53 の方です。

pi@raspberrypi:~/rpiLogger $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- 53 -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --

今回、I2Cの Read/Write には pigpio というライブラリを使っています。 abyz.me.uk

pigpioで読み出した x, y, z の3軸データをビジーループの中でCSVファイルに吐き出すようにしてみました。 CSVの左列にはunixtimeとマイクロ秒を並べて時系列データのようにしています。 時系列のピッチが不揃いなのはご容赦ください。ビジーループで雑に吐き出しただけですので。

書いたソースを全文貼っておきます。雑なC言語ですみません。もし同じようなことをする人がおられましたら、

$ gcc -Wall -pthread  file.c  -lpigpio -lrt

pigpio のインストール後、このようにコンパイルして実行ファイルが作れます。

ちなみにこのpigpioで i2cOpen() するときにアドレスを 0x53 ではなく間違った値を入れてしまっても正常リターンが返されます。 その後読み書きのAPIが PI_I2C_READ_FAILED や PI_I2C_WRITE_FAILED で失敗する振る舞いになりました。Openの時点でエラーになってくれれば分かりやすいのに、かるくハマりました。。

ソースはこちら

#include <stdio.h>
#include "pigpio.h"

#define ADXL343_I2C_ADDR_PRIMARY    0x53
#define ADXL343_BW_RATE             0x2C
#define ADXL343_DATA_FORMAT         0x31
#define ADXL343_FIFO_CTL            0x38
#define ADXL343_POWER_CTL           0x2D
#define ADXL343_DATAX0              0x32
#define ADXL343_DATAY0              0x34
#define ADXL343_DATAZ0              0x36

static int handle;
static FILE *fp;

void initSensor()
{
    /* BW_RATE : 0x0f = 1600Hz */
    i2cWriteByteData(handle, ADXL343_BW_RATE,       0x0f );
    i2cWriteByteData(handle, ADXL343_DATA_FORMAT,   0x00 );
    i2cWriteByteData(handle, ADXL343_FIFO_CTL,      0x00 );
    i2cWriteByteData(handle, ADXL343_POWER_CTL,     0x08 );
}

void writeCSV(int x_dat, int y_dat, int z_dat )
{
    int seconds,micros;
    gpioTime(1, &seconds, &micros );
    
    fprintf(fp, "%d %6d: x:y:z ,%6d,%6d,%6d\n",seconds,micros,x_dat,y_dat,z_dat );
}

void readSensor()
{
    int x_dat, y_dat, z_dat;

    while(1)
    {
        x_dat = i2cReadWordData(handle, ADXL343_DATAX0);
        y_dat = i2cReadWordData(handle, ADXL343_DATAY0);
        z_dat = i2cReadWordData(handle, ADXL343_DATAZ0);    
        writeCSV( x_dat, y_dat, z_dat );
    }
}

int main(int argc, char *argv[])
{
    if (gpioInitialise() < 0) return 1;
    handle = i2cOpen(1, ADXL343_I2C_ADDR_PRIMARY, 0);
    fp = fopen("save.csv","w");

    initSensor();
    readSensor();

    fclose(fp);
    i2cClose(handle);
    gpioTerminate();
}

実行してみたところ、CSVファイルは3軸それぞれの値が2バイトデータで出力されます。 時間出力の読み方ですが、左列の1563603955のような10桁数字が1970年1月1日からの秒で、その横の6桁数字がマイクロ秒です。このマイクロ秒部分を読み取ると、サンプルごとの時間間隔はおおむね1500マイクロ秒(1.5ミリ秒)ぐらいになっている模様です。

1563603955 512977: x:y:z ,    12,    62,   228
1563603955 514534: x:y:z ,    18,    74,   238
1563603955 516064: x:y:z ,    16,    58,   238
1563603955 517594: x:y:z ,    12,    56,   242
1563603955 519121: x:y:z ,    16,    58,   242
1563603955 520650: x:y:z ,    20,    58,   236
1563603955 522177: x:y:z ,    26,    64,   236
1563603955 523705: x:y:z ,    22,    66,   240
1563603955 525233: x:y:z ,    24,    62,   232
1563603955 526762: x:y:z ,    20,    62,   232
1563603955 528290: x:y:z ,    20,    68,   230
1563603955 529817: x:y:z ,    22,    66,   230
1563603955 531345: x:y:z ,    16,    64,   232
1563603955 532873: x:y:z ,    10,    74,   224
1563603955 534401: x:y:z ,    16,    70,   228
1563603955 535929: x:y:z ,     8,    60,   232
1563603955 537458: x:y:z ,    14,    64,   224
1563603955 538985: x:y:z ,    12,    64,   224

すこし気に入らなかったので I2C の速度をデフォルトの 100KHz から 400KHzに変更してみました。 /boot/config.txt に

dtparam=i2c_baudrate=400000

と書いて再起動します。

この状態で実行してみたところ、時間間隔は約0.8ミリ秒ぐらいに縮まりました。1.0KHzサンプリングの時系列データを作るぐらいならぎりぎりなんとかなりそうな性能ですね。このあともう少し試行錯誤していると0.4ミリ秒ピッチぐらいで動けるようになってきました。安定した定周期で時系列データを取れるようにしていきたいと思います。

1563605344 553451: x:y:z , 65472, 65520,   240
1563605344 554291: x:y:z , 65478, 65528,   230
1563605344 555131: x:y:z , 65476, 65518,   220
1563605344 555972: x:y:z , 65478, 65530,   222
1563605344 556814: x:y:z , 65482, 65524,   236
1563605344 557654: x:y:z , 65480, 65530,   234
1563605344 558499: x:y:z , 65502, 65528,   240
1563605344 559340: x:y:z , 65492, 65530,   224
1563605344 560180: x:y:z , 65480, 65524,   232
1563605344 561021: x:y:z , 65480, 65524,   232
1563605344 561861: x:y:z , 65452, 65526,   234
1563605344 562702: x:y:z , 65486, 65524,   238
1563605344 563543: x:y:z , 65486, 65532,   214
1563605344 564384: x:y:z , 65476, 65526,   200
1563605344 565225: x:y:z , 65482, 65524,   224