4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP32を使ってヘッド不良のHDDから無理やりデータを取り出したお話

4
Posted at

どういうこと?

知人からデータ保管用にしてたHDDが突然壊れたと連絡。直接見に行くと、確かに認識した途端読み込みができなくなりOSごとスタックする。

知人の環境は以下の通り。

  • Windows 11(バージョンは不明)
  • HDD: Seagate ST1000LM035 1TB (USB3.0接続)

自分はセクタ単位でディスクをクローンする装置を持っていたので、新しいHDDを購入して1週間放置してみてもそもそもリードエラーで進まない。Live USBで起動させたFedoraでlsblk -fしても表示はするけどマウントする頃にはOSごとスタックする。どうしようもなかった。

ただし、不審な点が一つあった。それはWindowsで接続した際、フォルダのツリーが読み込まれることだった。
本当にヘッドや円盤に不良があれば、データが完全に吹き飛んでいることもありうるのに接続直後(=電源が入る)は読み込めたのであった。

直接HDDを触ってみたところ、以下の状況がわかった

  1. 電源投入
  2. ヘッドが動き始める
  3. OSで認識
  4. 20秒程度で回転が停止(認識は行われたまま)
  5. 読み込みができずフリーズ

ということだった。
ということは?最初の20秒で取れるだけのデータを取って強制停止させて再始動させて繰り返せばデータは取り出せるのではないのでは・・・?と思いつき、実行に移した。

※今回の現象ではなぜそうなったかの追求は控える。なぜならそこまでHDDのことはわからないから。有識者教えて。

実行環境

image.png
image.png
image.png

  • OS: Cachy OS
  • Terminal???: bash
  • IDE: Visual Studio Code (v1.117.0)
  • IDE2: Platform IDE IO (3.3.4)
  • 開発モジュール?: Espressif ESP32 Dev Module
  • ESP32: 古代昔に買ったやつ

1. 設計

ゴチャゴチャ言っていてもしょうがないので、箇条書きしてみる。
ESP32、リレーモジュール、安定化電源(もしくは5Vを出せる電源)、Micro USB(USB 2.0)を用意した上で

  1. リレースイッチに電圧源の5Vとスイッチとなる3.2V(GPIOから)を接続する
  2. シリアル通信でESP32にリレーのON/OFFできるようにプログラムを組む
  3. リレーがONになったとき、5VがHDDに掛かって動き始める
  4. 20秒程で停止する前にリレーをOFFにする
  5. すぐに再始動させて1に戻る

上記の計画を作って実行した。

まずHDDの電源を強制的にON・OFFにできるケーブルを作らないといけない。これは幸いSATA→USB3.0の変換装置がSATA→USB2.0でも接続できたのでUSB2.0ケーブルを切断。電源(V+、GND)を切断してPC側の電源を遮断して独立させることで解決した。

ただし、USB2.0のデータ線(D+、D-)はノイズにめちゃくちゃ弱いらしく、確かに切断してはんだ付けで再接続したときは反応に悪かった?そのため、ハサミやカッターで導線が見えるくらいに表面を削り、赤(V+とGND)だけを切断した。
(後に判明するがGNDをつないでなかったので認識しなかっただけかもしれない?処分したから不明)

次にESP32のコードと配線を組む。コードと配線図は以下の通り。配線図は使用後なのでだいぶ終わっているが、とにかく特定のGPIOがHIGHにしたときにリレースイッチが動作するようにすればいい。

main.cpp
#include <Arduino.h>

// ここのピンを指定のGPIOピン二設定する
#define HDD_PIN 17

void setup()
{
  pinMode(HDD_PIN, OUTPUT);
  Serial.begin(115200);
}

void loop()
{
  if (Serial.available() > 0) {
    // シリアル通信で送られてくるデータ待ち
    String command = Serial.readStringUntil('\n');
    
    // 不要な部分をカット
    command.trim();
    if (command == "ON") {
      digitalWrite(HDD_PIN, HIGH);
      Serial.println("リレーをONにしました");
    } 
    else if (command == "OFF") {
      digitalWrite(HDD_PIN, LOW);
      Serial.println("リレーをOFFにしました");
    }
  }
}

コードは見ての通りシンプルなもの。

上記のmain.cppに対応したスクリプトを構築した。bashで動く。

start-rescue.sh
#!/bin/bash

