Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Sansan AIくん時計を作ってみたよ [Arduino]

はじめまして、Sansan事業部 プロダクト開発部の古石です。
普段はWEBエンジニアとしてSansanの開発をしています。

タイトルからしてもう場違いな感じがするのですが、
今回は趣味でAruduino3Dプリンタを使ってSansanのマスコットキャラクター?AI(あい)くんの時計を作ったよ、という話です。

f:id:furuishi_sansan:20200318170735j:plain

f:id:furuishi_sansan:20200318170627j:plain
手を振ったらウィンクしてくれます。かわいい!

参考: AIくんとは
jp.corp-sansan.com

最近3Dプリンタを買ったので、元々趣味で齧っていたArduinoと組み合わせておもちゃを作ってみたいなと思い、今回に至りました。
今回は製作しながら記事を書いていたので製作日誌・過程みたいなものになります。

1. 全体のイメージを決める

f:id:furuishi_sansan:20200318045245j:plain
書いているときはテンション高いのですが、後で見返すと小学校の自由研究かな?って気がしてきますね...

残り時間が土日しかないという制限もあったので、機能はこの程度にしておきます。
特にIoT的なこともしないので、レベル的にはちょうどArduino入門ぐらいですね。

  • 基本的には時計
  • 音を出すと時計から温度へ表示を切り替える
  • 手を振ると笑ってくれる(重要)

2. 用意するもの

f:id:furuishi_sansan:20200314205811j:plain
ほとんどいつ買ったかわからない代物なんでメーカーとかわからず...すみません...

メイン

  • Arduino Nano
  • 7セグメントディスプレイ
  • 時計モジュール(ボタン電池CR2032を忘れずに)
  • 温湿度センサー(プルアップ抵抗として10kΩ抵抗も用意します)
  • サウンドセンサー
  • 赤外線センサー
  • 切り替えスイッチ

検証用

  • ブレッドボード
  • ジャンパ線

製作用

f:id:furuishi_sansan:20200318041305j:plain

  • ユニバーサル基板
  • ナイロンネジとかスペーサー(3Dプリンタで作ったガワにつける用)
  • ピンヘッダ、ピンソケット、ピンコネクタ(ケーブル自作用です)
  • 9V電池

その他

  • 3Dプリンタ(私のはNova3Dという4万ぐらいの安いやつです)
  • スプレー塗料
  • その他工具とかもろもろ

ソフト

  • Aruduino IDE : コーディングとArduinoに書き込む用
  • Fritzing : 回路設計用のツール IDEとしても使えるらしい(けど使ったことない)
  • Fusion360 : ガワ設計用の3Dモデリングツール

社内で金額について質問があったのでこちらでも触れたいと思います。
パーツだけだと2,000円もしないと思いますが、基本的にバラで売っていないので初回は全部で1万超えちゃうかもしれません。
ちなみプリンタを除いて一番高いのは... 3Dプリンタ用のレジンです。ランニングコスト高い。辛い。

3. パーツの動作確認

電子工作のパーツはノーブランドも多く、初期不良で動かないものがあったりするので、組み込んでからショボーンしないためにも一つ一つ検証していきます。
ついでにスケッチ例を見て、使い方を覚えていきます。
(関数を網羅しているような親切なスケッチが多いので、ググらなくてもすぐ使えるようになるのが嬉しいですね!)

Arduino Nano

f:id:furuishi_sansan:20200318035859j:plainf:id:furuishi_sansan:20200318135855p:plain
右はサイズ比較として参考までに。Arduino Leonardo互換のUSBサイズのマイコンです。

マイコン本体です。各社から廉価版が出ていて、500円程度で買えると思います。
家に余っていたのが Nano だったので使いましたが、mini-usbのため少し不便です。
Arduino Microであればmicro-usbが使えるので、新しく買うならそちらがおすすめです。

ピンをはんだ付けしてPCと繋いだら、↓のスケッチを使って検証します。

【検証】★これからこんな感じで書いていきます
ライブラリ : なし(あるときは、ツール→ライブラリを管理→ 検索)
スケッチ例 : 01.Basics/Blink(ファイル→スケッチ例)
結果 : Lチカ(LEDがチカチカ)したので、とりあえずは問題なさそうです。

7セグメントディスプレイ

