とっくんラボ

電子工作、プログラミングで日々の発見や成果をよろづに

Git超初心者がRaspberry PiでGitサーバを構築して、Windowsでcloneするまで! 後編 Git構築

こんにちは。前回に続き、今回は実際にRaspberry PiDebian 8.0)でGitサーバ(リモートリポジトリ)を構築し、Windows PCからcloneしてみます。


tocknlab.hatenablog.com



Raspberry Piにリモートリポジトリを作成!


まずはRaspberry PiにGitをインストールします。

(Raspberry Pi)
apt-get install git

次に、Git専用のユーザーを作成しましょう。今回はgitというユーザーを追加します。

(Raspberry Pi)
useradd -m git
passwd パスワード


そして、リモートリポジトリを作成したいディレクトリ上で(今回は/home/git)

(Raspberry Pi)
cd /home/git
git init --bare --shared hoge.git

こうすることで/home/gitにhoge.gitという名前でリポジトリフォルダが作成されます。
--bareは作成するリポジトリをベアリポジトリとして、--sharedはみんな書き込みできるよ~というオプションです。
ベアリポジトリはフォルダ名に.gitを付けるのが慣例のようです。

ベアリポジトリについては前回の記事を参考に!

ls -a

で、".git"というフォルダが作成されていることが確認できると思います。


一旦これでRaspberry Piでの作業は置いておきます。
次にWindowsでの作業に移ります。



Windows PCでローカルリポジトリを作成!

・Gitのインストール

まずはWindowsにGitをインストールしましょう。
こちらのページよりダウンロードできます。

git-for-windows.github.io

インストール後、私はCygwinからGitを使用していきますが、コマンドプロンプトでもほぼ同じ内容で作業ができると思います。


・鍵の生成、登録

早速clone!と行きたいところですが、まだやらなければいけないことがあります。
Windowsから先ほど作成したRaspberry Piのgitユーザーでssh接続をできるようにします。
まずはWindows PCのわかりやすい場所に.sshというフォルダを作成し、そこに公開鍵とそれに対応する秘密鍵を作成しましょう。


Cygwin

