ソロでたのしむ

キャンプ、電子工作、DIY、乗り物などの趣味を紹介

簡単な電子回路を使うと、もっと便利にできる。「日常で使えるArduino作品」別冊

以前の記事で、車やバイクとキャンプにおけるArduino実用例をいくつか紹介しました。

www.solocamptouring.com

 

そこで紹介した作品でも実践していますが、Arduinoを実用するにあたり電子部品を使ってArduinoに適したデジタル信号をつくることがあります。

今回は、実際に電子部品を使った例について紹介いたします。

記事内の回路図はFritzingで作りました。


デジタルについて

まず簡単にデジタル回路について紹介します。

デジタル信号の基本構成は、

  •  1  か  0

です。

同じ状態に対して、他にも使い方(呼び方)があります。

  •  1   か   0
  • ON   か OFF
  • High か Low
  • 5V   か  0V

5Vで動かす電子回路の場合、最後の「5Vか0V」を回路内で作れば、その電圧を電子回路のデジタル信号として使えます。
5Vを使うArduinoでは、デジタルピンにかかっている電圧が「5Vか0V」を読み取って、「HIGHかLOW」と読み替えて制御用の情報にします。

HIGHとLOWの境目は、Arduinoの種類によっても違いますが、ここでは中央値の2.5V近辺としておきます。

スイッチ操作をデジタル信号に変える

スイッチのON/OFF状態を正しくArduinoに認識させるために抵抗を使います。

まず下の抵抗を使わない回路で考えてみます。

f:id:solocamptouring:20180304194503j:plain

スイッチS1がつながると、ArduinoのD7ピンには5Vがかかります。その時ArduinoはD7ピンが「HIGH」だと認識します。

スイッチS1がつながっていない時のD7ピンが問題です。「5Vかかっていないのだから0V」だと勘違いしそうですが、D7ピンはどこにもつながっていないので、「電圧がわからない状態」が正解です。

スイッチS1がつながっていない時にArduinoからD7のデジタル状態を読もうとしても、場合によってHIGHだったりLOWだったりして安定しません。

プルダウン抵抗とプルアップ抵抗

どこにもつながっていないArduinoのデジタルピンは、HIGHでもLOWでもないことを紹介しました。

スイッチの状態を正しくArduinoに教えるためには、積極的に5Vと0Vを作ることが必要です。

下の回路で考えてみます。

f:id:solocamptouring:20180304195045j:plain

スイッチS1がつながっていると、ArduinoのD7ピンには5Vがかかります。この時、抵抗R1には5Vがかかっていますが、10KΩなど高い抵抗値を設定しておけば、ほとんど電流は流れません。

スイッチS1がつながっていない時、ArduinoのD7ピンは抵抗R1を中継してグランドに接続されています。電子回路では電流はほとんど流れないので抵抗R1での電圧変化はなく、D7ピンは約0Vの状態に保たれます。

この抵抗R1をプルダウン抵抗と呼びます。

 

次に、プルダウン抵抗の回路からスイッチと抵抗のつなぎ方を変えてみます。

f:id:solocamptouring:20180304195246j:plain

スイッチS1がつながっている時、ArduinoのD7ピンはグランドに接続されてるので0Vです。

スイッチS1がつながっていない時、ArduinoのD7ピンは抵抗R1を中継して5Vに接続されており、プルダウン回路と同様に抵抗には電流がほとんど流れないので、D7ピンは約5Vになります。

この抵抗R1をプルアップ抵抗と呼びます。

Arduino内部のプルアップ抵抗を使う

プルダウン抵抗、プルアップ抵抗について紹介しましたが、実はArduinoの内部にプルアップ抵抗が準備されており、少しスケッチを変えるだけで簡単に使うことができます。
たとえば、これまで紹介してきた回路でデジタルピン7の状態(HIGH,LOW)を調べた結果を”sw1Status”に代入する場合、スケッチ(抜粋)は

void setup() {
pinMode(7, INPUT);
}
void loop(){
int sw1Status = digitalRead(7);
}

となります。

これが、Arduino内部のプルアップ抵抗を使う場合は、

void setup() {
pinMode(7, INPUT_PULLUP);
}
void loop(){
int sw1Status = digitalRead(7);
}

として、「7番ピンはインプットで使うけど、ついでに内部のプルアップ抵抗も使います」と宣言するだけです。

ただし、そのピンに何も接続していない状態では、常に5Vがかかっている事になるので、隣りのピンなどとショートしないように注意しないといけません。

12V電圧をデジタル信号に変える

一般的に、車やバイクのブレーキ灯、ウインカー、リバース灯から並列で得られる電圧は約12~14Vです。

Arduinoで使える「HIGHかLOW」という信号にするために、下の回路で変換します。

12Vをデジタル信号(5V)に変える_回路図

 

スイッチがつながっている時、ArduinoのD7ピンの電圧は約4.5V(5V×10÷11)になっています。

スイッチがつながっていない時、ArduinoのD7ピンはプルダウン抵抗R1を中継してグランドに接続されてるので、D7ピンは約0Vになります。


可変抵抗をセレクタとして使う

最後に、Arduinoのアナログピンで、可変抵抗(ボリューム)をセレクタとして使う方法を紹介します。

可変抵抗をセレクタとして使う

可変抵抗に5Vを印加して、可変抵抗で変えた電圧を、Arduinoのアナログピンに接続します。

電圧とArduinoの読み取り値は、下記の条件で比例しています。

  • 電圧; 0〜5V
  • Arduinoの読み取り値; 0〜1023(整数)

セレクターとして使う場合は、1023を選択肢数で割って、それぞれの範囲での条件式を作ります。

下のスケッチは、以前に8x8カラーLEDボードを6種類で光らせた時に紹介した記事からの抜粋です。

void loop()
{
val = analogRead(analogPin);

if (val < 150) {
gCurrentPatternNumber = 0;
} else if (val < 300){
gCurrentPatternNumber = 1;
} else if (val < 450){
gCurrentPatternNumber = 2;
} else if (val < 600){
gCurrentPatternNumber = 3;
} else if (val < 750){
gCurrentPatternNumber = 4;
} else if (val < 900){
gCurrentPatternNumber = 5;
} else {
gCurrentPatternNumber = 6; 
}
}

測定した電圧に応じて、パターン番号を0~6まで変えています。

パターン「0」では何も光らせていないので、実際は6種類の光らせ方をコントロールしています。

ボリュームは、変化を確認しながらワンモーションで狙いのパターンに変更できるので、車のような手元に視線を集中できない環境化ではプッシュ式の切り替えスイッチよりも操作性がいいです。

www.solocamptouring.com

以上が、Arduinoを使った作品で、私がよく使う回路です。

DCモーターなど電力消費が多いものを動かす場合は、トランジスタやリレーをを使うこともありますが、小電流の作品であれば今回紹介した回路の応用で、ほとんど事足ります。

日常で使えるArduino 作品集。使い方とできることを回路やスケッチ付きで紹介します

Arduino の実用的な使用例と作品紹介〜車とバイク

Arduinoで遊び始めてから、その面白さにはまってしまい、次々に作品をつくってきました。

なるべく普段使えるものを作るようにしてきたので、ほとんどのものは今なお現役で動かしています。

その作品たちを簡単に紹介したいと思いますが、思いのほか作品が多くて、少し長めの記事になってしまいました。

既につくりたいものが決まっている場合は、下の目次をクリックして、その項に直行していただくと、目的の情報を素早く発見できると思います。

回路図やスケッチ(プログラム)は、制作記事リンクのクリック先で確認していただけます。

はじめに

Arduinoとサンプルスケッチ(プログラム)を使い、ブレッドボード上でLEDやモーターなどを作動させるだけでも楽しいのですが、ある程度扱えるようになってくると実用的なものに応用したい!との想いが強くなってきます。

ここでは、まずはサンプルスケッチでの基本的な動かし方、そして趣味の世界が多いですが、実用している作品例を紹介して、「Arduino を日常生活に活かしたい!」と考えている方に、少しでも参考にして頂ければいいなと思います。

冒頭の繰り返しになりますが、回路図やスケッチ(プログラム)は、それぞれの製作記事内で紹介しています。

参考にしていただけそうなものがあれば、記事へのリンクから、制作記事に直接移動できます。

なお、記事内の回路図作成にはFritzingを使いました。

ArduinoでLEDを光らせる(Lチカ)

 サンプルスケッチでLEDを光らせてみる

Arduino IDEのサンプルスケッチ(ファイル→スケッチ例→01.Basics→Blink)を使いますが、どうせならArduinoのオンボードLEDではなく外付けのLEDを光らせてみます。

LEDの配線

Arduino Lチカ 回路のつなぎかた

上の絵はArduino UNOで、右側の番号がふられているピンがデジタルピンです。光らせるLEDはどのデジタルピンにつないでもいいのですが、今回は7番を使う場合で進めます。

LEDをArduinoに直結すると、LEDに5V電圧が直接かかってしまうので、抵抗を直列でつないでおきます。

5V電圧において一般的な20mAのLEDであれば抵抗は150オーム、不安であれば少し大きめの抵抗値のものでも光ります。

LEDのサンプルスケッチに手を加える 

LEDを7番のデジタルピンにつないでいるので、サンプルスケッチの中に3か所登場する「LED_BUILTIN」を「7」に書き換えて使います。

無事に点滅したら、次は点滅周期を変えてarduinoにスケッチを送りなおして光らせてみるなどのプチ改造を繰り返すと、スケッチを作ってから実際に動かすという一連の操作に慣れてきます。

LEDの実用的な使用例

多数の3色LEDをコントロールすることが簡単に実現できて便利なWS2812Bモジュールを使って、いくつかイルミネーション作品をつくりました。

その1;好きな色で光らせてみる

64個のカラーLEDを使って、いろいろな光り方を選択できるようにして車に装着しました。

実用的とは言えませんが、装着した車内の雰囲気は盛り上げてくれます。

www.solocamptouring.com 

その2;ナイトライダー

ナイトライダーのボイスインジケータのように光るサウンドインジケータも作ってみました。

ドラマでは車内のステアリングホイール前に設置されていましたが、私は天井のコンソールに付けて楽しんでいます。

www.solocamptouring.com

その3;キャンプのテント周りのイルミネーション

キャンプでテントまわりの安全確保をしたいと思い、好みの光り方で、常夜灯を作ってみました。

省電力なのでモバイルバッテリーで一晩中使えて、遠くから自分のテントを発見しやすくなる効果もあり、たいへん便利です。

www.solocamptouring.com

その4;お部屋でキャンプファイヤー気分

家でもキャンプファイヤーの雰囲気が出せたら楽しいに違いない!と思い、フロアーランプにファイヤー フレーム パターンを仕込んでみました。

自分でもびっくりするくらい本物感がでていて、毎晩見入っています。

www.solocamptouring.com

その5;夜釣りで使う集魚灯

色や光り方を自由に変えられる点を活かして、魚の方から寄ってきてくれそうな集魚灯を、自作してみたくなりました。

これで爆釣できるか?!

www.solocamptouring.com

Arduinoでステップモーターを動かす 

 ステップモーターは、安価で入手しやすい28BYJ-48とドライバー基板のセットを使います。

安価で入手しやすい28BYJ-48とドライバー基板のセットを使いArduinoで動かす

ステップモーターの使い方

28BYJ-48はユニポーラのステップモーターのため、Arduino IDEのバイポーラモーター用のサンプルスケッチを使う場合は、工夫が必要になります。

そんな苦労をするくらいなら、サンプルスケッチを使わずに動かしてみます。