ESP_PORT="/dev/ttyUSB0"      # ESP32のシリアルポート(ls -la /dev/で自分で確認して)
TARGET_DISK="/dev/disk/by-id/usb-Seagate_Expansion_00000000NAC3FYGG-0:0-part1" # 重要。ls -la /dev/disk/by-id/で確認する。lsblk -fと合わせて接続前と接続後で比較して確認する。
IMG_FILE="{YOUR_DIR}/recovery.img"            # ddrescueの保存先のファイル。確実に保存できるならどこでもいい。復元容量に注意。
MAP_FILE="{YOUR_DIR}/recovery.map" # ddrescueが再開できるように記録するファイル。これがないと切断するたび1から始まって本末転倒になる。
RUN_TIME="30s"                # 秒。ddrescueを実行させる時間。これを超えるとkillされる。読み込みがスタックする前を狙う。sをつけるのを忘れずに。
COOL_TIME="5"                # 秒。電源OFFにしてからプラッタが止まるまで待つ時間。ぶっちゃけいるのかはわからん。

# シリアルポートのボーレートをESP32側(115200等)と合わせる
stty -F $ESP_PORT 115200

while true; do
    echo "-----------------------------------"
    echo "[1] HDDの電源をONにする"
    echo "ON" > $ESP_PORT

    echo "[2] ディスクの認識を待機中..."
    while [ ! -b "$TARGET_DISK" ]; do
        sleep 0.5
    done
    echo "ディスクを認識!"

    sleep 1

    echo "[3] ddrescue実行!(${RUN_TIME})"
    timeout $RUN_TIME ddrescue -d -n $TARGET_DISK $IMG_FILE $MAP_FILE

    echo "[4] 時間切れ。ddrescue強制終了"
    echo "OFF" > $ESP_PORT

    echo "[5] プラッタ停止とクールダウン待機(${COOL_TIME}s)"
    sleep $COOL_TIME
done

2. 設計(回路)

ソフトはできてもハードは全くわからないのでGeminmiに聞きまくったり調べまくって設計。リレーモジュールはこれを買った
image.png

IMG_20260429_160528.jpg

回路図はない。絵面が終わってるのはそんなものはわかっている。当方は電気に対して全くのド素人。

要するに、ESP32→リレー→MicroUSB(Vin+、GND)→HDDという順番でつないだらいい。

ポイントとして、MicroUSBのピン(緑、白、赤、黒)の赤はVoutと繋げばいいが、黒(GND)はPCのUSBポート側の黒も一緒につなぐこと。そうしなければ、PCで認識しない。これがわからず2時間くらい戸惑った。

5Vの電源はなんでもいい。当初は安定化電源を使っていたが、Surface Pro 7+のポート数に困りデスクトップに移動したのち、コンセントから5V出せる普通の充電器から充電専用のケーブルを切断。そこから5Vを取った。
※この方法は短絡すると割と危ないので参考程度に。昔のiPhone純正のコンセントを使ったが保護回路が聞くだろうとか抜かしていたが、今思えばイカれてる。一応短絡対策で物理的に距離を離した。

それからMicroUSB、ESP32、リレーのGNDを揃えていざ実践!

3. 動作実験

ああ写真を取り忘れたが、とにかく予想していた通り動いた。

夜中の0時似始めて4時くらいに作業を終了させスクリプトを実行させて寝たが、昼の2時頃には8割ほど完了してた。それ以降進まなくなっていて抜き差ししたり手動でリレーをON/OFFにしたりしてるとついに認識すらしなくなった。RIP

元々空き容量が2割残っていることは事前に確認済みだったので何回か試して完全に認識しなくなったところを確認したところで終了。
image.png

.shで指定したディレクトリに上記のファイルが生成されているのでrecovery.imgを違うディスクに焼くなりマウントしてrsynccpするなり好きに移動する。
注意点としてこのrecovery.img、取り出したディスクの形式に沿って生成されるようでntfsだった。そらまあ当たり前といえば当たりだが・・・。データ自体を救出したかったので当方は焼かずにマウントしてntfsにフォーマットし直した新しいディスクにrsyncした。

最後に

自分としては初めてマイコンを使う機会になった。マイコン自体は昔から持ってたがなんせ使い道がない。WIFIとかBluetoothとかついててもしょうがないが、こういうリレーを使ったりちょっと深いところを触るにはとっておきに便利なもんだと認識した。今回はHDDを復元させるための電源装置として使ったが、もっと知識を深めればヘッダも読み込めるようになるのかね・・・?電気電子専攻なクセして電気に関しては大学に入ってからが本当初めてなので何も知らない。車やバイクの電装系を触ってから多少抵抗がなくなったので今回のも試してみようと思った。

本題とはそれますが、車の電装関係はこっちでよく上げてます。ソフトウェア関係が出てきたらこっちでも書くかも。興味がある方はこちらもどうぞ。
https://minkara.carview.co.jp/userid/3775831/

前触ったときは抵抗を燃やしたり配線が燃えたりしたが、今回は火事にならずここまで完成させれたことに満足。

参考になるかはわかりませんが、同じ症状になった方の参考になれば幸いです。
どうぞ、見ていただきありがとうございました。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?