

マイコンボードの時計の精度を信用しすぎた結果、失敗してしまったお話
- 廉価なマイコンボードの時計は機械式時計に劣る精度しか出せない可能性がある
- 時刻の基準となりうるクロックの供給源としてセラミック振動子が使われていることがあるが、その精度はクォーツ時計で使われる水晶振動子に劣る
- 正確な時刻が欲しいのであればそのための仕組みをちゃんと載せないといけないし、それが不可能であるのなら精度が低い前提で設計をやらないといけない
文書を整理していたら私が数年前に業務でやらかした失敗に関するメモが出てきたので、誰でも見れる形にまとめてみることにしました。
おことわり
- いろいろな事情があるので、詳細を意図的に省いています。
-
ここに書いてあることは推測が含まれます
- 機器を分解してのリバースエンジニアリングをやっていない(やったら怒られる)ため
-
私自身がハードウェアに全然詳しくないため、完全な正確さは保証できません
- 「だいたいあってる」程度に考えてください
-
これは数年前(コロナ以前)にさまざまな制約下でやった業務であることを明記しておきます
- 今なら別のやりようがあるかもしれません
どんなシステムを構築していたのか
しばらく前、私は業務においてこんな動きをするシステムを作っていました。
- 店舗に発信機(いわゆるビーコン)を設置
- スマホアプリがその機器のIDを取得
- ネットワーク経由でサーバーにデータを送信
- ユーザーに報酬を渡す
要は わざわざ実店舗に足を運んでくれた人にだけ特別な報酬を渡したい という感じのものです。一見するとそれほど技術的難易度は高くないです
しかしながら開発当時の情勢では、悪意を持った人間から攻撃を仕掛けられる可能性を考慮しなければならない状態でした。
攻撃の具体的な例として「悪意を持った人間が識別情報をコピーして偽の発信機を設置し、現地に足を運ばずに報酬を得られるようにする(そしてその手法をばら撒いたり売ったりする)」といったものが考えられました。
そのため正規のデバイスかどうかを判定する何らかの手段が必要でした。
色々と検討した結果、とあるハードウェアを他社から導入して時刻ベースのワンタイムパスワード(TOTP)を使えば強力に防御できるのではないかということになりました。
こうして作った仕組みを店舗にある程度の長期間(数週間〜数ヶ月)設置しました。
するとどうなったか
運用開始後数日間は調子良く運用できていました。
しかしながら、時が経つにつれてワンタイムパスワード認証が失敗する現象が多発。
どうやら 機器に内蔵された時計が想定以上にズレている ことが原因であるようです。
当然ながら問い合わせが続々とくるので対応に迫られました。
どうしてこうなった?
当時の私のこのコメント(廉価なマイコンボードの時計の精度はクォーツ腕時計と同じくらいだと思い込んでいる)に失敗の元凶が全て詰まっていると言えます。
今考えてみるとツッコミどころしかありません。
実際にはコンピューターの時計の精度は、かなり低いかもしれないのに・・・。
たぶんわかっていれば実装段階でもうちょい色々工夫してただろうし、そのハードウェアの会社に的確な質問をしていたと思います。
実際のところコンピューター(廉価なマイコン)の時計の精度ってどれくらいなのか?
まず比較対象として、身近な時計の精度を確認する
ここでは「ミヨタ(シチズン系・日本製)」の腕時計ムーブメントを参考にしてみます。身近にある時計の中に高確率で入っているはずです。
クォーツ腕時計
ミヨタ2025というムーブメントでは
±20 秒/月
とのことです。
このムーブメントは 事実上の世界標準 と言われるものです。「日本製クォーツムーブメント搭載」と書かれているアナログウォッチには、きわめて高確率でこの系統のムーブメントが搭載されています。
https://miyotamovement.com/jp/product/2025/
機械式腕時計
ミヨタ8315というムーブメントでは
-20~+40 秒/日
とのことです。
これは廉価な機械式時計によく入っているものです。高級品に比べれば精度は低めですが実用面では問題のない精度です。
https://miyotamovement.com/jp/product/8315/
ちなみに現代のちょっと良い時計だと -4~+6 秒/日 (クロノメーター規格の認定基準・現代だともっと厳しい規格が多数ある)を最低限満たしているものが多いです。
よくある廉価なマイコンボードの時計の理論上の精度は?(例として少し古いArduinoを使用)
自分が使っていたものは一般販売されていない機器でした。
なので近しいアーキテクチャを持つものとして少し古いArduino Unoを例として使います。
そして
システムで使用しているクロックの精度がそのまま時計の精度になる
と仮定します。
マイコンボードの例としてArduinoを使っているのは以下の理由からです
- きわめて普及しており、どこでも誰でも買える
- 特殊な設計が採用されていない
-
ハードウェア構成が完全に公開されている(超重要)
- 例を示すために「あるもの」が使われている必要がある
ハードウェア構成の図を見てみます。
https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf
それによるとクロックジェネレータとして
セラミック振動子
の「
CSTCE16M0V53-R0
」が使用されているようです。公式サイト見る感じではディスコンになってるので現在売られているArduinoは違うやつ使ってそうな気がしますが・・・まあ例なので気にしないことにします。
これはカタログスペックでは周波数許容偏差±0.50%以内とのことです。
https://www.murata.com/ja-jp/products/productdetail?partno=CSTCE16M0V53-R0
一見するとすごくズレが少なそうに見えます。考えてみてください。たったの0.5%ですよ?
ですが1日は86400秒なので、理論上最大で86400×±0.005 = ±432秒(7分12秒)/日ズレる ことになります。
まあ実用上はそれほどズレないかもしれません。とはいえ時計として使った場合に 1日に数分ズレるのはもはや仕様 といえるでしょう。
ちなみに水晶振動子(つまりクォーツ時計の中身)の誤差は%ではなくppm(百万分の一)単位で表記されていることが多いです。セラミックとクォーツでは、もはや精度の桁が明らかに違うのです。
マイコンボードでどうしても正確な時間を扱いたい場合はどうするべきか
リアルタイムクロック(RTC)モジュールを乗せる
正確な時間を得られるこのようなモジュールが存在しています。Amazonにも売ってます。
こんなモジュールがわざわざ存在するという事実は、特別な工夫がないコンピュータの時計は基本的にそれほど正確ではないことを示唆してるともいえます。
これには以下のようなものが搭載されており、手軽に正確な時刻を得られるようになっています。
-
水晶振動子
- セラミックよりは高精度
-
温度補償回路
- 気温が変化した時の影響を受けにくくする
-
バックアップバッテリー
- 電源喪失しても時間リセットされないようにする
定期的に同期する
多少時計の精度が悪くても、一定時間ごとに何かと同期すれば問題は起こらないでしょう。
今の時代ならNTP・電波時計・GPSなど色々な方法で正確な時間を得ることが可能だと思います。
短期間だけ使う
ズレるのはしょうがないと割り切って短期間だけ使うのなら問題は発生しにくいと思います。
実際、似た仕組みを別のイベント(数日程度)で使ったときは特に大きな問題が発生していませんでした。
メンテナンスも兼ねて、人力でこまめにハードの入れ替えを行う
要は実質的に使用期間を短くするということです。
ただ、人間を使用する最もハイコストな方法でもあります。
最後に
これを実装した当時の自分には本当に知識がありませんでした。というかこれ知ってたらもうちょっと実装変えてたと思います。
なので気をつけましょう。