ステップモーターをシンプルに説明すると、内部の電磁石に順番に電気を流すことで、永久磁石がついている出力軸が回転します。

順番に電気を流す命令を送るのが、ドライバーのIN1~4に接続する4本の信号線です。

この4本の信号線を横に並べて,HIGH(5V)を1、LOW(0V)を0として、

1,0,0,0

1,1,0,0

0,1,0,0

0,1,1,0

0,0,1,0

0,0,1,1

0,0,0,1

1,0,0,1

 の8パターンの信号を順番に、そしてループして出し続ければ、ステップモーターの出力軸が回ります。

4本の信号線をArduinoのデジタルピン4~7につないでモーターを回すだけのスケッチを紹介します。

void setup()

{

  pinMode(4, OUTPUT);  

  pinMode(5, OUTPUT);  

  pinMode(6, OUTPUT);  

  pinMode(7, OUTPUT);  



  int speedL = 10;

}



void loop()

{

  digitalWrite(4, 1);    

  digitalWrite(5, 0);

  digitalWrite(6, 0);

  digitalWrite(7, 0);

  delay(speedL); 



  digitalWrite(4, 1);    

  digitalWrite(5, 1);

  digitalWrite(6, 0);

  digitalWrite(7, 0);

  delay(speedL); 



  digitalWrite(4, 0);    

  digitalWrite(5, 1);

  digitalWrite(6, 0);

  digitalWrite(7, 0);

  delay(speedL); 



  digitalWrite(4, 0);    

  digitalWrite(5, 1);

  digitalWrite(6, 1);

  digitalWrite(7, 0);

  delay(speedL); 



  digitalWrite(4, 0);    

  digitalWrite(5, 0);

  digitalWrite(6, 1);

  digitalWrite(7, 0);

  delay(speedL); 



  digitalWrite(4, 0);    

  digitalWrite(5, 0);

  digitalWrite(6, 1);

  digitalWrite(7, 1);

  delay(speedL); 



  digitalWrite(4, 0);    

  digitalWrite(5, 0);

  digitalWrite(6, 0);

  digitalWrite(7, 1);

  delay(speedL); 



  digitalWrite(4, 1);    

  digitalWrite(5, 0);

  digitalWrite(6, 0);

  digitalWrite(7, 1);

  delay(speedL); 

}

ステップモーターを動かすスケッチは様々な書き方(種類)があります。この次に紹介する実用作品の制作記事では、少し違った書き方になっています。

ここでは配線について詳しく紹介しませんが、一点おすすめしておきたい事があります。

モータードライバーの電源は、Arduinoの5V出力から取るのではなく、外部電源を使うようにしておくと、Arduinoの許容電流を超えて動きがおかしくなったり、故障したりする可能性を減らせます。

ステップモーターの実用的な使用例

その1;車の電動開閉バックモニター

12V用のステップモーター28BYJ-48を使って、リバースギアに連動する電動開閉バックモニターを作成して、車に装着しました。

簡単に速度制御ができる上に静かなので、滑らかに動く作品を目指す場合は、ステップモーターがおすすめです。

www.solocamptouring.com

 

youtu.be

その2;車の電動開閉テーブル

車用としては他にも、普段は格納しておきたい助手席用のテーブルを、電動開閉式で自作してみました。

自重の影響を受けない水平方向の動きなので、5V用のステップモーター28BYJ-48を使っています。

これもステップモーターのおかげで静かに動くので、それだけで高級感がある動きになります。

www.solocamptouring.com

その3;キャンプ用の電動ロティサリー(回転焼き器)

シンプルに回すだけですが、自在に回転数を変えられるステップモーターの利点を生かして、ロティサリーを作ってみました。

ソロキャンプで食べきれる具材の大きさは限られているので、持って行きやすいコンパクトなロティサリーを、モバイルバッテリーで動かしています。

食材が自動でクルクル回りながら焼かれているのを見ているだけで、自作した達成感に満たされます。

www.solocamptouring.com

Arduinoでサーボモーターを動かす

f:id:solocamptouring:20181007050128j:plain

ラジコンでよく使われる、DCサーボモーターを動かしてみます。

写真の2種類のサーボモーターは、どちらも3本の電線がついていて、その配線配列は同じです。

  • オレンジ色 ; PWM信号
  • 赤色    ; プラス電源
  • 茶色    ; マイナス電源(GND)

サーボモーターは電力を使うので、Arduinoで使う電源の電流量が少ない場合は、サーボモーターは別電源にしてマイナス電源をArduinoのGNDと繋ぎます。

PWM(Pulse width modulation、パルス幅変調)信号は、Arduinoのスケッチ(プログラム)で作ることもできますが、わざわざ複雑なスケッチを作るよりも、Arduino IDEに準備されているライブラリやスケッチを使う方が楽です。

スケッチ例でサーボモーターを動かす

Arduino IDEの、

ファイル → スケッチ例 → Servo → Knob

を選択します。

サーボモーター用のライブラリが使われているので、スケッチの最初の部分に、

#include <Servo.h>

が記載されています。

サンプルスケッチの配線は、

  • ポテンショメーター(ボリューム)は、A0
  • サーボモーターへのPWM信号は、D9

に接続するものになっています。

短いスケッチですが、ボリュームから得られる0~5Vの電圧に応じて、サーボモーターの出力軸角度が変わります。

後ほど紹介する実用的な使用例の作品も、ピン番号は違いますが、配線方法と動かし方は同じです。

ライブラリでサーボモーターを動かす

速度も制御したい場合は、GitHubのVarSpeedServoライブラリが便利です。

Arduino IDEに準備されている<Servo.h>ライブラリは、

  myservo.write(角度);  

で、フルスピードで目標角度まで動くものですが、<VarSpeedServo.h>ライブラリは、

  myservo1.write(角度, 速度, true);

で、動く速度を変えつつ、"true"で目標角度になるまで次のコマンドに移行しないように制限をかけることもできます。

サーボモーターの実用的な使用例:半自動飯盒炊飯器

キャンプ用のガスバーナー(コンロ)の火力をサーボモーターで制御して、自動炊飯器を作りました。

記事内で配線図やスケッチも紹介しているので、サーボモーターの具体的な配線や制御方法の参考にしてみてください。

www.solocamptouring.com

 

ArduinoでLCDに表示する

サンプルスケッチでLCDに表示する(hello world)

液晶ディスプレイ(Liquid Crystal Display、LCD)を初めて試してみる場合、「hello world」が有名です。

 Arduino IDEの、たいへん短いサンプルスケッチ(ファイル→スケッチ例→LiquidCrystal→HelloWorld)で動かすだけですが、LCDとの配線に少し手間がかかります。

f:id:solocamptouring:20171218192148j:plain

ブレッドボード上の配線(サンプルスケッチのピン選択とは異なります)

 

LCDの実用的な使用例

表示したい文字数に応じて、これまでに2種類の大きさのLCDを使ってみました。それぞれの使用例を、制作記事とともに紹介します。

f:id:solocamptouring:20171218161817j:plain

上が16x2文字、下が20x4文字のLCD

16x2文字LCDの実用例

GPSモジュールから、位置・高度・速度情報をArduinoに取り込んで、16x2文字のLCDに表示する作品を、車とバイクに装着しました。

f:id:solocamptouring:20180211222201j:plain

GPSモジュール

GPSモジュールは、緯度経度だけ扱うのであれば比較的に簡単ですが、高度などの計算に時間がかかる情報を取り出す場合は「その情報があるならば読み込む」ような命令文をスケッチに入れる工夫が必要です。

まずは16x2文字LCDと組み合わせた試作品で、試行錯誤しながらスケッチを修正して、GPSモジュールの使い方について勉強しました。

<車に装着した例>

www.solocamptouring.com

 

<バイクに装着した例>

車に取り付けた作品がたいへん便利に使えることがわかったので、コンパクトで防水性を考慮した作品も作って、オフロードバイクに取り付けました。

www.solocamptouring.com

 

20x4文字LCDの実用例:オーバーヘッド マルチモニター

 現在も車に装着しているLCDです。

一個のArduinoで、複数のセンサーからの情報を処理してみることを試してみたくなり、情報表示可能量を増やすために、20x4文字LCDを使いました。

現状では、GPSモジュール、加速度センサーモジュール、温湿度センサーから、8種類の情報を表示しています。

www.solocamptouring.com


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

 

Arduinoで傾きや加速度を測る

f:id:solocamptouring:20180818065644j:plain

加速度センサーは、加速度や軸加速度、傾きを計測できるセンサーで、自律してバランスをとるロボットやドローンを自作する場合などに使われています。

実用的な使用例は、先述の「20x4文字LCDの使用例」の記事内に記載されているので、ここでは少し趣向を変えて、お試しで使ってみた記事を紹介しておきます。

www.solocamptouring.com

加速度センサーの実用的な使用例:クライノメーター(傾斜計)

安く入手できるセンサーなので、ドローンのような高度な作品でなくても実用してみたいと思い、簡易クライノメーター(傾斜計)のセンサーとして使って、先述の20x4文字LCDに車の傾きを表示しています。

簡易クライノメーター(傾斜計)を自作して、車の傾きを表示

Arduinoで距離を測る

Arduinoで距離を測る

測距センサーは、「距離を測る」というシンプルなものですが、近い将来にもっと様々な物が自動化されていくのに欠かせないセンサーです。

価格に応じて、測定時間、範囲、距離や精度が良くなりますが、趣味のArduino作品、おもちゃ、お掃除ロボットでは、数百円程度までのものを使うのが、一般的です。

手軽に入手できるものの中でもよく使われている、超音波センサーモジュール赤外線センサーモジュールについて、別の記事で性能を比較しながらまとめてみました。

www.solocamptouring.com

 

測距センサーの実用的な使用例

1/fゆらぎ風のUSB扇風機

測距センサーの弱点でもある、衣服などの柔らかい対象物の測定ではバラツキ幅が大きくなる特徴を逆に活かして、1/fゆらぎ風を起こすUSB扇風機を作ってみました。

仕事中に使っていますが、高原のような風で、眠気に襲われることもある!ほどの気持ち良さです。

www.solocamptouring.com

 

トイラジコンを自動走行させてみる

扱いやすい超音波モジュールとArduinoをトイラジコンと接続して、自動走行に挑戦しています。実用的ではありませんが、動きを見ていると癒されるようなものを目指しています。

まだ粗削りな動きしかできていないので、随時更新していきたいと思います。

www.solocamptouring.com

 

(おまけ) 車でArduinoを使う際の電源について

 最後に、車でArduino を使う場合の電源についての紹介です。

車のアクセサー電源(普通はおおよそ12~14V)でも、ArduinoUNOやNanoは動きますが、このような高い電圧をかけ続けるとArduinoが熱を持ちます。

できることなら5~6V付近(種類によっては3.3V)で使用したいので、電圧安定化もかねて12Vから6Vへの電圧コンバーターを使い、上流の+側(12V側)にはヒューズを入れて、Arduinoやモジュール類の電源として使っています。

自作した電子回路を車で使うための安定化電源

車でArduino作品を動かすための電源として、5年以上使っていますが、駆動系と表示系の作品ともに、トラブルなく使えています。

GPS計測で正確なスピードメーターをバイク用で自作~ArduinoとGPSモジュール

バイクに付ける正確なデジタルスピードメーターを自作

最近の多くのバイクは、デジタルスピードメーターが当たり前のようについていますが、私が持っているバイクにはアナログのスピードメーターしか付いていません。

最初のバイクのメーターに追いつきたい!と思い、正確なデジタルスピードメーターを自作してみました。

目次

正確な速度をGPSで計測する

