Arduino のブートローダを焼いて安価に互換機を増やそう

いろいろな作業を手軽に自動化する目的に Arduino は非常に便利です。

使え方を覚えてしまえば、わずか30分以内にデスクトップ筐体内の温度を自動検知してファンを回したり、人が近づいたときだけ照明を照らしたり、GPS信号から現在地を取得する電子機器を自作できます。

センシングデバイスとしても優秀で、温度、照度、色、臭気、角速度といった馴染みのあるものから、風速、液体、紫外線量、土壌湿度、ガンマ線といった専門的なものまで幅広く用意されています。

センサー1つあたりの価格は数十円から数千円ぐらいであり、安価に必要なデータを収集して、統計分析ソフトで処理しやすい形式で出力できる点に大きな魅力があります。

そして Arduino 自体もわずか 200 円から 300 円程度で互換機を複製できます。




Arduino の正体をきわめて大雑把に説明すると、1つの基盤の上にマイクロコントローラと入出力ポートを載せ、それを専用ソフトウェアと併せてパッケージ化したものです。

その本体と言うか、頭脳とも言えるマイクロコントローラも市販品であり、1つあたり 200 円から 350 円ぐらいで購入できます。

そこで、同種のマイクロコントローラを購入してきて、Arduino のソフトウェアを書き込むと互換機として動作させることができるようになります。


ATMEGA328P-PUコントローラ ATMEGA328マイクロコントローラ DIP-28

詳細な手順は公式のウェブサイト上で説明されています。


From Arduino to a Microcontroller on a Breadboard – Arduino
https://www.arduino.cc/en/Tutorial/ArduinoToBreadboard


これを知っていると、書き込んだスケッチ(Arduinoプログラム)をマイクロコントローラ側に保持しておけるだけでなく、成果物を軽量化、省スペース化することにも役立ちます。

1つあたり 200 円ぐらいなので、用途が決まったらセンサと一緒に基盤に溶接してしまいましょう。


ユニバーサル基板 両面スルーホール ガラスエポキシ材 2.54mmピッチ

私はいつもセンサを購入するときに同数分のマイクロコントローラを一緒に購入しているので、無駄にたくさん持っています。

マイクロコントローラを購入してきたら、公式の解説どおりに回路を組んでブートローダを焼きます。

必要なのは 16MHz の水晶発振子20pF の積層セラミックコンデンサ、そして 10KΩ の抵抗です。

これらも1つあたり 10 円から 30 円ぐらいしか費用が掛かりません。

必要な部品を用意できましたら、実際に部品を接続します。

マイクロコントローラのピンには番号がついており、正しいピンに接続していないと書き込みに失敗しますので気をつけてください。

画像だとわかりにくいですが水晶発振子は D21 と D22 に接続して、それぞれ PB6 と PB7 のピンに繋がっています。

無事に接続できましたら、公式からハードウェア設定ファイルをダウンロードしてきて、指示通りに実行・・・する予定だったのですが、もっと良さそうなものがあったので、そちらを利用します。


GitHub – MCUdude/MiniCore: Arduino hardware package for ATmega8, ATmega48, ATmega88, ATmega168, ATmega328 and ATmega328PB
https://github.com/MCUdude/MiniCore


$ cd /usr/local/share/arduino/hardware/
$ unzip ~/Downloads/breadboard-1-6-x.zip -d .
$ ./tools/avr/bin/avrdude -v

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

$ git clone https://github.com/MCUdude/MiniCore ~/arduino/lib
$ ./tools/avr/bin/avrdude -v -v -v -v -P/dev/ttyACM0 -carduino -b19200 -C /home/buran/arduino/lib/packages/MiniCore-master/avr/avrdude.conf -patmega328 -e -Ulock:w:0x3f:m -Uefuse:w:0xfe:m -Uhfuse:w:0xd6:m -Ulfuse:w:0xe2:m

焼き終わりましたら基盤からマイクロコントローラを引き抜いて、新しく焼いたばかりのコントローラに差し替えます。

私はマイナスドライバで強引に引き抜いていますけれども、ピン先が非常に曲がりやすいので エンジニア 基板コネクタ抜き SS-10 のような専用工具を使用したほうがいいです。

