セキュリティ・キャンプ2022のX3【ハードウェア魔改造ゼミ】の参加記です。ルーターにArduinoをつなげてスマホから操作できるラジコンを作りました。
X3 ハードウェア魔改造ゼミ 概要
Wi-FiルーターにArduinoをつなげてスマホやパソコンから操作できるラジコンを作りました。セキュリティキャンプの中でも異色のゼミですが、分野を問わず存在する攻撃から守るために幅広い分野について知るべきで、電気回路からHTTPまで全レイヤーを触ってみようという趣旨になっています。
ハードウェア構成
黒枠内のラジコンにWi-Fiルーターを搭載し、スマホ・パソコンなどのクライアントからHTTPでルーターのサーバーと通信して操作します。モーターはルーターにUSBケーブルで繋いだArduinoからモータードライバ経由で回します。
- GL.iNet GL-MT300N-V2
- このルーターにはオープンソースのOpenWrtが初めからインストールされていて、Raspberry Piのようなシングルボードコンピュータとして扱えます。無線通信に関するコードを直接書き換えることはしないので、Raspberry Piのプログラミングと同じように電波法には抵触しません。
- Arduino Nano Every
- TB6612使用 Dual DCモータードライブキット
- ツインモーターギヤーボックス
Arduinoからモーターを回す
ArduinoはUARTで以下の情報を受け取ります。
- 左右のモーターの回転方向(ブレーキ・ニュートラル・時計回り・反時計回り)
- 左右のモーターの回転速度
これをモータードライバに伝えてモーターを回します。
- モータードライバのHブリッジ回路で回転方向を切り替え
- ONとOFFを高速に切り替え(PWM)、平均電力をコントロールして速度調整
今回は電源がモバイルバッテリーの5V系一つしかないため、モーターの大電流による電圧降下からArduino・ルーターを守る必要がありました。
- 回路にコンデンサを追加して瞬間的な電流をカバー
- PWMのON/OFF比(Duty比)の最大値を低くする
- PWM周期を短くして電源電圧の振動を軽減
- Duty比をゆっくり目標値に近づける
- 過負荷で電源電圧が落ちたらDuty比を半分にする
以下のオシロスコープの波形は黄色がPWM信号、青色がラジコン全体の電源電圧です。
サーバーの実装
ArduinoをUSBケーブルでルーターに繋ぎ、MicroPythonからモーターの状態をUARTで操作します。このMicroPythonの上にnanowebというフレームワークでWebサーバーを実装します。
以下の機能を実装しました。
- 矢印・STOP ボタンによる前後左右の動作
- レンジスライダーによる左右のモーターの直接操作
- ポーリングにより状態を同期し、複数クライアントでの同時操作に対応
ラジコンのフェイルセーフ
HTTPでやりとりするリソースであるJSONのデコードに失敗するバグが発生しました。時間内に根本原因は特定できませんでしたが、try-except
で対処しました。他にもバグがある可能性に備えて、フェイルセーフとして異常終了時にはモーターを停止するようにプログラムを変更しました。
|
|
コントローラーのフロントエンド実装
JavaScriptはサーバーとの通信に関わるのでそれなりに理解する必要がありましたが、HTMLやCSSは雰囲気で書きました。よくわからんが、まぁ動いてるからヨシ!
日記
日記という名のメモ
8/8(1日目)
- 開講式・LT会・共通講義・グループワークのみで開発ゼミの時間はなし
8/9(2日目)
電気回路
- STBYピンを基板内部でプルアップ
- モーターの極性は揃えた
- 電流食い過ぎ&電圧ヤバすぎ問題に気づく
- とりあえずたくさんコンデンサをつける
- 470uFと100uFを外付け
- 基板内に10uFの積セラあり
- 分圧してADCにつっこむ回路を組む
- 基準電圧が電源電圧だと意味がないので1.1V基準にするため12kと3kで分圧
- INTERNALじゃだめでINTERNAL1V1でやった
- とりあえずたくさんコンデンサをつける
マイコン開発
- 電圧降下対策でPWMの周期を早めた
- ロケットのテレメトリのコードを移植してカンマ区切りでデータを渡せるようにした (爆アド)
ルーターセットアップ
- 家のWi-Fiが見つからない!
- 家のルーターの設定で2.4GHzのアクセスポイントを無効にしていたのを思い出し2.4GHzに切り替え
- 電子レンジでよく切れた
- 家のルーターの設定で2.4GHzのアクセスポイントを無効にしていたのを思い出し2.4GHzに切り替え
ルーターとマイコンを結合
- minicomの設定いじいじ
- ハードウェアフローコントロールの解除(必須なのかは不明)
- Arduino→minicomはできたけど逆ができなくて、その対処としてやった
- minicom→Arduino
- minicomは改行コードなしでキーを押した瞬間に送信(TeraTermと同じ)
- 改行コードを使ってコマンドをパースしてたので改行コードの有無に関係なくカンマとセミコロンでパースできるように変更。(これもロケットのコードから移植)
- 改行コード
- CR+LFで送ると二行改行しちゃう
- CRで送ると改行するだけでカーソルが戻らないのでminicomでCRを有効化
- ハードウェアフローコントロールの解除(必須なのかは不明)
- HTTPを学ぶ
- curlからHTTP通信ができることを確認
- pythonからUART叩いてモーター回すとこまでやった
8/10(3日目)
サーバーサイドをサンプルコードで動かす
- まずはREST APIはいじりたくなかったのでUARTの通信内容を書き換えて動作確認
- curlで動作確認
フロントエンドもサンプルコードで動かす
- まずはサンプルコードでボタンの動作確認
- その後スライドバーでスロットルを直接動かす機能を実装
電源とかPWMとか
- モーターをぶん回したらルーターの電源が落ちた
- ちゃんと(?)制御をやってみる
- ルーターの電源回路を観察
CSSとの格闘
- 最低限はできたのでCSSと格闘
- bootstrap何もわからん
- 全部vmで設定
複数端末の対応
- ここらへんでREST APIをようやく理解
- 定期的にGETしてデータをもらう形式で実装
- 定期実行でアロー関数が使えないらしく、普通の関数に書き換え
- 理由は知らない
- 参考?
- JSONのデコードに失敗してサーバーが落ちる不具合が発生
- try-exceptで回避
- プログラム終了時にシリアルを閉じる直前にモーター停止のフェイルセーフ
8/11(4日目)
モーターが片方しか回らないバグの対処
- オーバーロードしたら両方同時に出力を切るように変更
- 原因じゃなかった
- ずっと出力がおかしいから一時的な制御の問題じゃなくて通信の問題
- ISR内部でのシリアル通信をやめた
- 通信を見ると明らかにUARTでの送信ができてなかった
- ISRでフラグ書き換え、メインループでフラグ監視方式
- Serialが衝突しないから通信エラーがなくなった
GETの頻度を1Hzから2Hzに
- ちゃんと動いた
発表資料の作成
- Marpはいいぞ
8/12(5日目)
- いろいろ発表
開発コース以外のイベント
LT会
参加者交流としてLT会が設けられています。講師・チューターの方と、受講者の希望者が発表します。1日目のLTを見て自分も発表したくなり、さらにその日のグループワークのテーマ決めでCPU自作の話題が出たので4日目に4bit CPU自作について発表できました。ブログをMarkdownで書いておくとMarpで簡単にスライドにできるのでおすすめです。
グループワーク
セキュリティ・キャンプ終了後も、受講生同士で集まって好きなことができるようにグループワークが用意されています。自分のグループではRustの勉強会をすることになりました。他のチームではメンバーの興味がバラバラなため、さまざまな分野が協力できるCTFや分野指定なしのブログリレーなどをするところが多かった印象ですが、このチームでは全員Rustに興味があったのでRustを選択できました。
完走した感想
- とにかく楽しい
- サンプルコードはあったけど2,3日で集中して作るのが楽しい
- discordでいろいろ話すのが楽しい
- 安定したハードを作るのが大事
- ハードが信頼できないと上のレイヤーに上がれない(今回は電源)
- 基本情報/応用情報の勉強が役に立った
- ネットワークとかHTTPとか、広く浅く知るのには良かった
- 手を動かす、大事
- サンプルコードを参考に手を動かして独自の機能を実装するうちにHTTP通信を理解できた
- 勉強したいことが増えた
- UARTとHTTPをMicroPythonで簡単に繋げられたので、中間の組み込みLinuxをやってみたい
終わったけどスタート感はある#seccamp
— 8bitマイコン (@771_8bit) August 12, 2022