スクリプト類とメニューボタン

トップ ソフト 雑記 日記 リンク

2015年12月24日木曜日

ArduinoでJJY発信(おうちハック Advent Calendar 2015)

おうちハック Advent Calendar 201515日目に書いた内容について、
ツッコミがあったのでおうちハックアドベントカレンダーの15日目として。
内容的には、完全にArduino Advent Calendar 2015なんですが、続き物ということでおうちハックにぶら下げます。


電波時計に供給される日本標準時電波(JJY)は、国立研究開発法人情報通信研究機構の日本標準時グループによって、福島県と佐賀県から送信されています。電波時計は、これらの電波を受信して現在時刻を知るわけです。

自宅に電波時計があり、買ったときに住んでいた家では電波を受信していたのですが、何度か引越をするうちに電波を受信しなくなってしまったようです。
何度手動で合わせても少しずつずれてしまう。電車やバスの時間に合わせて家を出ようと思うと、これが意外と辛い。 また、窓際に置いて強制受信ボタンを押してみたりしたのですが、どうも受信しない。

ということで、ちょうど家にあったArduinoをネットに繋いでNTPから時刻情報を受信し、そこからJJYを発信してみました。

必要なもの
  • Arduino
  • ネットシールド
  • 電源用USBケーブル
  • 通信用LANケーブル


以下、2019年7月2日更新。
で、肝心のスケッチなどですが、以前書いていたものは2015年当時のもので、だいぶ古くなっていたので書き直しました。
コードを出すとメンテナンスが継続できなくなったり、継ぎはぎだといい加減だと言われるので非公開にします。
GitHubで管理するにしても、Pull Requestに応えられなければ同じ事なので。

Timeライブラリは、新しくhttps://github.com/PaulStoffregen/Timeを参照するのが良いでしょう。
以前は固定IPで運用していましたが、最近のEthernetライブラリにはDHCPクライアントの機能が付いたため、http://arms22.blog91.fc2.com/blog-entry-445.htmlのような実装でいけるかと思います。

メインとなる変調部分はmillis()で比較していたのですが、50日でゼロに戻るという情報をいただいたので、古い情報も持っておいてリセットを検知したら引き算して・・・なんてことを考えたのですが、誤差が出てしまうため、もうすぐリセットされそうとなったところで発信をやめる方法にしました。
以上、2019年7月2日更新。

発信する電波は、40khz、ArduinoのPWM送信に対応している3番ピンを使います。

わたしの場合は50cmのリード線を3周巻いています。
アンテナとして機能するために、何周かのループになっている必要があります。
時計のすぐそばに設置するなら、それほど電波強度も必要ないので、3周程度できっちりと巻いてなくても受信できました。ただし時計の真裏でないと伝わりませんでした。
時計側の性能にもよるので、もう少し長いリード線を使って、きっちりと巻いた方がいいかもしれません。

我が家では、ルーター(NEC AtermWR9500N)にUSBポートと、余っているLANポートがあったので、そこに繋いでいます。

5 件のコメント:

  1. JJYがどうしても届かない場所に電波時計を置きたかったので実際に作ってみての1週間程度運用してみての微妙な点を指摘させて頂きます。

    1.millis() で待ちを行っている箇所がありますが、millis() は50日程度で0クリアされるため、0クリアが起きた場合の回避を記述していないので、最悪50日待ちとなります。(滅多に起きないでしょうが。。。)

    2.NTPの取得をサーバー側からの送信時間に頼り1回で時刻設定していますが、私の場合ちょうど10分程度ずれた(原因が通信遅延なのかNTPのデータ異常なのかは不明)ので、2回以上取得して、誤差が許容範囲ならば適用とかにしないと危険です。

    3.delay(900 - fraction_hi / (65536/1000)); の箇所が無限待ちとなる可能性がありそうです。というのもfraction_hi は最大4294967296を想定しなければいけないのに、それを65.536で割った値を引くと負数もしくはとんでもなく大きな正の数となるからです。
    計算式の正しさが今ひとつわからないのですが、最低限回避のコードを記述しないとハングした様な動きとなります。

    返信削除
    返信
    1. 検証ありがとうございます。
      コードは、あちこちから引っ張り寄せた物を継ぎはぎしたので、NTPDの仕様をきちんと理解した上で書かれたものでは無いのです。
      なんとなく、正しい時間で設定されたので良いかーという感じで運用していました。

      削除
    2. えー…
      まがりなりにも情報発信するなら、自分で作成したプログラムを使うか、流用したものがあるなら参照元を記載するべきでしょう。
      処理内容も理解せず、動いてるからいいや、レベルで人に教えるのは危険というか、無責任で図々しいです。

      削除
    3. とりあえず、参考にしないように注意を付けました。
      図々しいという感覚が理解できませんが、ご忠告どうもです。

      削除
  2. 前回と同じものです
    もう一点指摘させてください。
    恐らくは前回の2の問題に関連しています。

    if (Udp.parsePacket()) {

    とありますが、parsePacketは受け取れたデータサイズを示す様です。
    つまりは、
    if (Udp.parsePacket() >= NTP_PACKET_SIZE) {
    としておかないと、受信データが途中で切れた上に、正常受信した場合に
    時計情報が出鱈目となります。

    恐らくは元ネタという場所を知っていますが、色々考慮すべき事がありますね。。。
    無料でここまで提供頂いて指摘もなにもあったものではありませんが。。。

    返信削除

広告