Arduino

05/21/2020

NodeMCU1.0 or ESP32 Dev Module を使って 8x8 dotmatrix LEDでデジタル時計をつくる

Img_20200522_083257 Esp32doitdevkitv1-8x8led-clock

朝からず~と取り組んで、やっとこさ完成! ハードウェアはここにあるように、CPU1個とLEDデジタル表示器1個を5本のケーブルで繋ぐだけだけどね・・・。 電源はUSB(5V)で動いている。 肝心なのはソフト! 1週間ほど前に似たようなものを、習作で制作したのですが、表示フォントと表示の方法が気に入らなくて、何とか自分のアイデアで纏めたいと思い、今日は表示フォントも作った! ちょっと太目のフォントなので離れていても見やすい! ソフトが動いて、時間が表示できるようになるまで手古摺った~! 時間はWiFiから入力し処理している。

洒落たケースに入れられれば、もう少し格好が良くなるんだけど・・・。このCPUは、WiFiの技適が無いものだから、近々ESP32-WROOM-32に入れ替えよう!

Sketchには、いろいろ試しながら構築したので、不要な所も多々あると思うが、ご覧になる方にはご容赦願いたい。
中央付近に、時間と分表示の区切り「:」を入れると、時間部分の表示と分の表示部分に同じものを使うと、アンバランスな表示になってしまうので、時の表示と分の表示でフォントのデザインを変更した。

《その後、当日ですが・・・》
手元にあった ESP32-WROOM-32 (Espressif) 「技適済」で動作確認したので、Sketchも修正しておく 

使用部品
・NodeMCU
 又は ESP32 Dev Module (ESPRESSIF ESP32-WROOM-32) Amazonで2個2000円くらいです。
・8x8ドットマトリックスLED(MAX7219 ドット LED マトリックス MCU 制御 LED) Amazonで@1200円くらいです。
・5本ジャンパーケーブル
・ブレッドボード(スイッチサイエンス製を使った)

Sketch
// NodeMCU 1.0(ESP12-E Module)  /  ESP32 Dev Module / ESP32 Wrover Module
// Vcc to Vin .................. Vin or 5V or 3V3
// GND to GND
// Din to D7 .................... D27
// CS to D6 .................... D26
// CLK to D5 .................... D25

#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <LedControl.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
const char* ssid = "your SSID";
const char* password = "your Password";
const long utcOffsetInSeconds = 9*3600;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
int month,dayOfMonth,dayOfWeek,hour,minute,s;
int i=0;
int x=0;
int bstflag= 0;
int twelve = 0; //variable for 12 hour hour counter
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
// set up display - data, clock, cs, numdevices
LedControl lc = LedControl(D7,D5,D6,4); //pins for Din, CLK, CS
//matrix table for display
//first element on each row is the bottom row of the display, then rising up through the display
const int numh[10][8] = {
// ここに用意したフォントは、左側2文字、"Hour"表示用
{0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x1e}, // zero
{0x00,0x3f,0x0c,0x0c,0x0c,0x0c,0x0f,0x0c}, // one
{0x00,0x3f,0x06,0x0c,0x18,0x30,0x33,0x1e}, // two
{0x00,0x1e,0x31,0x30,0x1e,0x30,0x31,0x1e}, // three
{0x00,0x30,0x30,0x7f,0x33,0x32,0x34,0x38}, // four
{0x00,0x1e,0x31,0x30,0x30,0x1f,0x03,0x3f}, // five
{0x00,0x1e,0x33,0x33,0x1f,0x03,0x23,0x1e}, // six
{0x00,0x06,0x06,0x0c,0x18,0x30,0x33,0x3f}, // seven
{0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e}, // eight
{0x00,0x1e,0x33,0x30,0x3e,0x33,0x33,0x1e} // nine
};
const int numm[10][8] = {
// ここに用意したフォントは、右側2文字、"Minute"表示用
{0x00,0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0x78}, // zero
{0x00,0xfc,0x30,0x30,0x30,0x30,0x3c,0x30}, // one
{0x00,0xfc,0x18,0x30,0x60,0xc0,0xcc,0x78}, // two
{0x00,0x78,0xc4,0xc0,0x78,0xc0,0xc4,0x78}, // three
{0x00,0x60,0x60,0xfe,0x66,0x64,0x68,0x70}, // four
{0x00,0x78,0xc4,0xc0,0xc0,0x7c,0x0c,0xfc}, // five
{0x00,0x78,0xcc,0xcc,0x7c,0x0c,0x8c,0x78}, // six
{0x00,0x18,0x18,0x30,0x60,0xc0,0xc4,0xfc}, // seven
{0x00,0x78,0xcc,0xcc,0x78,0xcc,0xcc,0x78}, // eight
{0x00,0x78,0xcc,0xc0,0xf8,0xcc,0xcc,0x78} // nine
};
void drawhNum(int number, int display_div)
{ // drawNum は、数値"number"を、デバイス"display_div"に表示させる
lc.setRow(display_div, 7, numh[number][7]); // デバイス display_div の 1行分(x,y)を纏めて表示設定
lc.setRow(display_div, 6, numh[number][6]); // 変数名num [数値] [行目] 表示を示している
lc.setRow(display_div, 5, numh[number][5]);
lc.setRow(display_div, 4, numh[number][4]);
lc.setRow(display_div, 3, numh[number][3]);
lc.setRow(display_div, 2, numh[number][2]);
lc.setRow(display_div, 1, numh[number][1]);
lc.setRow(display_div, 0, numh[number][0]);
}

void drawmNum(int number, int display_div)
{ // drawNum は、数値"number"を、デバイス"display_div"に表示させる
lc.setRow(display_div, 7, numm[number][7]); // デバイス display_div の 1行分(x,y)を纏めて表示設定
lc.setRow(display_div, 6, numm[number][6]); // 変数名num [数値] [行目] 表示を示している
lc.setRow(display_div, 5, numm[number][5]);
lc.setRow(display_div, 4, numm[number][4]);
lc.setRow(display_div, 3, numm[number][3]);
lc.setRow(display_div, 2, numm[number][2]);
lc.setRow(display_div, 1, numm[number][1]);
lc.setRow(display_div, 0, numm[number][0]);
}
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid,password);
while (WiFi.status() != WL_CONNECTED ) {
Serial.print(".");
delay(500);
}
timeClient.begin();
// power up led matrices
for (i=0; i<4; i++)
{
lc.shutdown(i,false); // デバイス i をシャットダウンしてモードを切り替え
lc.setIntensity(i,0); // set brightness 0-15 デバイス i の明るさを指定
lc.clearDisplay(i); // デバイス i の表示を全クリア
}
}
void displayTime()
{
//modify brightness
for (i=0; i<4; i++)
}
// print hour to led =======================================================
//first set hours to show just 0 in second module after midnight
if (hour==24)
{
twelve=0; // midnight is 00:00
// drawNum は 数値を、デバイスに表示させる
drawhNum(0,3); //place 0 in second module
}
//change time display for BST/GMT - 'hour' is in 24H format and set for GMT
//first set BST summer time flag for months from April through Septemebr
if ((month>3) && (month<10))
{
bstflag=1;
}
else
{
bstflag=0;
}
// Now set the summer time flag after the last Sunday in March ===============
if ((month==3) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=1;
}
//and remove the BST flag after the last sunday in October
if ((month==10) && (dayOfMonth>24) && (dayOfWeek==1) && (hour>1))
{
bstflag=0;
}
//from here on use bstflag to increment the displayed hour ====================
//work out display for 12 hour format
hour += bstflag;
/*
if (hour>12)
{ // 下記が有効になると12時間表示になる
hour -= 12;
}
*/
twelve = hour;
if (twelve<10)
{
// drawNum は、数値 numberを、デバイスdisplay_div に表示させる
drawhNum(twelve,2); //and write whole hour in second module
}
if (twelve>9)
{
drawhNum(twelve/10,3); //write first digit in first module
drawhNum(twelve%10,2); //and write whole hour in second module
}
if (minute < 10)
{
// drawNum は数値 numberを、デバイスdisplay_div に表示させる
drawmNum(0,1); //put 0 in module 3
}
else
{
drawmNum(minute/10,1); //or put minutes/10 in mod 3
}
drawmNum(minute%10,0); //and the rest of the minutes/10 in module 4
// 10で分を割っているので、10以下の分の値が求められる
}
void loop()
{
timeClient.update();
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());
hour = timeClient.getHours();
minute = timeClient.getMinutes();
displayTime(); // display the real-time clock data on the Serial Monitor,
// blinking dot to show we are working
if (x==0)
{
lc.setLed(2, 1, 0, true); // これはデバイス2 の row=1 col=0 を点灯(true)させる
lc.setLed(2, 2, 0, false);
lc.setLed(2, 5, 0, false);
lc.setLed(2, 6, 0, true);
delay(1000); // every second
x=1;
}
else
{
lc.setLed(2, 1, 0, false); // これはデバイス2 のrow=1 col=0 を消灯(false)させる
lc.setLed(2, 2, 0, true);
lc.setLed(2, 5, 0, true);
lc.setLed(2, 6, 0, false);
delay(1000); // every second
x=0;
}
参考にしたのは
 時刻表示用の8x8フォントを制作するに際して、LED Matrix Tool を使わせて戴きました。インストール不要でオンラインで使える!
 それに、HEX Arryの枠には、私が使いたいデータが打ち出されるので、そのままコピーしてSketchに貼り付けることが出来た。

