エンジニアパパの育休序章

はじめに

いつもは技術ネタなどが多いこのブログですが、珍しくプライベートな話を少し・・

我が家に新しい家族が増えた話です。

育休

両親に頼らず育児する環境にあったので、育休取得を前提に会社と調整していました。

妻はつわりがひどく休職、からの産前産後休業(からの育休)ということでしばらくは完全2オペ体制で育児に臨みます。

生まれる前(妊娠初期)

妻はつわりが長かったので、自分も妊娠の比較的初期のころから生活の変化を意識することができました。

仕事はなるべく定時に切り上げ、家事に積極的に取り組み妻の負担を減らすべく行動しました。また勉強会などの参加の頻度も減らし、参加するときは妻と認識を合わせ、家事もあらかじめする、など「調整」をしっかりすることを心掛けました。

 

ドラム型洗濯機、ロボット掃除機などはすでに我が家は導入済みだったので、そもそもの家事が少ないという点は良かったです。

 

よく「妻が先に母親になり、夫との自覚の違いからトラブルになる」という事例を耳にしたので、自分も妊娠していないながら、「父親」の自覚を持てるように、まずは本を読むことから始めました。

 

極端な知識に偏りすぎてしまうのも違うのだろうと思いつつ、複数の本を読むことで、なるべくニュートラルに情報を摂取することを心掛けました。また、可能な限り夫婦で同じ情報を共有しておきたかったので、互いが読んだ本を交換して読み合いました。

幸い図書館には妊娠・出産周りの本がたくさんそろっており、大変助けられました。その中で、「これは我が家に置いておきたい」というものについては購入しました。

「つわり」については、食べられるものが少なくなり辛そうでした。それに合わせて食事を用意することに注力しました、理系な自分は「何か法則があるのでは?」と考えがちでしたが、結局突発的に「今食べられるもの!」が降ってくるような状況のようで、素直に要求に従って料理を用意しました。

生まれる前(妊娠中期)

つわりがひと段落し始めたころ、夫婦ともに育児への不安が募ってきました。

「無知が恐怖を呼ぶのでは?」ということでこれまたいくつかの本を読んだり、既に子育てを始めている友人宅にお邪魔したりすることで、過度に不安がらないように工夫しました。育休を取得する段取りを始め、それに向けても本を読みました。

地域のパパママ教室的なものにも参加し、「おもり」を使った妊婦体験や、人形を使った沐浴体験もしました。

同じ回に参加した貴重なパパ・ママ友の方とはLINEを交換したりしました。

妊娠後期になると、今度はいわゆる「マイナートラブル」というもので妻が苦しみ始めました。頻繁にこむら返りになったり、骨盤の痛みを訴えたりしていました。

寝る前のマッサージを手伝ったり、率先して物を運んだりと、できるサポートをしていました。

生まれる前(妊娠後期)

そろそろ出産が近づいてくる時期になると、産褥期産後鬱など、産後のトラブルについて心配が募ってきました、ここでも本で事前に知識を身につけました。

産褥記 産んだらなんとかなりませんから!

産褥記 産んだらなんとかなりませんから!

 
ふたりは同時に親になる: 産後の「ずれ」の処方箋
 

 また、これにより出産後の生活がイメージできるようになり、妻がまともに活動できない期間が1か月ほどあることを想定し、宅配弁当や、買い溜めのためのスーパーへ行くための車運転の練習などを始めました。(ちょうど家の近くにTimesのシェアカーがあったので、Timesの会員になりました)

また、赤ちゃんの睡眠のリズムについてもいくつか本を読みました。

赤ちゃんにもママにも優しい安眠ガイド

赤ちゃんにもママにも優しい安眠ガイド

  • 作者:清水 悦子
  • 発売日: 2011/11/23
  • メディア: 単行本(ソフトカバー)
 

 出産後すぐに必要な育児用品についても買いそろえました。特に新品にこだわりはなかったので、大物についてはリサイクルショップメルカリで調達しました。

出産

無痛分娩を選択したため、出産は計画分娩でした。そのため私も出産予定のその日から産院に赴き、その過程に立ち会うことができました。ただし、コロナの影響で出産当日のみ面会可能ということで、出産日以降の数日の入院期間は面会できず寂しい思いをしました。

 

出産は妻がとても頑張ってくれて、母子ともに健康な立派なものとなりました。

ひとまずここでひと段落ですが、ここからが育休のスタートです。

育休1週目

育児用品はやはり用意しておいたものでは不十分で、次々と必要なものが判明してきます。産婦人科で妻が「必要だ」と思ったものについて、リストで送ってきてくれたので、早速練習した車の運転を活用して、近所の西松屋に買い物に行ったりしました。

 

病院から帰った妻から、ささっと最低限の赤ちゃんの世話についてレクチャーを受け、自分もできるように教わりました。(おむつの替え方、沐浴の仕方、抱っこの仕方など)

出産直後の妻はとても疲れやすくなっているようで、想定していた通り、家事の大半を自分がこなすことになりました。また、夜に赤ちゃんと一緒に寝て、泣き出したときにミルクをやるという役割(夜番と呼んでいる)も自分が担当することにしました(その分は午前中寝ています)。

 

家事については、掃除周りは妊娠中も自分が大半を担当するようにしていたので、いつも通りという感じ、大きく変わったのが食事の用意です。

育休ということで1日中家にいるわけで、2人分朝・昼・夜の食事を用意する必要があります。せっかくのこの機会、”料理を楽しもう”と思い、この1週間は「作り置き」をいろいろ試しています。

ただ自分は「夜番」をしているため、午前中は寝不足分を補うために昼頃まで寝ており、昼ごはんの準備ができるかどうか怪しいということで、そこは冷凍食品・冷凍弁当・作り置きをうまく利用して手抜きをしています。

 

ここまでのまとめ

1週間もこういう生活をしていると、隙間時間にこうやってブログを書いたり、プログラムを書いたりと、少しずつ自分の時間を確保できるようになってきましたが、やはり赤ちゃんが泣きだすと、もちろんそちらが優先なので、今までのようにガッと「集中」して作業するというのはできなくなっています。

まぁせっかくの機会なので、自分の子供と触れ合える時は、じっくりとかわいがっていこうと思います。そのための育休です!

 

タイトルにもある通り、ここまではまだ「序章」にすぎません。これからも気合を入れつつ、楽しい育児をしていこうと思います。

おまけ・IT夫婦の生活管理術

以前、家事スプレッドシートがバズったことがありますが、我が家は夫婦ともにIT系で、生活のいろいろなところでITを活用しようとしています。

nlab.itmedia.co.jp

はてなブログをご覧の皆様も、IT系の方が多いと思うので、ここで少し我が家での生活管理方法を紹介します。(そして、ほかの方のこういうTipsもぜひ教えてほしいです)

運動習慣はWiiFit

育児をしていると、どうしても家の中にずっといることになってしまい、運動不足が心配です。私は、ここ1年くらいWiiダンスダンスレボリューションWiiFitを使って、屋内でも運動する習慣を実践していました。育児を始めたことで生活リズムが変わり「毎日」実施することがまだできていませんが、この習慣は続けていきたいです。

ちなみに、両方試しましたが体力を維持するためには「ダンスダンスレボリューション」よりWiiFit」のほうがおすすめです。

inajob.hatenablog.jp

inajob.hatenablog.jp

 

