Week 3 センサとの通信とデバッグ
スライドがうまく表示されない場合は、別タブでの表示か PDF を利用してください。
Title
衛星開発ゼミ 事前学習 WEEK 3 センサとの通信と デバッグ 6軸 IMU「MPU6050」を AI のコードで動かし、AI が注意した2箇所(プルアップ・アドレス)をわざと間違えて、問題を特定するプロセスを身につける。 動かす AI と公式サンプルから始める 間違える 注意書きの2箇所を踏み外す 特定する 二分探索・観測(printf / オシロスコープ / ロジックアナライザ)・対照実験
0.1 復習
0.1 前回の復習 今日使うのは I2C 2本のバスに複数の相手。 SDA(データ)と SCL(クロック)を全員で共有する。 アドレスで相手を選ぶ。 応答は ACK(Acknowledge)で確認する。 バスの H はプルアップ抵抗が作る。 オープンドレイン出力は L に引くことしかできない。 I2C のバス構成(Week 2 の再掲) Week3 センサとの通信とデバッグ 02
0.2 位置づけ
0.2 今回の位置づけ センサと通信=シリアル通信でセンサのレジスタを読み書き Week 0 電子工作の基礎 Week 1 マイコンの原理・レジスタ Week 2 通信の規格 Week 3 センサと波形観測 Week 4 リアルタイムシステム 第1段階「要素技術と根拠のある設計」(Week 1〜4)— 今日はその3回目 合宿にもそのまま通用する。 模擬衛星の IMU(ICM-42688)が相手でも、今日の進め方は変わらない。 Week3 センサとの通信とデバッグ 03
1. センサの中のレジスタ
1 センサの中にも、番地の付いたレジスタが並んでいる Week 1 の「レジスタ=CPUと周辺回路との間の掲示板」というモデルは、 通信の先にあるセンサの内部にもそのまま通用する。 マイコンの中 CPU(プログラム) ポインタ経由 マイコン内のレジスタ 番地に値を読み書き ペリフェラル 特別な周辺回路(GPIOやシリアル通信など)が動作する センサの中 CPU(プログラム) I2C/SPI 経由 センサ内のレジスタ 番地に値を読み書き 測定回路 専用のセンシング回路が測定結果をレジスタに書き込む 変わるのは経路だけ — 「番地に値を読み書きする」という形は同じ Week3 センサとの通信とデバッグ 04
1.1 通信の役割
1.1 シリアル通信の役割 通信の仕事は、センサのレジスタへ「番地」と「値」を運ぶこと I2C の1回のやり取り=依頼と応答。 「どの番地を」「読む/書く」の依頼を運び、応答を受け取る。 模擬衛星も同じ。 IMU(ICM-42688)のレジスタは I2C で、ADC(Analog-to-Digital Converter)の MCP3008 は SPI で読み書きする。 運ばれているのは「番地と値」。 経路が何であれ、この形は変わらない。 模擬衛星のシステム構成図。ICM-42688 は I2C、MCP3008 は SPI で Pico W とつながる Week3 センサとの通信とデバッグ 05
2. 題材 MPU6050
2 とりあえず動かす — 2つの方法で「動くコード」を手に入れる 題材は MPU6050 3軸ジャイロ+3軸加速度の6軸 IMU。資料とサンプルコードが豊富な定番。 方法は2つ ①:AI に書かせたコード。②:公式のサンプルコード。 模擬衛星搭載品とは別の型番 本番は ICM-42688 という別のセンサ。基本は同じ。 今日の題材となる MPU6050 搭載モジュール Week3 センサとの通信とデバッグ 06
2.1 入口① AI
2.1 方法①:AI に書かせる AI は、ほぼ動くコードと「注意書き」を返してくる 実際の会話: claude.ai/share/d543dcbd-ec47-445b-9d15-1811179875a6 (共有のため対話型の画面だが、開発時はエージェント型を使う) 依頼 「MPU6050をI2Cでpico sdkから 動かすC言語のコードを書いて」 コード(だいたい動く) i2c_init、gpio_pull_up、mpu6050_reset、読み出しループ… 注意書き① プルアップ抵抗を確認 注意書き② アドレスは AD0 で変わる (0x68/0x69) Week3 センサとの通信とデバッグ 07
2.2 入口② 公式サンプル
2.2 方法②:公式サンプル pico-examples にも MPU6050 のサンプルがある mpu6050_reset (); // 起こして while (1) { mpu6050_read_raw (acceleration, gyro, &temp); // 読んで printf ( "Acc. X = %d, ..." , acceleration[0]); // 表示する } Raspberry Pi 公式サンプル集 pico-examples の i2c/mpu6050_i2c(概要): github.com/raspberrypi/pico-examples/tree/master/i2c/mpu6050_i2c 骨格は3つだけ。 「リセットして、読み続けて、表示する」。AI のコードもほぼ同じ構造になる。 今回は方法①で進める。 サンプルは複数種(Pico・Pico W・Pico 2・Pico 2 W)で動くように少し複雑なので、分かりやすいAIのコードの方で Week3 センサとの通信とデバッグ 08
2.3 一発で動いた
2.3 動かす 一発で動いた コードは1行も変えていない ビルドして書き込むだけ。 数値が流れ、傾けると反応する シリアルモニタに計測値が流れ続ける。 実機の配線 — Pico と MPU6050 をブレッドボードで接続 AI のコードを動かしたシリアルモニタの出力(正常に動作) Week3 センサとの通信とデバッグ 09
2.4 Wokwi
2.4 手元で再現入する:Wokwi シミュレータでも実行可能 ブラウザだけで配線と実行 Pico と MPU6050 を Wokwi 上で接続して動かせる。 ジャイロの値をスライダーで動かせる 出力の変化を手元で確かめられる。 Wokwi で Pico と MPU6050 を接続したシミュレーション画面: wokwi.com/projects/469939527447668737 Week3 センサとの通信とデバッグ 10
3. 章扉:わざと間違える
3 とりあえず動いた。 では、注意された箇所を間違えていたら? 全て一発で動作させられるとは限らない。 AIも人間も、やってみて動かなかったら修正する、というプロセスを踏む。 一発で動いたが… AI の注意書き2つは未回収のまま 実験① プルアップを間違える 実験② アドレスを間違える
3.1 疑う場所の一覧
3.1 準備①:疑う場所 疑う場所は、理解した経路の上に並んでいる コード 設定・引数 HAL Hardware Abstraction Layer ペリフェラル I2C コントローラ ピン 機能の割り当て 配線・プルアップ 電気の層 センサ 中のレジスタ この経路が、そのまま故障時に「疑う場所の一覧」になる — Week 2 で深掘りした理由の答え 経路を知らないと、「動かない」は1個の大きな謎のまま。 経路を知っていれば、疑う場所を具体化できる。 Week3 センサとの通信とデバッグ 12
3.2 二分探索
3.2 準備②:二分探索 中点で割って、候補を半分に減らす 線形探索 — 端から1個ずつ潰す 候補 1 候補 2 候補 3 候補 4 候補 5(原因) 候補 6 端から1個ずつ順に調べる — 原因に届くまで、候補の数だけ時間がかかる 二分探索 — 中点で「そこまでは正しいか」を判定する 候補 1 候補 2 候補 3 中点で1回判定 候補 4 候補 5(原因) 候補 6 …前半分はまとめて除外 二分探索に必要なのは2つ 経路の順序を知っていること(対象の仕組みを知っていること)。中点で「分ける」手段があること。 当てずっぽうとの違いは「計画」 「どことどこを切り分けるか」を決めてから、手を動かす。 Week3 センサとの通信とデバッグ 13
3.3 分ける手段は2つ
3.3 準備③:分ける手段 分割点に注目する「測定」、ノードに注目する「対照実験」 トップ事象:通信が動かない 前半に原因(コード側) コード・HAL ペリフェラル・ピン 後半に原因(電気側) 配線・プルアップ センサ 測定 — 分割点に注目 分割点で「ここまでは正しいか」を道具で直接観測し、どちら側か決める。紹介する道具:printf・デバッガ・オシロスコープ・ロジックアナライザ 対照実験 — ノードに注目 仮説を1つ持ち、分割されたノードを1箇所だけ変えて比べる。 直れば原因、直らなければ他に原因。 Week3 センサとの通信とデバッグ 14
4. 章扉:実験①
4 実験①:プルアップを間違えてみる 内蔵プルアップの有効化をコードから外す(外部プルアップは外してある)。 バスを H に戻す部品が1つも無くなる。 gpio_pull_up(...); を外す 仕込み:バスの H を作る部品がゼロに ターミナルに何も出てこない 症状:手元にあるのはこれだけ
4.1 最初の分割
4.1 最初の分割 読み出しの失敗か、通信の失敗か 仮説A 読み出しの失敗 通信は生きている。 加速度の設定やデータの扱いに失敗している。 → 疑うのはコードの設定・値の変換。 仮説B 通信そのものの失敗 通信自体が成立していない。 経路の根本が壊れている。 → 疑うのは配線・電気信号・アドレス。 この2つを、1回で分けられる観測は何か? Week3 センサとの通信とデバッグ 16
4.2 資料は2分冊
4.2 分割の道具を探す MPU6050 の公式資料は2分冊 — 探し物は「レジスタ」 Product Specification 概要、電気的条件、ピン配置、通信方法が載っている。 Register Map and Descriptions レジスタの番地と各ビットの意味が載っている。今日開くのはこちら。 Week3 センサとの通信とデバッグ 17
4.3 WHO_AM_I
4.3 分割点 WHO_AM_I(0x75)は、読むと必ず 0x68 を返す ① 一覧表で当たりをつける 頭から読まず、目次 → レジスタ一覧表とたどる(Week 1 と同じ読み方)。 一覧の末尾近くに WHO_AM_I(0x75)。 ② 該当ページで確かめる 読むと固定値 0x68 が返る「答えの分かっている読み出し」。期待どおりなら経路の生存が1回で確定する。 Week3 センサとの通信とデバッグ 18
4.4 道具① printf
4.4 道具①:printf 中の値と進行を、文字で外に出す // 最初にWHO_AM_Iレジスタを読み、センサと正しく通信できているか確認する uint8_t whoami = mpu6050_read_whoami (); printf ( "WHO_AM_I = 0x%02X (expected 0x68)\n" , whoami); 組み込みでもよく使われる観測手段 ソフトウェアの実行状況をログに出せば二分探索が進む。 printf の中身は実はかなり複雑 マイコンにおける printf の経路は UART だったり USB だったりする。ソフトウェアでの"文字列"の扱いも難しい。 発展:デバッガ SWD(Serial Wire Debug)をつなぎ、実行を止めて中を覗く道具がある。今日は紹介まで。 Week3 センサとの通信とデバッグ 19
4.5 観測結果
4.5 観測結果 答えが返ってこない — 通信そのものが失敗している ターミナルに何も出てこない WHO_AM_I の結果の行が届かない。これ自体が観測情報。 「呼び出しから戻らない」と考えられる エラー値が返るだけが失敗ではない。 来ない応答を待ち続けて止まっている。 原因が絞り込めた 「読み出しと設定の扱い」側ではなく、通信側に原因があることが分かる。 「ここまでは動く」を示す。 今回は省略するが、本来は printf() が動作することは単体で検証が必要。 printf() の動作不良か、応答待ちで到達しないのか切り分けも必要。 mpu6050_read_whoami() 読み出しの呼び出し 応答を待ち続けて戻らない 1バイトの往復すら成立していない printf(...) この行に到達しない — 何も表示されない Week3 センサとの通信とデバッグ 20
4.6 発展:読むのに書く
4.6 発展 「読む」のシーケンスは、書くことから始まる 1段目は WRITE。 「これから読むのは 0x75 です」と番地を送る。 電気信号を見る — ソフトの道具では、ここから先が写らない コードの並びの理由。 i2c_write_blocking と i2c_read_blocking が並ぶのは、このため。 WHO_AM_I の番地 0x75 を WRITE してから、データ 0x68 を READ する2段のシーケンス Week3 センサとの通信とデバッグ 21
5. 電気信号を見る
5 電気信号を見る — ソフトの道具では、ここから先が分からない マイコンの中 — printf・デバッガで見える範囲 コード HAL ペリフェラル 観測の境界 マイコンの外 — ソフトからは見えない範囲 SDA・SCL の電気信号 配線・プルアップ センサ ソフト側の手がかりは「呼び出しから戻らない」だけ。 コードにもログにも、SDA・SCL の上の信号は現れない。 「はず」を確かめるには、信号を直接見るしかない。 次の中点はマイコンの外 — 電気信号を測る道具を使う。計測器はキット外、今日はデモで見せる。 Week3 センサとの通信とデバッグ 22
5.1 道具② オシロスコープ
5.1 道具②:オシロスコープ 電圧の変化を、波形として描画する 見えるのは電圧の形 波形の形、電圧レベル、立ち上がりのなまり。 デジタル信号の実体もアナログの電圧 通信中なら、H と L を行き来する矩形波が見えるはず。 デモ機材の構成 — Pico と MPU6050 の間の SDA・SCL にプローブを当てる Week3 センサとの通信とデバッグ 23
5.2 観測:立ち上がらない
5.2 観測 波形が全く立ち上がっていない 復習:オープンドレインとプルアップ(Week 2) どの部品も線を L に引くことしかできない。 H に戻す仕事は、プルアップ抵抗だけが担う。 実測:プルアップ無しの SDA・SCL 立ち上がりが無く、通信ができていない。 「H を作る部品が無い」ことが波形にそのまま現れている。 Week3 センサとの通信とデバッグ 24
5.3 対処:プルアップを戻す
5.3 対処 プルアップを戻すと波形が立つ SDA・SCL に外部プルアップ 1kΩ を追加 無し 全く立ち上がらない。 通信は成立しない。 内蔵のみ 動くが、立ち上がりが遅く余裕が無い。 AIのコードはこの状態だった。 外部 1kΩ H へ引き上げる力が強い。 理想的なクロック波形になった。 Week3 センサとの通信とデバッグ 25
5.4 復旧
5.4 復旧 復旧した — ただし WHO_AM_I は 0x70、中身は MPU6500 だった 通信は復旧 固定値が返り、計測値も流れている。経路の生存確認としては成立。 部品が偽物:WHO_AM_I = 0x70(期待は 0x68) 0x70 は後継 MPU6500 の値。刻印は MPU-6050 でも、中身は別品種。Amazon のレビューにも同じ報告があった。 まとめ:デバッグの流れ 症状 → 分割(WHO_AM_I・printf)→ 分割(波形) → 原因 → 復旧。 中点を決めて、観測して、半分ずつ捨てた。 復旧後の出力 — WHO_AM_I = 0x70 (expected 0x68) Amazon の商品レビューにも同じ報告 Week3 センサとの通信とデバッグ 26
6. 章扉:実験②
6 実験②:アドレスを間違えてみる AI の注意書きの2つ目「アドレスは AD0 で変わる」を、誤ったハード設計を想定して試してみる。 AD0 ピンを設計と違う側(H)に配線 仕込み:誤ったハード設計を再現 波形の形は正常なのに、読めない 予想される症状 気づく方法を2つ試す 測定と、対照実験
6.1 スレーブアドレス
6.1 アドレスとは何か 0x68 はレジスタではなく、センサを呼ぶ「アドレス」 マイコン 0x68 宛に依頼を送る I2C バス — 住所で相手を選ぶ センサ MPU6050 — 住所:スレーブアドレス 0x68(AD0=L)/0x69(AD0=H) WHO_AM_I 部屋番号 0x75 設定レジスタ 部屋番号 0x6B など 計測値レジスタ 部屋番号 0x3B〜 I2Cバス内の住所と、センサ内の部屋番号の2階層 スレーブアドレス(0x68)=建物の住所。 レジスタの番地(0x75 など)=建物の中の部屋番号。 AD0 ピンでアドレスを変更できる 同じセンサを1本のバスに2個つなぐための仕組み。 配線が想定と違えば、センサのアドレスが整合しない。 MPU6050 搭載モジュール — AD0 ピンの配線でアドレスが決まる Week3 センサとの通信とデバッグ 28
6.2 AD0 を変える
6.2 仕込み AD0 を H にすると、センサのアドレスは 0x69 になる 想定はハード側のミス AD0 の配線が設計と違っていた、という状況を再現する。 症状はまた「何も出ない」 0x68 を呼び続けるコードは、WHO_AM_I を読めなくなる。 ソフト側からは区別がつかない プルアップ無しのときと、見える症状はまったく同じ。 AD0=H で応答アドレスは 0x69 に。0x68 への呼びかけには誰も応答しない Week3 センサとの通信とデバッグ 29
6.3 道具③ ロジックアナライザ
6.3 道具③:ロジックアナライザ デジタル信号の意味を解読する装置 I2Cのシーケンス(Week 2 の復習) START の後にアドレス7ビット+読み書き1ビット。 9クロック目に受け手が ACK、応答が無ければ NACK。 ロジアナのプロトコルデコード機能 ビット列を意味の層に変換して文字で並べる。 オシロはアナログ、ロジアナはデジタル 電圧の形(なまり)は見えない。H/L の列と意味だけを見る。 ACK の拡大 — 9クロック目で受け手が SDA を L に引く 正常時のデコード — 0x68 WR に ACK、番地、Re-Start、0x68 RD に ACK。WRITE → READ の2段がそのまま現れている Week3 センサとの通信とデバッグ 30
6.4 測定で気づく
6.4 測定で気づく 0x68 へ呼びかけて、NACK — そのアドレスには誰もいない NACK=9クロック目で誰も SDA を L に引かなかった 「0x68 へ呼びかけ→NACK」が確認できる。 波形は正常=電気の層は健全 クロックは見えていて、アドレスが間違っているからACKが来ない。 NACK の拡大 — 9クロック目で誰も SDA を引かない AD0=H の実機に 0x68 で呼びかけたデコード — WR も RD も NAK で Stop Week3 センサとの通信とデバッグ 31
6.5 対照実験で気づく
6.5 対照実験で気づく アドレスを1箇所だけ変えて、結果を比べる コードA そのまま #define MPU6050_ADDR 0x68 現状の再現。動かないことを確かめる基準の側。 コードB 1箇所だけ変える #define MPU6050_ADDR 0x69 仮説「アドレスが違うのではないか」に対応する変更のみ。 結果を比べる — 直れば「アドレスの不一致」と確定。直らなければ「原因は他にある」と分かる。どちらに転んでも切り分けが進む 確かめ終わったら、設計としての正解に合わせて確定する。 今回はハード側の誤りの想定なので、配線を直してコードは 0x68 に戻す。「動いたからそのまま」とは違う。 Week3 センサとの通信とデバッグ 32
7. 整理:使い分け
7 整理:切り分けの手段は2系統 — 測定と、対照実験 測定 — 中点で実際に起きていることを、道具で直接見る printf マイコンの中の値と進行 オシロスコープ 電気信号の形(電圧・なまり) ロジックアナライザ 信号の意味(アドレス・ACK/NACK) 対照実験 — 道具が無くてもできる 1箇所変えて比べる 仮説と計画が前提 どちらも目的は同じ — 二分探索の中点で、候補を半分に減らす 順序は観測が先、修正は後。 対照実験の変更も「直すための変更」ではなく「分けるための変更」。当てずっぽうで修正するわけではない。 Week3 センサとの通信とデバッグ 33
7.1 切り分け表
7.1 切り分け表 症状から、壊れた層を逆引きする 症状(波形を見る) 壊れた層 次に疑う場所 波形が立ち上がらない・崩れている 今日の実験①(プルアップ無し) 電気の層 配線・プルアップ・ショート ソフトをいくらいじっても直らない 波形は正常なのに NACK(応答が無い) 今日の実験②(AD0 違い) 意味の層 アドレス・設定・相手の状態 電気の層は問題なしと確定できる Week 2 の「電気の層/意味の層」の2階建てが、そのまま切り分けの軸になる — デバッグでもレイヤー(仕組みの層)の理解が必要 Week3 センサとの通信とデバッグ 34
8. 少し作っては確かめる
8 進め方の教訓:少し作っては、動かして確かめる 一気に全部作って、最後に確かめる 作る 作る 作る 作る 確認 動かなかったとき、疑う範囲は「全部」 少し作るごとに、動作確認して足場を築く 作る 確認 ✓ 作る 確認 ✓ 作る 疑う範囲は、常に「直前の一歩」だけ 確認が通った地点は「ここまでは正しい」という足場。 配線1本、設定1つ、機能1つ。単位を小さく刻む。 壊れてから観測点を探すのが二分探索なら、作りながら観測点を残すのがこの進め方。 Week3 センサとの通信とデバッグ 35
8.1 任せ幅のバランス
8.1 ただし AI は一気に作れる 「一つずつ」と「一気に」— 任せ幅は対象の素性で決める 定番部品 今日の MPU6050。 情報が厚く、一発でも動きやすい。 ← 一気に任せる 小さく確かめながら進む → どこに置くかは設計判断 — 対象の素性で決める「つまみ」 初物・自作基板 合宿の実機。 外れたら絞り込みは自分の仕事。 一気に任せて動けば最速。 動かなければ、今日のように切り分ける。 初物ほど、小さく確かめる価値が上がる。 AI の当たる確率が下がるぶん、観測点を残しながら進む。 Week3 センサとの通信とデバッグ 36
9. まとめ
9 まとめ:特定のプロセスと「動く≠適切な設計」 特定のプロセス 中点を決め、測定(printf・オシロ・ロジアナ)か対照実験で半分に割る。 確実に動く設計 内蔵プルアップで動いてしまっても、実機は外部プルアップ。 合宿への接続 実機 TOP 基板の ICM-42688 も I2C。 模擬衛星 TOP 基板の ICM-42688 まわり 右側に R5・R6=1kΩの外付けプルアップ Week3 センサとの通信とデバッグ 37
9.1 宿題
9.1 宿題 身近な機械のトラブルを、どう調べるか — 手順書を設計する 経路の分解 例:スマホ → ルーター → 回線 → プロバイダ 分割点を決める 中点をどこに置くか 観測か対照実験か 設定画面で見る/別のスマホで比べる 次の一手 結果ごとの分岐まで設計する 題材は自由。 Wi-Fi ルーターにつながらない、リモコンが効かない、自転車のライトが点かない、など。AI に聞くのは前提。 Week3 センサとの通信とデバッグ 38