VSCodeとPlatformIOを用いた組み込み開発
===
[toc]
# 環境構築
## Visual Studio Codeのインストール
Visual Studio Code(VSCode)はエディタの一種である。
[Visual Studio Code公式ページ](https://code.visualstudio.com/download#)よりインストーラーをダウンロードし、インストールする。
## PlatformIOのインストール
PlatformIOは様々なマイコンのプログラムを開発するのに便利な統合開発環境用フレームワークである。AtomやVSCodeといったプログラミング向けのテキストエディタにプラグインとして導入できる。ライブラリの管理等が容易に行えるようになる。
![](https://i.imgur.com/EY8LzY3.png =50x)
ウィンドウ左の赤枠のアイコン(Extentions)をクリック
![](https://i.imgur.com/tXDETDT.png)
テキストフォームに"platformio"と入力し、"Install"(赤枠の箇所)をクリック
## ドライバのインストール
ESP32をパソコンと接続するためには以下のドライバをインストールする必要がある。以下のサイトからインストーラをダウンロードしてインストールする。
* [USB - UART ブリッジ VCP ドライバ - Silicon Labs](https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)
**VCPをダウンロード**のリンクをクリックしてダウンロードする。
# 機能説明
## PlatformIOタブの説明
![](https://i.imgur.com/z960rDz.png)
* > 赤色の枠: 新規プロジェクトを作成 [color=#ff0000]
* > 水色の枠: ライブラリの追加[color=#00ffff]
* > ピンクの枠: 接続されているデバイスの一覧を表示[color=#ff88ff]
* > 黄緑色の枠: 作成済みのプロジェクト一覧[color=#00ff00]
## 新規プロジェクトの作成
左のアイコン ![エイリアンのような見た目のアイコン](https://i.imgur.com/nVz5mAA.png =30x30) をクリックするとウィンドウ左下にQUICK ACCESSが表示される。`QUICK ACCESS > PIO Home > Open`をクリックするとPIO Homeのタブが開く。
PIO Homeタブから ![+ New Project](https://i.imgur.com/LtbIzxA.png =x30) をクリック。
![](https://i.imgur.com/VgAigSw.png)
Project Wizardが表示されるので、以下のように設定し ![Finish](https://i.imgur.com/TqTtwMb.png =x30) ボタンをクリックして新規プロジェクトを作成する。
* Name: プロジェクト名(自由)
* Board: Espressif ESP32 Dev Module
* Framework: Arduino
* Location: :white_check_mark: Use default location
## プロジェクトを開く
![](https://i.imgur.com/URSzmKF.png)
> プロジェクトが開き、main.cppを開いた状態
プロジェクトを作成するとプロジェクトが自動で開かれる。後からプロジェクトを開く場合や自動で開かれなかった場合は、PIO Homeタブのプロジェクト一覧(Recent Project)のOpenをクリックすれば良い。プロジェクトのフォルダは標準では書類フォルダの中の`PlatformIO/Projects/`に作成される。
## PlatformIOで追加されるボタン
PlatformIOをインストールするとウィンドウ下部のステータスバーに以下のようなボタンが追加される。
![](https://i.imgur.com/LR5x7Qp.png)
特に重要なのは以下の3つとなる。
* ![Build](https://i.imgur.com/QAJG63G.png =30x) ビルド(コンパイル)
* プログラムをコンパイルする
* ![Upload](https://i.imgur.com/o8jtWFI.png =30x) : アップロード(書き込み)
* プログラムをコンパイルしてボードに書き込む
* ![Serial Monitor](https://i.imgur.com/Q3uxF69.png =30x) : シリアルモニタ
* ボードとのシリアル通信を表示
# 用語解説
## マイコンと開発ボード
マイコンとは、マイクロコンピュータ、MCU(Micro Controller Unit)の略称で、ソフトウェアを実行できる小さなコンピュータである。身近な例では炊飯器が分かりやすい。時間指定で炊飯を始める機能や米を炊くための綿密な温度調整は全てマイコンが行なっている。自動車などでは数十個のマイコンが機能している。
マイコンはそれ単体では扱いづらいので、組み込み開発をする場合には使いたいマイコンを搭載した開発ボードと呼ばれる基板を用いることになる。開発ボードは多種多様であるが、電源回路とLEDやボタンを搭載しただけのシンプルなものから、液晶や各種センサーを搭載した高級なものまで存在している。
## Arduinoについて
Arduino(アルディーノ)はボードの名前であり、フレームワークの名前である。イタリア発祥で、安価で学生にも使いやすいマイコンボードとして開発され、世界中で人気を博している。
> フレームワークとは枠組みを意味し、プログラミングにおいてはその分野でよく使う機能を体系的にまとめたもの
オープンソースハードウェアであるため、公式が発売しているMade in Italyな数々のArduinoボードに加えて、個人が趣味で作ったArduino互換機も非常に多く出回っている。
今回用いるボードは公式のArduinoボードでは無いが、Arduinoフレームワークに対応しているのでArduinoと同じように開発することができる。
### リファレンス
Arduinoはフレームワークであるので、使用できる関数や定数の一覧が公開されている。プログラミングに置いてそのような文書のことをリファレンスと呼ぶ。
#### Arduinoのリファレンス
* [公式ページのArduinoの関数リファレンス](https://www.arduino.cc/reference/en/)
* [Arduinoの日本語リファレンス](http://www.musashinodenpa.com/arduino/ref/)
## ESP32について
ESP32はEspressif社の開発したマイコンの俗称で、ESP32-WROOM32-Dというのが正式な型番である。安価だが技適認証されたWiFiやBluetooth機能を搭載しており、Arduinoフレームワークに対応しているため2019年現在人気がある。
> 主な諸元
> * CPU 32bit デュアルコアプロセッサ(400MIPS)
> * WiFi(802.11 b/g/n)
> * bluetooth v4.2
> * SRAM 520KB
> * ROM 448KB
> * UART x 3
> * SPI x 2
> * I2C x 2
> * I2S x 2
> * DAC x 2
> * ADC x 16
> * GPIO x 21
ESP32は厳密には2センチ四方程度の大きさの銀色のチップを指す。しかし、ESP32単体には電源回路などが組み込まれていないため、開発ボードに搭載された状態のものを活用することが多い。今回使用したものと同じものは[こちらのサイト](https://www.aliexpress.com/item/e/32844263180.html)などや[こちらのサイトへ](https://www.amazon.co.jp/dp/B07NQ13X8C/)で購入できる。
なお今回開発に用いるボードは開発ボード単体ではなく、TTGO ESP32 T2という名前のESP32開発ボードに独自設計の基板を接続したものである。
## フライトコントローラ
航空機が空を飛ぶために姿勢や航行を制御する装置のことをフライトコントローラと呼ぶ。フライトコントローラには機体の姿勢や速度を知るためのセンサーがついており、そのデータに基づいて姿勢を適切に保つことができる。また、GPSを用いてあらかじめ指定した経路を飛行するといった航行を制御することもできる。
この講義で用いるフライトコントローラは、ESP32の開発ボードと専用に開発した基板からなっており、3軸加速度、3軸角速度、3軸地磁気センサーを搭載している。
> 3軸とは座標系におけるXYZ軸のことを指している
この講義ではフライトコントローラを用いて機体の滑空角度を適切に保つように制御を行う。
::: info
**Tips**
マルチコプターのフライトコントローラは数$ms$毎に空中での姿勢を推定し、各プロペラの推力を変化させることで機体を制御しているため、ホバリングすることができる
:::
# プログラミング
::: info
**用意するもの**
* PC(Visual Studio CodeとPlatformIOをインストールしたもの)
* micro USBケーブル(通信用)
* フライトコントローラ
* インターネット環境
:::
## プロジェクト: Lチカ(blink)
::: info
**目的** : フライトコントローラのLEDを点滅させて組み込み開発に慣れ親しむ
:::
以下のプログラムを`src/main.cpp`に書いて、ボードを接続し、アップロード ![](https://i.imgur.com/o8jtWFI.png =20x) ボタンを押すとボードのLEDが1秒ごとに点滅を繰り返し始める。
```cpp=
#include <Arduino.h> // Arduinoライブラリを導入
#define LED_PIN 32 // プログラム中のLED_PINという文字を32に置換
// 最初に一回だけ実行されるsetup()関数
void setup() {
pinMode(LED_PIN, OUTPUT); // LED_PIN(32番ピン)を出力ピンに設定
}
// setup()関数のあと無限ループするloop()関数
void loop() {
digitalWrite(LED_PIN, HIGH); // LED_PIN(32番ピン)をHIGH(5V)に設定
delay(1000); // 1000[ms]の間何もしない
digitalWrite(LED_PIN, LOW); // LED_PIN(32番ピン)をLOW(0V)に設定
delay(1000); // 1000[ms]の間何もしない
}
```
:::warning
### ボードに書き込めない時
* USBケーブルは繋がっているか?通信用のケーブルを使用しているか?
* モバイルバッテリーに付属するUSBケーブルは充電にしか使えないことがある
* ボードはデバイス一覧に表示されているか?
* ドライバがインストールされていないとボードは表示されない
* コンパイルエラーが出ていないか?
* プログラムを規則通り書けていないとコンパイルエラーとなり書き込みは行われない
* 行末の ; (セミコロン)を忘れていないか?
* カッコを閉じ忘れていないか?
* タイプミスが無いか?
:::
:::info
**Tips**
Lチカとは"LEDをチカチカ(点滅)させる"の略である。組み込み開発の第一歩として、整えた開発環境とマイコンの動作確認として、世界中で行われている。
:::
---
## プロジェクト: スイッチ入力(button-input)
::: info
**目的** フライトコントローラのタクトスイッチの入力を読み取る
:::
タクトスイッチの状態を読み取るには`digitalRead()`関数を用いる。この関数は指定のピンの電圧が一定以上(HIGH)だと`true`を返し、それ以外(LOW)で`false`を返す。
一方、タクトスイッチは押すと導通し、離すと絶縁状態になる。タクトスイッチ周りの回路図に修正を加えたものが以下の通りである。
![](https://i.imgur.com/9cmgTKN.png)
> タクトスイッチを押すとGPIO17がGND(0V)と接続される。
タクトスイッチを押さない状態と押した状態では電圧はどうなるだろうか?ボタンを押すとGPIO17とGNDが繋がりGPIO17の電圧は0Vになる(LOW)。ボタンを離した状態ではGPIO17は抵抗器を介してVCCと接続され、少なくとも0Vにはならないことがわかる(実際にはマイコンの内部抵抗が大きいためHIGHとなる)。
つまり、`digitalRead()`の値は==タクトスイッチを押すとfalseになり、タクトスイッチを離すとtrue==になる。
このことを踏まえて以下のプログラムを穴埋めし、タクトスイッチを押すとLEDが光るようにせよ。
```cpp=
#include <Arduino.h> // Arduinoライブラリを導入
#define LED_PIN 32 // プログラム中のLED_PINという文字を32に置換
#define BUTTON_PIN 17 // プログラム中のBUTTON_PINという文字を35に置換
// 最初に一回だけ実行されるsetup()関数
void setup() {
pinMode(LED_PIN, OUTPUT); // LED_PIN(32番ピン)を出力ピンに設定
pinMode(BUTTON_PIN, INPUT_PULLUP); // BUTTON_PIN(17番ピン)を入力(プルアップ)に設定
}
// setup()関数のあと無限ループするloop()関数
void loop() {
<<穴埋め箇所>>
}
```
::: info
**Tips**
* **プルアップ抵抗について**
前述の回路図でVCCとGPIO17の間に接続されている抵抗器をプルアップ抵抗と呼ぶ。プルアップ抵抗は端子の開放状態(Open)を防ぐためにある。
開放状態とは電圧が掛かっていない状態のことを指す。開放状態の配線はアンテナと同じで電磁波の影響を強く受け、電圧が安定しない。
もしプルアップ抵抗が無いと、タクトスイッチを押していない時の電圧は開放状態となり電圧が勝手に変化してしまうことになる。
プルアップ抵抗の逆にプルダウン抵抗というものも存在し、これはGNDと端子を接続する。
* **なぜ論理を反転させるのか?**
タクトスイッチをGNDではなくVCCに繋ぎ、プルダウン抵抗を採用すれば論理を反転させずに済むように見える。しかしこの場合、タクトスイッチを押すとVCCとGNDが直結されることになり、すなわちショートが発生する。この場合、VCCとGNDの間に新たに抵抗器を設置する必要があり、金銭と加工のコストが増加してしまう。このため、論理が反転したプルアップを採用している。
このように、組込み開発ではソフトウェアで簡単に対応できることをハードウェアで実装しようとするとコストの無駄が生じる事が良くある(逆もしかり)。
:::
---
## プロジェクト: Lチカ(blink-pwm)
::: info
**目的** : PWM(Pulse Width Modulation)を使う
:::
マイコンのピンは通常、ONの状態かHIGHの状態しか出力できないが、PWMという信号波形を用いることでLEDの明るさを変えることができる。
PWMはONとOFFを一定周期で繰り返す波形で、ONとOFFの比率(duty比)を変えることで電圧が変化しているのと同じような状態にできる。実際にはONとOFFを繰り返しているだけのため、LEDをスローモーションカメラで取れば点滅しているだけになってしまうが、人間の目には残像現象を起こす特性があるので問題なく明るさが変化しているように見える。
![](https://i.imgur.com/KIdce58.png)
以下のプログラムではLEDがゆっくりと明るくなり、一瞬消灯するのを繰り返す。
プログラムを修正し、ゆっくりと明るくなった後、ゆっくり消灯するのを繰り返すようにせよ。
```cpp=
#include <Arduino.h>
#define LED_PIN 32
int brightness = 0; // 明るさ保存用の変数
void setup() {
// 使用するタイマーのチャネルと周波数を設定
ledcSetup(0, 12800, 8);
// LED_PINをチャネル0へ接続
ledcAttachPin(LED_PIN, 0);
}
void loop() {
// チャネル0に明るさを設定
ledcWrite(0, brightness);
brightness += 1; // 明るさを増やす
if (brightness > 255) brightness = 0; // 明るさが255を超えたら0に戻す
delay(10);
}
```
ledcSetup()関数はチャネル, PWM周波数, デューティ比を表すbit数を指定する関数である。
上記プログラムではチャネルを0, PWM周波数を12800$[Hz]$,デューティ比を8bit指定(0から255まで)に指定している。チャネルは0から15までを自由に指定できる。
ledcAttachPin()関数は、特定のピンをチャネルに接続する関数である。
上記プログラムではLED_PINをチャネル0に接続している。なおチャネルに複数のピンを接続することもできる。
ledcWrite()関数はチャネルにduty比を指定する。duty比を8bitに指定している場合、0〜255の値が入力できる。チャネルのduty比を指定するので、複数のピンが繋がっていれば同時に変化する。
:::info
**Tips**
ledcWriteはESP32特有の機能である。
通常、ArduinoではanalogWrite()関数が用いられる。
身近で光っているもの(駅のLED電光掲示板など)は人間の目に見えない速さで点滅していることが多い。カメラで撮影すると、チラつくような映像が撮れることがあるのはそのためである。
:::
---