車もバイクも、タイヤの回転数を速度に換算して、メーターに表示しています。このため、タイヤの種類や状態によって誤差が生じます。

今回デジタルスピードメーターを自作するにあたり、どうせなら正確なものを作りたいと思いました。

ちょうど同時期に、車用でGPSを使ったデジタルディスプレイを作っていたので、アイデアを転用することにします。

バイク用GPSスピードメーターをArduinoとGPSモジュールで作成

スピードメーターにGPSを使うメリット

GPSを使って位置情報を得るために、GPSモジュールを使います。上の写真の茶色の基板と長方形のアンテナがセットで数千円で入手できます。

衛星受信状態やモジュールの種類にもよりますが、だいたい1秒に1回は各種の最新情報を取り出すことができます。取り出せる情報は、

  • 緯度経度
  • 速度
  • 時刻
  • 進行方向
  • 高度

などで、全てリアルタイムかつ正確な情報です。

速度だけでなく、進行方向などバイクでも役に立つ情報を入手でき、また時刻も補正不要となれば、これを使わない手はありせん。

スピードメーターにGPSを使うデメリット

デメリットもあるので、あげておきます。

車検があるバイクの場合、GPSメーターだけでは車検を受けられません。車検場のローラー上では車両の動きがないので、デジタルメーターの速度は「0Km/h」のままです。

またトンネル内や地下駐車場などのGPSを補足できない場所では、GPSメーターは作動しません。

このため、ノーマルメーターの置き換えではなく、あくまで補助的な役割の追加メーターとして使います。

デジタルメーターの自作 

スピードメーターをバイク用で自作~ArduinoとGPSモジュール

緯度経度を数字で表示しても、走行中には活用できません。

そこで、

  • 速度
  • 時刻
  • 進行方向
  • 高度

を表示します。

Arduino初心者(の私)でもできた作り方の詳細は、別の記事で紹介しています。回路やスケッチ(プログラム)は、車用に作ったものと全く同じです。

www.solocamptouring.com

車とバイク用で違う点としては、電源を5.5VのUSB電源にしておいて、バイクから電源がとれない場合でもモバイルバッテリーを使用できるようにしています。

なるべくコンパクトなものにしたいため、回路とモニターやアンテナがギリギリ収まるような大きさのプラスチック 製のプロジェクトボックスに納めました。

f:id:solocamptouring:20180527174834j:plain

オフロードバイクに取り付けた状態です。車用のものと違い、防水対策も手厚く施しています。

f:id:solocamptouring:20180204120923j:plain

使ってみた感想

背面照明付きのLCDディスプレイを使っていますが、直射日光が当たると見づらいため、バイザーを付けるなどの対策をしようと考えています。

一年以上にわたりオフロードバイクにつけてダートも走っていますが、振動による故障もなく、しっかり働いています。

オーバーヘッドコンソール付けGPSディスプレイ完成(Arduinoでコクピット⑦)

オーバーヘッドコンソール付けGPSディスプレイ完成

Arduinoを使って自作したGPS時計や方位計のディスプレイですが、車のオーバーヘッドコンソールにお試しで装着(シリーズ記事⑥)してから一週間たちました。

www.solocamptouring.com

 問題なく作動しており、おおむね満足していますが、改善したい点がでてきました。

少変更を入れつつ、最終的に完成させます。

最終改善ポイント

「S」が「5」に見える対策

GPSモジュールが位置計算に使用している人工衛星の数をLCDの中央下に表示しています。

数字の後ろに衛星(サテライト)を意味する「Sats」を表示していますが、パッと見たときに「S」が数字の「5」に見えてしまいます。

f:id:solocamptouring:20180203095841j:plain

写真は、衛星7機を使って位置計算している画面ですが、75っぽく見えてしまいます。

「S」を小文字に変更して「sats」と表示することで、見やすくします。

 

停止していると方位角度におかしな数値が出ることがある

GPSで得られる進行方向データを方位として代用しています。

しかし進行方向はGPSモジュールの位置(=車)を動かさないと計算できないため、車が停止している状態だと、稀におかしな数値を表示します。

進行方向を計算できていない時は方位角度を表示せず、「ACT. REQUIRED」と表示するようにスケッチ(プログラム)を変更します。

f:id:solocamptouring:20180203125501j:plain

最新のスケッチ全文は、最後に載せておきます。

 

オーバーヘッドコンソールへの取り付け

車に一週間装着してみて、ビビリ音もなく作動も安定しているので、透明パネルのままで手を加えていなかったディスプレイ取り付け面を仕上げます。

LCD表示部でない部位は、個人的に好きな黒カーボン柄のカッティングシートでブラックアウトします。

車のオーバーヘッドコンソールに取付けて、動作確認しました。 

自作オーバーヘッドコンソールの完成(Arduinoで表示する20x4LCDディスプレイ付き)


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

最新のスケッチ(プログラム)

GPSモジュールは、tinygpsplusライブラリ、

温湿度センサーは、GitHub - adafruit/ DHT11用ライブラリを使っています。

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
#include<Wire.h>
#include <DHT.h>
#define DHTPIN 13
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal lcd( 12, 11, 8, 7, 6, 5 );
byte upword[8] = {
  B00100,
  B01110,
  B11111,
  B00000,
  B00100,
  B01110,
  B11111,
};
byte downword[8] = {
  B11111,
  B01110,
  B00100,
  B00000,
  B11111,
  B01110,
  B00100,
};
byte righthand[8] = {
  B01000,
  B01100,
  B01110,
  B01111,
  B01110,
  B01100,
  B01000,
};
byte lefthand[8] = {
  B00010,
  B00110,
  B01110,
  B11110,
  B01110,
  B00110,
  B00010,
};
byte centerpoint[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};
TinyGPSPlus gps;
SoftwareSerial gpsSerial(9, 10); // RX, TX (TX not used)
const int serialTime = 200; // enough time to read all NMEA sentences once
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

void setup()
{
   Wire.begin();
  Wire.beginTransmission(MPU_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);
  lcd.createChar(1, upword);
  lcd.createChar(2, downword);
  lcd.createChar(3, righthand);
  lcd.createChar(4, lefthand);
  lcd.createChar(5, centerpoint);
  lcd.begin(20,4);
  lcd.clear();  
  gpsSerial.begin(9600);
  lcd.setCursor(0,0);
  lcd.print("  CAPTURING         ");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("  SATELLITES        ");
  lcd.setCursor(0,2);
  lcd.print("        Powered by  ");
  lcd.setCursor(0,3);
  lcd.print("           Arduino  ");
  delay(3000);
  lcd.clear(); 
  dht.begin();
  
} // end setup