ピン先を何度も曲げていると金属疲労で簡単に破断します。

私の場合は基盤に溶接することを前提にしていること、壊れる前から新しいものを調達してくることから気にしていませんが、再利用などを考えると本当は良くないことには違いがありません。

差し替えてデモ用のスケッチを書き込めれば、ブートローダの書き込みは成功です。

あとはこれに必要なスケッチを保存して、水晶振動子などと一緒に回路につなげば、Arduino ボードを使用しなくても Arduino のスケッチを動かせるようになります。

センサーの値を信用できないとき

Texas Instruments LM35DZは手軽に使えるアナログ温度センサです。

Arduino で使用する場合には抵抗を気にせずに回路に組み込めるので、PCケースの内部温度を計測して自動的に冷却ファンを回したり、サーバ室やビニルハウスの温度を遠隔通知したりするときなどに便利に使えます。

使いどころは無限にあり、価格も安いので、いくつ持っていても困りません。中国某所でもモジュール単位で投げ売りされていたので、お土産に一つ購入してみました。

ここまでは良かったのですが、これを接続してみるとおかしな数値が出力されます。

なにこれ、絶対にありえないだろという数値ですね。

この温度だと錫や鉛の融点を超えてますので、はんだ付けされた部分が無事ではすみません。

そもそも計測範囲外です(詳細は以下のデータシートを参照して下さい)。


LM35DZ Datasheet (PDF) – Texas Instruments
https://www.alldatasheet.com/datasheet-pdf/pdf/520582/TI1/LM35DZ.html





計測結果に話をもどしまして、となりの列にある Sensor2 の出力は、同じ回路に組み込まれた同種のセンサのものです。

こちらは秋葉原で購入しました。

こいつらを2つ一緒に並べて同じ条件下で計測を行った結果が先ほどの出力になります。

より具体的には1秒間に1度の頻度で計測した温度をシリアル通信で出力することを行っています。

const float vcc = 5.0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  int sensorValue0 = analogRead(A0);
  int sensorValue1 = analogRead(A1);
  Serial.println(String(getTemp(sensorValue0)) + "\t" + String(getTemp(sensorValue1)));
  delay(1000);
}

float getTemp(int sensorValue) {
  return sensorValue * vcc / 1023.0 * 100;
}

このスケッチを 30 分間動かして、得られた結果をファイルに書き出しています。

これでどうして、摂氏 454 度みたいなおかしな数値が出てくるのでしょう。その答えは計測中にジャンパワイヤを引っこ抜いたときに判明しました。

センサの信号がただしく伝送されていないときに、マイコンは先の異常値と似たような値を出力することを実験して確認しました。となると怪しいのは基盤か溶接部分です。

そこで、センサが生きていることを祈りながら、モジュールからセンサを分離します。

最初は はんだ吸取り線 を使って丁寧に溶接を剥がしていたのですが、途中から時間が惜しくなってきたので、ニッパーでぶった切る方針に変更しました。

ピンがだいぶ短くなりましたけれども、無事にモジュールからセンサを取り外すことができました。

これを先ほどとおなじ回路に接続し直して再度の計測を行います。

一般的にセンサは過電流では容易に壊れます。

その一方で物理的や衝撃や熱に対してはそこそこ丈夫なものが多いので、まだ使えるような気がするという目論見のもと計測再開です。

※もちろん、プラスとマイナスの向きを間違えると異常発熱して危険なので、そこは気をつけてください。

その結果は以下のとおりです。

出力を見れば一目瞭然ですが、ようやく常識的な数値が計測できました。目論見通り、センサは生きていたわけです。

しかし、同じセンサを使って同一条件で計測しているはずなのに、結構、微妙な誤差がありますね。

厳密な調査で用いるならば、プログラムの方で調整してあげる必要がありそうです。この辺り、まだ探求の余地がありますね。

ちなみにグラフは以下のようにして、直接 PNG 形式で書き出すことができます。覚えておくと便利です。

