Freenove ESP32-S3-WROOM CAMボードにデジタルコンパス・加速度センサ「LSM303DLH」を接続し、デジタルコンパス・加速度を入力プログラムを作成しました。「LSM303DLHを用いたPro Microのデジタルコンパス・加速度入力プログラム」では、Pro Microに接続しました。

ESP32-S3とデジタルコンパス・加速度センサ「LSM303DLH」の接続

ESP32-S3とデジタルコンパス・加速度センサ「LSM303DLH」間は、I 2 Cインタフェースで接続します。次のように各ピンを接続します。左側のピン番号がLSM303DLHで右側のピン番号がESP32-S3です。

  • VCC(3.3V) -> VCC
  • GND -> GND
  • SDA -> gpio1
  • SCL -> gpio2

Pro MicroによるOLEDディスプレイ への表示」で作成した「i2c_scanner1」を次のように変更してI2 Cのアドレスを確認します。

esp32s3_i2c_scanner

#include <Wire.h>

#define PIN_SDA 1
#define PIN_SCL 2

void setup() {
  Wire.begin(PIN_SDA, PIN_SCL);  // ok
  //Wire.setPins(PIN_SDA, PIN_SCL);  // ng
  Serial.begin(115200);
  while (!Serial)
    ;  // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");

  Serial.println("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
  for (byte n = 0; n <= 0x7F; n++) {  // I2Cアドレスを指定
    adrCheck(n);                      // デバイス有無を調べ結果を出力
  }
  Serial.println();
}

void loop() {
}

void adrCheck(byte adr) {
  byte dummy;

  if ((adr & 0x0F) == 0) {
    print_hex2chr(adr);
    Serial.print(":");
  }
  Serial.print(" ");

  if (adr < 8 || adr > 0x77) {
    Serial.print("xx");
  } else {
    Wire.beginTransmission(adr);
    Wire.write(&dummy, 0);
    if (Wire.endTransmission() == 0) {
      print_hex2chr(adr);
    } else {
      Serial.print("--");
    }
  }
  if ((adr & 0x0F) == 0x0F) {
    Serial.println();
  }
}

void print_hex2chr(byte x) {
  Serial.print((x >> 4), HEX);
  Serial.print((x & 0x0F), HEX);
}

「esp32s3_i2c_scanner」を実行した結果を次に示します。

I 2 Cアドレスは、「0x18」が加速度センサー、「0x1E 」がデジタルコンパスになっていました。

LSM303DLHによるデジタルコンパス・加速度プログラムの作成

LSM303DLHによるデジタルコンパス・加速度プログラムを次に示します。「LSM303DLHを用いたPro Microのデジタルコンパス・加速度入力プログラム」で使用したプログラムを一部変更しました。

デジタルコンパスのデータの解析をする場合、30-31行目をコメントにして、28-29行目のコメントを外し、CSV形式で出力します。

esp32s3_LSM303DLH

#include <Wire.h>

#define PIN_SDA 1
#define PIN_SCL 2

int compass_a_x, compass_a_y, compass_a_z;
int compass_m_x, compass_m_y, compass_m_z;

char report[80];

void setup() {
  Serial.begin(115200);
  while (!Serial) {
  }

  Wire.begin(PIN_SDA, PIN_SCL);  // ok
  compass_init();
}

void loop() {
  compass_read();

  //snprintf(report, sizeof(report), "A: %6d %6d %6d    M: %6d %6d %6d",
  //         compass_a_x, compass_a_y, compass_a_z,
  //         compass_m_x, compass_m_y, compass_m_z);
  //Serial.println(report);

 //Serial.printf("%d, %d, %d\n",  // デジタルコンパス
 //               compass_m_x, compass_m_y, compass_m_z);
 Serial.printf("accelX:%d, Y:%d, Z:%d\n",  // 加速度
               compass_a_x, compass_a_y, compass_a_z);

  delay(100);
}

void compass_init() {
  Wire.beginTransmission(0x18);
  Wire.write(0x20);
  Wire.write(0x27);
  Wire.endTransmission();

  Wire.beginTransmission(0x1E);
  Wire.write(0x02);
  Wire.write(0x00);
  Wire.endTransmission();
}

void compass_read() {
  Wire.beginTransmission(0x18);
  Wire.write(0x28 | 0x80);
  Wire.endTransmission();
  Wire.requestFrom(0x18, 6);
  byte b = Wire.read();
  compass_a_x = (int16_t)(Wire.read() << 8 | b);
  b = Wire.read();
  compass_a_y = (int16_t)(Wire.read() << 8 | b);
  b = Wire.read();
  compass_a_z = (int16_t)(Wire.read() << 8 | b);

  Wire.beginTransmission(0x1e);
  Wire.write(0x03);
  Wire.endTransmission();
  Wire.requestFrom(0x1e, 6);
  b = Wire.read();
  compass_m_x = (int16_t)(b << 8 | Wire.read());
  b = Wire.read();
  compass_m_y = (int16_t)(b << 8 | Wire.read());
  b = Wire.read();
  compass_m_z= (int16_t)(b << 8 | Wire.read());
}

67行目と69行目で、ベースとしたプログラムの保存するデータ(compass_m_y,compass_m_z)が誤っていたので修正しました。

LSM303DLHによるデジタルコンパス・加速度プログラムの実行

作成したデジタルコンパス・加速度プログラム「esp32s3_LSM303DLH」をFreenove ESP32-S3-WROOM CAMボードに書き込み、実行すると、Arduino IDEのシリアルプロッタには、次のような加速度センサX/Y/Zのプロットデータが表示されます。

デジタルコンパスのデータを解析するために、「esp32s3_LSM303DLH」のコメントを付け替えます。

「esp32s3_LSM303DLH」を実行しながら、そこそこ水平なテーブルの上で、Z 軸を中心にセンサをぐるっと 1 回転させ、その出力を Tera Termのログ機能を使って、データをファイル化「teraterm.txt」します。

Excelを使用して「teraterm.txt」を解析します。結果を次に示します。「X-Y」のグラフを見ると円形になっていることが確認できます(ただしX 軸および Y 軸の絶対値に差があり、中心が原点からずれています)

θを求めるためには単純にθ=arctan(y_mag/x_mag)とすればよい(地磁気センサでそこそこの精度の電子コンパスを作ってみたという話)。