1か月単位の予定はTrello

夫婦でTrelloのプロジェクトを作って運用しています。

trello.com

カラムに「2020/04」「2020/04 done」などを作り、終わったタスクをdoneに順次移行していきます。月末に残っているタスクを棚卸し、来月のカラムに移動させ、その月のdoneカラムはアーカイブ化します。

f:id:inajob:20200429234006p:plain

調査系はScrapboxにぶち込む

あれ、これってどうなんだっけ?と思ったことは2行とかでも良いので、Scrapboxにページを作って残しました。

scrapbox.io

特に育児にまつわる買い物は、知らないものが多く、そもそもどういう種類があるのか?価格帯は?といったことを調査し、結果をScrapboxにまとめました。

こうしておくとあとから夫婦で確認でき、何度も同じことを調べる手間が省けました。

また「あれ調べといて?」「OK?」みたいなやり取りから生まれたタスクは、ともすれば聞くだけ聞いて流されているのでは?と思うようなこともあったので、調べた結果を簡単で良いのでまとめるようにしました。

主に自分の備忘録としてですが、役立っています。

f:id:inajob:20200429234255p:plain

日付に関連する事項はTimeTree

日付にかかわる事項はTimeTreeで共有しています。自分だけの予定もカテゴリを変更して追加し、「飲み会で遅い」みたいな内容も共有しています。

play.google.com

また、この内容をリビングから、さっと確認できるように「おうちサイネージ」を作りました。

inajob.hatenablog.jp

育児の記録は「ぴよログ」

いつ授乳した?いつおむつを取り替えた?という内容を夫婦で共有するためにぴよログを使っています。「夜番」交代時に細かく夜の様子を説明することなくバトンタッチすることができるので大変有用です。

各イベントに「メモ」が残せるので、その時感じた発見や異常も共有することができます。

piyolog.mystrikingly.com

 

おまけのまとめ

まぁ、正直なところ「便利」で使っているツールが半分。自分の「趣味」で使っているツールが半分といったところですが、これをご覧の皆様の生活の役に立てば幸いです。

 

電子ペーパー手書きタブレット BOOX Nova Pro のススメ

手書き端末の夢

私は「手書き端末」が好きで、古くはPalm(VisorCLIEも含む)に始まり、シャープの電子ノートや、ペン付きのWindows端末、enchantMOONなど様々な手書きデバイスを試してきました。

 

(enchangMOONまだ売ってる!)

enchantMOON 16GB Standard Edition

enchantMOON 16GB Standard Edition

  • メディア: エレクトロニクス
 

 シャープの電子ノートも昔は使っていました。

シャープ 電子ノート ブラック系 WG-S50

シャープ 電子ノート ブラック系 WG-S50

  • 発売日: 2017/10/13
  • メディア: オフィス用品
 

 

今使っている電子ノート

古くは「NoteSlate」なんていう「出す出す詐欺」の製品がインターネットを騒がせたこともあったので眉唾ものかと思っていたのですが、最近は電子ペーパー(e-ink)」を使った電子ノートが結構出てきています。

 

私が使っているのはBOOX Nova Proです。

特徴を少し書くと・・ 

  • 7.8インチ 1872×1404
  • フロントライト
  • Wacomのペンと指のデュアルタッチ
  • Android
  • バッテリーが長持ち
  • 技適取得済み

といったスペックです。

BOOX社の電子ノートは他にも10インチのものがありますが、私はこの7.8インチの大きさ感が気に入っています。

また技適を取得済み」というのは日本で使う上では必須の項目です。(しかしほかの多くの電子ノートはこの要件を満たしていません)

 

一方残念ポイントもたくさんあります。

  • Androidなのでアプリをインストールできるが、画面更新が遅すぎなので利用できるアプリは限られる。(私は実質ノートアプリしか使っていないです)
  • ノートアプリで線を描くのは快適だが、ページ送りや一覧ページへの遷移がもっさりしている
  • ファームウェアは積極的にアップデートされているが、不具合が多い。

ということで、かなり「使う人を選ぶ」製品です。

電子工作プロトタイピングに便利

ちょっと私の活用事例を紹介します。

電子工作をしていると、ちょっと配線をメモして、そのメモ通りにはんだ付けし、プロトタイプを作るということをよく行いますが、このメモをテキトーなメモ用紙などにすると、後でなくしてしまって、回路がどうなっているのかわからなくなってしまいます。

このような、手軽に書き込めて、後からも参照でき、かつ電子工作中にいつでも見ることができる、という要件に電子ノートはぴったりです。

 

電子ペーパー電力を消費せずに表示することができるので、電子工作の間ずっと出しておきたい回路図などを表示するのにぴったりです。

f:id:inajob:20200405123300p:plain

f:id:inajob:20200405122032p:plain

レーザーカットの工程管理と試行錯誤に便利

また、レーザーカッターで作業をするときに、どの部品まで作業が終わったかを把握するために書いたメモも役立ちました。

ノートサイズなので、工作スペースで作業するときもかさばらず、さっと確認と編集ができるのが素晴らしいです。

f:id:inajob:20200405122353p:plain

イデア出しにも便利

手書きは「アイデアだし」にも有効です。キーボードで文字を打つよりも柔軟にアイデアを描く事ができます。特にハードウェアやユーザインターフェースの設計をする際には、自由に描くことができるということは非常に重要だと感じます。

f:id:inajob:20200405122544p:plain

f:id:inajob:20200405123726p:plain

このように電子ノートは、キーボードよりも手軽に編集ができ、紙よりも安全に保存ができるため、「清書未満のメモ」を書くのに非常に向いていると感じます。

 

電子書籍リーダーとしても使える

まぁ、もともとは電子ペーパー端末は電子書籍リーダーとして出てきたものなので、当然電子書籍リーダーとしても利用できます。

任意のPDFを表示できるので、後で読みたいな と思ったちょっと重ためのブログ記事をPDF化して入れておいたりすることもできます。

 

ペンがあるので、気になった個所にメモを描いたりした線を引いたりと、まぁできそうなことはたいていできます。

と、ここまで書きましたが、私はあまり電子書籍を読まないので、この機能は実際のところはあまり活用していません。

f:id:inajob:20200405122840p:plain

まとめ

趣味の電子工作をする人にとって手書きできる電子ノートがいかに便利かということを紹介しました。

電子ノートはまだまだ発展途中のデバイスで、正直なところ「使う人を選ぶ製品」です。しかし、どういうところで使えて、どういう欠点があるかを把握したうえで利用すれば、電子工作のお供として非常に便利なツールです。

 

私が使っているBOOXは不便なこともありますが技適取得済み」WACOMペン」電池が非常に長持ち(私の作業量だと2週間くらいは充電なしで使える間隔)」という3点が非常に気に入っています。

家電量販店などでもデモ機を展示していたりもするようなので、気になった人は探してみてはどうでしょうか? 

(ほかの電子ノートを使っている人は、ぜひ使い心地を教えてほしいです!)

 

Arduinoを内部発振器で動かす時の誤差とその補正について

内部発振器を使ったArduino

Arduinoの回路はAtmega328に16MHzの水晶発振子を接続したものが一般的です。しかし、Atmega328は内部発振器も持っています。

f:id:inajob:20200315214525p:plain

独自でArduino互換回路を作る際に、内蔵発振器を使うと、部品点数を減らすことができ、さらに水晶発振子を接続するための2本のピンをGPIOとして使うことができるようになります。