$ gnuplot -V
gnuplot 5.2 patchlevel 2
$ gnuplot
gnuplot> set datafile separator ","
gnuplot> set grid
gnuplot> set ytics
gnuplot> set xtics
gnuplot> set xdata time
gnuplot> set timefmt "%b %d %Y %H:%M:%S"
gnuplot> set xrange ["Sep 15 2019 14:01:30":"Sep 15 2019 14:21:30"]
gnuplot> set format x "%M:%S"
gnuplot> set xlabel "Time (Min)"
gnuplot> set ylabel "Temperature (°C)"
gnuplot> set terminal png
gnuplot> set output "output.png"
gnuplot> plot "output.txt" using 1:2 title "Sensor 1" w lines, "output.txt" using 1:3 title "Sensor 2" with lines

太陽光パネルの発電を計測する電子工作

家庭用の市販の太陽光パネルは違いがよく分かりません。

よく晴れた日には1日でスマートフォンを満充電にできるなど、それなりに実用性がありそうな話は耳にしますが、発電量が気象条件に依存するだけに実際のところはよく分かりません。

よく分からないものは、自分で調べてみるしかありません。

発電量を調べるのは割と簡単でして Hall effect sensor というものを用意すれば、個人でも測定できます。


30Aレンジ電流センサモジュール ACS712モジュール

このセンサモジュールを制御するための Microcontroller (MCU) と接続用のケーブル、そしてプログラミング用のパソコンさえあれば測定を始められます。

センサモジュールはセンサの計測範囲によって3種類に分類されますので、お使いの太陽光パネルに応じて適切な計測範囲のものをお求めください。

略称 計測範囲 センサ型番
5A ±5A ACS712ELCTR-05B-T
20A ±20A ACS712ELCTR-20A-T
30A ±30A ACS712ELCTR-30A-T

ここでは 5A (ACS712ELCTR-05B-T) を用いるものとして話を進めます。

※ 電子工作では電圧や電流の向きなどを間違えるとコンデンサなどが爆発したり、回路が発火したりすることもありますので、部品を揃える段階から細心の注意を払ってください




MCU もお好きなものを自由に使っていただいて構いません。

「購入するまでもなく自宅にいっぱい転がっているから」という理由から、私は Arduino Uno を使用します。

センサモジュールと MCU の準備ができましたら、やることはたったの3つだけです。

(1)センサモジュール制御用のプログラムを書いて MCU にアップロードします。

つぎに(2)MCU とセンサモジュールをジャンパワイヤを用いて接続します。

最後に(3)データ受信用のプログラムを書いてパソコンを待機させます。

ここまでできましたら、あとは太陽光パネルとセンサモジュール、MCU とパソコンをそれぞれ接続させて実際に計測を行えます。




(1)センサモジュール制御用のプログラムを書く

ここでは開発環境として Arduino Software (IDE) 1.8.10 Linux 64 bits を使用しています。

Arduino を初めて使用される方は 公式ページ から、お使いの環境に適した最新の Arduino Software (IDE) をダウンロードしてインストールしておいてください。

センサモジュールの制御と USB の出力には、最低限、これだけあれば動きます。SD カードへの出力など、必要に応じて適宜改編してください。

const int analogInput = A0;

const double vcc = 5; // 5V
const double quiescentVoltage = 0.5 * vcc;
const double sensitivity = 0.185; // 185mV

void setup() {
  Serial.begin(9600); //baud rate 9600bps
}

void loop() {
  double rawVoltageInput = (double) analogRead(analogInput) / 1023 * 5.0;
  double volts = rawVoltageInput - quiescentVoltage;
  double amps = volts / sensitivity;

  Serial.println(String(volts, 3) + "\t" + String(amps, 3));
  delay(500);
}

これを保存して MCU にアップロードするとセンサモジュールの出力を受け取って、USB経由でパソコンにデータを書き出せるようになります。

何をしているのかを一言でまとめると、センサがアナログの入力を読み取って 10bit の(0 から 1023 までの)数値に変換するので、その数値を理解できる単位に変えて画面に出力するという処理を書いています。

なんだか得体の知れない数値 sensitivity = 0.185 は製造元のデータシートから得られます。

https://www.allegromicro.com/~/media/files/datasheets/acs712-datasheet.ashx [PDF]