(Windows)
mkdir .ssh
ssh-keygen -t rsa -C "コメント"
Generating public/private rsa key pair.
Enter file in which to save the key (//.ssh/id_rsa): ここに.sshのパスを入れる


すると、指定した.ssh内に「id_rsa」「id_rsa.pub」が生成されることが確認できると思います。この.sshのパスは覚えておいてください。


Raspberry Piに戻り、/home/git(ユーザー名)に「.sshディレクトリを作成し、authorized_keysというファイルを作成しましょう。
そして、「id_rsa.pub」の中身をauthorized_keysへコピーしましょう。

(Raspberry Pi)
mkdir /home/git/.ssh
cd /home/git/.ssh
vim authorized_keys
(id_rsa.pubの中身をコピーして保存)


これでsshの為の鍵の登録は完了しました。
Windowsに戻ります。


次に、clone等をする際に行うsshで使用する秘密鍵の場所を設定してあげます。

(僕はこれを忘れていて、
The authenticity of host '' can't be established.
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
こんなエラーにしばらく悩まされましたとさ…)

(windows)
vim ~/.ssh/config

で設定ファイルを開き、

Host 任意の名前
    Hostname ssh://(さっき作ったユーザー名):(パスワード)@(IPアドレス)(リモートリポジトリのパス)
    User git
    IdentityFile "(さっき鍵を作ったパス)"
    Port 22

このように書き込みます。
IPアドレスの欄には、内部ネットワークから接続する場合はRaspberry PiのプライベートIPアドレスを、外部ネットワークから接続する場合はグローバルIPアドレスを入れましょう。
例えば

Host hoge
    Hostname ssh://git:password@192.168.0.50/home/git/hoge.git
    User git
    IdentityFile "c:/Users/$user_profile/.ssh/id_rsa"
    Port 22

こんな感じになります。


・いざclone!

これでようやくcloneの準備が整いました。
ローカルリポジトリを作成したいディレクトリへ移動し、以下のコマンドを実行します

git clone ssh://(さっき作ったユーザー名):(パスワード)@(IPアドレス)(リモートリポジトリのパス) (ローカルリポジトリフォルダ名)

例えば私の場合は

git clone ssh://git:password@192.168.0.50/home/git/hoge.git hoge

になります。


これでようやくcloneができましたね!(おそらく空のリポジトリをクローンしたよ!平気?という警告メッセージが出るかと思いますが、無視してください。)

ls -a

で、".git"というフォルダが作成されていることが確認できると思います。


・あとはこっちのモンだ

早速commit、pushしていきましょう!

ワーキングツリーで適当にファイルを作って…(ここではtest.txtを作りました)

(Windows)
git status

これで、インデックスに追加されていない変更内容を確認できます。

On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        test.txt

nothing added to commit but untracked files present (use "git add" to track)

test.txtが変更されてるけど追加されてないよ~って言ってますね

addでインデックスへ追加してあげましょう。

(Windows)
git add test.txt

そして

(Windows)
git status

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test.txt

これで準備完了!commitしましょう。

git commit -m "test.txtを追加"

-mオプションを付けて、スペース空けて後ろにコメントを書きます。主にどのような更新をしたのかを記しましょう。

最後にpush!
初回のpushでは、-uオプションを付けましょう。

git push -u ssh://(さっき作ったユーザー名):(パスワード)@(IPアドレス)(リモートリポジトリのパス) master

無事pushできましたか?


ここで、毎回毎回pushの度にssh://~~を入力していたら大変ですよね。それを省略する機能を使いましょう。

git remote add origin ssh://(さっき作ったユーザー名):(パスワード)@(IPアドレス)(リモートリポジトリのパス)

このように、ホストをoriginという名前に対応させましょう。すると

git push

このように省略が可能になりました。

ちなみに、こう書けるのは対応した名前が"origin"の時のみで、別名を付けた場合は

git push 付けた名前

としましょう。

pullしたい時は、同じように

git pull

もしくは

git pull 付けた名前

するだけです。


・終わった…

これで一通り環境が整ったのではないでしょうか!(書き忘れていることがあるような気がしますが…)

長かった…疲れた…後半はテキトーに書いてました。

ここが違うよ!できないよ!といった意見がございましたら、どしどしコメントをください!


それでは!良いGitライフを!!


Git超初心者がRaspberry PiでGitサーバを構築して、Windowsでcloneするまで! 前編 Gitとは?

こんにちは。久しぶりの更新です。


今まで何かアプリケーションを開発する時、日付.zipやバージョン名.zipでクソ管理してきた僕ですが、ついにGitを使うときがやってきました。 


訳あってGithub等の外部サービスにリモートリポジトリを置けない状況だったので、自宅にあるRaspberry Pi3でリモートリポジトリを作成し、手元のWindows PCにもGitを入れてそこからclone、pushできる環境を作りました。


Gitってなんだ?という状態から行ったこと、躓いたことを備忘録として書いていこうと思います。



・Gitってなんだ!

Gitはプログラムのバージョン管理を楽に行っちゃおうっていうツールです。

例えば1人でアプリを開発する場合。新たに機能を追加したいけど、それで何か不具合が起きたら困るし…と、既存のプログラムをoldVersionなんて言う名前にしてバックアップを取り、新たな機能を開発する…。そんな事を繰り返していると、フォルダの中はoldVersion1, oldVersion2, oldVersion2 - コピーと、意味分からないファイルでいっぱい!

または複数人で開発する場合。うまく連携が取れず、気がついたら同じプログラムを複数人で編集してしまい、競合が発生!

こんな経験、ありませんか?
これを全て解決してくれるのが、Gitなのです。

Gitは主に「リモートリポジトリ」「ローカルリポジトリ」「インデックス」「ワーキングツリー」から構成されます。
リポジトリは、ファイルの変更履歴を保存する場所を指します。)


・ローカルリポジトリ
個人の変更履歴を保存する場所です。

・ワーキングツリー
ローカルリポジトリにあります。要は作業場です。ここにあるファイル(フォルダ)を編集していきます。

