ArduinoデバッグTips


デバッグとは

バグ取り。
プログラムの動作確認。
不具合発見→原因究明→対策→動いた→嬉しい!!

Arduinoのデバッグ環境の特徴

  • デバッガが無い
  • GUIが無い

Web系やWin等のGUI系アプリ、スマホアプリのような、充実したIDE・デバッガ・GUIが無いので、動きが見えずらい!
見える化大事!
ってことで、Tipsを紹介します。

■Tips 初級編

デフォルトでどんなUIがある?

オンボードLED 13番ピン

ほとんどのArduinoには、デフォルトでプログラム制御可能なLEDが付いています。
機種ごとのLEDピン位置の違いを吸収するのに、定数LED_BUILTINを使うのがミソ。

  if(isPushed){
    digitalWrite(LED_BUILTIN, HIGH);
  }else{
    digitalWrite(LED_BUILTIN, LOW);
  }

ON/OFFだけしか見える化できないように思いますが、
点滅間隔(1秒点滅、0.5秒点滅、1秒点いて0.5秒消灯等)、点滅回数などで、デバッグの幅を広げられます。

シリアル出力

PCとUSB接続で動かせるなら、シリアルモニタに動作ログを出力すると動きが見えやすくなります。

  Serial.println(state);

println()は改行有り。print()は改行無しです。
複数の変数を出力する場合、見やすくできます。

  Serial.print("hoge=");
  Serial.print(hoge);
  Serial.print(", huga=");
  Serial.println(huga);
  // → "hoge=0, huga=1"

■Tips 中級編

パーツを追加することにより、UIを追加する。

LEDを追加

複数個のLEDを追加して、

  • 各LEDにフラグの状態を割り当て
  • 2進数で状態IDを表示
  • ナイトライダー、全点滅で特定の処理が動作したことを確認

とかで良く使っています。
割込み処理でLED制御するとコードがすっきりする。

ブザーで音で確認

特定の処理を通過したことがわかる。
LEDだと常に見ておかないとわからないが、音だと他の作業しながら気づけるのが良いです。
音程、長さ、繰り返し、メロディーで成功・失敗通知。
ボタン押したときに音を鳴らすと、ちゃんと押せたかがわかって良いです。
鳴らしまくるとうるさいので注意笑

tone(pin, frequency)で鳴らす。
tone(pin, frequency, duration)でduration(ms)の間鳴らす。
noTone(pin)で止める。

メロディーを鳴らすの音程と周波数の定数がめっちゃ便利。

画面を追加

LCD、OLED、TFT等の画面を追加します。
見える情報量を大幅に増やせます。

個人的にはOLEDが好き。
ArduinoでOLEDディスプレイを試す
GND、VCC、SCL、SDAの4本しか使わないので、あまりピンを占有しないし配線も楽。
ライブラリが大きいので、プログラムサイズが大きくなるのが難点。
UNOがサイズオーバーになってMEGAに変更して動かした思い出があります。

■Tips 上級編

上級ってことでもないのですが、その他のTipsです。

処理速度計測

処理速度の改善は計測(メトリクス)が命!
まずは定量的なデータを取れるようにする。
変更がどれぐらい効果があるか、定量的に評価する。
処理速度が問題になっていないのなら、あまり気にしないのが吉。

  • loop回数で時間を測る

処理が多い場合は、unsigned int countをbyteとかにすると良い。

int tmp = 256; 
unsigned int count = 0;
unsigned long oldTime = 0;

void loop() {
  // オーバーフローして0になった時だけ時間を出力。
  if(0 == count){
    unsigned long nowTime = millis();
    Serial.println(nowTime - oldTime);
    oldTime = nowTime;
  }
  count++;

  // 処理
  //tmp = tmp / 2;   // 185ms
    tmp = tmp >> 1;  // 177ms
  // 純正UNO R3 処理なし 136ms
}
  • 処理時間を測ってボトルネックを探す。

micros()でマイクロ秒も取れます!

int tmp = 256; 
void loop() {
  delay(1000);
  unsigned long startTime = micros();

  // 処理
  // 4μs単位で計測できる。差がわかりにくい場合は、繰り返す。
  for(int i = 0; i < 100; i++){
  //tmp = tmp / 2;  // 76μs
    tmp = tmp >> 1; // 40μs
  }

  unsigned long endTime = micros();
  Serial.println(endTime - startTime);
}

Arduino IDE for Visual Studio