void loop()
{
int start = millis(); // reference for starting timestamp
int now = millis();
do {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
now = millis();
} while ((now - start) < serialTime); // breaks out of read gps serial

  if (gps.altitude.isUpdated())
  {
    int h;
    h = (gps.time.hour()) + 9;
    if( 24 <= h ) {
    h = h - 24;
    }
       if (h < 10) {
       lcd.setCursor(0,0);
       lcd.print(" ");
       lcd.setCursor(1,0);
       lcd.print(h);
       } else  {
       lcd.setCursor(0,0);
       lcd.print(h);
       }

    lcd.setCursor(2,0);
    lcd.print(":");

    int m;
    m = gps.time.minute();
       if (m < 10) {
       lcd.setCursor(3,0);
       lcd.print("0");
       lcd.setCursor(4,0);
       lcd.print(m);
       } else {
       lcd.setCursor(3,0);
       lcd.print(m);
       }
       
   int sec;
    sec = gps.time.second();
       if (sec < 10) {
       lcd.setCursor(0,1);
       lcd.print("     ");
       } else  if (sec < 20){
       lcd.setCursor(0,1);
       lcd.write(5);
       } else  if (sec < 30){
       lcd.setCursor(1,1);
       lcd.write(5);
       } else  if (sec < 40){
       lcd.setCursor(2,1);
       lcd.write(5);      
       } else  if (sec < 50){
       lcd.setCursor(3,1);
       lcd.write(5);
       } else {
       lcd.setCursor(4,1);
       lcd.write(5);         
       }

  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  //starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

    lcd.setCursor(16,2);  
    lcd.write(5);

     if (AcX < -5000) {
       lcd.setCursor(16,1);
       lcd.write(1);
       } else {
       lcd.setCursor(16,1);
       lcd.print(" ");
       }

     if (AcX > 5000) {
       lcd.setCursor(16,3);
       lcd.write(2);
       } else {
       lcd.setCursor(16,3);
       lcd.print(" ");
       }

     if (AcY < -5000) {
       lcd.setCursor(14,2);
       lcd.write(4);
       lcd.write(4);
       } else if (AcY < -2500) {
       lcd.setCursor(14,2);
       lcd.print(" ");
       lcd.write(4);
       } else  {
       lcd.setCursor(14,2);
       lcd.print("  ");
       }

     if (AcY > 5000) {
       lcd.setCursor(17,2);
       lcd.write(3);
       lcd.write(3);
       } else if (AcY > 2500) {
       lcd.setCursor(17,2);
       lcd.write (3);
       lcd.print(" ");
       } else  {
       lcd.setCursor(17,2);
       lcd.print("  ");
       }
  }
  
 if (gps.altitude.isUpdated())
  {
    lcd.setCursor(6,1);  
    lcd.print("Alt");
     int koudo;
     koudo = (int)(gps.altitude.meters()); 
     if (koudo == 0) {
     lcd.setCursor(9,1);
     lcd.print("----"); 
     } else if (koudo < 10) {
     lcd.setCursor(9,1);
     lcd.print("   "); 
     lcd.setCursor(12,1);
     lcd.print(koudo); 
     } else if (koudo < 100) {
     lcd.setCursor(9,1);
     lcd.print("  "); 
     lcd.setCursor(11,1);
     lcd.print(koudo); 
     } else if (koudo < 1000) {
     lcd.setCursor(9,1);
     lcd.print(" "); 
     lcd.setCursor(10,1);
     lcd.print(koudo); 
     } else {
     lcd.setCursor(9,1);
     lcd.print(koudo); 
     }
    lcd.setCursor(13,1);
    lcd.print("m");
  }

  if (gps.speed.isUpdated())
  {
        int satV;
        satV = (int)(gps.satellites.value());
        if (satV < 10){
        lcd.setCursor(8,3);
        lcd.print(" ");
        lcd.setCursor(9,3);
        lcd.print(satV);
         } else {
        lcd.setCursor(8,3);
        lcd.print(satV);
         }
        lcd.setCursor(10,3);
        lcd.print("sats");            
    
    int s;
    s = (int)(gps.speed.kmph());
       if (s == 0) {
       lcd.setCursor(0,3);
       lcd.print("---");
       lcd.print("Km/h");
       } else if (s < 10) {
       lcd.setCursor(0,3);
       lcd.print("  ");
       lcd.setCursor(2,3);
       lcd.print(s);
       lcd.print("Km/h");
       } else if (s < 100) {
       lcd.setCursor(0,3);
       lcd.print(" ");
       lcd.setCursor(1,3);
       lcd.print(s);
       lcd.print("Km/h");
       } else {
       lcd.setCursor(0,3);
       lcd.print(s);
       lcd.print("Km/h");
       }
  }

   if (gps.course.isUpdated())
  {
   int headDir = (gps.course.deg());
   
    if ((gps.course.deg()) <= 0) {
     lcd.setCursor(6,0);
     lcd.print("ACT. REQUIRED ");     
    }
    else if ((gps.course.deg()) > 360) {
     lcd.setCursor(6,0);
     lcd.print("ACT. REQUIRED "); 
    } 
    else if ((gps.course.deg()) < 11.3) {
     lcd.setCursor(13,0);
     lcd.print("W--N--E"); 
      if ((gps.course.deg()) < 10) {
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print("  "); 
      lcd.print(headDir);
      lcd.print(" "); 
      }else {
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(" "); 
      lcd.print(headDir); 
      lcd.print(" "); 
      }    
     }
    else if ((gps.course.deg()) < 33.8) {
     lcd.setCursor(13,0);
     lcd.print("--N");
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);
     lcd.print("--E"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(" "); 
      lcd.print(headDir); 
      lcd.print(" "); 
     }
   else if ((gps.course.deg()) < 56.3) {
     lcd.setCursor(13,0);
     lcd.print("-N-"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("-E-"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(" "); 
      lcd.print(headDir);
      lcd.print(" "); 
     }
   else if ((gps.course.deg()) < 78.8) {
     lcd.setCursor(13,0);
     lcd.print("N--"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("E--"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(" "); 
      lcd.print(headDir);
      lcd.print(" "); 
     }
   else if ((gps.course.deg()) < 101.3) {
     lcd.setCursor(13,0);
     lcd.print("N--E--S"); 
      if ((gps.course.deg()) < 100) {
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(" "); 
      lcd.print(headDir);
      lcd.print(" "); 
      }else {
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir); 
      lcd.print(" "); 
      }    
     }
  else if ((gps.course.deg()) < 123.8) {
     lcd.setCursor(13,0);
     lcd.print("--E"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("--S"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);
      lcd.print(" "); 
     }
 else if ((gps.course.deg()) < 146.3) {
     lcd.setCursor(13,0);
     lcd.print("-E-");  
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("-S-"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
 else if ((gps.course.deg()) < 168.8) {
     lcd.setCursor(13,0);
     lcd.print("E--");  
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("S--"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
 else if ((gps.course.deg()) < 191.3) {
     lcd.setCursor(13,0);
     lcd.print("E--S--W"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
 else if ((gps.course.deg()) < 213.8) {
     lcd.setCursor(13,0);
     lcd.print("--S"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("--W"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else if ((gps.course.deg()) < 236.3) {
     lcd.setCursor(13,0);
     lcd.print("-S-"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0);   
     lcd.print("-W-"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else if ((gps.course.deg()) < 258.8) {
     lcd.setCursor(13,0);
     lcd.print("S--"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0); 
     lcd.print("W--"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else if ((gps.course.deg()) < 281.3) {
     lcd.setCursor(13,0);
     lcd.print("S--W--N"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
      }
else if ((gps.course.deg()) < 303.8) {
     lcd.setCursor(13,0);
     lcd.print("--W"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0); 
     lcd.print("--N"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else if ((gps.course.deg()) < 326.3) {
     lcd.setCursor(13,0);
     lcd.print("-W-"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0); 
     lcd.print("-N-"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else if ((gps.course.deg()) < 348.8) {
     lcd.setCursor(13,0);
     lcd.print("W--"); 
     lcd.setCursor(16,0);
     lcd.write(1); 
     lcd.setCursor(17,0); 
     lcd.print("N--"); 
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     }
else {
     lcd.setCursor(13,0);
     lcd.print("W--N--E");
      lcd.setCursor(6,0);
      lcd.print("Dir"); 
      lcd.print(headDir);  
      lcd.print(" "); 
     } 
    
  }

 int hmdt = dht.readHumidity();
 int tmpr = dht.readTemperature();

  if (isnan(hmdt) || isnan(tmpr) ){
     lcd.setCursor(0,3);
     lcd.print("UPDATING           ");
  }else{
   lcd.setCursor(0,2);
   lcd.print("Tmp");
   if (tmpr < 10) {
   lcd.setCursor(3,2);
   lcd.print(" ");
   lcd.setCursor(4,2);
   lcd.print(tmpr);
   } else {
   lcd.setCursor(3,2);
   lcd.print(tmpr);
   }
   lcd.setCursor(5,2);
   lcd.print("c ");
   lcd.setCursor(7,2);
   lcd.print("Hmd");
   lcd.setCursor(10,2);
   lcd.print(hmdt);
   lcd.setCursor(12,2);
   lcd.print("%");
  }

}

64個のLEDでレインボーカラー。シリアルLEDのWS2812BとArduinoで簡単に実現

64個のRGB-LEDをいくつかのパターンで光らせます。

f:id:solocamptouring:20180201054058j:plain

光り方のパターンは、ボリューム(可変抵抗)で変えられるようにします。

見た目だけなので利便性の効果はありませんが、車のオーバーヘッドコンソールに埋め込んで使っています。

ランダムな光り方に1980年代の映画に出てくるコンピュータ的な雰囲気が漂い、気分は007かナイトライダーです。

ナイトライダーのボイスインジケータ風バージョンも作ってみたので、記事内に動画リンクをはっておきます。

原点回帰してLEDで遊ぶ

私は、マイコンを扱った経験は無いなかで、初めてArduinoを手にしてすぐに「Lチカ」をやってみました。儀式的にLEDを点滅させただけですが、スケッチ(プログラム)の数値を変更し、点滅間隔やパターンを変えてみたりして、Arduinoの基礎の基礎がなんとなく理解できた気がしました。

 それからしばらくの間はモーターを動かしたりGPSモジュールで遊んでいましたが、原点回帰でLEDを綺麗に光らせてみたいと考えました。

クリスマスの綺麗なイルミネーションのような、見ているだけで幸せになる点滅光やカラフルな光を目指します。

f:id:solocamptouring:20180916190042j:plain

 Arduinoを使いLEDをどう光らせるか

 Arduinoで遊びはじめる前から、ランダムな、もしくは有機的な光らせ方に興味があり、ホタル発光する回路とか、100均のロウソクLEDをランダムパターン発生器の代わりにした回路を作って遊んでいました。

せっかく Arduinoを使うのであれば、もっと多くのLEDを使って、いろんな光り方を試してみたいと思います。

LEDは WS2812Bを選択

 多数のLEDを備えたモジュールは、おもには一列に配置したテープ状のものと、マトリックスに配置されたボード状のものがあります。

 

今回は光らせて遊ぶだけでなく実際に何かに使いたいので、テープ状のものよりも使いやすそうなボード状のものを使うことにします。

次にLEDの選択ですが、これも実使用を考慮すると配線数を極力減らしたいと思います。調べてみるとWS2812Bというニーズに合致したLEDがある事がわかりました。

WS2812Bはマイコンチップを搭載したシリアルLEDで、直列に繋いだ多数のLEDを、数に限界はありますが信号線一本で制御できます。

マイコンチップごとにアドレシングできるので、制御信号としては個々のLEDの光り方情報が数珠繋ぎになっているデータを送ります。

一個目のLEDが自分の光り方情報だけ抜き取って、次のLEDに渡す。次のLEDがまた同じ動作をする。ということを繰り返していき、各LEDが個別に違った発光をするものです。

このWS2812Bを64個(8x8個)ならべたボードが市販されているので、入手しました。

f:id:solocamptouring:20180408114052j:plain

Arduinoとの配線

 配線は、少なくていいので簡単です。

5~6V電源でArduinoとWS2812Bを駆動して、ボリュームにも電圧をかけたら、

  • WS2812BのデータピンとArduinoのデジタルピン(D4)
  • ボリュームで変えた電圧とArduinoのアナログピン(A5)

を配線して終了です。

カッコ内のピン番号は最後に紹介するスケッチ(プログラム)の場合です。

私のWS2812Bモジュールは、DINがデータのアウトプット(次のモジュールにデータをわたす)ピンで、DOUTがデータの入力ピンになっています。その場合の回路図をFritzingで作成しました。

f:id:solocamptouring:20180408112231j:plain

光らせ方パターン

 多くの光り方パターンが定義されていて、簡単なスケッチ(プログラム)で思い通りの光らせ方ができるGitHubのFastLEDライブラリを使うことにします。

あまり多くのパターンを使うと、ボリュームでパターン変更する時にセンシティブになってしまうので、光らせ方は以下の7パターンだけにしておきます。

  1. onlycolorGlitter,;ストロボっぽくランダム発光
  2. sinelon, ;尾を引きながら横に流れる光
  3. onecolorconfetti, ;残像を残しながらランダム発光(一色)
  4. confetti,;残像を残しながらランダム発光(変色)
  5. sinelonWithGlitter ;上記組み合わせ
  6. rainbowWithGlitter; 64個全面で虹色発光(変色)しながら、白色Glitterを入れる
  7. allwhite,;全面で白色発光

7つの アルファベット名称はスケッチで定義したものです。

ArduinoでWS2812B(RGB-LED)を光らせる
ArduinoでWS2812B(RGB-LED)を光らせる
sinelonとallwhite

車のオーバーヘッドコンソールに装着 

 せっかく作ったので、車の中で光らせます。

 天井の自作コンソールに埋め込みました。

WS2812Bを64(8x8)個ならべたボードをオーバーヘッドコンソールに装着

今回のレインボーカラーとは違って、サウンドレベルメーター風の光らせ方ですが、同じ車のコンソールに取り付けた状態を、動画で確認できます。

今回つかったsinelon(尾を引きながら横に流れる光)も、一部に取り込んでいます。


Arduino project #3 「サウンドレベルメーターをWS2812Bでつくる」Sound level meter with WS2812B

 Arduinoのスケッチ(プログラム)

GitHubのFastLEDで公開されているサンプルスケッチに手を加えて作成しました。

光り方に飽きてしまった場合に簡単に変えられるように、今回は使っていない光らせ方も定義だけは記載しています。

#include "FastLED.h"

FASTLED_USING_NAMESPACE
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif

#define DATA_PIN    4
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
#define HEIGHT 8
#define WIDTH 8
#define NUM_LEDS HEIGHT*WIDTH
CRGB leds[NUM_LEDS];
#define BRIGHTNESS          3
#define FRAMES_PER_SECOND  60
int analogPin = 5;
int val = 0;
void setup() { delay(3000); // 3 second delay for recovery // tell FastLED about the LED strip configuration FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); // set master brightness control FastLED.setBrightness(BRIGHTNESS); } // List of patterns to cycle through. Each is defined as a separate function below. typedef void (*SimplePatternList[])(); SimplePatternList gPatterns = { onlycolorGlitter, sinelon, onecolorconfetti, confetti, sinelonWithGlitter, rainbowWithGlitter, allwhite }; uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current uint8_t gHue = 96; // rotating "base color" used by many of the patterns void loop() { val = analogRead(analogPin); if (val < 150) { gCurrentPatternNumber = 0; } else if (val < 300){ gCurrentPatternNumber = 1; } else if (val < 450){ gCurrentPatternNumber = 2; } else if (val < 600){ gCurrentPatternNumber = 3; } else if (val < 750){ gCurrentPatternNumber = 4; } else if (val < 900){ gCurrentPatternNumber = 5; } else { gCurrentPatternNumber = 6; } // Call the current pattern function once, updating the 'leds' array gPatterns[gCurrentPatternNumber](); // send the 'leds' array out to the actual LED strip FastLED.show(); // insert a delay to keep the framerate modest FastLED.delay(1000/FRAMES_PER_SECOND); // do some periodic updates EVERY_N_MILLISECONDS( 800 ) { gHue++; } // slowly cycle the "base color" through the rainbow } void rainbow() { // FastLED's built-in rainbow generator fill_rainbow( leds, NUM_LEDS, gHue, 1); } void rainbowWithGlitter() { // built-in FastLED rainbow, plus some random sparkly glitter rainbow(); addGlitter(40); } void addGlitter( fract8 chanceOfGlitter) { if( random8() < chanceOfGlitter) { leds[ random16(NUM_LEDS) ] += CRGB::White; } } void addcolorGlitter( fract8 chanceOfGlitter) { if( random8() < chanceOfGlitter) { leds[ random16(NUM_LEDS) ] += CHSV( gHue, 255, 192); } } void sinelon() { // a colored dot sweeping back and forth, with fading trails fadeToBlackBy( leds, NUM_LEDS, 30); int pos = beatsin16(13,24,32); leds[pos] += CHSV( gHue, 255, 192); } void sinelonWithGlitter() { // built-in sinelon, plus some random sparkly glitter sinelon(); addGlitter(5); } void onlycolorGlitter() { // some random sparkly glitter FastLED.clear(); addcolorGlitter(5); } void confetti() { // random colored speckles that blink in and fade smoothly fadeToBlackBy( leds, NUM_LEDS, 20); int pos = random16(600); leds[pos] += CHSV( gHue, 255, 192); } void onecolorconfetti() { // random colored speckles that blink in and fade smoothly fadeToBlackBy( leds, NUM_LEDS, 20); int pos = random16(600); leds[pos] += CRGB::MidnightBlue; } void allwhite() { // all led white color fill_solid(leds, NUM_LEDS, CRGB::White); }

 

自作オーバーヘッドコンソールにLCDモニターをに取付ける(Arduinoでコクピット⑥)

Arduinoで作るジムニーのコクピットディスプレー。スケルトンモデルが完成

 今回のシリーズ記事⑥では、20x4文字の大きなLCDが収まるオーバーヘッドコンソールを組み立てます。

前回の記事⑤のおさらい

前回は、オーバーヘッドコンソールの箱を作成しました。

www.solocamptouring.com

今回つくる回路

Arduino(アルドゥイーノ)nano1個で、20x4文字のLCDモニターに8種類の情報を表示します。

  • 時刻
  • 高度
  • 速度
  • 進行方向
  • 捕捉している衛星数
  • 温度
  • 湿度
  • 加速度

 

使用するセンサーモジュールは

  • GPSモジュール
  • 温湿度センサーモジュール
  • 加速度センサーモジュール

の3種類です。

 

Fritzingで作成した回路図。

Arduinoでつくるコクピット情報表示LCDモニターの回路図

 

ブレッドボードで試作した時の様子。

Arduinoで作るコクピットモニター ブレッドボードで試作

回路図を見てもブレッドボードでの試作時の写真を見ても、今回は配線が多くてはんだ付けがたいへんそうですが、気持ちを奮い立たせてやりきってしまいます。

作業を開始します!

フリップダウンモニターの移植

まず、今回は何も変更しないフリップダウンモニターを、古いコンソールから新しいものに移植します。

このモニターもArduinoを使っており、リバース連動オート化されています。

断線しないように注意しながら、Arduinoとステップモータードライバーをはずして、モニター機構部ごと新しいコンソールに移植します。

Arduinoで作動するオートフリップダウンモニターを新しいオーバーヘッドコンソールに移動

新しいコンソールの回路スペースのうち、写真だと右側の部分を空けておきます。今回作るコクピット情報表示用のArduinoを、この部分に取り付けます。 

回路の作成

先延ばししていたはんだ付け作業を開始します。配線数が多いですが、一本づつ丁寧にはんだ付けしていきます。今回、この作業にいちばん時間がかかりました。

LCDモニターから作り始めます。

JB23ジムニー オーバーヘッドコンソールにモニターをつける
JB23ジムニー オーバーヘッドコンソールにモニターをつける

汎用基盤の、写真だと裏側にコントラスト調整用の可変抵抗を付けておきました。

 

Arduinoと温湿度センサー、加速度センサー、GPSモジュールも、はんだ付けで結線します。

JB23ジムニー オーバーヘッドコンソールにArduinoで作った戦闘機風モニターをつける

はんだ付けがたいへんでしたが、完成後の「ごちゃごちゃ感」が好きです。

映画でよくある「どの色のケーブルを切るか、一か八か....」のような手作り回路感がたまりません。

Arduinoの車載状態

ダッシュボードの写りこみが激しいですが、車への取付け状態です

スケルトンモデルの完成

下の写真は、車への装着状態からは上下逆転した状態で床に置いて撮影しています。

LCDモニターを取り付けたPET板が透明のままなので中の木が丸見えですが、試験運用が終わったらモニター部以外はブラックアウトします。

Arduinoで作るジムニーのコクピットディスプレー。スケルトンモデルが完成

底面となるアクリルパネルは透明のままにして、ArduinoなどのオペレーションLEDの光を見られるようにします。

f:id:solocamptouring:20180604210259j:plain

 これで、オーバーヘッドコンソールの作成作業は全て終了です。

⑦(最終回)に向けて

車に取り付けて、作動状態を少し様子を見た後、問題なければモニター面のブラックアウトなどをして、最終的に完成とします。

車両へ取り付けた後の状態は、動画でも確認できます。


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

 

オーバーヘッドコンソールを木工で自作する(Arduinoでコクピット⑤)

今回の記事⑤では、20x4文字の大きなLCDが収まるように、オーバーヘッドコンソールを作りなおします。

Arduinoとセンサーで20x4LCDに情報表示
20x4LCDをオーバーヘッドコンソールに埋め込む

前回④までのおさらい

Arduino(アルドゥイーノ)nano1個で、20x4文字のLCDモニターに、時刻や速度、加速度、温湿度など8種類の情報を表示して、作動することを確認しました。

www.solocamptouring.com

 使用するセンサーモジュールは、GPSモジュール、温湿度センサーモジュール、加速度センサーモジュールの3種類です。

今回やること

はんだ付け作業は後回しにして、まずは取付先となるオーバーヘッドコンソールを作成します。

これまで使っていた16x2文字のLCDが、20x4文字で大型になるために、コンソールのモニター埋め込み部を下方向に拡大します。

同時に、今までコンソール下にアイフォンのイヤホンケースに入れてぶら下げていたステップモーター駆動用の回路も、見栄えを良くする予定です。

現状のコンソール。フリップダウンモニターと回路ケースが丸見え。

作業を開始します!

現状のコンソールを車から取り外す

まず、細いスクリュー2本でとまっているLCDディスプレイ部をはずします。

コンソール裏に詰まっている配線から、目的のコネクターを見つけ出して外します。

オーバーヘッドコンソール裏の配線たち(Arduinoを使ったモニター)

コネクターだらけで収拾がつかなくなりつつあるので、今回のコンソール拡大時に配線も整理します。 

木材の切り出し

今のコンソールを参考に側面の板の形を決めます。

下方向に拡大することを考慮しつつ、今のコンソールをなぞってMDF板に書き写しました。

JB23ジムニ 自作オーバーヘッドコンソール作成

コンソールの側面となるパネルはMDF板を2枚重ねて、ジグゾーで切り出しました。

他にも底面や補強とする板もジグゾーで作ります。昔は糸ノコで必死に切っていたのに比べて、たいへん便利です。

JB23ジムニ 自作オーバーヘッドコンソール作成

組み立て 

上の写真では既に穴をあけておいたのですが、木工用ボンドを塗布しながら、板どうしをスクリューで締め付けて組み立てます。

底面となるパネル(切り欠きがある正方形に近い板)だけは、表皮を巻いてから締め付けたいので、穴をあけていません。

前回作ったときに余っていた表皮を、新しいものにもボンドG17で貼りつけて、コンソールの大枠ができあがりました。

JB23ジムニー 自作オーバーヘッドコンソール作成中
JB23ジムニー 自作オーバーヘッドコンソール作成中

表皮がクセ付きしやすいものを使っているため、接着直後はシワだらけですが、そのうち良い感じになじむ筈です。

プラスチックの外形も切っておきます。下面はアクリル、モニター面は穴があけやすいPETの透明樹脂の板を使います。下面のアクリル板は、アルミのアングル材でとめることにしました。

f:id:solocamptouring:20180129000058j:plain

これで、コンソールの作成は終了です。

次回⑥の予定

Arduinoとセンサーモジュール類やLCDを汎用基盤に実装したら、今回作成したオ-バーヘッドコンソールに取付けます。

加速度センサーGY-521(MPU-6050)を使う。(Arduinoでコクピット③,④)

 Arduino で加速度、位置、時計、温度をLCDに表示。ウェルカム画面

今回は、加速度センサーモジュールGY-521(MPU-6050)を使って、

③センサーの感度確認と閾値決め。

④20x4文字LCD画面に全ての情報を表示。

の2パートに分けて進めていきます。

③センサーの感度確認と閾値決め

前回の②で決めたこと

前回の記事では、20x4文字LCDディスプレイに表示する各情報の位置を決めました。

www.solocamptouring.com

 

2004LCDにArduinoでたくさんの情報を表示する。採用案(色あり)

今回の内容

 3方向加速度&3軸角加速度センサーのGY-521(MPU-6050)モジュールを使って、傾斜計としてLCDに表示するための準備(閾値決め)をじます。

GY-521(MPU-6050)モジュール

 小さなモジュールですが、3方向&3軸まわり加速度に加えて、温度情報も出力しているようです。

私は傾斜計として使いたいので、回転方向のジャイロ情報は使いません。

Arduino Playground - MPU-6050に、モジュールの説明(英語)と、”Short example sketch” という完結で使いやすいスケッチが紹介されているので、使わせていただきます。

Arduino nanoとGY-521(MPU-6050)の接続

I2C接続を使えるので簡単です。

Arduinoの種類によって異なりますがが、nanoの場合のモジュールとの接続は、

A4SDA  

A5SCL  

D2INT   

に繋ぐほかは、電源とグランドだけです。

ブレッドボード上で、接続してみました。

Arduino nanoとGY-521(MPU-6050)の接続

加速度の出力をシリアルモニターで確認

本番では、X方法を前後方向、Y方向を横方向とする予定なので、写真の状態が車が前向きでの取り付け状態になるようにします。

シリアルモニターで出力値を確認してみました。

G sensor serial monitor output

とりあえず、無事に出力されています。

モジュールをいろんな方向に傾けてみたところ、車用で使用する閾値としては、AcX、AcYともに±5,000あたりが、加減速とコーナリング時に、頻繁でもなく稀でもないぐらいで良さそうな気がします。

暫定の閾値を決定

前後方向は±5,000、左右方向は±2,500と±5,000の二段階を閾値とします。これらの閾値を超えたら▲表示をするスケッチは、次回の記事で紹介いたします。

 次は、他のセンサーモジュールもつないで、全ての情報をLCDモニターに出力します。

④20x4文字LCD画面に全ての情報を表示

下表の情報をLCDに表示させます。速度と使用衛星数の配置を、前前回の記事から少し変更しました。

20x4文字LCDに時間、高度、速度、進行方向、温度、傾斜を表示する

回路図

最後に追加したGY-521(MPU-6050)モジュールが、I2C接続のため必然的にArduino nanoのA4,A5,D2ピンを使うことになり、各モジュールとの接続ピン割振りを見直しました。

ArduinoとGY-521(MPU-6050)を使うスケッチ(プログラム)~ArduinoとLCDでコクピット情報を表示

回路図はFritzingで作成しました。
左上付近にあるGY521が今回追加するセンサーです。回路図では違う部品が載っていますが接続は同じです。

ブレッドボードで作動確認

スケッチは最後に紹介します。

スケッチをArduinoに書き込んで、ブレッドボード上で配線して表示させてみました。

ウエルカム画面

Arduino で加速度、位置、時計、温度をLCDに表示。ウェルカム画面

電源オン後、走り出すまでの画面

Arduino で加速度、位置、時計、温度をLCDに表示。車両停止時画面

 動きがないと進行方向が計算できないので、LCD画面の右上に「ACT. REQUIRED」と表示します。

平坦路で、前後および横Gが発生していない時の画面

Arduino で加速度、位置、時計、温度をLCDに表示。Gがない時の画面

 LCD画面の右下の■(車のイメージ)のまわりには、どの向きにも▲マークがありません。

坂路もしくはGがかかっている状態

Arduino で加速度、位置、時計、温度をLCDに表示。Gがかかっている時の画面

写真手前の加速度センサーを傾けたので、LCD画面の右下の■のまわりに、▲マークが表示されます。

スケッチ

③の加速度センサーのサンプルスケッチと、前回記事②のGPS&温湿度センサーのスケッチを足し合わせてから、LCDの表示場所取りを見直したり条件式をいくつか追加したりして書いてみました。

スケッチは、完成した時の記事内で紹介しています。

次回⑤以降の記事

Arduinoとセンサーモジュール類、LCDを汎用基盤に実装したら、車のオ-バーヘッドコンソール部に埋め込みます。

完成後に撮った動画で、車に装着して走った時のディスプレイを確認できます。


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

いろんなセンサーでコクピット情報を20x4LCDモニターに表示(Arduinoでコクピット②)

今回の記事②では、いろいろなセンサーから得た情報を、20x4LCDモニターに表示する場所を決めます。

前回①のおさらい

これまでに、Arduino(アルドゥイーノ)nano1個で、20x4文字のLCDモニターに表示できている情報は、
・時刻
・高度
・速度
・進行方向
・捕捉している衛星数
・温度
・湿度
の7項目です。

Arduinoとセンサーモジュールでバージュンアップ途中の車内モニター

使用しているモジュールは
・GPSモジュール
・温湿度センサーモジュール
の2つです。

ArduinoのデジタルI/OピンもアナログINピンもまだ余っているので、加速度センサーモジュールも今後追加する予定です。

www.solocamptouring.com

今回②の目標

今後、加速度センサーモジュールをArduinoにつないで、傾斜計(クライノメーター)風の表示ができるようにしますが、その前にLCD内の表示位置決めをしておきたいと思います。

今回は20x4文字LCDの画面レイアウトについて考えます。

LCDの画面レイアウト

現状の車内モニター

ArduinoとGPSモジュールで作った、現状の車用GPSモニター

車両停止時のLCD表示。移動中は左下の使用GPS数の位置に速度を表示。

16x2文字のモニターでは、ちょうどいいくらいの情報量と場所取りになっています。
図表化すると、このようになります↓

1602LCD 衛星情報表示レイアウト 現状

各情報を色分けして、わかりやすくした図表↓

1602LCD 衛星情報表示レイアウト 現状(色分け)

温度、湿度、傾斜計を追加した画面レイアウト案

案1

2004LCDにArduinoでたくさんの情報を表示する。案1
まず、場所をとる傾斜計表示(●、▲、▼、<、>で表示する部分)を中央に置いて、そのまわりに他の情報を置いてみました。

まあまあ上手く配置できているのですが、傾斜計の中心点(●)と、進行方向の中心点(この図表の場合は”N”)の、各中心が別の位置にあるのが気になります。


傾斜計と進行方向(磁針)を縦にならべてみる事にしました。

案2

2004LCDにArduinoでたくさんの情報を表示する。案2
傾斜計と進行方向(磁針)を縦にならべました。
速度を示す”Spd”は場所がなくなり、”S”のみとなりました。
進行方向(角度)を示す”Dir”も同様の理由で、”HD”(ヘッディング)にしました。
黒く塗りつぶされている部分は、時刻の秒針を10秒刻み(この図表は50から60秒の間の状態)で示しています。

この案だと傾斜計の周りが窮屈そうに見えるので、次の案では傾斜計と進行方向(磁針)を右隅に寄せてみます。

案3

2004LCDにArduinoでたくさんの情報を表示する。案3
傾斜計と進行方向(磁針)を右隅に寄せました。
残りのスペースに、他の情報を入れていきます。
進行方向(角度)を示す”Dir”は、復活できました。

あと少し、傾斜計まわりをスッキリさせたいので、
次の案では、速度を示す”S”とセミコロンを無くしてみます。

最終案

2004LCDにArduinoでたくさんの情報を表示する。採用案(色あり)
窮屈感もなくなり、見やすくなりました。

実際の見え方に近くするために、色分けをなくすと、こうなります↓

2004LCDにArduinoでたくさんの情報を表示する。最終案

 

画面レイアウトも決まったので、次回は加速度センサーモジュールをArduinoとつないで、動作確認してみます。

動画でも画面レイアウトを確認できます。


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

 

温湿度センサーDHT11で温度と湿度をディスプレイに表示する(Arduinoでコクピット①)

車に装着している、ArduinoとGPSモジュールを使用したモニターに、全7回に分けて表示情報量を多くするバージョンアップを紹介していきます。

バージョンアップ前のGPSモニター制作記事はこちら↓

solocamptouring.hatenablog.com

 

現在(バージョンアップ前)の車両取付状態↓

JB23ジムニーに装着した、自作オーバーヘッドディスプレイのGPSモニター

モニターの選択

現在使っているGPSモニターには、
・時刻
・高度
・速度
・進行方向
・捕捉している衛星数
の5項目の情報を表示しています。

16x2文字のLCDモニターを使っていますが、5項目を表示するのが精いっぱいで、さらに追加で情報を表示するためには、モニターを大型化しないといけません。


簡単に入手できるLCDのうち、次に表示文字数の多いものは20x4文字なので、これに変更する前提でセンサー等を追加していきます。

LCDモニター 1602と2004 比較

追加表示する情報

今後、追加表示していきたいのは、
・温度
・傾斜計(クライノメーター)
の2項目です。

まず今回は、比較的に簡単な温度表示の追加について試してみます。

温湿度モジュール

DHT11というセンサーモジュールを使います。

安くて精度はまあまあというものですが、今回は小数点以下の精度を必要としないので十分使えます。

Arduinoで、GPSモジュールと温湿度モジュールを使いLCDディスプレイに表示する

左上のクリップで挟んでいるのがDHT11

回路図

DHT11で温度と湿度をディスプレイに表示するArduinoスケッチ

Fritzingで回路図作成しました。


バージョンアップ前の回路に対して、左上の温湿度センサーが追加になっています。センサーの電源電圧は5Vです。

温湿度センサー用のスケッチ

温湿度センサー用のライブラリーは、GitHubのadafruit/DHTセンサライブラリからダウンロードして使いました。
前回記事で紹介したGPSモニターのスケッチに、次に紹介する行を挿入します。

まずは、DHT11用ライブラリを使う事を宣言します。

#include <DHT.h>
#define DHTPIN 13
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

 セットアップ部で、DHT11と通信開始します。

void setup()
{
  dht.begin();
}

 ループ部で、DHT11からの読み込みとLCDディスプレイへの書き出しを命令します。

void loop()
{
 int h = dht.readHumidity();
 int t = dht.readTemperature();
  if (isnan(h) || isnan(t) ){
     lcd.setCursor(0,3);
     lcd.print("UPDATING           ");
  }else{
   lcd.setCursor(0,3);
   lcd.print("Humid:");
   lcd.setCursor(6,3);
   lcd.print(h);
   lcd.setCursor(8,3);
   lcd.print("%");
   lcd.setCursor(10,3);
   lcd.print("Temp:");
   lcd.setCursor(15,3);
   lcd.print(t);
   lcd.setCursor(17,3);
   lcd.print("c");
  }
}
 

作動確認

20x4文字のLCDを使い、問題なく作動しました。

Arduinoで、GPS情報、温度、湿度をLCDモニターに表示する
センサーを手で温めると、すぐに温度が上がってくるので、変動レスポンスも良さそうです。

今回はDHT11とGPSモジュールを同時に使えるか確認することが主目的なので、各情報の表示位置は暫定です。次回は、傾斜計など全ての表示を含めたレイアウト検討をします。

スケッチは、完成記事(⑦)内で紹介しています。

www.solocamptouring.com

 

完成状態の動画もつくりました。


Arduino project #1「GPSマルチモニター 」Multi-information monitor with GPS module

 

ステップモーター28BYJ-48で、リバース連動オートフリップダウン式モニターを自作

JB23ジムニー フリップダウンバックモニター 自作 1
JB23ジムニー フリップダウンバックモニター 自作 2

リバース連動で開閉する自作バックモニター、サーボモーターを使った1号機が思いのほか騒がしい為、ステップモーター(ステッピングモーター)に変更します。この2号機が、現在の最新状態です。

使用するステップモーター;28BYJ-48

JB23ジムニー フリップダウンモニター自作 ステップモーターとサーボモーター

右が、ステップモーター(5V用)とドライバー

ステップモーターは、低速ほどトルクがでます。今回は低速作動で、さらに外部ギヤでも減速して使用するので、安価な28BYJ-48でも動くと考えて選択しました。

この28BYJ-48ですが、作動電圧が5Vと12Vの2種類あります。はじめは5Vのものを使用してみましたがトルクに余裕がなかったために、12Vのものを採用しました。

 外部減速用のギヤ(ドライブギヤとドリブンギヤ)は、28BYJ-48の出力軸径に合うものを市販品から見つけられず、やむなく壊れたプリンターから取り出したギヤを加工して使っています。


オートフリップダウンモニターのギヤ部

 
回路図

f:id:solocamptouring:20171223183150j:plain

回路図は、Fritzingで作成しています。

右側半分の回路は、ステップモーターとドライバーです。セットで安く入手できるので、自作してはいません。

 左半分の、Arduino本体以外が、自作した部分となります。

Reverse Signal

車のギアをリバースに入れた時の信号で、具体的には後退灯の12Vを分岐してきています。そのままだと12Vなので、抵抗3個とダイオード1個で5Vのデジタル信号にして、ArduinoのD10につないでいます。

Full Close SW

ステップモーターには位置情報がないのですが、モニターの現位置がわからないと、制御できません。そのため、モニターを全閉した時に押される位置にプッシュスイッチをつけて、全閉するたびに位置情報をリセットするようにしています。スイッチの状態を5Vのデジタル信号にするために、抵抗1個を使用して、ArduinoのD8につないでいます。

LED5

故障時のトラブルシュートが簡単になるように、モーターへの回転指令が出ているかどうかの確認用でつけておきました。

Arduinoを使った位置と速度管理

モニターが開く(降りる)方向は、モーターのステップ数だけで位置管理しています。そのため、開いている途中でモニターの動きを強制的に止めると、中途半端に開いた状態でも全開だと誤認識して止まります。

全開検出スイッチを追加すれば回避できるのですが、そもそもモニターの自重が開き方向に働いているので開く途中でモーターが脱調することは0%に近いと考えられます。開き方向はステップ数だけで位置管理して止める事にしました。

 

モニターが閉じる方向は、徐々にゆっくり閉まるようにしています。動きに高級感を出しつつ、多少の外乱があったとしても徐々にトルクが強くなる効果でいつかは閉まることを狙っています。 

 

モニターの動きがわかる動画をアップしました。

 


Arduino project #2 「リバースギヤ連動 オートフリップダウン バックモニター」Auto flip down rear view monitor

 スケッチ

int reversePin = 10;    // reverse signal input
int operationPin = 9;     // operation indicator led output
int motororiginPin = 8;    // motor initial position sw input
int motorPin1 = 4;    // Blue   - 28BYJ48 pin 1
int motorPin2 = 5;    // Pink   - 28BYJ48 pin 2
int motorPin3 = 6;    // Yellow - 28BYJ48 pin 3
int motorPin4 = 7;    // Orange - 28BYJ48 pin 4
int motorSpeed;  
int count = 0;          // count of steps made
int speedcontr = 0;
int countsperrev = 320; // number of steps for full open
int lookup[8] = {B01000, B01100, B00100, B00110, B00010, B00011, B00001, B01001};
unsigned long timeZero = millis();
boolean fullOpenning =false;
boolean fullClosing =false;
void setup() {
  pinMode(reversePin,INPUT) ;  
  pinMode(operationPin,OUTPUT) ; 
  pinMode(motororiginPin,INPUT) ;
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
  Serial.begin(9600);
}
void loop() {
  if (digitalRead(reversePin) == HIGH) { 
       timeZero = millis();
       fullClosing =false;    
         if(count < countsperrev ){
         digitalWrite(operationPin, HIGH);
         speedcontr = (1*count);
         motorSpeed = 900;
         clockwise();
         count++;
         } else {
         digitalWrite(operationPin, LOW);    
         digitalWrite(motorPin1,LOW);
         digitalWrite(motorPin2, LOW);
         digitalWrite(motorPin3, LOW);
         digitalWrite(motorPin4, LOW); 
         fullOpenning =true;
        }    
   } else {
     if (digitalRead(motororiginPin) == LOW) {
          if (fullOpenning == true){ 
               if (millis() - timeZero > 1000) {
               digitalWrite(operationPin,HIGH);
                 if (count > 100){
                 motorSpeed = 1000;
                 anticlockwise();
                 count--;
                 } else {
                 speedcontr = (30*count);
                 motorSpeed = (4000-speedcontr);
                 anticlockwise();
                 count--;  
                 }
               } else {
               digitalWrite(operationPin,HIGH);
               }
           } else if (fullClosing == true){
           digitalWrite(operationPin, LOW);    
           digitalWrite(motorPin1,LOW);
           digitalWrite(motorPin2, LOW);
           digitalWrite(motorPin3, LOW);
           digitalWrite(motorPin4, LOW); 
           } else {           
               if (millis() - timeZero > 1000) {
               digitalWrite(operationPin,HIGH);
                 if (count > 100){
                 motorSpeed = 1000;
                 anticlockwise();
                 count--;
                 } else {
                 speedcontr = (5*count);
                 motorSpeed = (1500-speedcontr);
                 anticlockwise();
                 count--;  
                 }
               } else {
               digitalWrite(operationPin,HIGH);
               }
           }           
      } else {
       digitalWrite(operationPin, LOW);    
       digitalWrite(motorPin1,LOW);
       digitalWrite(motorPin2, LOW);
       digitalWrite(motorPin3, LOW);
       digitalWrite(motorPin4, LOW); 
        count = 0;
        fullOpenning =false;
        fullClosing = true;
      }
    }   
 }
void anticlockwise() 
{
  for(int i = 0; i < 8; i++)
  {
    setOutput(i);
    delayMicroseconds(motorSpeed);
  }
}
void clockwise() 
{
  for(int i = 7; i >= 0; i--)
  {
    setOutput(i);
    delayMicroseconds(motorSpeed);
  }
}
void setOutput(int out)
{
  digitalWrite(motorPin1, bitRead(lookup[out], 0));
  digitalWrite(motorPin2, bitRead(lookup[out], 1));
  digitalWrite(motorPin3, bitRead(lookup[out], 2));
  digitalWrite(motorPin4, bitRead(lookup[out], 3));
}

 

サーボモーターで、電動フリップダウン式モニターを自作。Arduinoのスケッチ(プログラム)紹介

Arduinoで電動フリップダウンモニターを自作し、車の天井に装着してみました。

現在はステッピングモーターを使っていますが、初号機はサーボモーターを使って作動していたので、スケッチを含めて紹介いたします。

現在の完成状態画像↓

JB23ジムニー フリップダウンバックモニター 自作 3
JB23ジムニー フリップダウンバックモニター 自作 4

 

 

ナビ画面でのバックモニターは使いづらい

車でバックする時に後方画像を映し出すバックモニター、ほとんどの車がナビ画面を併用しているのではないでしょうか。


私のJB23ジムニーも、ナビ画面で映すようにしていました。しかし、後退する時に、ナビ画面で確認している間は、目から入ってくる情報が偏ってしまいます。

 以前乗っていた車は、室内ミラーの一部がモニターになっており、後方確認時は視界が前のガラスエリアに向いており、車両前方も視界の中で確認できて安心感がありました。

モニター付きの室内ミラーについて検討

JB23ジムニーの室内ミラーが、前方ガラスにステーがついている最近の構造だったら、室内ミラーごとモニター付きのものに替えていました。

しかしステーが天井についているタイプのため、汎用のモニター付きミラーが使えません。

室内ミラーに被せるタイプのミラー&モニターは使えますが、ミラーが重くなると自重での垂れ下がりや振動がでてしまう可能性があるので、導入を見送りました。

バック専用モニターの設置位置

前方視界の範囲内に設置したいバックモニターですが、室内ミラーとの一体化はあきらめたので、天井付近から吊り下げることになります。

サンバイザーに取付けることを検討しましたが、バイザーとしての機能が無くなるのは困ります。

 残った候補位置は室内ミラーのすぐ前しかありません。

ちょうどArduinoが少しわかってきた頃だったこともあり、モニターを電動で格納して、普段はミラー確認の視界を妨げないようにする事に挑戦します。

モーターの選択

  • DCモーター
  • サーボモーター
  • ステップモーター

の3種類から選択します。

 このうちDCモーターは、モーター自体には位置情報がなく制御が難しいので最初に候補から外しました。

同じ理由で、トルク不足になると脱調をおこすステップモーターも、位置制御に不安要素があるため、一旦は候補から外しました。

こうして一号機は、位置管理しやすいサーボモーターで作成することになりました。

Arduinoでサーボモーターを動かす

電動フリップダウンモニター試作1号機

最終的に不採用になったので、簡単に紹介します。

サーボーモーターを使用することにした1号機は、ラジコン用のトルク重視のものを選択しています。

 スピード重視のものに比べ、回転速度は落ちますが、モニターを昇降するのに速度は必要ないどころか、それでも早すぎるくらいです。

 

JB23ジムニー フリップダウンバックモニター自作 サーボモーター

写真はサーボモーターを使った機構部ですが、黒い樹脂のステーが固定部、アルミのステーが可動部でモニターを取り付ける側になります。

 スケッチ(プログラム)は、速度制御が簡単にできるGitHubのVarSpeedServoライブラリを使います。

 スケッチ全体は、記事の最後にのせておきます。

 しっかり作動していたのですが、サーボモーターを使った一号機にはデメリットがありました。

一号機のデメリット


・電源ON時に、細かく動いてしまう

ラジコンやロボットを制作されている方はご存知のとおり、電源ON時、車でいうとアクセサリー電源ON時とエンジンスタート直後に、雑音(パルス)が入るので、シャカシャカと小さく動いてしまいます。


・作動音が大きい

トルクが太いのはありがたいのですが、内部ギヤの音が大きく、気になります。速度制御している事も、音の発生を助長しています。

 

ステップモーターに変更することを決意

デメリットの2点を改善するために、一度は採用を見送ったステップモーターに変更して2号機をつくりました。

JB23ジムニー フリップダウンバックモニター ステップモーターに変更

 

solocamptouring.hatenablog.com

参考;サーボモーターを使うスケッチ

#include <VarSpeedServo.h>
VarSpeedServo myservo1; 

void setup() {
  pinMode(10,INPUT) ;  // 車のリバース信号を5Vに落として入力
  pinMode(9,OUTPUT) ;  // サーボと接続中と9番につないだLEDで表示できるようにする
        digitalWrite(9, HIGH);  // サーボと接続中とLEDで表示
        myservo1.attach(8);  // サーボのピンを8番に接続して初期化作動を始める
        myservo1.write(5); 
        myservo1.write(39, 30, true); 
        delay(300);
           myservo1.write(0, 20, true);  
           delay(500);
        myservo1.detach();// サーボと遮断
        digitalWrite(9, LOW); // サーボと遮断したのでLEDを消灯
} 

void loop() {
      if (digitalRead(10) == HIGH) {   //リバースの時
        myservo1.attach(8);  // サーボのピンを8番に接続して作動開始
            digitalWrite(9, HIGH);  // サーボと接続中とLEDで表示
            myservo1.write(77, 50, true); 
            delay(1000);
     } else {                        //リバースではない時
           digitalWrite(9, HIGH);  // サーボと接続中とLEDで表示
           myservo1.write(20, 30, true); 
           myservo1.write(10, 25, true);
           myservo1.write(0, 20, true); 
           while((digitalRead(10) == LOW)){
            delay(500);     
           myservo1.detach();  // モニターが閉じきったらサーボのピンを8番から遮断
           digitalWrite(9, LOW);  // サーボと遮断したのでLEDを消灯
            }
         }
     }

車の天井GPSモニター作成編~16x2LCDとパラレル通信するArduino回路とスケッチ

LCD1602でGPSモニター自作

Arduinoを使った自作GPS方位計を車に装着したことを、別の記事で紹介しました。

solocamptouring.hatenablog.com

今回は、その制作内容を紹介します。スケッチ(プログラム)も記事の最後に載せておきます。

使用するモジュールなど

Arduino

Arduino本体、いろいろ種類がありますが私はunoとnanoをよく使います。

どちらも同じ使い勝手です。このGPSモニターにはnano(の互換機)を使っています。

LCDモニター

1602と2004 LCDモニター

 

写真で上のLCDが、横16x縦2文字を表示するもの(1602)、
下のLCDが、横20x縦4文字(2004)です。

配線はどちらも同じなので、表示させる文字数に応じて使い分けます。

今回は、1602を使って、

  • 時刻
  • 高度
  • 速度
  • 方位

を表示します。

GPSセンサーモジュール

アンテナ一体や別体などいろいろなものがありますが、どれも使い方はほぼ同じです。今回は、約1,000円で入手したアンテナ別体のものを使いました。

f:id:solocamptouring:20171218162800j:plain

回路図

車の天井GPSモニター作成編~Arduinoとパラレル通信する回路図とスケッチ

回路図はFritzingで作成しています。

写この記事で使っている16x2LCDモジュールは、I2C通信を使えば、少ない電線でArduinoと接続することができます。

今回は、あえてパラレル通信で、多くの電線を使って接続しています。LCDのピンについて、簡単に紹介します。

  • D0~D7;実際にデータを送受信する。今回の通信レベルならD4~D7の4本だけでも可能
  • RS;レジスターセレクト。Arduinoに接続
  • R/W;送受信の切り替え。今回は一方通行なので、グランドに接続
  • E;データ取り込みの信号。Arduinoに接続
  • VO;コントラスト調整。10KΩの可変抵抗に接続
  • VDD;+(5V)電源
  • VSS;グランド
  • A;バックライト(LED)電源。220Ωの抵抗を使用
  • K;バックライト(LED)のグランド

 

GPSユニットは、回路図と実際に使っているものが違いますが、接続は一緒です。

最初、RXとTX(データの送受信)が、GPSユニットとArduino側で逆転させないといけないことに気づかずに接続してしまい、作動しない理由がわからずに悩みました。

開封後の初回使用時は、緯度経度を特定してデータを送信し始めるまで時間がかかります。私は15分くらいかかりました。

気長に待っていると、GPSユニットのLEDが点滅して、各種情報がArduinoに送られてきます。

次回の電源投入時からは、前回の位置情報を記憶しているので、すぐに自位置特定して起動します。

TinyGPS++を使用して、正確な時間、高度、速度、進行方向を、LCDディスプレイに表示

GPSモジュールがやっていること

GPSモジュールは、NMEAフォーマットという数列で、多くの情報を送ってきます。 

モジュール自体が計算してアウトプットする情報が多いですが、こんな小さなモジュールなのに賢くて感心します。

その多くの情報の中から、私が使いたい情報は、

  • 緯度経度
  • 速度
  • 高度
  • 協定世界時(UTC)
  • 進行方位

の5種類です。

 

TinyGPS++を使ったサンプルスケッチ 

GPSモジュール用のライブラリは、tinygpsplusから入手します。

ベテランが作るともっと短く完結なスケッチにできる筈ですが、初心者なので”if---else”を多用して、動けば良し!というスケッチになっています。

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd( 12, 11, 5, 4, 3, 2 );
byte smiley[8] = {
  B00100,
  B01110,
  B11111,
  B00000,
  B00100,
  B01110,
  B11111,
};
byte sat1[8] = {
  B00110,
  B01110,
  B01110,
  B01111,
  B01110,
  B01110,
  B01100,
};
byte sat2[8] = {
  B01110,
  B00100,
  B01110,
  B11111,
  B01110,
  B00100,
  B11111,
};
byte sat3[8] = {
  B01100,
  B01110,
  B01110,
  B11110,
  B01110,
  B01110,
  B00110,
};
TinyGPSPlus gps;
SoftwareSerial gpsSerial(6, 7);
const int serialTime = 200;
void setup()
{
  lcd.createChar(1, smiley);
  lcd.createChar(2, sat1);
  lcd.createChar(3, sat2);
  lcd.createChar(4, sat3);
  lcd.begin(16,2);
  lcd.clear();  
  gpsSerial.begin(9600);
  lcd.setCursor(0,0);
  lcd.print("   CAPTURING    ");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print(" SATELLITES");
  lcd.setCursor(12,1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);
  delay(10000);
  lcd.clear(); 
} // end setup
void loop()
{
int start = millis(); 
int now = millis();
do {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
now = millis();
} while ((now - start) < serialTime); 
  if (gps.altitude.isUpdated())
  {
    int h;
    h = (gps.time.hour()) + 9;
    if( 24 <= h ) {
    h = h - 24;
    }
       if (h < 10) {
       lcd.setCursor(0,0);
       lcd.print(" ");
       lcd.setCursor(1,0);
       lcd.print(h);
       } else  {
       lcd.setCursor(0,0);
       lcd.print(h);
       }
    lcd.setCursor(2,0);
    lcd.print(":");
    int m;
    m = gps.time.minute();
       if (m < 10) {
       lcd.setCursor(3,0);
       lcd.print("0");
       lcd.setCursor(4,0);
       lcd.print(m);
       } else {
       lcd.setCursor(3,0);
       lcd.print(m);
       }
  }
 if (gps.altitude.isUpdated())
  {
    lcd.setCursor(7,0);  
    lcd.print("Alt:");
     int koudo;
     koudo = (int)(gps.altitude.meters()); 
     if (koudo == 0) {
     lcd.setCursor(11,0);
     lcd.print("----"); 
     } else if (koudo < 10) {
     lcd.setCursor(11,0);
     lcd.print("   "); 
     lcd.setCursor(14,0);
     lcd.print(koudo); 
     } else if (koudo < 100) {
     lcd.setCursor(11,0);
     lcd.print("  "); 
     lcd.setCursor(13,0);
     lcd.print(koudo); 
     } else if (koudo < 1000) {
     lcd.setCursor(11,0);
     lcd.print(" "); 
     lcd.setCursor(12,0);
     lcd.print(koudo); 
     } else {
     lcd.setCursor(11,0);
     lcd.print(koudo); 
     }
    lcd.setCursor(15,0);
    lcd.print("m");
  }
  if (gps.speed.isUpdated())
  {
    int s;
    s = (int)(gps.speed.kmph());
       if (s == 0) {
        int satV;
        satV = (int)(gps.satellites.value());
        if (satV < 10){
        lcd.setCursor(0,1);
        lcd.print(" ");
        lcd.setCursor(1,1);
        lcd.print(satV);
         } else {
        lcd.setCursor(0,1);
        lcd.print(satV);
         }
        lcd.setCursor(2,1);
        lcd.write(2);
        lcd.write(3);
        lcd.write(4);
        lcd.print("s ");  
       } else if (s < 10) {
       lcd.setCursor(0,1);
       lcd.print("  ");
       lcd.setCursor(2,1);
       lcd.print(s);
       lcd.print("Km/h");
       } else if (s < 100) {
       lcd.setCursor(0,1);
       lcd.print(" ");
       lcd.setCursor(1,1);
       lcd.print(s);
       lcd.print("Km/h");
       } else {
       lcd.setCursor(0,1);
       lcd.print(s);
       lcd.print("Km/h");
       }
  }
   if (gps.course.isUpdated())
  {
    if ((gps.course.deg()) == 0) {
     lcd.setCursor(9,1);
     lcd.print("WAITING"); 
    }
    else if ((gps.course.deg()) < 11.3) {
     lcd.setCursor(9,1);
     lcd.print("W--N--E"); 
     }
    else if ((gps.course.deg()) < 33.8) {
     lcd.setCursor(9,1);
     lcd.print("--N");
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);
     lcd.print("--E"); 
     }
   else if ((gps.course.deg()) < 56.3) {
     lcd.setCursor(9,1);
     lcd.print("-N-"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("-E-"); 
     }
   else if ((gps.course.deg()) < 78.8) {
     lcd.setCursor(9,1);
     lcd.print("N--"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("E--"); 
     }
   else if ((gps.course.deg()) < 101.3) {
     lcd.setCursor(9,1);
     lcd.print("N--E--S"); 
     }
  else if ((gps.course.deg()) < 123.8) {
     lcd.setCursor(9,1);
     lcd.print("--E"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("--S"); 
     }
 else if ((gps.course.deg()) < 146.3) {
     lcd.setCursor(9,1);
     lcd.print("-E-");  
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("-S-"); 
     }
 else if ((gps.course.deg()) < 168.8) {
     lcd.setCursor(9,1);
     lcd.print("E--");  
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("S--"); 
     }
 else if ((gps.course.deg()) < 191.3) {
     lcd.setCursor(9,1);
     lcd.print("E--S--W"); 
     }
 else if ((gps.course.deg()) < 213.8) {
     lcd.setCursor(9,1);
     lcd.print("--S"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("--W"); 
     }
else if ((gps.course.deg()) < 236.3) {
     lcd.setCursor(9,1);
     lcd.print("-S-"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1);   
     lcd.print("-W-"); 
     }
else if ((gps.course.deg()) < 258.8) {
     lcd.setCursor(9,1);
     lcd.print("S--"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1); 
     lcd.print("W--"); 
     }
else if ((gps.course.deg()) < 281.3) {
     lcd.setCursor(9,1);
     lcd.print("S--W--N"); 
     }
else if ((gps.course.deg()) < 303.8) {
     lcd.setCursor(9,1);
     lcd.print("--W"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1); 
     lcd.print("--N"); 
     }
else if ((gps.course.deg()) < 326.3) {
     lcd.setCursor(9,1);
     lcd.print("-W-"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1); 
     lcd.print("-N-"); 
     }
else if ((gps.course.deg()) < 348.8) {
     lcd.setCursor(9,1);
     lcd.print("W--"); 
     lcd.setCursor(12,1);
     lcd.write(1); 
     lcd.setCursor(13,1); 
     lcd.print("N--"); 
     }
else {
     lcd.setCursor(9,1);
     lcd.print("W--N--E");
     }   
  }
}

ジムニーの天井にGPSモニターを装着する。はじめてのArduino

f:id:solocamptouring:20180404211538j:plain

 

正確で見やすいコンパスが欲しい!

私の車にはナビ一体ヘッドユニットがついているので、ナビ画面に切り替えれば自車の進行方向が表示されます。

 しかし、運転中に一瞬しか画面を見られない時に、ナビ画面の方位磁針からわかるのは、例えば「なんとなく北の方」といった感じです。

 そこで、「南南西」など、360度の16分割までで、パッと見てわかるコンパスを車内に追加したくなりました。

磁場を利用したコンパス

最初に思いついたのは、オーソドックスな、丸いカプセルの中でくるくる回る磁石をつかったコンパスです。

f:id:solocamptouring:20171215184034j:plain

10年以上前にバイクのウインドスクリーンにつけていたことがあり、そこそこ正確に方向を指し示していました。

車でも使えるだろうと思い、さっそく入手して車内で正確に方向を示す場所を探しましたが、良い位置が見つかりません。

鉄の塊であり電子機器を多用している車の中では、地球の磁場を利用することは難しいようです。

 船用の調整機能付きコンパスも考えましたが、磁場を乱す車内では調整しても無駄な気がしたので、磁場検知式のものを使うことは早々にあきらめました。

磁場検知方式ではないコンパス

磁場検知方式以外のコンパスといっても、手法をなかなか思いつきませんでしたが、「そもそもカーナビは、どのように方位がわかるのか?」を調べた結果、GPSモジュールを使えば可能なことがわかってきました。

市販されている完成品では、GPSを使ってヘッドアップディスプレイ(HUD)に各種情報を映し出すタイプのものがあります。しかし、「北東」など8分割表示までしかしないものが多く、またHUD方式も私はあまり嬉しくありません。

 なんとかGPSを使ったディスプレイを自作できないか、さらに調べてみました。

GPS情報ディスプレイの自作に挑戦

ネットで調べてみると、Arduinoというマイコンを使用した、自作GPSロガーの紹介記事が多いことがわかりました。

 緯度経度を表示もしくは記録するものの制作記事が多いですが、GPSアンテナモジュールからは、そのほかにも時刻、速度、進行方向や高度の情報も得られるようです。

これは使える!と思い、Arduinoの勉強を始めました。

車で使えるコンパスの自作に成功

 いきなりですが、完成写真を紹介します。Arduinoを使った初めての工作でしたが、まったくの初心者でも楽しみながらつくることができました。

電源ON時

まずは車のアクセサリー電源がONになったときのウェルカム画面です。

f:id:solocamptouring:20171214223730j:plain

次に走り出す前の画面です。方位(進行方向)は走り出さないと計算できないので、「待機中」となっています。

f:id:solocamptouring:20171214223822j:plain


 ・左上;時刻
 ・右上;高度
 ・左下;受信している衛星の数(停止中だけ表示)
 ・右下;「待機中」(電源ON後で車が動き出すまでの間のみ表示)

走行中

走行中の画面です。と言いつつ、走行中に写真は撮れないので、製作途中に撮った写真です。

自作GPSモニター 時刻 海抜 速度 方位
 ・左上;時刻
 ・右上;高度
 ・左下;速度(走行中のみ表示)
 ・右下;方位

停止時 

一度でも車が動けば、その後は停止時でも直前の進行方向を方位として表示しつづけます。

f:id:solocamptouring:20171214224110j:plain

感想~はじめてのArduino

今回作ったものは、車の天井コンソールに埋め込みました。

 隣で「5.04」と赤く光っているのは、Arduino回路用に降圧した電源の電圧計です。

JB23ジムニー 自作GPSモニター取付け

Arduinoを使うと、今まで手が出せなかった電子工作が簡単にできます。

 温度センサーから人感センサーまで様々なセンサーモジュールも簡単に安く入手できるので、電子工作の幅が大いに広がります。

今回自作した回路やスケッチ(プログラム)は別記事で紹介しています。

solocamptouring.hatenablog.com