・インデックス
ローカルリポジトリへ変更内容を記録したいワーキングツリーのファイルを、まずはここに格納します。ここに格納されていないファイルは、変更内容がローカルリポジトリへ記録されません。

・リモートリポジトリ
サーバ等へ置き、みんなで共有するリポジトリ。みんなの変更履歴がどんどん追加されていく。基本的にリモートリポジトリはワーキングツリーを持たない。これをベアリポジトリという。

gitでは主なコマンドとして、

clone
add
commit
push
pull

があります。

・clone
リモートリポジトリを、個人(ローカル)のディレクトリへコピーする(クローンを生成する)コマンドです。それがローカルリポジトリとなります。

・add
指定したワーキングツリーのファイル(フォルダ)をインデックスへ格納するコマンドです。

・commit
インデックスにあるファイル(フォルダ)の前回commitからの更新内容をローカルリポジトリへ保存するコマンドです。普通はメッセージを付け、何をどう変更したのかを明白にします。

・push
ローカルリポジトリの中身をリモートリポジトリへ追加するコマンドです。

・pull
誰かが更新し、リモートリポジトリへ追加した内容を、自分のローカルリポジトリへ反映させるコマンドです。


他にもbranch等、大事な大事な機能がありますが、今はとにかくRaspberry Piでリモートリポジトリを作ってwinPCでcloneするのが目的なので、今回は省略!

もう文章だらけで飽きましたよね。

百聞は一見に如かず、次回はいよいよRaspberry Piでの作業に移ります!



後編はこちらから!
tocknlab.hatenablog.com

ESP32 (ESP-WROOM-32)でSDカードへ読み書きする。(Arduino IDE)

ESP32弄り第三弾は、SDカードへの読み書きです。



SDカードはSPIを使って通信します。

今回はこちらのSDカードモジュールを使用しました。

ピン配置は、


f:id:tocknblog:20170312021909p:plain


このようになっています。

ESP32への配線は以下の通り行いました。

  • DAT2 -> 無し
  • CD/DAT3 -> GPIO5
  • CMD -> GPIO23
  • VDD -> +3.3V
  • CLK -> GPIO18
  • VSS -> GND
  • DAT0 -> GPIO19
  • 以下接続なし

ちなみに、どうにかすれば接続するピンを変えられるみたいです。多分。


また、先に言っておきますが、絶対にいらないSDカードを使用してください。中身が飛ぶことがよくあります。
そして配線は慎重に行ってください。3.3V以上の電圧をかけるとSDカードがぶっ壊れると聞いたことがあります。
そして、SDカードの抜き差しは電源が入っていない状態で行ってください。SDカードを読み込まなくなったりします。
何か起きても私は責任トリマセン…


スケッチは、公式のExampleをそのまま使いました。ここにあります。

これを使えばSDカードの読み書きに関する大抵のことはできると思います。

もしライブラリを追加する方法がわからない~とかでしたら、コメントください。

上手く行けば実行結果はこんな感じになると思います。

SD Card Type: SDSC
SD Card Size: 1875MB
Listing directory: /
  DIR : /SYSTEM~1
  FILE: /YEAH.TXT  SIZE: 8
  FILE: /TEST.TXT  SIZE: 1048576
  FILE: /FOO.TXT  SIZE: 13
  DIR : /MYDIR
  DIR : /TESTDIR
Creating Dir: /mydir
Dir created
Listing directory: /
  DIR : /SYSTEM~1
  FILE: /YEAH.TXT  SIZE: 8
  FILE: /TEST.TXT  SIZE: 1048576
  FILE: /FOO.TXT  SIZE: 13
  DIR : /MYDIR
  DIR : /TESTDIR
Removing Dir: /mydir
rmdir failed
Listing directory: /
  DIR : /SYSTEM~1
Listing directory: /SYSTEM~1
  FILE: /SYSTEM~1/WPSETT~1.DAT  SIZE: 12
  FILE: /SYSTEM~1/INDEXE~1  SIZE: 76
  FILE: /YEAH.TXT  SIZE: 8
  FILE: /TEST.TXT  SIZE: 1048576
  FILE: /FOO.TXT  SIZE: 13
  DIR : /MYDIR