有償版は、ブレイクポイントを設定して、ステップ実行ができる。
IDEもパワーアップしていい感じ!
ここが良くまとまっています。【2017年版】Visual Studio で Arduino 開発

Arduino IDE for Visual Studio

マクロを使用したログ出力

【Arduino】デバッグ用のコードを仕込む
マクロの__func__、__FILE__、__LINE__を使用して関数名、ファイル名、行数を出力!
C言語ではポピュラーな方法。
出力しないようにしたり、出力先を切り替えたりできるメリットもある。

sprintf()で数値フォーマット

stdioをインクルードすると、sprintf()で整形できます。
数値の桁を揃えたいときに便利です。

#include <stdio.h>

// フォーマット付き数値出力
void printVal(int val){
  char buf[16];
  sprintf(buf, "%3d, ", val);
  Serial.print(buf);
}

/*           出力例
右へ傾く   -20,   0, -20,  35, 
左足を前へ  20,  25,  20,   0, 
足を下す    20, -10,  20,  10, 
左へ傾く    20, -35,  20,   0, 
右足を前へ -20,   0, -20, -25, 
足を下す   -20, -10, -20,  10, 
*/

EEPROM

Arduinoにはデフォルトで、EEPROMという電池不要でバックアップ可能なメモリ領域(不揮発メモリ領域)があります。データ量が少なかったり、書き込み回数に制限があるので、頻繁な書き込みは注意が必要です。
数日に1回とか、たまーにしか発生しないバグ発生時に、デバッグ情報を残したり、
キャリブレーションモードで調整値を保存するのに便利です。(いちいちパラメータ変更してコンパイルし直さなくても良い。)
EEPROM への書出しと読込み方法

RTC

リアルタイムクロック。
時刻を取得できるので、長期間の動作確認で何時に発生とか、定期的なデータ収集ができます。
DS3231はeeepromや温度計も付いてて最高です!ロガーとしても使えます。
ArduinoでRTCモジュールを使う
ライブラリのサンプルをよく読んでお使いくださいー。

自分は自動水やり機のタイマー+ロガーで使ってみました。
Remote Watering System(遠隔自動水やりシステム)

エラーが出る場合は、こちらも参考にしてください。
DS3232RTCライブラリのサンプルSetSerialで「error: 'tmElements_t' has not been declared」の対処方法

IDEのエラー表示オン

コンパイルでなぜかエラー、Arduinoへのプログラム書き込みになぜか失敗して原因不明の場合は、IDEのログを多く出力する設定を試してみましょう。
ファイル>環境設定>設定タブで設定できます。
より詳細な情報を表示する:のコンパイルと書き込みにチェック。
コンパイラの警告を「なし」から「全て」。かなり出ます。

自分は通常時も書き込みにチェックしています。

Arduino本体のコードを読む。

どうしても動きがおかしい場合は、Arduino本体のソースを読むと解決するかもしれません。
(ドキュメントを先に読む事をお勧めします。)
純正のUNOなどは枯れていますが、ESP32なんかはまだバグがあるようです。

自分はSPIのSRAMの処理を高速化したくて、必要な処理を直接inoに移植して高速化に成功しました。
ボードごとの違いを吸収する処理が入っていたりして、結構最適化できます。

本体のパスの例:
MAC
/Users/[USERNAME]/Library/Arduino15/packages/arduino/hardware/avr

WIN
C:\Program Files (x86)\Arduino\hardware\arduino\avr

■ハード編

自分はあまり詳しくないので、間違っていたらご指摘お願いします!!

テスター

電圧や電流や抵抗値を測ったりするやつです。必須です。
物理的に配線してなかったり、断線していたりがわかります。
LEDが点くか?とかも確認できます。

オシロスコープ

電気の波形がわかります。
音の波形、立ち上がり、立ち下がりとかノイズとか。
PWMが綺麗に出てるかとか。
ツイッターの先輩方は波形で絵を描きます笑

パスコン

魔法。おまじない。
ノイズを消してくれたり、突発的な電気消費に強くしてくれたり?
あっれー?って時に、とりあえず入れてみるのも効いたりします。

電源

結構ハマります。定格足りているか?を確認すべし。
LED沢山光らせたり、モーターとか動かすときは要注意。
電源分けたり、余裕のある電源に変えてみましょう。
突入電流対策には、大きめのコンデンサが有効かも。

まとめ

これで少しでも皆さんのハマる時間が減って、Arduinoライフが充実すれば幸いです!
他にもこんなんやってるよーとか便利技があれば、コメントなどで教えて頂けると嬉しいです!
ありがとうございました。