NodeMCUを使った8x8ドットマトリックスLED時計の作り方
  Simple Dot Matrix Clock Using Node MCU
 これは、RTC Clock を使った方法で、WiFiから時間データを読み取る方法は記載されていない。
 そのため、下記のURLを参考にして、NTPサーバーから時間データを読み取るようにした。
 使っている表示フォントは気に入ったので、使わせて戴いた。但し”7”は少し変更を加えた。

NTPサーバーからの時間入力方法
 Getting Date & Time From NTP Server With ESP8266 NodeMCU

ESP32用のLED matrix 接続ピン
 Demo 5: How to use Arduino ESP32 to display information on SPI LED matrix

《更にその後、当日ですが・・・》
Espressif ESP32-Wrover-B  も ESP32 Dev Module と同じようなピン配列なので、D25,D26,D27 ピンに8x8ドットマトリックスを接続して起動を確認してみた ・・・ 問題なく時間を表示出来た!
Esp32wroverb Espressif ESP32 Wrover-B

《その後》
上図にあるEspressif ESP32 Wrover-B で運用しているのですが・・・いくつか問題が見つかりました。未だ直していません。
➀ある時間経過すると表示が消えてしまう。「RST」ボタンで直ぐに復帰します。スリープ状態なのでしょうか?
➁24時を過ぎてもどんどん時間数表示を加算してゆく。例えば27時とか表示する。なにかのトリガーが入ると、正常な表示になる。

05/06/2020

14segment LED を使ってみる

Img_20200506_092159 Img_20200506_092219 Img_20200506_092251
0.54インチスクリーン、14セグメントの4桁LEDディスプレイをArduino NANO制御ロボットの表示用に購入した。
4桁LED は、I2Cコントロール仕様で、6個セットで1832円(Amazonで購入)。1個約300円。

電源を入れて気づいたのは、左2桁が赤で右2桁がオレンジの表示! 寸法、14segmentとI2Cインターフェイスを使用と書いてあったので、それ以上深く考えずに購入。他の項目には注意が及んでいなかった。

4桁LEDディスプレイのドライバ用のピンは5本ある。普通4本でしょ・・・とよく見ると、ピンの配列は次のようになっている。
SCL、SDA、GND、VCC、Vi2C。 Vi2C って何だ! 電源用らしい。

ここに来てから、14segmentディスプレイの使用方法に関する情報を調べたが・・・ほとんど見つからない。「HT16K33」をキーワードにネット上を探し回って、購入したものと同じLEDディスプレイの写真を表示しているブログを発見し、参考にさせて戴いた。
https://draeger-it.blog/arduino-lektion-108-14-segmentanzeige/?cn-reloaded=1&cn-reloaded=1
「7セグLED表示 その8 4文字-HT16K33② (https://www.denshi.club/cookbook/output/led/7seg/7led54-ht16k33.html)」


このLED購入の目的は、arduino NANOを使った超音波センサー付きロボットの状態を表示するため。これまでは、7セグメントのものを使って表示していたが、7セグメントでは文字表示が分かり難い。もう少し分かり易い表示にしたいので、これを買ってみた。

arduino NANOのピン配列で、SCLとSDAのピンを調べてみる。
https://i.pinimg.com/originals/c2/c2/e6/c2c2e68f8dab93647c3a39b04d61fda5.jpg

これを見ると、SCLは A5ピン。 SDAは A4ピンに接続すればいい。

購入した14segmentのLEDにピンを半田付けして、
そして、ブレッドボードに、Arduino NANO とジャンパーピンを接続して・・・ 

このようにジャンパーピンを配置してみた。

さて、sketch であるが・・・
4桁のLEDは、次にように目的別に表示するようにしたい。
左から、
1桁目:超音波センサの向いている方向(L=左方向、F=前方、R=右方向)
2~4桁:超音波センサーで検出した空間距離をcm値で表示
     例えば、 50 ならば、50cmという具合に・・・
     1mを越える場合もあるので、3桁分を用意した。
数値が1桁ならば、数値は右に詰めて表示し、左側の桁部分には、ゼロを表示する。
数値のゼロを置いて表示させたが、見栄えが良くないので、小文字の「o(オー)」を表示する事にした。

数値の文字長さを調べて、「case文」を使い、桁数に合わせ表示を切り替えるようにした。
数値が1桁なら、LEDの右端(4桁目)に数値を表示し、2桁目と3桁目には「o」を入れて表示する。
数値が2桁なら、LEDの3桁目と4桁目を使って数値を表示し、左から2桁目には「o」を入れて表示する。
数値が3桁なら、LEDの2桁目から4桁目を使って数値を表示する。
もしそれ以外の数値が入力されたら、defaultで、2桁目から4桁目には「*」を表示させる。

Sketch は、表示テスト用として使ったものなので、少し長めのdelay(3000)を入れて確認を容易にした。

Sketch の後半部分は、robot の判断内容を表示するもので、「Back(後退)」「Stop(停止)」「FWD(前進)」という内容を表示させようとした。

《Sketch》

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
int jgo;
Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();
void setup() {
alpha4.begin(0x70); // pass in the address
alpha4.setBrightness(1);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
int inum = 2;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
inum = 15;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
alpha4.clear();
alpha4.writeDisplay();
inum = 123;
jgo=String(inum).length();
switch(jgo)
{ case 1:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, String(inum).charAt(0) );
break;
case 2:
alpha4.writeDigitAscii(1, 'o');
alpha4.writeDigitAscii(2, String(inum).charAt(0) );
alpha4.writeDigitAscii(3, String(inum).charAt(1) );
break;
case 3:
alpha4.writeDigitAscii(1, String(inum).charAt(0) );
alpha4.writeDigitAscii(2, String(inum).charAt(1) );
alpha4.writeDigitAscii(3, String(inum).charAt(2) );
break;
default:
alpha4.writeDigitAscii(1, '*' );
alpha4.writeDigitAscii(2, '*' );
alpha4.writeDigitAscii(3, '*' );
}
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Back
alpha4.writeDigitAscii(0, 'B');
alpha4.writeDigitAscii(1, 'a');
alpha4.writeDigitAscii(2, 'c');
alpha4.writeDigitAscii(3, 'k');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Stop
alpha4.writeDigitAscii(0, 'S');
alpha4.writeDigitAscii(1, 't');
alpha4.writeDigitAscii(2, 'o');
alpha4.writeDigitAscii(3, 'p');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text Stop
alpha4.writeDigitAscii(0, 'F');
alpha4.writeDigitAscii(1, 'W');
alpha4.writeDigitAscii(2, 'D');
alpha4.writeDigitAscii(3, '*');
alpha4.writeDisplay();
delay(3000);
// -------------------------------------------------------------
// display text May
alpha4.writeDigitAscii(0, '*');
alpha4.writeDigitAscii(1, 'M');
alpha4.writeDigitAscii(2, 'A');
alpha4.writeDigitAscii(3, 'Y');
alpha4.writeDisplay();
delay(3000);
}
void loop() {
}

03/11/2020

@nifty ココログでアップロードしたソースリストを綺麗に見せる方法

Esp32_20200315090701 記事にしておきたい内容を纏める際のソースリストが綺麗に掲載出来ないストレス、取り組んでいる電
子工作が壁に当たって進まない事、家事の忙しさ、その他いろいろとあって、なかなか記事が書けないでいた。

ソースリストが綺麗に掲載出来ないのは、僕のやり方がどこか間違っているのだろう。ネット上を調べたが、僕の悩みに対する書き込みは見当たらない。

それで、Arduinoで試した数行のソースリストを使って、この紙面上で試してみたいと思う。

Arduino IDE を起動して、下記のソースリストを綺麗に表示する方法をいろいろ試してみたい。
下記のSketchは、ESP32を使って、圧電ブザーを鳴らすもので、その際「SSD1306」に周波数を表示できるようにしてある。

500Hzから500Hz刻みで周波数を上げて圧電ブザーを鳴らします。
使っているESP32は、ESPRESSIF ESP32-WROOM-32 (技適対応済み)
A19というのは、D26ピン

#include "SSD1306.h"
const int ledPin = A19;
int freq;
int channel = 0;
int resolution = 8;
int dutyCycle = 125;
String Freq;
SSD1306 display(0x3c, 21, 22);

void setup() {
Serial.begin(115200);
display.init(); //SSD1306を初期化
ledcSetup(channel, freq, resolution);
ledcAttachPin(ledPin, channel);
}

void loop() {
for ( freq = 500; freq < 21000; freq = freq + 500) {
Serial.println(freq);
ledcWriteTone(channel, freq);
Freq = String(freq);
show_freq();
delay(1500);
}
}

void show_freq(){
display.clear();
display.setFont(ArialMT_Plain_16);
display.drawString(30, 20, Freq);
display.setFont(ArialMT_Plain_16);
display.drawString(75, 20," Hz");
display.display();
}

以上のソースリストを、次回のブログでは見やすく表示したい!

以下にやってみる

まず、記事投稿を書いているこの画面の右上の大きく太い黄色の枠どりされた中の右下にある「設定」をクリックする。

次の画面の基本情報をクリックして、中にある「ブログのサブタイトル(キャッチフレーズ)」の下の枠内に、下記(薄い緑色の背景のテキスト)を書き込む。
(コピーしてペーストすればいい)
この直ぐ下の行 ↓ から
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
<link rel="stylesheet" href="/css/prettify.css">
<style>
.prettyprint ol.linenums > li {
list-style-type: decimal;
}
</style>
↑ ここまでを枠内にコピーしたら保存して、記事投稿に移る。

通常エディタにして、ソースコード部分を、下記のようにして<pre>と</pre>で挟み込むようにする。

<pre><code class="prettyprint linenums">
ソースコード部分
</code></pre>