Listing directory: /MYDIR
  DIR : /MYDIR/TEEEEE
Listing directory: /MYDIR/TEEEEE
  DIR : /MYDIR/TEEEEE/SDF
  DIR : /TESTDIR
Listing directory: /TESTDIR
Writing file: /hello.txt
File written
Appending to file: /hello.txt
Message appended
Reading file: /hello.txt
Read from file: Hello World!
Deleting file: /foo.txt
File deleted
Renaming file /hello.txt to /foo.txt
File renamed
Reading file: /foo.txt
Read from file: Hello World!
1048576 bytes read for 3219 ms
1048576 bytes written for 5442 ms


SDカードのルートディレクトリにFOO.TXT、TEST.TXTというファイルが生成され、FOO.TXTの中にHello World!と書いてあれば成功だと思います。

以上!

ESP32 (ESP-WROOM-32)でMPU6050を使おう!(i2C) (Arduino IDE)

ESP32弄り日記第二弾は、安くて有名なInvenSense製6軸センサ、MPU6050を使おう!です。

MPU6050には3軸加速度センサー、3軸ジャイロセンサーが積んであります。3+3=6軸センサーというわけです。

ESP32とMPU6050を用いて、角度計を作ってみましょう。
今回もArduino IDEを使って開発していきます。

私が使用したのは以下のモジュールです。



これでOKです。(めちゃくちゃ安い。ありがたい。)

まず配線ですが、ESP32は以前書いたように、SCL、SDAピンを対応している中から自由に選べます。

今回はSCLピンをGPIO25、SDAピンをGPIO26にしました。

するとブレッドボードはこんな具合になります。

f:id:tocknblog:20170311164837j:plain


いやぁ、、、わちゃわちゃしてるなぁ、、、

スケッチはこんな感じです。
(一応断っておきますが、私は素人です…こんな書き方はヤメロぉ!とかありましたらご指摘ください…)

#include <Wire.h>

#define MPU6050_ADDR         0x68 // MPU-6050 device address
#define MPU6050_SMPLRT_DIV   0x19 // MPU-6050 register address
#define MPU6050_CONFIG       0x1a
#define MPU6050_GYRO_CONFIG  0x1b
#define MPU6050_ACCEL_CONFIG 0x1c
#define MPU6050_WHO_AM_I     0x75
#define MPU6050_PWR_MGMT_1   0x6b

double offsetX = 0, offsetY = 0, offsetZ = 0;
double gyro_angle_x = 0, gyro_angle_y = 0, gyro_angle_z = 0;
float angleX, angleY, angleZ;
float interval, preInterval;
float acc_x, acc_y, acc_z, acc_angle_x, acc_angle_y;
float gx, gy, gz, dpsX, dpsY, dpsZ;

void culcRotation();

//I2c書き込み
void writeMPU6050(byte reg, byte data) {
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(reg);
  Wire.write(data);
  Wire.endTransmission();
}

//i2C読み込み
byte readMPU6050(byte reg) {
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(reg);
  Wire.endTransmission(true);
  Wire.requestFrom(MPU6050_ADDR, 1/*length*/); 
  byte data =  Wire.read();
  return data;
}