f:id:furuishi_sansan:20200314162842j:plainf:id:furuishi_sansan:20200318140453p:plain
本当は14セグメントが欲しかったのですが、さすがに翌日配送で手に入るモノではなかったので諦めました...

これだけは新規に買いました。
チップなしのディスプレイは持っていましたが、こちらは自分で実装することが多く面倒なのでTM1637という制御チップがついたものを調達しました。(手抜き)

【検証】
ライブラリ : TM1637 GitHub - avishorp/TM1637: Arduino library for TM1637 (LED Driver)
スケッチ例 : TM1637Test
結果 : ちゃんと動きました、発色もきれいです。

f:id:furuishi_sansan:20200314221629j:plain

RTCモジュール

f:id:furuishi_sansan:20200314162919j:plainf:id:furuishi_sansan:20200318140934p:plain

こちらはDS3231というチップを搭載したRTC (Real Time Clock)です。
Arduinoが起動していなくても、ボタン電池(CR2032)を使って時刻を保持してくれます。
(ボタン電池買ってなくて慌てましたが、普通にコンビニに売ってて感動しました。)

接続はSCLSDAというピンを使います。I2Cというシリアル通信に使うものらしいです。
Arduino nanoの場合、SDA=A4 , SCL=A5 ピンを使います。
(参考 : Arduino公式ドキュメント https://content.arduino.cc/assets/Pinout-NANO_latest.pdf

【検証】
ライブラリ : RTClib GitHub - adafruit/RTClib: A fork of Jeelab's fantastic RTC library
スケッチ例 : DS3231
結果 : シリアル通信で情報を送ってくれるので、確認します。
ツール→シリアルモニタ (改行コードCRLF 、bpsはSerial.begin(xxxx)の値)
f:id:furuishi_sansan:20200318141101p:plain
大丈夫そうですね。コード抜いたあとに1,2時間放置していましたが、目立ったずれは無かったです。

温湿度センサー

f:id:furuishi_sansan:20200315024012j:plainf:id:furuishi_sansan:20200318141710p:plain

左が今回使うDHT22(AM2302)というタイプのセンサーです。
右のDHT11は安くてよく売っているのですが、精度が低い(少数部が取れない)ので、少しお高いですがDHT22のほうがおすすめです。

4線ありますが、1つはダミーなので放置です。
プルアップ抵抗を入れたほうが良いとのことなので、10kΩほどセットしています。

【検証】
ライブラリ: DHT-sensor-library GitHub - adafruit/DHT-sensor-library: Arduino library for DHT11, DHT22, etc Temperature & Humidity Sensors
スケッチ例: DHTester
結果: こちらもシリアルモニタで確認します。
f:id:furuishi_sansan:20200318142632p:plain
市販の温度計と比べて温度が0.5〜1.0℃ほど高かったですが、許容します。

赤外線センサー

f:id:furuishi_sansan:20200315023141j:plainf:id:furuishi_sansan:20200318142745p:plain

シンプルなセンサーです。引き出しの奥底から出てきました。動くのか不安...
感度は本体についているネジを回して調整します。

【検証】
ライブラリ : なし
スケッチ例 : 手をかざすと反応するように適当に書いてみました。

#define LED 13
#define SENSOR_PIN 2
int isDetected = LOW;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  Serial.begin(9600);
}

void loop() {

  // 状態が同じなら何もしない
  if (isDetected == digitalRead(SENSOR_PIN)) {
    delay(100);
    return;
  }

  isDetected = digitalRead(SENSOR_PIN);
  if (isDetected == LOW)
  {
    Serial.println("detected!");
    digitalWrite(LED, HIGH);
  } else {
    Serial.println("free");
    digitalWrite(LED, LOW);
  }
  delay(100);

}

結果 : 手をかざすと、本体のLチカとシリアル通信がされました。ノープロブレムです。

サウンドセンサー

f:id:furuishi_sansan:20200318160156j:plainf:id:furuishi_sansan:20200318160103p:plain
回路図は後で買い直した3pinのほうに変えています

こちらも引き出しから出てきました。たぶん何かのセットに付いてきたおまけだと思います。
DO(Digital Out)AO(Analog Out)がありますが、今回はDOを使います。
感度は本体についているネジを回して調整します。