この方法で上記のソースリストを設定すれば、以下のように表示される。

#include "SSD1306.h" 
const int ledPin = A19;
int freq;
int channel = 0;
int resolution = 8;
int dutyCycle = 125;
String Freq;
SSD1306 display(0x3c, 21, 22);
void setup() {
Serial.begin(115200);
display.init(); //SSD1306を初期化
ledcSetup(channel, freq, resolution);
ledcAttachPin(ledPin, channel);
}
void loop() {
for ( freq = 500; freq < 21000; freq = freq + 500) {
Serial.println(freq);
ledcWriteTone(channel, freq);
Freq = String(freq);
show_freq();
delay(1500);
}
}
void show_freq(){
display.clear();
display.setFont(ArialMT_Plain_16);
display.drawString(30, 20, Freq);
display.setFont(ArialMT_Plain_16);
display.drawString(75, 20," Hz");
display.display();
}

表示の背景色を変更するには、前記2行目の
<script type="text/javascript" src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

<script type="text/javascript" src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=sons-of-obsidian"></script>
等と変更すればよい。

skin= は、シンタックスハイライトのテーマ(skin)を指定するので、どのようなテーマがあるかは skin gallery を参照のこと。複数指定した場合は、読み込みに最初に成功したテーマが使われるとのこと。

ヘッダ部分は、一度設定しておけばいい筈なので、ソースリストを記載する際には、通常エディタにして
<pre><code class="prettyprint linenums">
ソースコード部分
</code></pre>
と書くように・・・と記憶しておけば良さそうだ。

上手く行ったようなので、既に記載したブログについても少しずつ表示を直してゆこうと思う。

09/26/2019

4-8x8dot LED matrix を使ったテキストの scrolling 表示

筆者は最近ドライブレコーダを購入してAK12とAK13、2台のマーチに取り付けた。そこで思いついたのは、後方から迫る車に、4-8x8dot LED matrix を使って、ドライブレコーダで録画していると知らしめれば、防御運転には更に効果的ではないかと思った。
仮に後方からの運転者が、英語を理解できるとして「Drive recorder working!」と表示するとする。しかし、この表示装置では「Drive」までしか表示できないため、すべてのテキストを表示するには、テキストを scrolling しなければならない。
先日、4-8x8dot LED matrixを使って、時刻表示したときの sketchや、Github にあるテキストのスクロール表示を参考に、取り組んでみた。
Arduino NANO を使えば、物理的な回路は、結線だけで出来てしまう。

《使用部品》
1) arduino用 4-8x8dot LED matrix MAX7219
2) Arduino NANO
3) ジャンパー用配線

《接続》
Arduino NANO ---- MAX7219
5V  ---------------- VCC : 写真では「茶色」
GND --------------- GND : 写真では「赤色」
D11 --------------- DIN : 写真では「橙色」
D10 --------------- CS : 写真では「黄色」
D13 --------------- CLK : 写真では「緑色」

《参考にしたブログ》
1)  私が以前に投稿したブログ
  http://spice-cabinet.cocolog-nifty.com/blog/2019/06/post-6766a7.html