void setup() {

  Wire.begin(26, 25);
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  
  Serial.begin(9600);
  delay(100);
  
  //正常に接続されているかの確認
  if (readMPU6050(MPU6050_WHO_AM_I) != 0x68) {
    Serial.println("\nWHO_AM_I error.");
    while (true) ;
  }

  //設定を書き込む
  writeMPU6050(MPU6050_SMPLRT_DIV, 0x00);   // sample rate: 8kHz/(7+1) = 1kHz
  writeMPU6050(MPU6050_CONFIG, 0x00);       // disable DLPF, gyro output rate = 8kHz
  writeMPU6050(MPU6050_GYRO_CONFIG, 0x08);  // gyro range: ±500dps
  writeMPU6050(MPU6050_ACCEL_CONFIG, 0x00); // accel range: ±2g
  writeMPU6050(MPU6050_PWR_MGMT_1, 0x01);   // disable sleep mode, PLL with X gyro

  //キャリブレーション
  Serial.print("Calculate Calibration");
  for(int i = 0; i < 3000; i++){
    
    int16_t raw_acc_x, raw_acc_y, raw_acc_z, raw_t, raw_gyro_x, raw_gyro_y, raw_gyro_z ;
    
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU6050_ADDR, 14, true);
  
    raw_acc_x = Wire.read() << 8 | Wire.read();
    raw_acc_y = Wire.read() << 8 | Wire.read();
    raw_acc_z = Wire.read() << 8 | Wire.read();
    raw_t = Wire.read() << 8 | Wire.read();
    raw_gyro_x = Wire.read() << 8 | Wire.read();
    raw_gyro_y = Wire.read() << 8 | Wire.read();
    raw_gyro_z = Wire.read() << 8 | Wire.read();
    dpsX = ((float)raw_gyro_x) / 65.5;
    dpsY = ((float)raw_gyro_y) / 65.5;
    dpsZ = ((float)raw_gyro_z) / 65.5;
    offsetX += dpsX;
    offsetY += dpsY;
    offsetZ += dpsZ;
    if(i % 1000 == 0){
      Serial.print(".");
    }
  }
  Serial.println();

  offsetX /= 3000;
  offsetY /= 3000;
  offsetZ /= 3000;

  Serial.print("offsetX : ");
  Serial.println(offsetX);
  Serial.print("offsetY : ");
  Serial.println(offsetY);
  Serial.print("offsetZ : ");
  Serial.println(offsetZ);
  
}

void loop() {

  calcRotation();

  Serial.print("angleX : ");
  Serial.print(angleX);
  Serial.print("    angleY : ");
  Serial.print(angleY);
  Serial.print("    angleZ : ");
  Serial.println(angleZ);
 
}

//加速度、ジャイロから角度を計算
void calcRotation(){

  int16_t raw_acc_x, raw_acc_y, raw_acc_z, raw_t, raw_gyro_x, raw_gyro_y, raw_gyro_z ;
  
  //レジスタアドレス0x3Bから、計14バイト分のデータを出力するようMPU6050へ指示
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU6050_ADDR, 14, true);
  
  //出力されたデータを読み込み、ビットシフト演算
  raw_acc_x = Wire.read() << 8 | Wire.read();
  raw_acc_y = Wire.read() << 8 | Wire.read();
  raw_acc_z = Wire.read() << 8 | Wire.read();
  raw_t = Wire.read() << 8 | Wire.read();
  raw_gyro_x = Wire.read() << 8 | Wire.read();
  raw_gyro_y = Wire.read() << 8 | Wire.read();
  raw_gyro_z = Wire.read() << 8 | Wire.read();
  
  //単位Gへ変換
  acc_x = ((float)raw_acc_x) / 16384.0;
  acc_y = ((float)raw_acc_y) / 16384.0;
  acc_z = ((float)raw_acc_z) / 16384.0;
  
  //加速度センサーから角度を算出
  acc_angle_y = atan2(acc_x, acc_z + abs(acc_y)) * 360 / -2.0 / PI;
  acc_angle_x = atan2(acc_y, acc_z + abs(acc_x)) * 360 / 2.0 / PI;

  dpsX = ((float)raw_gyro_x) / 65.5; // LSB sensitivity: 65.5 LSB/dps @ ±500dps
  dpsY = ((float)raw_gyro_y) / 65.5;
  dpsZ = ((float)raw_gyro_z) / 65.5;
  
  //前回計算した時から今までの経過時間を算出
  interval = millis() - preInterval;
  preInterval = millis();
  
  //数値積分
  gyro_angle_x += (dpsX - offsetX) * (interval * 0.001);
  gyro_angle_y += (dpsY - offsetY) * (interval * 0.001);
  gyro_angle_z += (dpsZ - offsetZ) * (interval * 0.001);
  
  //相補フィルター
  angleX = (0.996 * gyro_angle_x) + (0.004 * acc_angle_x);
  angleY = (0.996 * gyro_angle_y) + (0.004 * acc_angle_y);
  angleZ = gyro_angle_z;
  gyro_angle_x = angleX;
  gyro_angle_y = angleY;
  gyro_angle_z = angleZ;
}