ここまでだと良いことづくしなのですが、内蔵発振器は8MHzで16MHzの水晶発振子と比べると遅いです。また、水晶発振子ではなく、RC発振で実装されているため、精度は水晶発振子に比べるとかなり劣ります。その後差は±10%とされていますが、動作させる電圧や、気温でも大きく変化します。この誤差のために、内部発振器で動作するArduinoは115200bpsでのシリアル通信は非推奨となっています。

 

これらのメリット・デメリットを踏まえたうえで、内部発振器を使うかどうかを判断する必要があります。

内部発振器の誤差による問題

内部発振器の誤差があると様々な問題が生じます。そのうちで最も大きなものは「外部機器との同期がずれる」というものがあります。特にシリアル通信でこの問題が起きるとArduinoとしての書き込みができなくなってしまい、使い物になりません。

 

私が、今作っているHACHIBAR(https://inajob.github.io/hachibar/)というゲーム機は内部発振器を使ったArduinoを利用しているのですが、まさにこの問題が起きました。ほとんどの個体は正しくArduinoとしてプログラムを書き込むことができるのですが、一部(今のところ5個中1つ)の個体で書き込みができないのです。115200bpsが非推奨ということで19200bpsまで周波数を下げたのですが、それでも書き込めません。

 

おかしなAtmega328はICSP経由ではプログラムを書き込むことができたので、一見うまく動いているようなのですが、Arduinoブートローダを書き込んでもうまくPCからの書き込みができないという状態でした。

 

始めはAtmega328か、USBシリアル変換ICが壊れているのかと思っていたのですが、個別に挙動を確認するとうまく動いているように見えるので、何か変だな?と思っていました。

 

内部発振器に誤差があることは知っていたのですが、シリアル通信ができないほどずれているものがあるというのは知らなかったので、しばらくはどうしようもない問題としてほったらかしていました。しかし内部発振器の誤差を調整する方法があることを知り、このおかしな挙動をするAtmega328もArduinoとして使用できるのでは?と思いさらに調査を進めることにしました。

 

OSCCALによる内部発振器の補正

 内部発振器の誤差を調整する方法とはOSCCALというレジスタを利用することです。このレジスタは、起動時にAtmega328のシグネチャバイトに工場出荷時に記録された値が設定されています。

このOSCCALはプログラムから書き込むことができ、それにより内部発振器の周波数をクロックアップしたり、クロックダウンさせることができます。

例えば下のようなコードを書く事で内部発振器で動作するArduinoの速度を標準より早くしたり遅くしたりすることができます。この値を変化させるとシリアル通信ができなくなったり、delayの待ち時間がずれたりと、様々なおかしなことが起きます。

void setup(){
  OSCCAL = 100; // 好きな値に設定
}
void loop(){
  // Lチカ
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
} 

内部発振器の誤差が大きくてシリアル通信がまともにできないAtmega328でも、このOSCCALを変更することで、通信ができるようになることが想像できました。

OSCCALはリセットで初期値に戻る

しかし、話はそう簡単ではありませんでした。前述したようにOSCCALは起動時にAtmega328のシグネチャバイトに工場出荷時に記録された値が書き込まれるようになっています。

そのため、Arduinoブートローダが動作しているときのOSCCALをいじる方法がありません。先程の例のようにArduinoのスケッチ内でOSCCALが変更できても何の意味もありません。

ブートローダーを改造する

Arduinoブートローダーに何かOSCCALを調整する機能があれば良いのでは?と思いちょっと調べたのですが、そういうIssueはちらほら見かけたのですが、そのものずばりの機能が見当たりませんでした。

ということで「ないなら作ればいいじゃない!」ということでブートローダーに手を加えてみることにしました。改造する対象は本家Arduinoではなく、互換ブートローダであるOptiboot(https://github.com/Optiboot/optiboot)にしました。

変更はいたって単純で、makeする際にOSCCAL_VALUEというオプションが設定されている場合は、ブートローダーのmain関数の頭でOSCCALの値を書き換えるというものです。

 

この改造を行い、かつ適切なOSCCAL_VALUEを設定したブートローダを焼きこむことでおかしな周波数だったボードでも無事シリアル通信ができるようになり、Arduinoとして書き込むことができるようになりました。

補正値の求め方

 補正値を正しく求めるために、AnalogWriteの際のPWMの周波数をテスターで読み取って補正しました。

幸い、今回問題になった基板はゲーム機の基板で、良い具合にたくさんのスイッチが搭載されています。そこであるピンでAnalogWriteで128の値を出力し、↑、↓ボタンでOSCCALの値を変更するようなプログラムを書き、そのPWM周波数の変化をテスターで観測し、適切な補正値を求めました。

 

たまたま購入していた下記テスターが周波数測定の機能を持っていたので役立ちました。

 

本家にPullRequest

この調査をする中で、結構多くの人が内部発振器で動かすArduinoでのOSCCALの値の変更に悩んでいることがわかりました、そこで、私の変更を本家にPullRequestができるのでは?と思いカジュアルにPullRequestを出してみたところ、無事マージされました!

ArduinoやOptibootには日々お世話になっていたので、良いPullRequestで貢献することができてうれしかったです。

github.com

Tips: Dockerでビルドする

私は普段Windowsを使っているのですが、Optibootをビルドするためにいろいろ環境を整えるのが面倒だったのでDockerを利用しました。下記のような感じでビルドすることができたので、環境を用意するのが面倒な人にはお勧めです。

$ cd optiboot/optiboot/bootloaders/optiboot/
$ docker run -v /`pwd`:/src -w //src rubberduck/avr make BAUD_RATE=19200 OSCCAL_VALUE=145 atmega328_pro8

他の解決策 

github.com

これは外部のRTCを使い、内部発振の誤差を測定し、その誤差を設定するような特殊なブートローダーを書き込むというプロジェクトです。RTCが手元にあるなら、これを使うのがよさそうです。

まとめ

内部発振器で動作するArudinoを使う際には、その誤差に気を付ける必要があります。個体によってはシリアル通信がまともに出来ないことがあります。Arduinoとして書き込み機能ができないほどに誤差がある場合は、ブートローダ内でOSCCAL値を書き換えるなどを行い、クロックを補正する必要があります。

 

今回のPullRequestによりOptiboot(https://github.com/Optiboot/optiboot)では、この変更が簡単に出来るようになりました。

https://github.com/pkarsy/rcCalibratorもよくできているプロジェクトです。

 

参考書籍

 たまたま買ったこの本にOSCCALについて書かれていたのが非常に参考になりました。Arduinoに慣れてきてAVRのことも気になってきた方にお勧めの一冊です。リファレンスの名の通り、そばに1冊置いておくと安心できそうです。

 

Raspberry Piでおうちサイネージを作ってみよう!

おうちサイネージとは

おうちサイネージというのは、家のリビングなどに設置するスマートディスプレイのことです。

日常生活で役に立つ情報をいい感じに表示することで、生活がより便利になります。

f:id:inajob:20200229180713p:plain

おうちサイネージの要件

ここで扱うおうちサイネージに求める要件はこんな感じです。

  • 常時起動せず必要な時に起動する(電気代削減)
  • ディスプレイをほかの機器と共用する
  • 直近の予定を表示する
  • 時刻を表示する

基本的な構成

基本的な構成はRaspberry PiとPCモニタです。

(いま新たに買うならRaspberry PI 4のほうがおすすめですが、我が家にはRaspberry Pi 3が転がっていたのでこれを使っています。)

我が家ではHDMI出力のあるテレビチューナをPCモニタにつなげてリビングに置いています。そこにRaspberry Piを追加するということです。

 

f:id:inajob:20200229174006p:plain

必要な時に起動する

「常時起動せず必要な時に起動する」「ディスプレイをほかの機器と共用する」を実現するためには、Raspberry Piをスリープモードに出来れば良さそうですが、実際のところRaspberry Piはスリープすることができません。

ここでは妥協案として「HDMI出力を停止する」ことでこの要件を達成します。

一般的なPCモニタはHDMI出力を停止するとスタンバイモードに入ります、また複数の入力を受け付けるモニタや切り替え機の「自動切換えモード」も、出力がある機器に自動的に切り替えてくれるため、おうちサイネージの起動のためにリモコンで入力切替をする必要がありません。

 

XOrgの機能として、「一定時間入力がないと勝手に画面がブランクになる」というものがあり、まずはこれを当てにしていたのですが、どうもこの「ブランクになる」という動作ではHDMI信号は出続けており、ディスプレイも点いたままですし、ほかの機器を起動しても、Raspberry Piの「黒い画面」を表示し続けてしまいました。(入力切替を手動で実行すると切り替わりますが・・)

 

いろいろ調べているとtvserviceというコマンドでHDMI接続したモニタの電源を操作できることがわかりました。

具体的には下記のコマンドでディスプレイの電源が切れます。

$ tvservice -o

そして下記のコマンドでディスプレイの電源が点きます(環境によってパラメータが違うかもしれません)。

$ tvservice -p
$ fbset -depth 8
$ fbset -depth 32
$ xrefresh -d :0.0

起動のトリガを作る

 プログラムからRaspberryPiと接続されたPCディスプレイの電源をON/OFFできることがわかりましたが、どうやって「必要な時に起動する」を実現するかが問題です。

ここでは「Escキー」を押すことでおうちサイネージを起動するようにしました。起動後は3分経過すると再びPCディスプレイの電源を落とすことにします。

 

キーボードの入力を受けるためには、一般的に考えると、そのウィンドウにフォーカスが当たっている必要ありそうですが、おうちサイネージとしてはいくつかのプログラムを画面分割して動作させたいと考えていたので、ウィンドウにフォーカスが当たっていなくてもキーの入力をキャプチャしたいと考えました。

 

ちょっと調べてみると、まさにこれを実現するためのPythonのライブラリを発見しました。

github.com

 これを使うことで、CUIのプログラムから、どのウィンドウにフォーカスがあってもキー入力をキャプチャできるようになりました。

前述のPCディスプレイの電源周りのコードと合わせてプログラムにするとこんな感じです。

import keyboard
import subprocess
import time

while True:
    # standby
    subprocess.run(["tvservice", "-o"])
    
    # wait untill escape pressing
    keyboard.wait('esc')
    
    # resume
    subprocess.run(["tvservice", "-p"])
    subprocess.run(["fbset", "-depth", "8"])
    subprocess.run(["fbset", "-depth", "32"])
    subprocess.run(["xrefresh", "-d", ":0.0"])
    
    # start timer
    time.sleep(60 * 3)

画面レイアウト

おうちサイネージでは複数のプログラムを起動して情報を表示したいと考えました。そのレイアウトを簡単に固定するためにdwmというタイル型ウィンドウマネージャを採用しました。

dwmでは画面左をマスターと使用し、残る右部分を縦分割してスタックとして利用するレイアウトを実現できます。

f:id:inajob:20200229174910p:plain

実際のところはメインパネルで動くプログラム以外はデバッグ用のコンソールとなっていますが、ほかのプログラムを動かす際はdwmのパネルレイアウトが役に立つと考えています。

f:id:inajob:20200229175041p:plain

カレンダーの取得

我が家は家族カレンダーとしてTimeTreeを使用しています。最近TimTreeはAPIを公開したらしい、というので今回はTimeTreeのAPIを使ってカレンダーを取得しました。

developers.timetreeapp.com

下記のようにコマンドラインでも簡単にカレンダーの内容を取得できました。(実際はPythonのプログラムで取得し、後述のtkinterで画面に表示しています。)

$ curl 'https://timetreeapis.com/calendars/<カレンダーのID>/upcoming_events?timezone=Asia/Tokyo&days=3&include=creator,label,attendees' \
  -H "Accept: application/vnd.timetree.v1+json" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

メイン画面

おうちサイネージのメイン画面は初めはChromiumを起動して、Webアプリとして実装していたのですが、Raspberry Pi 3には重荷のようで、動作がもっさりしてしまいました。

そこでPythontkinterというライブラリを使い軽量な画面を作ることにしました。

tkinterはあまり使ったことがなかったのですが、この程度の画面であれば非常に簡単に作ることができました。printfでコンソールに出すだけでは、味気ない情報をGUIとして表示する際には非常に便利なツールです。

↓デフォルトだとちょっと古めかしいスタイルで描画されます。これはこれで味がある・・

f:id:inajob:20200229181126p:plain

リモートデバッグ環境

おうちサイネージはリビングのRaspberryPiで動いていますが、その画面の開発などはできれば自室のメインPCから行いたいところです。簡単なロジックはメインPCで作ることができますが、表示確認などは、実機の画面を見ながら行うのが楽です。

メインPCとRaspberry Piを行ったり来たりするのはストレスなので、うまくリモートデバッグする方式としてx11vncを使うことにしました。

VNCサーバによっては、表示されている画面とは別のもう一つの仮想スクリーンを提供するものがありますが、今回はそうではなくメインディスプレイと同じものを配信するミラーリングの機能が必要でした。

 ↓Windowsマシンからアクセスしている様子。

f:id:inajob:20200229175506p:plain

リモートデバッグ環境を整えることで開発サイクルが加速させることができました。

 起動のための物理ボタン

おうちサイネージの起動は前述のように「Esc」キーを押すことにしました。

しかし、このためだけにリビングのディスプレイの前にキーボードを置いておくのもナンセンスです。

そこで、Arduinoを使ってEscキーだけのキーボードを自作しました。Arduino Pro Mircoを使うとこのようなカスタムキーボードを作ることは簡単です。

プログラムはこれだけです。

#include "Keyboard.h"

#define BTN1 6

void setup() {
  Keyboard.begin();
  pinMode(BTN1, INPUT_PULLUP);
}

void loop() {
  if(digitalRead(BTN1) == LOW){
    Keyboard.press(KEY_ESC);
    delay(100);
    Keyboard.releaseAll();
    while(digitalRead(BTN1) == LOW);
  }
  delay(100);
}

↓回路はこんな感じ。6番ピンとGNDにスイッチの両足をつなげているだけです。基板とボタンは直結しても良いのですが、なんとなくソケットを使って分離できるようにしています。

f:id:inajob:20200229175717p:plain

さらにこのArduino Pro Microとスイッチをマウントするためのケースを3Dプリンタで作成しました。

f:id:inajob:20200229175913p:plain

f:id:inajob:20200229175823p:plain

完成!

ここまでの成果をガガガっと組み合わせるとこんな感じになります。

まだまだ 改良したい点はたくさんありますが、ひとまず形になったので、ここまでの苦労と知見を記事にしてみました。

 

さぁ、これを見ている皆さんも「おうちサイネージ」作ってみませんか?

みんなでアドベンチャーゲームを作ってみませんか?

これは何?

「みんなでアドベンチャーゲームを作ったらどうなるのだろうか?」

f:id:inajob:20200208133330p:plain

ふと浮かんだ、この試みを実際に始めてみました。

 

↓↓↓早速プロジェクト自体を見たい方はこちら↓↓↓

github.com

 

アドベンチャーゲームとは?

ここで言うアドベンチャーゲームというのは、テキストと選択肢によって構成される物語で、選択肢に応じて物語が分岐し、プレイヤー毎に異なるストーリーを楽しむことができるゲームのことです。

 

単なる小説とは違い、選択肢による分岐ごとに異なるストーリを展開することができるため「みんなで作る」のに向いているのでは?と考えました。

みんなで作るために工夫していること

 Git/GitHubを使う

みんなでアドベンチャーゲームを作るためには、差分を取り込む仕組みが必要です。今回はこれを簡単に解決するためにGit/GitHubを使うことにしました。

差分はGitで管理し、GitHub上で取り込みのためのコミュニケーションができます。

ブラウザですぐに遊べる

みんなで作るためには、「みんなで遊べる」ことが重要です。特定の環境に依存していたり、インストールが必要であったりすると、遊ぶためのハードルが高くなります。

またストーリを作る際も、さっと動作を試せることが重要です。

そのため、今回はブラウザで動作するようにゲームエンジンを作成しました。これによりGitHub Pagesで簡単にホスティングすることもできました。

またgit cloneしてきたhtmlをブラウザで開くだけで遊ぶことができるので、開発時も簡単に動作確認できます。

 

↓ちょっと味気ないですが、Webブラウザで誰でも遊べます。

f:id:inajob:20200208133519p:plain

https://inajob.github.io/cyoa-experiment/

アドベンチャーゲームの仕様を最小限にする

昨今のアドベンチャーゲームエンジンは多機能です。背景画像、音声、BGM、書式設定などなど、アドベンチャーゲームを盛り上げるための様々な機能を搭載しています。

しかし、「みんなで作る」という観点では、これらの機能が利用できることで、アドベンチャーゲームにクォリティが求められるようになり、参入の障壁が高くなってしまうことが予想されました。

そこで、今回はシンプルなゲームエンジンを自作し、本当にストーリーだけに注力してアドベンチャーゲームを開発できるようにしました。

ゲームエンジンから揉めそうな要素を排除

それでもゲームエンジンには、いくつかの機能があります。選択肢でジャンプする先を表す「ラベル」や、状態を表す「フラグ」、フラグによる「条件分岐」などです。

ここで「ラベル」と「フラグ」に関してはそれぞれ固有の名前が必要です。

一般的なゲームエンジンでは「場面1」「学校のシーン」「ライフルを持っているか」など、「ラベル」「フラグ」にはわかりやすい名前を付けます。

しかし、みんなでアドベンチャーゲームを作る場合、これらの名前が衝突したり、一定のルールを強制するなど、わかりやすい名前にしたいがためにもめごとが起きることが予想されました。

そこで、今回はUUIDをベースとした名前を採用することで、わかりやすい名前という利点とは引き換えに、命名が衝突するという問題を回避しました。

ライセンスを明記

アドベンチャーゲームをみんなで作るということは、そのシナリオのライセンスで揉めることが予想されました。そこでリポジトリにあらかじめCC BY-SAのライセンスを明記しています。

このライセンスにより、誰でもこのストーリーを利用することができ、またこのストーリーから派生したストーリについても同様のライセンスを強制することを実現しています。

ゲームエンジン紹介

 このゲームエンジンの雰囲気を知ってもらうためにストーリの例を紹介します。

下に示したように、基本的にはストーリを書いていくだけです。選択肢は「:」で始め、選択肢の文字列と、飛び先ラベルIDを記載します。

ラベルIDは暗号のようですが、これは自動生成したものです。このようにラベルIDを自動生成することで、命名で揉めないようにしています。ラベルは「*」で始め、ラベルIDとそれに続けて人間がわかるラベルの名前を記載します。このラベルの名前は他と被っても大丈夫です。

「%」で始まるのはその他の命令で、ここでは「%end」というゲーム終了の命令を利用しています。今のところ他には「%set」と「%eqif」があります。(詳しく知りたい方はリポジトリの説明を読んでください。)

*l972e5150755648f9abe435c10df2d231,初めのシーン
みんなで作るゲームエンジンのサンプルです。

このプロジェクトに興味がありますか?

:はい, l1b8a48cf456f43c69241cdf40b7a1417
:いいえ, ld21c8d7d9a2e42828c6f8fed022bb593

*l1b8a48cf456f43c69241cdf40b7a1417,はいの場合

やったー!
今すぐ https://github.com/inajob/cyoa-experiment をForkして物語を作ってみてください!

%end

*ld21c8d7d9a2e42828c6f8fed022bb593,いいえの場合
そんなぁ~

周りにこういうのが好きそうな人がいたら紹介してほしいです!

%end

 

少し運用してみて感じたこと

1週間ほど運用してみて、ストーリー周りに関して4つのPull Requestをいただきました。

自分でもいくつかのストーリーのPull Requestを作成したのですが、変更の仕方によってずいぶん印象が違うように思いました。

既に存在しているストーリーを少しだけ変更することは、様々な整合性を考慮する必要があり、普通に0からストーリーを作るのとはまた違った難しさを感じました。しかし、選択肢を増やすだけで、またすぐ元の流れに合流するような変更は変更差分が少ないためストーリーそのものを考えるほどの想像力や労力はかからないように思いました。

f:id:inajob:20200208161459p:plain

一方、既に存在しているストーリーから分岐するものの、その後の展開は完全にオリジナルというようなストーリーを作るのは、整合性に関する難しさはほとんどない代わりに、新たなストーリを考えるという想像力と比較的長い文章を書くための労力が必要だと感じました。

f:id:inajob:20200208161514p:plain

このように、このみんなでアドベンチャーゲームを作るという試みでは、従来の1人でストーリを作るのとはまた違ったスタイルで開発が行えることがわかりました。

まとめ

とりあえずはじめてみたこのプロジェクトですが、既にいくつかの方からPull Requestをいただき、一応コラボレーションできているという状態まで持ってこれました。

 

今後ものんびりと進めていければと考えていますので、この記事を読んでみて「面白そうだな」と思った方は、ぜひプロジェクトをforkして物語を追加してみてください。

f:id:inajob:20200208161727p:plain

 

FusionPCBを使って(ほぼ)はんだ付けせずに自作ゲーム機を作った(PCBA)

f:id:inajob:20200126160107p:plain

↑この状態で中国から届く!というのがPCBAです。

どういうこと?

PCBAというのをご存知でしょうか?

Printed Circuit Board Assemblyの省略なのですが、要は電子基板の作成(PCB)」「電子パーツのはんだ付け(A)」をやってくれるサービスです。

 

電子工作をある程度取り組んでいると、「自分の作ったものを人に配りたい/売りたい」という欲求がわいてきます。

 

最近は中国のサービスを使うと比較的安くでプリント基板(PCB)の製造をお願いすることができます。(10cmx10cm以内なら10枚で$4.9+送料 1枚あたり500円いかない)

これを使うことで、人に配る・売ることがかなり現実味を帯びてきます。

 

そこで、まず思いつくのは「自分で作って売る」です。しかし、これはなかなか大変。5個くらいなら何とかなりそうですが、10個を超えたあたりからつらくなってきそうです。

次に思いつくのは「キットとして売る」です。実際私も自作電子楽器RakuChordをキットとして何度か販売しました。しかし、これも思ったほど楽ではない、、何なら「自分で作って売る」より神経を使います。

 

そして究極は「誰かに作ってもらって売る」です。そんなことやってくれる人はいるのでしょうか・・・?

そう、それがPCBAです。

作ってもらう流れ

PCBAは名前の通りPCB+Aです。なので、手順はほとんどプリント基板(PCB)を発注するときと同じです。

PCBの手順については以前ブログ記事に書いたので(RakuChordの回路を発注してみた。 - inajob's blog)、基本的にはそれと同じです。

気になるAの部分について少し紹介します。

 

A=Assembleを依頼するために必要なのは、PCBの依頼に加えて、わずか3種類のファイルを用意するだけです。

実装図

これは基板のどこにどの番号の部品を置くかを記載したPDFファイルです。

KICADを使って回路を設計していれば、本当に簡単な手順で出力することができます。

f:id:inajob:20200126142621p:plain

ピック&プレースファイル

こちらもKICADでポチポチするだけで出力できます。

f:id:inajob:20200126142726p:plain

BOM(部品表)

最後が一番用意するのが大変な部品表です。

これは要は、基板上のどの番号に、どの部品を配置するかという対応表です。

以前私はここを用意するのが大変で、PCBAをためらってしまっていました。しかし今回の私には強い味方がいます。それがFusionPCBが提供する「OPL」です。

 

OPLはOpen Parts Libraryの略で、FusionPCBが在庫として抱えているパーツの一覧です。(https://www.fusionpcb.jp/opl.html)ここにあるパーツであればFusionPCB内で在庫が存在するため、比較的早く見積もり・製造をしてくれるというものです。

私にとってうれしかったのは、星の数ほどある部品の中から良さげなものを選んでくれているという点です。もちろん高周波なものやアナログ回路などを設計する人にとっては部品選定こそがメインの戦場なのでしょうが、私が作るような16MHz程度のデジタル回路においては、部品の違いなんていうのはほとんどありません。

ということで、今回はほぼ「OPLにあるパーツ縛り」で基板を設計しました。

 

OPLは一部の部品に対してはフットプリントも公開しているので、これを使うと本当に簡単にPCBAに挑戦することができます。

残念ながらすべての部品に対してフットプリントがあるわけではないので、無い部分はそれっぽいものを自作するなり、KICADの標準ライブラリのものを使いました。 

 

この「それっぽいフットプリント」も発注前は心配でしたが、ちゃんと部品が実装できるように作ってあれば、それっぽいフットプリントで問題なく実装してくれました。

 

 一部の部品はOPLには存在しなかったので、BOM表にはURLを書く形でみんな大好きLCSCのパーツのURLを貼り付けて発注してみました。

f:id:inajob:20200126142923p:plain

 

そうすると、「カートに入っているのですが、決済できない」、という状態になり(どうやらOPL以外の部品を入れると部品の見積もりを行っているようです。)数日後に見積もりが終わり決済ができるようになりました。

おそらくOPLだけで設計してあればすぐに決済できたのだと思います。

 

その後決済を行うと、基板の製造と部品の調達が並行して行われます。ここでもOPLの場合はすぐに調達できるのですが、今回のように別のところから調達しようとすると数日待たされます。(おそらく調達先は少ないほうが良いだろうと思い今回はLCSCだけにしました。)

そして、部品が調達できると実装(Assemble)が行われて、製品が発送されます。

とても簡単です。

時間

前述したように、カートに入れてから決済できるようになるまで2日間ほどかかりました。その後は下の図に書かれたようなスケジュールで製造が進みました。

f:id:inajob:20200126143402p:plain

2020/01/02に入稿されたデータは、01/10に実装が完了しました。

その後DHLで配送され、1/14に我が家に届きました。

f:id:inajob:20200126143612p:plain

f:id:inajob:20200126160107p:plain

お値段

現在FusionPCBではPCBA5枚限定の「実装無料」というセールをやっています。

このセールにより段取り費用、実装費用、運営費用、送料がなんと0円になります!(通常これらは$150ほどかかります。そのためPCBAは大量に発注しないと割に合いません)

で、実際にお金がかかるのは、基板製造費、消耗品費、部品代だけです。

そしてなんと送料も無料です。すごい!

 https://www.fusionpcb.jp/free-assembly-for-5-pcbs.html

f:id:inajob:20200126143644p:plain

今回の基板の場合は5枚で大体$40くらいでした。1枚$10しない!すごい!

 

あくまでセール価格なので、この値段を基にして原価を計算すべきではありませんが、PCBAを試したい人にとってはまたとないチャンスです。 

 

追記: 今はこのセールは終了しているようですが、PCB,PCBAは下記から注文することができます。

www.fusionpcb.jp

品質(濡れ衣でした!!!注記あり!)

 実装については個人的には大満足です。自分でやるのに比べて明らかにきれいです。
しかし今回は5枚中1枚、どうも不良の部品が実装されているようで、正しく動作しないものがありました。

f:id:inajob:20200126160229p:plain

クレームをつけても良いのでしょうが、OPLではない部品だったこともあり、今回は何も言わずに受け取っていますが、たくさん作ってこの割合で不良品が入っていたら大変つらそうです。部品選定は大事だなと感じています。

この辺をしっかりするためには、怪しいパーツの動作テストをしてもらうなどが必要そうです(FusionPCBでできるのかな?)

※濡れ衣でした!!! 内部発振でATMega328で動かしていたため、シリアルの速度が不安定になっているためでした!そのための対策は↓の記事にまとめました!

inajob.hatenablog.jp

バグ

どんなものにもバグはあります。今回私が設計した自作ゲーム機のハードウェアにもバグがありました。このスイッチです(右上)。

私の計画ではこの部品はUSB端子と同じ側に実装されるつもりでした(左下)。しかし私の送ったデータはそうなっておらず、(当然)指示通りの間違った側に実装されてしまいました。

f:id:inajob:20200126144105p:plain

この部品はフットプリントが大きめだったので、5つすべてのスイッチをつけなおしました。当然つけなおすためには、はんだを加熱して部品をはがす必要があり、これは部品を実装する以上に手間です。やりたくないです・・

 PCBAのコツ

表面実装部品を積極的に使う

PCBAの醍醐味は表面実装部品です。リード部品は手でも簡単に実装できますが、面積を取ります。またICなどは表面実装パッケージしかないものもあります。実装費に関しては、リフローで実装できる表面実装部品のほうが安い(はず)です。

せっかくPCBAするからには表面実装部品を使いたいところです。

初めからOPLにある部品で設計する

OPLにある部品を使うと、製造がスムーズにできます。そのため、PCBAで製造する基板で使用する部品はOPLにある部品を指定するのが良いです。
後から部品を変更するのは大変です。OPLにある部品はAliExpressでも簡単に買える部品が多いので、事前にそれらの部品で動作確認をしておくのが良いでしょう。

今回は抵抗・コンデンサ1206サイズを使って設計したのですが、OPLで安く手に入るのはもう少し小さなサイズ(0805とか0603、0402など)でした。次回作るときは先にサイズを確認しようと思っています。

手はんだできる部品で設計する

表面実装部品もある程度の大きさであれば手ではんだ付けできます。後述する手実装のフェーズのためになるべく手実装しやすい大きさの部品を使いましょう。

一度PCBで発注して手実装して様子を見る

PCBAは結構お金がかかります。そのため失敗したときのダメージが大きいので、一度PCBを作ってもらい自分で実装して動作確認をするのが良いです。今回の自作ゲーム機は3回PCBを作り部品の種類や配置の変更を繰り返し4回目にPCBAに挑戦しました。

f:id:inajob:20200126160033p:plain

4回の変更で実装部品が大幅に減り、実装ミスの少ない基板が設計できました。

まずは5枚PCBAする

せっかくセールで安く少ないロットで注文できるので、これを利用しない手はありません。数百個作りたい場合はまずは5枚のPCBAで様子を見るのはどうでしょう?

私のケースのように品質の悪い部品や、実装面のまちがいなど意外な凡ミスに早期に気づくこととができるでしょう。(大量ロットを注文した時も事前に数枚作って確認する、などができると聞いたことがありますが、私はまだ試していません。)

OPLでおススメ部品

部品についてはそれぞれ皆さんこだわりがあると思いますが、今回偶然にも発見したおススメ部品は「タクトスイッチ DTSM-62K-S-V-T/R(SN431) 」です。

f:id:inajob:20200126144404p:plain

個人的な印象ですが、中国で買うタクトスイッチは、安いのですが、なぜか異常にボタンが固いものが多いです。そんな中今回利用した6mmの表面実装タクトスイッチは100gFという軽いタッチが特徴です。

データシートを見て、「この値段で100gF?!まさか~?」と思って発注したところ、本当に軽く押しやすいスイッチが実装されて届きました。

スイッチの軸の高さが低いのがちょっと気になりますが、100gFのスイッチが欲しい人にはかなりおススメの逸品です。

まとめ

前々からやりたかったPCBAに挑戦し、そこそこ気に入った基板を作ることができたため、PCBは発注したことはあるが、PCBAはまだ・・ という人のためにちょっと紹介を書いてみました。

ここまでそれっぽいことを書いてきましたがまだたった5枚発注しただけのぴよぴよMakerですので、おかしなことを書いているぞ!とか、ほかにも面白いTipsがあるぞ!とう方は、ぜひぜひ教えてください。

 

 

Arduinoだけで和音を鳴らす方法

f:id:inajob:20200103112556p:plain

はじめに

私はRakuChordというArduinoを基にした電子楽器を作っています。

RakuChordはArduinoたった1つでキーの押下の読み取り、ディスプレイの制御、音の生成を制御しています。

inajob.github.io

この記事では、RakuChordでどのように和音を生成しているか?ということを解説していきます。

 

実はこのRakuChord。初期バージョンは10年前くらいで、和音のロジックもそのころから少しずつ改良を加えてきています。

しかし、どこにもドキュメントを残さずにここまで来たため、自分でもなぜこのソースコードで和音が鳴っているのかよくわからなくなることがありまして・・・自分の備忘録的な意味も込めてこの記事を書く事にしました。

Arduinoで「単音」 

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

  • メディア: Personal Computers
 

Arduinoで「単音」を出すのはとても簡単です。最も簡単なのは無限ループを作り、そこでdigitalWriteであるピンの出力を上げたり下げたりする方法です。そのピンにスピーカをつなげることで、単音を再生することができます。

適切に待ち時間を入れることで、これだけで単音を鳴らすことができます。

例えば440Hz(ラの音)を鳴らす時は 1/440秒の半分の待ち時間を入れてdigitalWriteでHIGH/LOWを繰り返せばよいのです。

f:id:inajob:20200104181608p:plain

void setup() {
  pinMode(9, OUTPUT);
}

bool flip = false;
void loop() {
  flip = !flip;
  digitalWrite(9, flip);
  delayMicroseconds(2272/2); // 1/440 = 0.0022727... = 2272uS
}

この方法では、音を鳴らしている間はほかの処理を行うことができません。

しかしArduinoの関数であるtoneを使うとこの問題も解決します。toneは周波数を指定すると即座に処理が終わり、次の命令を実行することができますが、音は鳴り続ける。という動作をします。

void setup() {
  pinMode(9, OUTPUT);
  tone(9,440);
}

void loop() {
// ここで処理中も音は鳴り続けている }

https://www.arduino.cc/reference/jp/language/functions/advanced-io/tone/

例えばゲーム機などを作る際、簡単なBGMであればtoneで十分です。

Arduinoで「和音」

Arduinoで「和音」というのは「単音」の時ほど簡単ではありません。

和音を鳴らすためにはいくつかの方法が考えられます。

1. 複数のピンを使う

和音の数だけピンを使い、オペアンプなどで合成したのちにスピーカーとつなげることで和音を鳴らすことができます。この方法は「単音」を複数並べるという点で単純でわかりやすいですが、ピンをたくさん使うことや、音の合成のためにオペアンプなどの部品が必要なことがデメリットです。

2. ソフトウェアで合成する

今回紹介するのはこちらの方法です。この方法では1つのピンの出力で和音を演奏する方法です。ソフトウェアの処理が複雑になりますが、単純な回路で和音を再生することができます。(音量が小さくて良いなら、それこそArduinoに直接スピーカをつなげるだけでもOKです)

2.1 既存のライブラリ

ソフトウェアで和音を合成するためには、これから紹介する「1から処理を書く」方法とは別に、既存のライブラリを利用することもできます。


2.1.1 Mozzi

MozziはArduinoで利用できるシンセサイザーライブラリとして非常に有名なものです。下記ページで大量のサンプルを聞くことができます。

おそらく音関係でやりたいことの大半は、このライブラリを使うことで実現できます。

このライブラリは音を扱う様々な処理の詰め合わせセットのようなものです。そのため単に「和音を鳴らしたい」という場合でもそこそこのプログラミングが必要となります。単純に和音を鳴らしたい場合はこの後紹介する別のライブラリのほうが簡単に実現できると思います。

一方、単純な和音ではなく、「音作り」にこだわりたい人にとってはMozziの豊富な音関係の関数群は非常に強い武器となるでしょう。

sensorium.github.io

2.1.2 PWMDAC_Synth

PWMDAC_Synthはまさに「Arduinoで和音を鳴らす」ことに特化したライブラリです。6重和音を扱うことができ、さらにエンベロープも設定できます。 

https://ja.osdn.net/users/kamide/pf/PWMDAC_Synth/wiki/FrontPage

2.1.3 VRA8-Pシリーズ

VRA8-Pで利用できる3音を扱えるシンセサイザーのライブラリです。ArduinoのCPUをフルに使うことで、ほかのライブラリを圧倒する高音質を実現しています。

ただし、この音源はArduinoのメモリ・CPUをかなり占有してしまうため、何かのロジックと組み合わせる場合は注意が必要です。場合によってはArduinoを2つ並べるなどして、片方は制御、片方はVRA8-Pを用いた音源、というような使い方のほうが良いかもしれません。

github.com

2.2 自分で和音を鳴らす処理を書く

既存のライブラリでは「痒い所」に手が届かない場合や、メモリ・CPU使用量を細かく調整したい場合、和音の合成処理自体に興味があるような場合は、自分で和音を鳴らす処理を書く事のがおすすめです。

ということで、以降RakuChordの音源での和音の処理について解説していきます。

RakuChordの音源のソースコード

RakuChordのファームウェアオープンソースで公開しています。

音源周りの処理は https://github.com/inajob/rakuchord/blob/cc088ecfc711f7f432e1a3cc55a3f5a8bb0b9c37/firmware/src/MultiTunes.cpp にまとめています。

ここからは、このソースコードを眺めながらArduinoで和音を鳴らす方法を紹介します。

soundSetup

 この関数が音を鳴らすための準備をするものです。起動時に1度だけ呼び出すことを想定しています。

内部では和音合成に必要なタイマーのセットアップを行っています。

RakuChordで使うのはArduinoのピンのうちDigitalの9番ピンです。まずは9番ピンをOUTPUTに設定しています。

 

次にタイマーの設定を行います。このタイマーは9番ピンのPWMの制御と、和音の波形の計算のタイミング制御のために利用しています。

Arduinoが使用しているマイコンATMega328には複数のタイマーが存在しますが、ここではTimer1を使用します。

Timer1の設定のためにはTCCR1AとTCCR1Bという2つのレジスタを用います。このレジスタの特定のビットを上げたり、下げたりすることでTimer1の挙動を設定します。

ここでは下記のような設定をしています。

  • WGM13~10 = 0001
    • 8bit位相基準PWM
  • COM1A1~0 = 10
    • カウントアップ比較一致でLOW、カウントダウン比較一致でHIGH
  • CS12~10 = 001
    • 分周なし

 ちょっとこれだけでは何を言っているかわかりませんね・・もう少し解説します。

分周比

 Timer1はTCNT1の値を適当な間隔でインクリメントしたりデクリメントしたりする仕組みです。具体的にどのようにTCNT1を動かすのかは後ほど説明しますが、その間隔について指定するときに用いるのが分周比です。

ATMega328が動作している周波数に対しての比率でこの間隔を指定します。

今回は「分周なし」の指定なので、Arduinoに搭載されている水晶発振子である16MHzの間隔でTCNT1を動かすことになります。

8bit位相基準PWM と 比較一致

WGM13~10によりTCNT1をどのように動作させるかを指定しています。

今回は8bit位相基準PWMという指定です。このモードではTCNT1は0から1ずつカウントアップしていき0xff(8bitの上限)までカウントアップしたら次は1ずつカウントダウンしていきます。そして0まで下がったらあとは繰り返しです。

オーバーフロー割込みは0xffに達したタイミングで実行されます。

つまり図にするとこのような感じです。

f:id:inajob:20200103105132p:plain

 

COM1A1~0,はTCNT1の動作と連動してデジタル9番ピンにどのような信号を出力するかを設定しています。今回は「カウントアップ比較一致でLOW、カウントダウン比較一致でHIGH」を指定しています。

比較に用いる値はOCR1Aレジスタの値です。

つまり図にするとこのような感じです。

f:id:inajob:20200103105625p:plain

このようにタイマーと連動してデジタル9番ピンを制御することで、非常に高速にピンをHIGH/LOWに切り替えることができます。またOCR1Aの値を変更することで、ON/OFF時間の比率を変更することができます。

これがPWM(Pulse Width Modulation)というテクニックです。このように短い間隔でHIGH/LOWを切り替えることで、HIGH(5V)とLOW(0V)という2種類の値しか出力できないデジタル回路においてアナログっぽい値を作ることができます。(厳密にはアナログとは違いますが・・)

 このPWMを使うことで、単なる矩形波よりも複雑な様々な波形を生成することができます。もちろん「和音」も「波形」であらわすことができるため、そのような信号をPWM作ることで和音を鳴らすことができます。

タイマー割込みの設定

最後にこれらのタイマーを有効にするためにTIMASK1にTOIE1のビットを設定します。これでTCNT1が上限に達したときに割込みが発生します。 

TIMER1_OVF_vect

今回利用するTimer1のオーバーフロー割込みはこの名前で呼び出されます。

ここまでの話を総合すると16MHzでTCNT1が0 → 0xFF → 0と繰り返し変化していきます。 これを1周期とするとこの1周期にかかる時間は

f:id:inajob:20200103110223p:plain

となります。

ソースコード上ここでTCNT2に値を代入しているが、これは何の意味もなさそう・・・)

基本的にはこの割込みルーチンの中でdn[x]にd[x]を足していきます。xは0~4の5通りあり、これがオシレータを表しています。つまり独立した5つの音を制御しているということです。

最終的にはこのdn[x]から波形テーブルを引いて、5つあるそれぞれの結果をすべて足し合わせてOCR1Aレジスタの値として設定しています。

dn,dと音程

dn[x]とd[x]はunsigned intです。つまり16ビットの値です。

先ほど見たように割込みルーチンの中でdn[x]にd[x]をどんどん足していきます。

このd[x]はRakuChordの鍵盤の押下により「音程に対応した値」が代入されています。

「音程に対応した値」というのはhttps://github.com/inajob/rakuchord/blob/cc088ecfc711f7f432e1a3cc55a3f5a8bb0b9c37/firmware/src/tones.hに定義しています。

このソースコードによると「音程に対応した値」というのは周波数そのものとなっています。(NOTE_A4が440、NOTE_A5が880となっていることからも、これが良く知っている周波数と同じであることがわかります。)

一方、d[n]の値は割込みルーチンの中で、上位6ビットを使ってテーブルを引いています。

波形テーブルは64サンプルで1波形を表しています。dn[x]は16ビットですが、その上位6ビット(0~63)を取り出すことでこのサンプルを読みだしています。

d[x]の値を変数としてdn[x]が何回の割込みで1周するかを計算します。

f:id:inajob:20200103110252p:plain

割込みの発生間隔は上で求めたので、これを掛け合わせることで波形1周期にかかる時間が計算できます。

f:id:inajob:20200103110338p:plain
式を変形します

f:id:inajob:20200103110357p:plain

波形1周期にかかる周波数を求めます(↑の逆数)

f:id:inajob:20200103110420p:plain

これによりd[n]の値は周波数をだいたい2で割ったものとなります。

つまり実際にはd[n]の値の表す周波数より1オクターブ低く、かつ少し誤差のある音が鳴っていることがわかります。

オーディオアンプ

どの方法をとったとしても、Arduinoのピンから出てくる信号のレベルは低いものです。イアホンや小さなスピーカであれば何とか音が鳴りますが、大きな音を鳴らしたい場合は、Arduinoとは別にオーディオアンプが必要です。

RakuChordではLM386というICを利用してこれを実現しています。

調べるとLM386を採用したオーディオアンプのモジュールも販売されているため、回路を作るのが面倒な人は、これらを使うのが良いでしょう。

まとめ

Arduinoで和音を生成する方法を紹介しました。

この方法は私が様々なライブラリや、タイマーの仕様を読んで試行錯誤して作成したもので、この方法が唯一の方法ではありませんが、Arduinoで1から和音を生成したい人にとっては試行錯誤の足掛かりとなるのでは、と考えています。

(もっと良い方法や、間違いなどがあれば教えてください。→https://twitter.com/ina_ani) 

 

Arduinoでちょっとリッチな音が鳴るようなガジェットを作りたい人の助けになれば幸いです。