【検証】
ライブラリ : なし
スケッチ例:

#define LED 13
#define SENSOR_PIN 3

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  Serial.begin(9600);
}

void loop() {
  int sounded = digitalRead(SENSOR_PIN);
  Serial.println(sounded);
  delay(100);
}

結果 :
f:id:furuishi_sansan:20200318143313p:plain
...うーん、調整してもマイクを強く叩かないと反応しないレベルだったので、急いでAmaozonで代替品を注文しました。

4. パーツを組み合わせて動くようにする

さて、役者は揃ったので組み合わせていこう...と思ったらそうすんなりとは行きません。

マルチスレッドっぽくする

センサーで入力待ちのループと、ディスプレイを秒単位で表示するループ...2つのタスクを同時にこなしたい!となるとArduinoでは結構面倒です。
自前で実装する時間と技術が無いので、ここもライブラリの力を借ります。

Arduino Thread https://github.com/ivanseidel/ArduinoThread()github.com

Arduinoでマルチスレッド風の書き方ができるライブラリです。
スケッチ例にも全部載っていますが、今回使う分にはこれだけで大丈夫です。作者に感謝...

#include <ThreadController.h>

ThreadController controller = ThreadController();
Thread hogeThread = Thread();
Thread fugaThread = Thread();

void setup() {
  hogeThread.onRun(doHoge());
  hogeThread.setInterval(1000);

  fugaThread.onRun(doFuga());
  fugaThread.setInterval(3000);

  controller.add(&clockThread);
  controller.add(&soundThread);
}

void loop() {
  controller.run();
}

void doHoge() {
  Serial.println("hoge");
}

void doFuga() {
  Serial.println("fuga");
}

補足1 : 公式から Scheduler という並列処理ができるライブラリが出ていますが、Arduino DueなどSAM/SAMDアーキテクチャのチップ専用のため、Nanoでは使えません。)
補足2 : このライブラリはThreadとなっていますが、実際は割り込み処理をよしなにWrapしてくれているものなので、厳密にやろうとしてもミリ秒単位でずれが生じます。

スケッチを書いて全部組み合わせる

ブレッドボードに載せる、スケッチを書く、を繰り返しつつ組み上げていきます。

f:id:furuishi_sansan:20200315222124j:plain
だいぶごちゃごちゃしてきました

組み合わせたときに実装にはまったところのコードを載せておきます。

コロンの表示方法

他にもいろいろありましたが、showNumberDecExを使うやり方が簡単でした。

// :の点滅の出し分け
if (isBlink) {
  display.showNumberDecEx(now.hour(), 0x40, true, 2, 0); // expect "00:__"
  display.showNumberDec(now.minute(), true, 2, 2);       // expect "__ 00"
} else {
  display.showNumberDecEx(now.hour(), 0, true, 2, 0);    // expect "00 __"
  display.showNumberDec(now.minute(), true, 2, 2);       // expect "__ 00"
}
isBlink = !isBlink;
7セグに自由に表示する

SEG_Xにあたる記号はincludeしてあるファイルを見るか、Wikipediaを見ればわかります。

const uint8_t SEG_FACE_WINK[] = {
  0,                                               // expect " "
  SEG_A | SEG_B | SEG_F,                           // except "^"
  SEG_G,                                           // except "-"
  0                                                // expect " "
};
display.setSegments(SEG_FACE_WINK);
温度の表示

最後に℃を混ぜるためにencodeDigitを使っていますが、絶対もっと賢いやり方ある。

int t = int(dht.readTemperature() * 10);
uint8_t segTemperature[] = { 0x00, 0x00, 0x00, 0x00 };
segTemperature[0] = display.encodeDigit(t / 100 % 10);
segTemperature[1] = display.encodeDigit(t / 10 % 10);
segTemperature[2] = display.encodeDigit(t % 10);
segTemperature[3] = display.encodeDigit(0x0c);
display.setSegments(segTemperature); // expect "00.0C"

電池駆動にする

Arduino Nanoの推奨電圧は7〜12Vです。
部品が少なければ6Vでも動くので、当初は単4(1.5v)x4=6Vで動かそうと思っていましたが、少し電圧が足りなくて動かず...
アップコンバータも持ち合わせていなかったので、急遽余っていた9V電池を使いました。
Arduinoの VINピンGNDピンに繋げば動きます。