まず最初のsetup()内のfor文ですが、これでジャイロセンサーのドリフト誤差を抑える為の計算をしています。

ドリフト誤差とはなんぞ?という方のために…
ジャイロセンサとは、つまりは角速度センサなのであります。角速度から角度を得るには…そう、積分ですよね!
プログラム内では、毎回毎回ジャイロセンサからの出力値と時間(秒)を掛け合わせたものを足していき、それが出力する角度としています。

理想的なジャイロセンサならば静止状態の時の出力値はゼロなのですが、世の中そうは行きません。普通は、静止状態でも常にゼロ以外の小さな値を出力し続けてしまいます。
放っておくと、どうなるでしょうか。
エス、どんどん角度が増えて(減って)いってしまう!!!
これをドリフト誤差といいます。

それを防ぐために、静止状態で出力し続ける値を1000回位読み取って平均値を取り、その値を積分時に生の値から引いているのです。


さて次は、一番下の関数calcRotation()に注目してください。

その一部分

  raw_acc_x = Wire.read() << 8 | Wire.read();
  raw_acc_y = Wire.read() << 8 | Wire.read();
  raw_acc_z = Wire.read() << 8 | Wire.read();
  raw_t = Wire.read() << 8 | Wire.read();
  raw_gyro_x = Wire.read() << 8 | Wire.read();
  raw_gyro_y = Wire.read() << 8 | Wire.read();
  raw_gyro_z = Wire.read() << 8 | Wire.read();

ここ、何だこれって思いませんか?私は思います。

MPU6050は、各センサの出力値を

x軸加速度、y軸加速度、z軸加速度、温度、x軸角速度、y軸角速度、z軸角速度

の順番に出力しますが、さらにその各データは上位8bit→下位8bitの順に出力されています。つまり計14個のデータですね。
そこで、上記の部分ではビットシフト演算を行い、正しい値へ変換しているのです。


そしてその下、「単位Gへ変換」という部分ですが、MPU6050は出力した加速度センサのデータを、16384で割ることで単位Gへ変換することが出来ます。
ただしこれは設定で変更することが出来ます。
ちゃっかりその設定を、最初のsetup()内で行っていました。

  //設定を書き込む
  writeMPU6050(MPU6050_SMPLRT_DIV, 0x00);   // sample rate: 8kHz/(7+1) = 1kHz
  writeMPU6050(MPU6050_CONFIG, 0x00);       // disable DLPF, gyro output rate = 8kHz
  writeMPU6050(MPU6050_GYRO_CONFIG, 0x08);  // gyro range: ±500dps
  writeMPU6050(MPU6050_ACCEL_CONFIG, 0x00); // accel range: ±2g
  writeMPU6050(MPU6050_PWR_MGMT_1, 0x01);   // disable sleep mode, PLL with X gyro

ここです。(上から3,4行目)
今回は加速度センサは±2G、ジャイロセンサは±500dps(degree per second)まで計測できる設定にしています。
ここの設定によって、取得した生のデータから変換するための計算式が変わってくるのです。
詳しくはデータシートを見てネ!

その下

  //加速度センサーから角度を算出
  acc_angle_y = atan2(acc_x, acc_z + abs(acc_y)) * 360 / -2.0 / PI;
  acc_angle_x = atan2(acc_y, acc_z + abs(acc_x)) * 360 / 2.0 / PI;

こちらは書いてある通り、逆三角関数を用いて角度を計算しています。
選ぶ軸と正負には気をつけてね!!

  dpsX = ((float)raw_gyro_x) / 65.5; // LSB sensitivity: 65.5 LSB/dps @ ±500dps
  dpsY = ((float)raw_gyro_y) / 65.5;
  dpsZ = ((float)raw_gyro_z) / 65.5;