《Sketch》

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
int pinCS = 10; // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI )
int numberOfHorizontalDisplays = 4;
int numberOfVerticalDisplays = 1;
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);
String tape = "Drive-recorder working!";
int wait = 100; // In milliseconds
int spacer = 1;
int width = 5 + spacer; // The font width is 5 pixels
void setup() {
matrix.setIntensity(7); // Use a value between 0 and 15 for brightness
// Adjust to your own needs
matrix.setPosition(0, 3, 0); // The first display is at <0, 0>
matrix.setPosition(1, 2, 0); // The second display is at <1, 0>
matrix.setPosition(2, 1, 0); // The third display is at <2, 0>
matrix.setPosition(3, 0, 0); // And the last display is at <3, 0>
// ...
matrix.setRotation(0, 1); // The first display is position upside down
matrix.setRotation(1, 1); // The first display is position upside down
matrix.setRotation(2, 1); // The first display is position upside down
matrix.setRotation(3, 1); // The first display is position upside down
}
void loop() {
for ( int i = 0 ; i < width * tape.length() + matrix.width() - 1 - spacer; i++ ) {
matrix.fillScreen(LOW);
int letter = i / width;
int x = (matrix.width() - 1) - i % width;
int y = (matrix.height() - 8) / 2; // center the text vertically
while ( x + width - spacer >= 0 && letter >= 0 ) {
if ( letter < tape.length() ) {
matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
}
letter--;
x -= width;
}
matrix.write(); // Send bitmap to display
delay(wait);

08/25/2019

DHT11 で計測の温度と湿度を TM1637 に表示する

Thd11tm1637 Dht11tm1637
TM1637は、7セグメント4桁表示器なので、「℃」や「%」の表示は、7セグメントの1文字では表示できない。
それゆえ、写真にあるように「℃」と「%」を簡易表示するようにした。
温度と湿度は、1秒ごとに切り替えて表示する。

《ピン接続について》
① DHT11 の左から2番目の信号ピン -> D2
② TM1637 の CLK -> D9
③ TM1637 の DIO -> D10 


《Sketch》

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain
// REQUIRES the following Arduino libraries:
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor
#include "DHT.h"
#define DHTPIN 2 // Digital pin connected to the DHT sensor
// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
// Pin 15 can work but DHT must be disconnected during program upload.
#include <TM1637Display.h>
#define CLK 9   //can be any digital pin
#define DIO 10 //can be any digital pin
#define CHAR_DEG 0b01100011
#define CHAR_C 0b00111001
// Uncomment whatever type you're using!
#define DHTTYPE DHT11    // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);
TM1637Display display(CLK, DIO);
const uint8_t Letter_deg[] = { SEG_A | SEG_B | SEG_F | SEG_G };
const uint8_t Letter_C[] = { SEG_A | SEG_D | SEG_E | SEG_F };
const uint8_t Letter_o[] = { SEG_C | SEG_D | SEG_E | SEG_G };
void setup() {
Serial.begin(9600);
Serial.println(F("DHTxx test!"));
display.setBrightness(4); // 0x01 << dark -- bright >> 0x0f
display.clear();
dht.begin();
}
void loop() {
// Wait a few seconds between measurements.
delay(1000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, h);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(t, h, false);
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.print(F("% Temperature: "));
Serial.print(t);
Serial.print(F("°C "));
Serial.print(f);
Serial.print(F("°F Heat index: "));
Serial.print(hic);
Serial.print(F("°C "));
Serial.print(hif);
Serial.println(F("°F"));
display.clear();
display.showNumberDec(t,false, 2, 0); // distance to front obstacle
display.setSegments(Letter_deg,1,2);
display.setSegments(Letter_C,1,3);
delay(1100);
display.clear();
display.showNumberDec(h,false, 2, 0); // distance to front obstacle
display.setSegments(Letter_deg,1,2);
display.setSegments(Letter_o,1,3);
delay(100);
}

《参考にした資料》
https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHTtester/DHTtester.ino

08/12/2019

Tank Robotの背中に処理状況を表示

Tank Robot の動き方をいろいろ調整して、ほぼ満足のゆく状況になってきた。Sketch については、前回のものに対して少し加筆修正も行ったが・・・、Sketch内の各ステートメントで、変数の意味は何で、また何の処理をしているのか、後で見直した際にも分かるように、コメントを追記した。
Img_20190808_115947

《 Sketch 》

const int PIN_SONAR_ECHO = 5; // define pin for sensor echo
const int PIN_SONAR_TRIGGER = 6; // define pin for sensor trig
#include <Servo.h>
#include <TM1637Display.h>
#define CLK 7 //can be any digital pin
#define DIO 8 //can be any digital pin
int Fdistance = 0; // Distance to the obstacle in the direction of the sensor
float Dlh; // Distance to left obstacle
float Drh; // Distance to right obstacle
float Dfr; // Distance to front obstacle
int Ls = 35 ; // short range threshold changed from 30
int Ll = 55 ; // long range threshold = 55
int angle;
int pinSRB = 9; // servo motor output pin (PWM)
int random_No4;
float multiplier = 1.35; // add variable and changed number from 1.3
int delaytime = 350; // chaged from 400
// next pins(10~13) are depended on L298P motorshield
int pinLB = 12; // direction control function
int pinLF = 10; // motors' control chip with speed control function from 10
int pinRB = 13; // direction control function
int pinRF = 11; // motors' control chip with speed control function
int FullSpeed = 255; // max 255
int HalfSpeed = 240; // when the number is less than 180 will be stopp
Servo myServo; // set myservo

TM1637Display display(CLK, DIO);
// Data setting for 7-segment display
const uint8_t Letter_F[] = { SEG_A | SEG_E | SEG_F | SEG_G }; // F
const uint8_t Letter_b[] = { SEG_C | SEG_D | SEG_E | SEG_F | SEG_G }; // b
const uint8_t Letter_H[] = { SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // H
const uint8_t Letter_r[] = { SEG_E | SEG_G }; // r
const uint8_t Letter_L[] = { SEG_D | SEG_E | SEG_F }; // L
const uint8_t Letter_A[] = { SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // A
const uint8_t Letter_c[] = { SEG_D | SEG_E | SEG_G }; // c
const uint8_t Letter_t[] = { SEG_D | SEG_E | SEG_F | SEG_G }; // t
const uint8_t Letter_LT[] = { SEG_A | SEG_F | SEG_G }; // <
const uint8_t Letter_GT[] = { SEG_A | SEG_B | SEG_G }; // >

void setup()
{
  Serial.begin(9600);
  pinMode(PIN_SONAR_TRIGGER,OUTPUT);
  pinMode(PIN_SONAR_ECHO,INPUT);
  display.setBrightness(0x0f); // 0x01 << dark -- bright >> 0x0f
  display.clear();
// Define motor output pin
  pinMode(pinLB,OUTPUT); // pin 12 direction control function
  pinMode(pinLF,OUTPUT); // pin 10 (PWM)
  pinMode(pinRB,OUTPUT); // pin 13 direction control function
  pinMode(pinRF,OUTPUT); // pin 11 (PWM)
  myServo.attach(pinSRB); // Define servo motor output pin(PWM)
}

void Advance() // move to forward
{
  display.setSegments(Letter_F,1,0); // display "go to foward"
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void Back() // move backward
{
  display.clear();
  display.setSegments(Letter_b,1,1); // display "go to backward"
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  delay(50);
  digitalWrite(pinLB,HIGH); // motor moves to left rear
  digitalWrite(pinRB,HIGH); // motor moves to right rear
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void MidSpeed() // move to forward
{
  display.setSegments(Letter_F,1,0); // display "go to foward"
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,HalfSpeed);
  analogWrite(pinRF,HalfSpeed);
}

void Stopp() // all wheel stop
{
  display.setSegments(Letter_H,1,0); // display "Stop"
  display.setSegments(Letter_A,1,1);
  display.setSegments(Letter_L,1,2);
  display.setSegments(Letter_t,1,3);
  digitalWrite(pinLB,HIGH); // left wheel stop
  digitalWrite(pinRB,HIGH); // right wheel stop
  analogWrite(pinLF,0);
  analogWrite(pinRF,0);
}

void BackRight() // turn right
{
  display.setSegments(Letter_r,1,0); // display "back right"
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB,HIGH);
  digitalWrite(pinRB, LOW); // wheel on the right moves backward
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void BackLeft() // turn left
{
  display.setSegments(Letter_L,1,0); // display "back left"
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB, LOW); // wheel on the left moves backward
  digitalWrite(pinRB,HIGH);
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void loop()
{
  labelF:
  long random_No1 = random( 20, 120); // Generate random numbers
// --- Forward obstacle detection and moving ---
// angle = 90;
  myServo.write(90); // use fixed number(90deg)
  delay(10); // changed delay time from 50

label1:  // add a statement
  ask_pin_F(); // Fdistance

  if(Fdistance <= Ls)
  {
    Stopp(); // stop for a while
    goto label2;
  }

  if((Fdistance > Ls ) & (Fdistance <= Ll ))
  {
    MidSpeed(); // at a slightly reduced speed
    goto label1;  // changed statement from labelF
  }

  if(Fdistance > Ll )
  {
    Advance();   // at full speed
    goto label1;  // changed statement from labelF
  }

label2:
// angle = 90; // Check the distance ahead again
  myServo.write(90); // use fixed number(angle --> 90)
  delay(10); // changed delay time from 50
  ask_pin_F();

  if(Fdistance < Ls )
  {
    Back(); // go back a little
    delay(random_No1); // backward progress time
    Stopp();
  }
// Measure left and right space
  angle = 3; // check for obstacles in the right direction
  myServo.write(angle);
  delay(1000); // time to reserve for servo motor
  ask_pin_F();
  Drh=Fdistance;

  angle = 177; // check for obstacles in the left direction
  myServo.write(angle);
  delay(1000); // time to reserve for servo motor
  ask_pin_F();
  Dlh=Fdistance;

  angle = 90; // check for obstacles ahead
  myServo.write(angle);
  delay(1000); // time to reserve for servo motor
  ask_pin_F(); // check forward distance
  Dfr=Fdistance;

label3:
  if(Dlh > Drh)
  {
    display.setSegments(Letter_GT,1,0); // display ">"
    delay(350); //changed delay time from 300
// Calculate the time to change the moving direction of the tank
// "ie. delay(random_No4)" from the distance to the obstacles
// in the front and rear direction and the side direction

    float rn1 = Dlh / Dfr ;

    if( rn1 >= multiplier ) rn1 = multiplier ; // changed sketch
    random_No4 = delaytime * rn1 ;
    BackRight();
    delay(random_No4); // backward progress time
    Stopp();
    delay(400); // display time for display unit
    goto labelF;

  }
else if( Dlh <= Drh )
{
  display.setSegments(Letter_LT,1,0); // display "<"
  delay(350); //changed delay time from 300

  float rn2 = Drh / Dfr ;

  if( rn2 >= multiplier ) rn2 = multiplier ; // changed sketch
  random_No4 = delaytime * rn2 ;
  BackLeft();
  delay(random_No4); // backward progress time
  Stopp();
  delay(400); // display time for display unit
  goto labelF;

  }
}

void ask_pin_F() // Measure the distance at the specified angle
{
  digitalWrite(PIN_SONAR_TRIGGER,LOW); // Set the trigger pin to low for 2micro_S
  delayMicroseconds(2);
  digitalWrite(PIN_SONAR_TRIGGER,HIGH); // Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(PIN_SONAR_TRIGGER,LOW); // Send pin low again
  float distance = pulseIn(PIN_SONAR_ECHO,HIGH); // Read in times pulse
  Fdistance = distance/58; // Calculate distance from time of pulse
  delay(60);
  if(( 89 < angle) & (angle < 91))    display.setSegments(Letter_F,1,0);
  if(( 0 < angle) & (angle < 35))      display.setSegments(Letter_r,1,0);
  if(( 145 < angle) & (angle < 180)) display.setSegments(Letter_L,1,0);
  display.showNumberDec(Fdistance,true, 3, 1); // distance to front obstacle
  delay(200); // changed display time from 300
}

08/11/2019

GPS Clock and display the time when posted to the post box

Img_20190810_153857Gps-watch-with-twelite
ポストボックスの蓋が開けられた際に、Twe-Liteを使って離れた場所にある書斎に信号を送り、投函されたという信号をLED点滅で表示する装置を以前に作った。
LEDの点滅ではわからない情報(例えば、何回投函された?何時投函された?)を表示させたいと思い、それぞれの目的に応じたものをNANOを用いて製作した。しかしNANOで作った前述の装置を見ると、使っているPINには重複が無いので、下記の①~⑤の内容を、1つのNANOで処理できると考え、これまで2個のNANOを使って表示していたものを纏めてみた。(写真は、壁のボードに各部品類を両面テープで貼り付けて設置している。)

①GPSによる時間捕捉
②4桁7セグメントを用いた時刻表示
③TWE-Liteからの投函信号
④8x8ドットマトリックスを用いた現在の投函数
⑤20x4LCDを用いた投函回数とその時刻表示(この表示器を用いれば、もう少し詳細なGPS時計としても表示出来る)

《使用した部品とポート間接続》
Arduino NANO --- 接続先
 Pin No.  
   A4  ---  SDA (20x4 LCD I2C 接続)
   A5  ---  SCL (20x4 LCD I2C 接続)
   D2  ---  TWE-Lite 受信後のフォトカプラより
   D3  --- RX (GPS)
   D4  --- TX (GPS)
   D6  ---  CLK (4桁7セグメント)
   D7  ---  DIO (4桁7セグメント)
   D10  ---  CS (8x8 ドットマトリックスディスプレイ)
   D11  ---  DIN (8x8 ドットマトリックスディスプレイ)
   D12  ---  NANO内部結線
   D13  ---  CLK (8x8 ドットマトリックスディスプレイ)

GPS: Cikuso  NEO-6M GPS module  GY-GPS6MV2

4桁7セグメントDisplay:
  KKHMF モジュールは12ピンの時計点付きの4位共通アノードデジタルチューブ(0.36インチ)の表示モジュール,
  ドライブチップはTM1637


TWI-Lite からの信号用フォトカプラ:

8x8ドットマトリックス:SODIAL(R) MAX7219

20x4 LCDディスプレイ:Aideepen  I2C HD44780コントローラ 
  Arduino対応(2004 LCD 5V blue)

《注記1》
これを記載した翌朝、新聞の投函があったので、表示装置を見ると・・・投函された際に表示する表記が想定していたのと違う!
表示の問題点が分かったので、2019/08/21 sketch(下記)を加筆修正した。また、Frizingを使って回路を記載した。しかし、LEDを1秒毎に点灯するためのデバイス(M34-1L)がないため、外観が同じものを流用して記述しているのでご容赦ください。

ダウンロード - gps20watch20with20twelite20sketch2020190821.fzz

注記2
Sketch の loop 内に if 文の範囲ミスが見つかったので2か所修正した。2019/08/28


《Sketch》
// GPS Clock and display the time when posted to the post box My Spice Cabinet
#include <Wire.h>
#include <TimeLib.h>     // include Arduino time library
#include <SoftwareSerial.h>  // include software serial library
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
const int numberOfHorizontalDisplays = 1;
const int numberOfVerticalDisplays = 1;
const int pinCS = 10; // Cs - SS (Pin 10)
// Din - Mosi (Pin 11)
// Clk - Sck (Pin 13)
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

#include <TinyGPS++.h> // include TinyGPS++ library
TinyGPSPlus gps;
static const int TXPin = 4, RXPin = 3;   // TX -> D4, RX -> D3
SoftwareSerial Serial_GPS(TXPin, RXPin);
static const uint32_t GPSBaud = 9600;

#include <LiquidCrystal_I2C.h>
#define I2C_ADDR  0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 20, 4);   // I2C: 0x27 20x4 LCD
// LCD(20x4) --- Arduino NANO (I2C connection)
// GND --- GND
// VCC --- 5V
// SDA --- A4
// SCL --- A5

#include "SevenSegmentTM1637.h"
#include "SevenSegmentExtended.h"
const byte PIN_CLK = 6;    // define CLK pin (any digital pin)
const byte PIN_DIO = 7;    // define DIO pin (any digital pin)
SevenSegmentExtended display(PIN_CLK, PIN_DIO);
int Satellites = 12;
int hours;
int minutes;
const int UTC_offset = 9;   // Tokyo Japan Time
#define time_offset 3600   // define a clock offset of 3600 seconds (@hour)

// variable definitions
char Time[] = "Time: 00:00:00";
char Date[] = "Date: 00_   _2000";
char visit[]  = "            ";  // changed 20190821
byte last_second, Second, Minute, Hour, Day, Month;
int Year;

char time_value[20];
#define PUSH_SHORT 100
int count = 2;   // counter from outside TWE-Lite
int icount = 0;   // number of switched on
int jcount = 0;   // column location on the display
int row = 0;
char c;
String s;
String visitor;
int count_low = 0;

void setup(void)
{
Serial.begin(9600);                 // added 20190821
Serial_GPS.begin(GPSBaud);   // initialize software serial
display.begin();                      // initializes the display
display.setBacklight(30);         // set the brightness to 30%
matrix.setIntensity( 1 );         // Adjust the 8x8 brightness (dark)0 << 15(bright)
matrix.setPosition( 0, 3, 0);
matrix.setRotation( 0, 3) ;      // rotation position
pinMode(count, INPUT_PULLUP);

c = char(icount + 48);
Serial.print("c = ");
Serial.println(c);
matrix.drawChar( 2, 1, c, HIGH, LOW, 1);
matrix.write();    // Send bitmap to display
delay( 50);

pinMode(Satellites, INPUT_PULLUP);
delay(100);

// set up the 20x4 LCD's number of columns and rows
lcd.begin(20, 4);
lcd.init();
lcd.backlight();
lcd.setCursor(2, 0);    // move LCD cursor to column 1, row 0 [upper left position (0, 0)]
lcd.print("GPS clock (UTC_ )");
lcd.setCursor(17, 0);
lcd.print(UTC_offset);

Wire.begin();
pinMode(count, INPUT_PULLUP); // switch on signal from TWE-Lite
String s;
}

void loop()
{
  matrix.fillScreen(LOW);
  while (Serial_GPS.available() > 0)
  {
    if (gps.encode(Serial_GPS.read()))
    {
// get time from GPS module
    if (gps.time.isValid())
    {
      Minute = gps.time.minute();
      Second = gps.time.second();
      Hour = gps.time.hour();
    }

// get date drom GPS module
    if (gps.date.isValid())
    {
      Day = gps.date.day();
      Month = gps.date.month();
      Year = gps.date.year();
    }

    if(last_second != gps.time.second()) // if the time has changed
    {
      last_second = gps.time.second();
// set current UTC time
      setTime(Hour, Minute, Second, Day, Month, Year);
// add the offset to get local time
      adjustTime(UTC_offset*time_offset);

// update time array
      Time[12] = second() / 10 + '0';
      Time[13] = second() % 10 + '0';
      Time[9] = minute() / 10 + '0';
      Time[10] = minute() % 10 + '0';
      Time[8] = char(58) ;
      Time[6] = hour() / 10 + '0';
      Time[7] = hour() % 10 + '0';

      hours = hour();
      minutes = minute();
// update date array
      Date[15] = (year() / 10) % 10 + '0';
      Date[16] = year() % 10 + '0';
      Date[8] = char(47) ;
      Date[9] = month() / 10 + '0';
      Date[10] = month() % 10 + '0';
      Date[11] = " ";
      Date[6] = day() / 10 + '0';
      Date[7] = day() % 10 + '0';

      if(jcount == 0)
      {
// print time & date to 20x4 LCD display
        print_wday(weekday());   // print day of the week
        print_wmonth(month());

        lcd.setCursor(0, 2);   // move cursor to column 0 row 2
        lcd.print(Time); // print time (HH:MM:SS)

        lcd.setCursor(0, 3);   // move cursor to column 0 row 3
        lcd.print(Date); // print date (DD-MM-YYYY)
        print_wmonth(month());
      }

      display.printTime(hours, minutes, true);   // overwrite to LCD display
    }
//  }  // deleted 20190827

// http://techblog.wp.xdomain.jp/2018/10/27/arduino_tactile_switch/
  if(digitalRead(count) == LOW){   // when switch on
  if(count_low <= PUSH_SHORT) count_low ++;
  }else{   // switch off state
    count_low = 0;
  }
  if(count_low == PUSH_SHORT){
    Serial.println("Pushed Button!");
    icount = icount + 1 ;
    if(icount == 1 )  lcd.clear();
    displayInfo();   // display the number of visitor and the time
    jcount = jcount + 1 ;
  }
 }  // added 20190827
 }
}

// function for displaying day of the week
void print_wday(byte wday)
{
  lcd.setCursor(5, 1);   // move cursor to column 5, row 1
  switch(wday)
  {
    case 1: lcd.print(" Sunday "); break;
    case 2: lcd.print(" Monday "); break;
    case 3: lcd.print(" Tuesday "); break;
    case 4: lcd.print("Wednesday"); break;
    case 5: lcd.print("Thursday "); break;
    case 6: lcd.print(" Friday "); break;
    default: lcd.print("Saturday ");
  }
}

// function for displaying month of year
void print_wmonth(byte wmonth)
{
  lcd.setCursor( 9, 3);   // move cursor to column 9, row 3
  switch(wmonth)
  {
    case 1: lcd.print("Jan"); break;
    case 2: lcd.print("Feb"); break;
    case 3: lcd.print("Mar"); break;
    case 4: lcd.print("Apr"); break;
    case 5: lcd.print("May"); break;
    case 6: lcd.print("Jun"); break;
    case 7: lcd.print("Jul"); break;
    case 8: lcd.print("Aug"); break;
    case 9: lcd.print("Sep"); break;
    case 10: lcd.print("Oct"); break;
    case 11: lcd.print("Nov"); break;
    default: lcd.print("Dec");
  }
}

void displayInfo()
{     // write information to 20x4 LCD Display and 8x8 matrix Display
  c = char(icount + 48);
  visit[0] = hour() / 10 + '0';
  visit[1] = hour() % 10 + '0';
  visit[2] = char(58) ;  // changed 20190821
  visit[3] = minute() / 10 + '0';
  visit[4] = minute() % 10 + '0';
  visit[5] = char(32);  // changed 20190821

  visit[6] = month() / 10 + '0';
  visit[7] = month() % 10 + '0';
  visit[8] = char(47) ;  // changed 20190821
  visit[9] = day() / 10 + '0';
  visit[10]= day() % 10 + '0';

  if( row == 4 ) row = 0;
  lcd.setCursor(0, row);  // changed 20190821
  lcd.print("Posted");      // changed 20190821
  lcd.setCursor(7, row);  // changed 20190821
  lcd.print( c );
  lcd.setCursor(9, row);  // changed 20190821
  lcd.print(visit);
  Serial.print("Posted ");  // changed 20190821
  Serial.print(visit);         // changed 20190821

  matrix.drawChar( 2, 1, c, HIGH, LOW, 1);
  matrix.write();   // Send bitmap to display
  delay(100);
  row = row + 1;
}

08/07/2019

乱数発生関数で Tank Robot の動きに変化を付ける

Img_20190808_115947 Img_20190808_120054

何時も決められた同じような動きしかしないので、乱数発生関数を利用して、Sketchの数か所を書き直し、Tank Robotの動きに変化を付けてみた。
加えて、Tank Robotが斜め前方に進めるように、左右方向と前方、それぞれの干渉物までの距離を利用して、後方回転で方向変換する時間を調整するようにした。
乱数発生機能を使った事によって、時々意外な動きが加えられたので、見ていて、その動きに飽きなくなった。
電源のパワーが小さいので、これまでと同様に、超音波センサーで検出できない低い障害物などに捕まって、停まってしまう状況はあまり変わらない。
注記1)Sketchの中で、上記以外の新たな改善や変更も行った。
  モーターを低速で動かそうとして「HalfSpeed」という項目を作ったが、値が低いとモーターのパワーも落ちてしまうので、どれくらいの値にするのが良いか悩ましいところだ。ここでは、230としてみた。動画をアップロードしたいところだが・・・
注記2)Tank Robot が計測している示される方向と障害物迄の距離が合っていない。調べると、Sketch上で変数の型を無茶苦茶にして使っていた。いろいろな所から持ってきたり変更したりする間に、確認せず使っていた。これを見直さないとめちゃくちゃな処理になる。事実そうなっている。加えて、サーボモータを任意の角度で正しく止めるには、delayの時間を1000msは必要になる。しかし直進状態で前方との距離を計測する際には、サーボモーターは前方を向いているので、delay時間は必要無いだろう。入れることによって設定した距離で止まらず、障害物に激突してしまう。
ask_pin_F()の中に入れていた「myServo.write(angle)」を外に出して、直進状態と停まって左右を確認する場合のdelay時間を分けられるようにした。
その他、いろいろ変更したので・・・ 08/07 version は削除し、08/08 versionに置き換えた。未だ、問題点などあるかもしれないが・・・

《Sketch 2019/08/08 version》

const int PIN_SONAR_ECHO = 5; // define pin for sensor echo
const int PIN_SONAR_TRIGGER = 6; // define pin for sensor trig
#include <Servo.h>
#include <TM1637Display.h>
#define CLK 7 //can be any digital pin
#define DIO 8 //can be any digital pin
int Fdistance = 0;
float Dlh;
float Drh;
float Dfr; 
int Ls=30 ; // short range threshold 
int Ll=55 ; // long range threshold 
int angle;
int pinSRB= 9; // servo motor output pin (PWM)
int random_No4;
// next pins(10~13) are depended on L298P motorshield
int pinLB = 12; // direction control function
int pinLF = 10; // motors' control chip with speed control function from 10
int pinRB = 13; // direction control function
int pinRF = 11; // motors' control chip with speed control function
int FullSpeed = 255; // max 255
int HalfSpeed = 240; // when the number is less than 180 will be stopp
Servo myServo; // set myservo

TM1637Display display(CLK, DIO);
const uint8_t Letter_F[] = { SEG_A | SEG_E | SEG_F | SEG_G }; // F
const uint8_t Letter_b[] = { SEG_C | SEG_D | SEG_E | SEG_F | SEG_G }; // b
const uint8_t Letter_H[] = { SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // H
const uint8_t Letter_r[] = { SEG_E | SEG_G }; // r
const uint8_t Letter_L[] = { SEG_D | SEG_E | SEG_F }; // L
const uint8_t Letter_A[] = { SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // A
const uint8_t Letter_c[] = { SEG_D | SEG_E | SEG_G }; // c
const uint8_t Letter_t[] = { SEG_D | SEG_E | SEG_F | SEG_G }; // t
const uint8_t Letter_LT[] = { SEG_A | SEG_F | SEG_G }; // <
const uint8_t Letter_GT[] = { SEG_A | SEG_B | SEG_G }; // >

void setup()
{
  Serial.begin(9600);
  pinMode(PIN_SONAR_TRIGGER,OUTPUT);
  pinMode(PIN_SONAR_ECHO,INPUT);
  display.setBrightness(0x0f); // 0x01 << dark bright >> 0x0f
  display.clear();
// Define motor output pin
  pinMode(pinLB,OUTPUT); // pin 12 direction control function
  pinMode(pinLF,OUTPUT); // pin 10 (PWM)
  pinMode(pinRB,OUTPUT); // pin 13 direction control function
  pinMode(pinRF,OUTPUT); // pin 11 (PWM)
  myServo.attach(pinSRB); // Define servo motor output pin(PWM)
}

void Advance() // move to forward
{
  display.setSegments(Letter_F,1,0);
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void Back() // move backward
{
  display.clear();
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  delay(50);
  digitalWrite(pinLB,HIGH); // motor moves to left rear
  digitalWrite(pinRB,HIGH); // motor moves to right rear
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void MidSpeed() // move to forward
{
  display.setSegments(Letter_F,1,0);
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,HalfSpeed);
  analogWrite(pinRF,HalfSpeed);
}

void Stopp() // all wheel stop
{
  display.setSegments(Letter_H,1,0);
  display.setSegments(Letter_A,1,1);
  display.setSegments(Letter_L,1,2);
  display.setSegments(Letter_t,1,3);
  digitalWrite(pinLB,HIGH); // left wheel stop
  digitalWrite(pinRB,HIGH); // right wheel stop
  analogWrite(pinLF,0);
  analogWrite(pinRF,0);
}

void BackRight() // turn right
{
  display.setSegments(Letter_r,1,0);
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB,HIGH);
  digitalWrite(pinRB, LOW); // wheel on the right moves backward
  analogWrite(pinLF,FullSpeed); // from FullSpeed
  analogWrite(pinRF,FullSpeed); // from FullSpeed
}

void BackLeft() // turn left
{
  display.setSegments(Letter_L,1,0);
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB, LOW); // wheel on the left moves backward
  digitalWrite(pinRB,HIGH);
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void loop()
{
labelF:
  long random_No1 = random( 20, 120);
// --- Forward obstacle detection and moving ---
// angle = 90;
  myServo.write(90);
  delay(50);
  ask_pin_F(); // Fdistance

  if(Fdistance <= Ls)
  {
    Stopp(); // stop for a while
    goto label2;
  }
  if((Fdistance > Ls  ) & (Fdistance <= Ll ))
  {
    MidSpeed();
    goto labelF;
  }
  if(Fdistance > Ll )
  {
    Advance();
    goto labelF;
  }

label2:
// angle = 90; // Check the distance ahead again
  myServo.write(90);
  delay(50);
  ask_pin_F();
  if(Fdistance < Ls )
  {
    Back(); // go back a little
    delay(random_No1);
    Stopp();
  }
// Measure left and right space
  angle = 3;
  myServo.write(angle);
  delay(1000);
  ask_pin_F();
  Drh=Fdistance;

  angle = 177;
  myServo.write(angle);
  delay(1000);
  ask_pin_F();
  Dlh=Fdistance;

  angle =90; //added
  myServo.write(angle);
  delay(1000);
  ask_pin_F(); // check forward
  Dfr=Fdistance;

label3:
  if(Dlh > Drh)
  {
    display.setSegments(Letter_GT,1,0);
    delay(300);

      float rn1 = Dlh / Dfr ;

      if( rn1 >= 1.3 ) rn1 = 1.3 ;
      random_No4 = 400 * rn1 ;
      BackRight();
      delay(random_No4);
      Stopp();
      delay(400);
      goto labelF;

  }
  else if( Dlh <= Drh )
  {
    display.setSegments(Letter_LT,1,0);
    delay(300);

      float rn2 = Drh / Dfr ;

      if( rn2 >= 1.3 ) rn2 = 1.3 ;
      random_No4 = 400 * rn2 ;
      BackLeft();
      delay(random_No4);
      Stopp();
      delay(400);
      goto labelF;

  }
}

void ask_pin_F() // Measure the distance at the specified angle
{
  digitalWrite(PIN_SONAR_TRIGGER,LOW);// Set the trigger pin to low for 2uS
  delayMicroseconds(2);
  digitalWrite(PIN_SONAR_TRIGGER,HIGH);// Send a 10uS high to trigger ranging
  delayMicroseconds(10);
  digitalWrite(PIN_SONAR_TRIGGER,LOW);// Send pin low again
  float distance = pulseIn(PIN_SONAR_ECHO,HIGH);// Read in times pulse
  Fdistance = distance/58;// Calculate distance from time of pulse
  delay(60);
  if(( 89 < angle) & (angle < 91)) display.setSegments(Letter_F,1,0);
  if(( 0 < angle) & (angle < 35)) display.setSegments(Letter_r,1,0);
  if(( 145 < angle) & (angle < 180)) display.setSegments(Letter_L,1,0);
  display.showNumberDec(Fdistance,true, 3, 1);
  delay(300);
}

08/06/2019

Arduino Tank Robot Sketch修正

Tank Robotを動かして、その挙動を見ていると、いろいろ気になるところが出てくる。間違えてプログラムを書いていたところもある。
こうすれば、もっと無駄な動きが少なくなるだろうと思って複雑にしてゆくと、逆に思わぬところでフリーズしてしまう。
それでプログラムは、なるべくシンプルにして・・・ 超音波距離測定も、ライブラリーを使っていたが、計測距離が大きく表示されるので、それらの課題も入れて、少し直してみた。
動かしている際の問題点として、下記のようなものがある。
 ①センサーの高さが高いので、高さの低い障害物との距離を計測出来ない。
 ②平面を持った障害物に対して、棒や細い柱のようなものは上手く補足できない。
 ③クローラーの高さに近い高さの窪みに嵌り込んで、動けなくなる。
 ④段差がある場所や、ちょっと太めの電線ケーブル等を跨いでしまうと、動かなくなる場合がある。
 ⑤摩擦係数の低い床では、クローラーが滑ってスケートでもしているような動きになる。
 ⑥超音波センサーの高さを床面から50mmぐらいの高さで設置できれば、上記の課題の幾つかは解消できるかもしれない。

《Sketch 2019/8/6 version》

const int PIN_SONAR_ECHO = 5; // define pin for sensor echo
const int PIN_SONAR_TRIGGER = 6; // define pin for sensor trig
#include <Servo.h>
#include <TM1637Display.h>
#define CLK 7 //can be any digital pin
#define DIO 8 //can be any digital pin
double Fdistance = 0;
double Dlh;
double Drh;
double Dfr;
double Ls = 30; // short range threshold
double Ll = 55; // long range threshold
int angle;
int pinSRB= 9; // servo motor output pin (PWM)

// next pins(10~13) are depended on L298P motorshield
int pinLB = 12; // direction control function
int pinLF = 10; // motors' control chip with speed control function from 10
int pinRB = 13; // direction control function
int pinRF = 11; // motors' control chip with speed control function

int FullSpeed = 255; // max 255
int HalfSpeed = 200; // when the number is less than 180 will be stopp
Servo myServo; // set myservo

TM1637Display display(CLK, DIO);
const uint8_t Letter_F[] = { SEG_A | SEG_E | SEG_F | SEG_G }; // F
const uint8_t Letter_b[] = { SEG_C | SEG_D | SEG_E | SEG_F | SEG_G }; // b
const uint8_t Letter_H[] = { SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // H
const uint8_t Letter_r[] = { SEG_E | SEG_G }; // r
const uint8_t Letter_L[] = { SEG_D | SEG_E | SEG_F }; // L
const uint8_t Letter_A[] = { SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // A
const uint8_t Letter_c[] = { SEG_D | SEG_E | SEG_G }; // c
const uint8_t Letter_t[] = { SEG_D | SEG_E | SEG_F | SEG_G }; // t
const uint8_t Letter_LT[] = { SEG_A | SEG_F | SEG_G }; // <
const uint8_t Letter_GT[] = { SEG_A | SEG_B | SEG_G }; // >

void setup()
{
  Serial.begin(9600);
  pinMode(PIN_SONAR_TRIGGER,OUTPUT);
  pinMode(PIN_SONAR_ECHO,INPUT);
  display.setBrightness(0x0f); // 0x01 << dark bright >> 0x0f
  display.clear();
// Define motor output pin
  pinMode(pinLB,OUTPUT); // pin 12 direction control function
  pinMode(pinLF,OUTPUT); // pin 10 (PWM)
  pinMode(pinRB,OUTPUT); // pin 13 direction control function
  pinMode(pinRF,OUTPUT); // pin 11 (PWM)
  myServo.attach(pinSRB); // Define servo motor output pin(PWM)
}

void Advance() // move to forward
{
  display.setSegments(Letter_F,1,0);
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void Back() // move backward
{
  display.clear();
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  delay(50);
  digitalWrite(pinLB,HIGH); // motor moves to left rear
  digitalWrite(pinRB,HIGH); // motor moves to right rear
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void MidSpeed() // move to forward
{
  display.setSegments(Letter_F,1,0);
  digitalWrite(pinLB,LOW); // left wheel moves forward
  digitalWrite(pinRB,LOW); // right wheel moves forward
  analogWrite(pinLF,HalfSpeed);
  analogWrite(pinRF,HalfSpeed);
}

void Stopp() // all wheel stop
{
  display.setSegments(Letter_H,1,0);
  display.setSegments(Letter_A,1,1);
  display.setSegments(Letter_L,1,2);
  display.setSegments(Letter_t,1,3);
  digitalWrite(pinLB,HIGH); // left wheel stop
  digitalWrite(pinRB,HIGH); // right wheel stop
  analogWrite(pinLF,0);
  analogWrite(pinRF,0);
}

void BackRight() // turn right
{
  display.setSegments(Letter_r,1,0);
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB,HIGH);
  digitalWrite(pinRB, LOW); // wheel on the right moves backward
  analogWrite(pinLF,FullSpeed); // from FullSpeed
  analogWrite(pinRF,FullSpeed); // from FullSpeed
}

void BackLeft() // turn left
{
  display.setSegments(Letter_L,1,0);
  display.setSegments(Letter_b,1,1);
  display.setSegments(Letter_A,1,2);
  display.setSegments(Letter_c,1,3);
  digitalWrite(pinLB, LOW); // wheel on the left moves backward
  digitalWrite(pinRB,HIGH);
  analogWrite(pinLF,FullSpeed);
  analogWrite(pinRF,FullSpeed);
}

void loop()
{
labelF:
// --- Forward obstacle detection and moving ---
  angle = 90;
  ask_pin_F(); // Fdistance
  if(Fdistance <= Ls)
  {
    Stopp(); // stop for a while
    goto label2;
  }
  if((Fdistance > Ls) & (Fdistance <= Ll))
  {
    MidSpeed();
    goto labelF;
  }
  if(Fdistance > Ll)
  {
    Advance();
    goto labelF;
  }

label2:
  angle = 90; // Check the distance ahead again
  ask_pin_F();
  if(Fdistance < Ls )
  {
    Back(); // go back a little
    if(Fdistance < 30 ) delay( 30);
    if(Fdistance < 20 ) delay( 60);
    if(Fdistance < 10 ) delay(120);
  Stopp();
  }
// Measure left and right space
  angle = 3;
  ask_pin_F();
  Drh=Fdistance;
  delay(700);
  angle = 177;
  ask_pin_F();
  Dlh=Fdistance;
  delay(700);
  angle =90; //added
  ask_pin_F(); // check forward
  Dfr=Fdistance;
  delay(700);

if((Dfr > Dlh) & (Dfr > Drh)) goto labelF; // added
if(Dlh < Drh)
{
  display.setSegments(Letter_LT,1,0);
  delay(1000);
  BackLeft();
  delay(600);
  Stopp();
  delay(400);
  goto labelF;
}
//
else
{
  display.setSegments(Letter_GT,1,0);
  delay(1000);
  BackRight();
  delay(600);
  Stopp();
  delay(400);
  goto labelF;
}
}

void ask_pin_F() // Measure the distance at the specified angle
{
  myServo.write(angle);
  delay(10);
  digitalWrite(PIN_SONAR_TRIGGER,LOW);
  delayMicroseconds(1);
  digitalWrite(PIN_SONAR_TRIGGER,HIGH);
  delayMicroseconds(11);
  digitalWrite(PIN_SONAR_TRIGGER,LOW);
  unsigned long t = pulseIn(PIN_SONAR_ECHO,HIGH);
  unsigned long distance = t*0.017;
  Fdistance = distance;
  if((  89 < angle) & (angle <  91)) display.setSegments(Letter_F,1,0);
  if((    0 < angle) & (angle <  10)) display.setSegments(Letter_r,1,0);
  if(( 170 < angle) & (angle < 180)) display.setSegments(Letter_L,1,0);
  display.showNumberDec(distance / 100,true, 1, 1);
  display.showNumberDec(int( distance - int(distance/100)*100 )/10,false, 1, 2);
  display.showNumberDec(int( distance - int(distance/10)*10 ),false, 1, 3);
  delay(30);
}

08/04/2019

Arduino Tank Robot

Img_20190803_165802 Img_20190803_165720
Img_20190803_165812 Img_20190803_165821
100均セリアで Arduino UNOとMotor Shield が丁度入る カードケースを見つけたので、小型のロボットタンクのシャシーの上に載せてみた。
シャシーとケースとの間は、M3のネジで接合してある。
ボディの前方は、超音波測定器(HC-SR04)を設置し、前方の障害物との距離を計測する。
HC-SR04は、ミニブレッドボードを使い取り付けた。ミニブレッドボードの底面の突起を削って平らにして、サーボモータのアーム部分に両面テープで接着し、表側のピン穴を使ってHC-SR04を差し込み取り付けたのだ。
距離の測定には、「NewPing」ライブラリーを使った。

ロボットが動いている時に「距離をどのように計測し、それから何を判断したか」を、僕が見て分かるようにしたいと思い、TM1637 4桁7セグメント表示器を付けた。 表示器は4桁なので、基本的に、左1桁は、進行方向に対する判断結果表示を、残り3桁は、計測した方向にある障害物との距離をcmで表示するようにした。
このような仕掛けを組み込んだので、不具合発生時、問題の調査が行いやすかった。 

表示内容は、7セグメントでのASCII文字表示に従い表示するようにした。
①前方障害物との距離・・・計測した距離の単位はcmで、3桁で表示
②モーター制御の方向
 前進(1桁目に「F」表示 及び 前方障害物との距離を3桁で表示)、停止(「HALt」と表示)、後退(「bAc」と表示)、左方向へ後退(「LbAc」と表示)、右方向へ後退(「rbAc」と表示)
③左右方向の余裕距離・・・計測した距離の単位はcmで表示
 左側より右側が広く空いている場合は、1桁目に < のASCII文字表示で示し、距離を3桁で表示。
 右側より左側が広く空いている場合には、1桁目に > のASCII文字で示し、同様に距離を3桁で表示した。

 注意)事例として、ロボットが一旦停止して表示する1桁目が「<」の表示の場合は、右側が左側より広く空いているので、左方向にバックしてから直進し、右方向に進む。

部品構成
 Arduino:UNO
 Motor Shield:Rasbee L298P  @591
 Sensor:HC-SR04 超音波センサーモジュール
 ServoMotor:Lemcos MG 996R(メタルギヤ デジタルRCサーボモーター) @480
 Battery:KEEPPOWER IMR 18650サイズ互換 2600mAh リチウムマンガンバッテリー 
 Display:0.36インチ(
42X24X12mm) 4桁7セグメント (ドライブチップはTM1637 )  @188
 本体ケース:100均セリアのカードケース
 シャシー:KKmoon ロボットタンク クローラーシャーシ  @2499
 Switch:オン/オフSPDTミニ2ポジションラッチトグルスイッチ
その他
 Battery充電器:XTAR VC2S USB 急速 電池 マルチサイズ対応 充電器
 基板の固定用として、六角ナットねじスペーサ(長さ10mmのものを使用)
など

本体に入れた頭脳となる基板は、 arduino UNO の上に arduino専用の L298P motor shield を載せた2層構造にしてある。
電池は、カードケースの裏蓋の中に収めることが出来た(両面テープで電池フォルダーを接着)。
カードケース内の高さは、それほど余裕が無いので、ピン端子と干渉しないように注意して配置する必要がある。
接続ピンは、Motor Shieldカードの左右に配置されると思うので、Battery Holder はなるべく中央部に配置するのが良いと思う。
USB端子と電源の両方を使えるように、ケースに穴を開け、ポートアクセスが可能なようにした。
バッテリ電源用ON/OFFスイッチとして、スナップスイッチを設置した。


配線接続について
1)Motor Shield を使う場合には、PWMピンは使用方法に指定があるので、そのように使わないと制御できない。
 (参考:L298P 2-A Dual H-Bridge Motor Shield for Arduino .pdf)
 ①詳細は、上記pdfを確認する事。表にして記載されている。
 ②2つのブラシ付きDCモーターを、本シールドのモーターAとモーターBの端子に接続する事で使用できる。
 ③方向制御AはD12ピン、方向制御BはD13ピンをHIGHまたはLOWにすることで、モーターの方向を制御できる。
 ④D10ピンとD11ピンにより、モーターの速度を制御できる。
 ⑤従って、D10~D13ピンは内部で使われるので、別の目的のピンをD10~D13には接続しない事。
L298p-motor-shield L298poriginal2
Img_20190804_110801 Img_20190804_110734

2)センサー用サーボモーターの接続は、Motor Shield の「SERVO(G +5 9)」と書かれたピン(Pin9)に刺す。
  写真では、G(GND)は、茶色の配線
       +5は、赤色の配線
       9 は、オレンジ色の配線
Img_20190803_165907 Img_20190803_165941

3)超音波センサー(HC-SR04)のピン接続は、Echo-Pin5、Trig-Pin6 に刺す。Motor Shield 側のピン接続部分は、オス用・メス用両方が用意されているのでどちらを使ってもよい。+5V電源とGNDピンは、接続しやすく、バッテリーなどと干渉しない部分を使えばよい。
  写真では、GND は 青色の配線
       Echo 
は 黄色の配線
       Trig は 緑色の配線
       Vcc は 赤色の配線

4)4桁7セグメント表示器の接続は、
 CLK - Pin7(写真では黄色の配線)
 DIO - Pin8(写真ではオレンジの配線)
 VCC - 接続しやすい5V端子へ接続(写真では赤色の配線)
 GND - 接続しやすいGND端子へ接続(写真では茶色の配線)
Img_20190804_110648
 4桁7セグメント表示器のケースへの取り付けは、上の写真のように2本のボルトで止めてある。

5)バッテリー、スイッチ、Motor Shield 外部電源端子間を接続



《Sketch》

// Obstacle avoidance Tank Robot program 2019/08/03
// New algorithm version My Spice Cabinet

#include <NewPing.h>
const int PIN_SONAR_ECHO = 5; // define pin for sensor echo
const int PIN_SONAR_TRIGGER = 6; // define pin for sensor trig
const int MAX_DISTANCE = 200;
NewPing sonar(PIN_SONAR_TRIGGER, PIN_SONAR_ECHO, MAX_DISTANCE);
#include <Servo.h>

#include <TM1637Display.h>
#define CLK 7 //can be any digital pin
#define DIO 8 //can be any digital pin
double Fdistance = 0;
double Dlh;
double Drh;
double Ls = 30; // short range threshold
double Ll = 55; // long range threshold
int angle;
int pinSRB= 9; // servo motor output pin (PWM)

// next pins(10~13) are depended on L298P motorshield
int pinLB = 12; // direction control function
int pinLF = 10; // motors' control chip with speed control function from 10
int pinRB = 13; // direction control function
int pinRF = 11; // motors' control chip with speed control function

int FullSpeed = 255; // max 255
int HalfSpeed = 233;
Servo myServo; // set myservo

TM1637Display display(CLK, DIO);
const uint8_t Letter_F[] = { SEG_A | SEG_E | SEG_F | SEG_G };              // F
const uint8_t Letter_b[] = { SEG_C | SEG_D | SEG_E | SEG_F | SEG_G }; // b
const uint8_t Letter_H[] = { SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // H
const uint8_t Letter_r[] = { SEG_E | SEG_G };              // r
const uint8_t Letter_L[] = { SEG_D | SEG_E | SEG_F }; // L
const uint8_t Letter_A[] = { SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G }; // A
const uint8_t Letter_c[] = { SEG_D | SEG_E | SEG_G };             // c
const uint8_t Letter_t[] = { SEG_D | SEG_E | SEG_F | SEG_G }; // t
const uint8_t Letter_LT[] = { SEG_A | SEG_F | SEG_G }; // <
const uint8_t Letter_GT[] = { SEG_A | SEG_B | SEG_G }; // >

void setup()
{
Serial.begin(9600);
display.setBrightness(0x0f);   // 0x01 << dark bright >> 0x0f
display.clear();
// Define motor output pin
pinMode(pinLB,OUTPUT);  // pin 12 direction control function
pinMode(pinLF,OUTPUT);   // pin 10 (PWM)
pinMode(pinRB,OUTPUT);  // pin 13 direction control function
pinMode(pinRF,OUTPUT);   // pin 11 (PWM)
myServo.attach(pinSRB);   // Define servo motor output pin(PWM)
}

void Advance() // move to forward
{
display.setSegments(Letter_F,1,0);
digitalWrite(pinLB,LOW); // left wheel moves forward
digitalWrite(pinRB,LOW); // right wheel moves forward
analogWrite(pinLF,FullSpeed);
analogWrite(pinRF,FullSpeed);
}

void Back() // move backward
{
display.clear();
display.setSegments(Letter_b,1,1);
display.setSegments(Letter_A,1,2);
display.setSegments(Letter_c,1,3);
delay(50);
digitalWrite(pinLB,HIGH);   // motor moves to left rear
digitalWrite(pinRB,HIGH);   // motor moves to right rear
analogWrite(pinLF,FullSpeed);
analogWrite(pinRF,FullSpeed);
}

void MidSpeed() // move to forward
{
display.setSegments(Letter_F,1,0);
digitalWrite(pinLB,LOW);   // left wheel moves forward
digitalWrite(pinRB,LOW);   // right wheel moves forward
analogWrite(pinLF,HalfSpeed);
analogWrite(pinRF,HalfSpeed);
}

void Stopp() // all wheel stop
{
display.setSegments(Letter_H,1,0);
display.setSegments(Letter_A,1,1);
display.setSegments(Letter_L,1,2);
display.setSegments(Letter_t,1,3);
digitalWrite(pinLB,HIGH);   // left wheel stop
digitalWrite(pinRB,HIGH);   // right wheel stop
analogWrite(pinLF,0);
analogWrite(pinRF,0);
}

void BackRight() // turn right
{
display.setSegments(Letter_r,1,0);
display.setSegments(Letter_b,1,1);
display.setSegments(Letter_A,1,2);
display.setSegments(Letter_c,1,3);
digitalWrite(pinLB,HIGH);
digitalWrite(pinRB, LOW);       // wheel on the right moves backward
analogWrite(pinLF,FullSpeed); // from FullSpeed
analogWrite(pinRF,FullSpeed); // from FullSpeed
}

void BackLeft() // turn left
{
display.setSegments(Letter_L,1,0);
display.setSegments(Letter_b,1,1);
display.setSegments(Letter_A,1,2);
display.setSegments(Letter_c,1,3);
digitalWrite(pinLB, LOW);   // wheel on the left moves backward
digitalWrite(pinRB,HIGH);
analogWrite(pinLF,FullSpeed);
analogWrite(pinRF,FullSpeed);
}

void loop()
{
labelF:
// --- Forward obstacle detection and moving ---
angle = 90;
ask_pin_F();   // Fdistance
if(Fdistance <= Ls)
{
Stopp();         // stop for a while
goto label2;
}
if((Fdistance > Ls) & (Fdistance <= Ll))
{
MidSpeed();
goto labelF;
}
if(Fdistance > Ll)
{
Advance();
goto labelF;
}

label2:
angle = 90;   // Check the distance ahead again
ask_pin_F();
if(Fdistance < Ls )
{
  Back();         // go back a little
  if(Fdistance < 30 ) delay( 50);
  if(Fdistance < 20 ) delay(100);
  if(Fdistance < 10 ) delay(100);
  Stopp();
}
// Measure left and right space
angle = 3;
ask_pin_F();
Dlh=Fdistance;
angle = 177;
ask_pin_F();
Drh=Fdistance;

 

if(Dlh < Drh)
{
display.setSegments(Letter_LT,1,0);
delay(1000);
BackLeft();
delay(600);
Stopp();
delay(400);
goto labelF;
}
//
else
{
display.setSegments(Letter_GT,1,0);
delay(1000);
BackRight();
delay(600);
Stopp();
delay(400);
goto labelF;
}
}

void ask_pin_F()   // Measure the distance at the specified angle
{
myServo.write(angle);
delay(10);
unsigned long microSec = sonar.ping_median();
unsigned long distance = sonar.convert_cm(microSec);
Fdistance = distance;
display.showNumberDec(distance / 100,true, 1, 1);
display.showNumberDec(int( distance - int(distance/100)*100 )/10,false, 1, 2);
display.showNumberDec(int( distance - int(distance/10)*10 ),false, 1, 3);
delay(30);
}

《備考》
参考としたブログなど
1)http://www.handsontec.com/dataspecs/arduino-shield/L298P%20Motor%20Shield.pdf
  L298P Motor Shield の使い方のマニュアル

2)https://iot.keicode.com/arduino/arduino-sonar-hc-sr04.php
  超音波センサーの使い方 NewPing の使い方など

《あとがき》
 前回のブログでは、Motor Shield に問題があって中断とした。既に廃却してしまったので検証は出来ないが、もしかすると、モータを低速で回転させたいと思って選んだ制御用数値が、使えない範囲のものを選んだ可能性が高い。また、L298P Motor Shield はPWMピンとして使えるものが、前述の配線接続についての項目の最初の絵にある表のように指定されているので、それを守らないと制御できない。
 超音波センサーの位置が高い場所に設置してしまった事と、シャシーの幅が広いので・・・(低い位置に設置する良いアイデアが思い浮かばなかったので・・・)時々、低い場所にある障害物に衝突して、動けなくなることがある。Sketchを改善するかセンサーの位置を変更するなどする必要がありそう
 Sketchの中で「l(Lの小文字)」と「|(理論和の記号)」の違いが分かりにくいが、Sketch の中で「|(理論和の記号)」を使っているのは、TM1637のDisplay設定の中だけである。他の部分は全てLの小文字「l」である。
 LsとLlの閾値を変えると、タンクの挙動も大きく変わってくる。遊ばれる環境で数値を変えてみるといい。
 前回記載のタンクロボットは、Sketchも含めて今回のものに改新したので、前回のブログも抹消する事にした。

より以前の記事一覧

July 2020
Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Recent Trackbacks

無料ブログはココログ