5. ユニバーサル基板に移行

本当はちゃんと設計したほうが良いのですが、タイムリミットが近づいてきたので、考えもなしにユニバーサル基盤に載せはじめちゃいました。

f:id:furuishi_sansan:20200318013611j:plain
裏面は魔界なので見せられません

この段階で動くか確認していきます。

途中動かない事故に合いましたが、なんとか動かせました。
動かない原因はだいたい「ピンの指す場所間違えている」「はんだが甘い」「ショートしている」の3つぐらいなので、順番に確認していくことでなんとかなると思います。

f:id:furuishi_sansan:20200318024553j:plain

余談ですが、ケーブルは長さへの謎のこだわりで自作してしまいました。
時間と皮膚と爪を犠牲にするので、丁度いいジャンパ線があるならおすすめしません...

f:id:furuishi_sansan:20200317123216j:plainf:id:furuishi_sansan:20200317190827j:plain
でもこういう作業好き

6. 3Dモデルを作る

Fusion360でモデルを作っていきます。
(印刷に3時間以上かかるので実際は並行して作業していました。)

f:id:furuishi_sansan:20200318144155p:plainf:id:furuishi_sansan:20200318144200p:plain

表に見えない部分で作ったのはこんな感じです。

  • ユニバーサル基盤用のねじ穴
  • 前面センサー用の切り欠き、台
  • 背面と底面に通気用のスリット
  • 電池ボックス
  • 電源スイッチ用の穴
  • ガワをくっつけるための磁石用の穴

他にも手を可動式にしたりとか、色々やりたいことはありましたが断念…

いざ印刷!

ちなみにNova3Dは光造形方式なのでレジンを使うタイプです。FDM方式より高精度にプリントできるのですが、レジンが高い、後処理(アルコールでレジン落とす→紫外線硬化)が面倒、シンプルに臭い、と中々クセはあります。

f:id:furuishi_sansan:20200318144332j:plainf:id:furuishi_sansan:20200318144338j:plain
一気に印刷できないので、小分けにしました。あと確実に印刷したかったので、サポートをがっつり入れています。

また余談ですが、付着したレジンを落とす用のアルコールがコロナの影響で売り切れてました...恐るべし...

7. 塗装

3Dプリンタは黒色のレジンを使ったので、サーフェイサー(グレー)で下地を塗っています。
その上から青色のスプレーで塗装していきます。

ここで大失敗。
本当はヤスリがけや重ね塗りをした方が良かったのですが、時すでに締め切り前日。
ほぼ下処理なしでやってしまったが故に、塗り不足と粗が出てしまいました…

f:id:furuishi_sansan:20200318112330j:plain
線部分はガンダムマーカーを使ってます。当日の朝に書くものじゃないですね。ミスった。

なんだかちょっとチープな感じになってしまいました。もっとマットな質感で彩度控えめのほうが良かったのかもしれません。
あと、白色の塗料を買い忘れていたことに気が付いたので、手足はサーフェイサーのままにします…やっちまった…

8. 完成

最後に組み合わせていきます。
f:id:furuishi_sansan:20200318120134j:plain
手足の接続部を作っていないので、接着剤を使ってしまいます…

ついに完成!!
せっかくなのでオフィスで撮影しました。

f:id:furuishi_sansan:20200318170018j:plainf:id:furuishi_sansan:20200318170312j:plain
持ったらセンサー反応しちゃいました、なんかかわいい。

なかなかかわいくできたので満足です。
ただ、心残りというか、塗装に関しては本気の反省点ですね...

9. 最後に

時間があれば電波時計化したり、アラートメール受け取ったら光るみたいなIoT的な使い方もしてみたいですね。
もしかしたら次はパトランプ風AIくんができているかもしれません。
とりあえず、次は余裕をもって計画的にやろうと心に誓いました。

ちなみに弊社ではFusion360の社内勉強会があったり、3Dプリンタで自作キーボード製作している猛者が在籍していたりするので、興味がある方はぜひこちらのページへどうぞ。(宣伝)

jp.corp-sansan.com
buildersbox.corp-sansan.com


以上、お疲れさまでした。

© Sansan, Inc.