ジャイロセンサーから取得した生のデータを、dps (degree per second)へ変換しています。加速度のときと同じですね。

  //前回計算した時から今までの経過時間を算出
  interval = millis() - preInterval;
  preInterval = millis();
  
  gyro_angle_x += (dpsX - offsetX) * (interval * 0.001);
  gyro_angle_y += (dpsY - offsetY) * (interval * 0.001);
  gyro_angle_z += (dpsZ - offsetZ) * (interval * 0.001);

ここでは数値積分を行っています。最初に計算したoffset達がここで役立つわけなんです!

millis()は、ESP32の起動から今までの経過時間を単位ミリ秒で取得できます。interval * 0.001は、ミリ秒から秒へ変換しているわけです。

そして最後の

  //相補フィルター
  angleX = (0.996 * gyro_angle_x) + (0.004 * acc_angle_x);
  angleY = (0.996 * gyro_angle_y) + (0.004 * acc_angle_y);
  angleZ = gyro_angle_z;
  gyro_angle_x = angleX;
  gyro_angle_y = angleY;
  gyro_angle_z = angleZ;

ここでは相補フィルターというものを使い、加速度センサーから求めた角度と、ジャイロセンサーから求めた角度を組み合わせています。
なぜそんなことをする必要があるのか、それは、互いの欠点を打ち消し合い、長所を活かしているのです。

まずジャイロセンサーには前述の通り、ドリフト誤差という欠点があります。一応このプログラムではそれを出来る限り抑えるようにしていますが、それでもやはりドリフトしてしまいます。

そして加速度センサーは、角度を加速度で求めているというのが欠点になります。なぜなら、静止状態なら良いのですが、対象が動く物体だったらどうでしょう。激しく動けば動くほど、あらゆる軸に加速度がかかり、角度がブレてしまうのです。

まとめると、

  • 加速度センサーは長時間運用に強いが、瞬間的なもの(外力)には弱い

そこで

 angleX = (0.996 * gyro_angle_x) + (0.004 * acc_angle_x);
  angleY = (0.996 * gyro_angle_y) + (0.004 * acc_angle_y);

この式なのです。
瞬間的にはジャイロセンサーの値を適用するが、ほぼ静止するとじわじわと加速度センサーの値へ近づいていくのがわかると思います。
これが相補フィルターなのです。(多分)
他にもNASAの?何かの?姿勢制御に使われた?カルマンフィルターなどがあるそうなのですが?、よくわかりませんでした。
こういったセンサーを組み合わせることを、センサフュージョンというらしいです。かっこいい!


説明は大体こんな感じでしょうか。


f:id:tocknblog:20170311175829p:plain


ちゃんと書き込めれば、こんな感じになると思います。

何か質問、ご指摘等ありましたら、気軽にコメントしてください!

以上!


ESP32 (ESP-WROOM-32)でi2C通信

2017/03/12追記:実際に使ってみました


先日、Arduinoの環境で開発できるということで、ESP32を購入しました。

 


私はATmega328(Arduino UNO)ではi2Cを頻繁に使用していたので、早速購入したESP32でもi2Cを使ってみました。

しかし、躓いた点があったので報告します。

 

Arduinoでi2C通信する際に欠かせないWireライブラリですが、最初に

Wire.begin();

を実行しますよね。

ATmegaではi2Cで使うSCL, SDAピンは固定されていますが、ESP32では対応している複数のピンの中から2つを選んで使うことができます。そのため、まず最初に使用するピンを指定しなければなりませんでした。

ESP32でWireライブラリを使う場合、SCL, SDAピンの指定は

int SDA = 25;
int SCL = 26;

Wire.begin(SDA, SCL);


のように、beginの引数にSDA、SCLの順にピンの番号を入れることで出来ます。

i2Cで使えるセンサーを使う時、データシートをみながらプログラムをコツコツ書かずに、誰かが作ったライブラリを用いることがあると思います。その場合にも、ライブラリ内のbegin()の部分を書き換える必要がありそうです。

以上!