ついでにデータシートからは ±5 A で気温 25°C のとき、センサの固有誤差は ±1.5% で精度階級は 1.5 ということが分かります。

なお Arduino の操作や用語については、日本語の参考書もありますので分かりにくかったら参考にしてください。


みんなのArduino入門

(2)MCU とセンサモジュールを接続する

ソフトウェアの準備ができましたら、次はハードウェアの準備です。

センサモジュールには VCC OUT GND という端子があります。それぞれ、電源端子、出力端子、グランド端子という意味があります。

検索すると大学の講義資料などで詳しく解説されていますので、興味がありましたら調べてみて下さい。

計測するために必要なことは、それぞれの端子を識別して、正しく接続することです。

具体的には以下のようになります。

プログラムの方で analogInput に A0 を指定して読み込んでいるので A0 に繋いでます。

接続に使っているのはジャンパワイヤという部品です。電子工作の基本部品の一つで、よく使われるので通常はまとめ買いされます。


ELEGOO 多色デュポンワイヤ 120pcs

(3)データ受信用のプログラムを書く

ソフトウェアとハードウェアの準備ができましたら、あとは実際に計測をおこなうだけです。

ただし、現状のままでは MCU はセンサモジュールの出力を無限に垂れ流すだけなので、どこかに(SDカードなどに)出力を書き出すか、USB から出力を受け取らないとデータを利用することができません。

SDカードソケットモジュールなどを利用すると外部メディアも利用できますが、そのモジュールを私が持っていないので USB で接続したパソコンに出力することにします。

出力されたデータを受け取るプログラムは Python でも Ruby でも、お好きな言語で実装していただいて問題ありません。

今回は JavaScript (node.js) を使って手抜きします。

この場合は適当なプロジェクト(以下の例では currentMeasurer)を作成して、serialport をインポートする準備をお願いします。

$ mkdir currentMeasurer && cd currentMeasurer
$ npm init
$ npm i serialport
$ touch measurer.js
$ vim measurer.js # ファイル編集

編集するファイルの中身は以下のようになります。標準出力 (stdout) している部分は直接ファイルに書き出してしまう形式に書き換えてしまっても構いません。

const SerialPort = require('serialport');
const Readline = require('@serialport/parser-readline');
const port = new SerialPort('/dev/ttyACM0', {baudRate: 9600,});
const parser = port.pipe(new Readline());

parser.on('data', line => console.log(`${line}`));

また、上の3行目で /dev/ttyACM0 と決め打ちしているところがありますが、これはシリアルポートなので、お使いの環境ではこのまま実行できない可能性があります。

以下の方法で MCU が使用しているシリアルポートを特定して、該当部分を必要に応じて書き換えてください。

Linux

$ ls /dev/tty*

ターミナルから上のコマンドを打つと ttyUSB もしくは ttyACM で始まるシリアルポートが見つかります

Mac

$ ls /dev/tty*

ターミナルから上のコマンドを打つと tty.usbmodem もしくは tty.usbserial で始まるシリアルポートが見つかります

Windows
デバイスマネージャーを立ち上げて ポート(COMとLPT という項目をクリックすると表示されます

準備ができましたら、USB ポートに MCU を接続した状態でプログラムを実行してください。

$ node measurer.js > log.txt 

計測

この状態のまま、センサモジュールと太陽光パネルを接続すると計測が始まります。

私が購入した太陽光パネルの出力は 2.1mm DC プラグになっていましたので、それに合うアリゲータクリップスを用意しました。

このアリゲータクリップスを介してセンサモジュールと太陽光パネルを接続します。


uxcell DCパワージャックアダプター 2.1mm x 5.5 mm

そしてセンサモジュールから得られた出力を MCU 内でボルトとアンペアに変換して USB ケーブルを通して PC に出力します。

出力された数値を PC で受け取ってテキストファイルに記録していきます。

うまく行けば log.txt というファイルの中にボルトとアンペアの数値が並んでいくはずです。

プログラム上は止めないと無限にループするようになっているので、計測を終えるときに停止させてください。

これで実際に出力された数値が出せればよかったのですが、いつまで経っても晴天にならないうちに某国に出張して、また自宅に帰れない生活が始まってしまったので、一度、ここで区切ります。