CM4 フリート管理 (cm4-fleet)¶
ホスト PC から複数の CM4 に対して、OTA アップデート・SSH 鍵配布・設定配布を一括で行うツールです。
背景・制約¶
- OTA はホスト PC から
git archiveで作った tarball を SFTP で転送します。CM4 の通常のインターネット到達性には依存しません。 cm4/bin/*.out(C++ ブリッジ)は毎回デバイス上で再ビルドします。g++のみで完結し数秒、ネットワーク不要です。cm4/camera/dist/cam_server_v3(PyInstaller ビルド)は**デフォルトで再ビルドしません**。pip install pyinstallerがネットワークを要求するためです。カメラコードを変更した場合は--rebuild-cameraを指定してください(cm4-fleet deployが自動でオンデマンドの HTTP プロキシトンネルを張るため、手動でのネットワーク切り替えは不要です。詳細は オンデマンドインターネット到達 (cm4-fleet proxy) を参照)。cm4/runtime/*.json(機体固有の HSV キャリブレーション等)は tar 展開でもpush-configでも意図せず上書きされません。転送は既存ファイルへの上書き・追加のみで、明示的に指定しない限り削除・全体同期は行いません。
前提条件¶
cm4-fleet deploy は**軽量な更新**であり、初回のフルセットアップ(CM4 セットアップの cm4/setup.sh)を代替しません。対象デバイスには事前に cm4/setup.sh が(インターネット到達可能な環境で)一度実行され、fastapi/uvicorn の pip install と g++(build-essential)が導入済みである必要があります。これらが無い状態で deploy すると stage=build で分かりにくいエラーになります。
インストール¶
paramiko はホスト専用の依存です。cm4/setup.sh の pip install -e . はデバイス側にもインストールされる dependencies のみを見るため、通常の uv sync では入りません。
インベントリ¶
デフォルトでは機体番号 N(0〜12) に対して 192.168.20.(100+N) を対象とします(既存の接続規則と同じ)。
台数追加や IP を個別に固定したい場合は、環境変数 ORION_FLEET_INVENTORY で JSON ファイルを指定できます。
{
"ip_base": "192.168.20.",
"ip_offset": 100,
"hosts": [
{ "machine_no": 0 },
{ "machine_no": 3, "ip": "192.168.20.150" }
]
}
対象の選択は各コマンド共通で次のいずれかを指定します。
--all # 全機体
--machines "0,1,5-8" # 機体番号(範囲指定可)
--ips "192.168.20.101,192.168.20.105" # IP直接指定(インベントリ外も可)
初回セットアップ: SSH 鍵のブートストラップ¶
対象デバイスがパスワード認証のみの場合、まずこの PC の公開鍵を配布します。
- パスワードは環境変数
ORION_FLEET_PASSWORDまたは対話プロンプトでのみ受け付けます(CLI 引数では受け付けません)。 - 配布する公開鍵は
~/.ssh/id_ed25519.pub/~/.ssh/id_rsa.pubを自動検出します。--pubkey-fileで明示指定も可能です。 - 既存の
authorized_keysの内容(他の開発者の鍵)は保持したまま追記します。 - 鍵追加後、鍵認証での再接続を検証してから成功を報告します。失敗した場合は他の対象機には影響しません。
- 初回はこのコマンドを先に実行してください。
status/deployはデフォルトで未知のホスト鍵を拒否するため、事前にこの PC からその機体へ一度も SSH していない場合は失敗します(bootstrapはホスト鍵を自動受理し~/.ssh/known_hostsに保存します)。
OTA デプロイ¶
uv run cm4-fleet deploy --all
uv run cm4-fleet deploy --machines "0,1,5-8"
uv run cm4-fleet deploy --ips 192.168.20.101 --ref v1.2.3 # 特定タグ/コミットへ
uv run cm4-fleet deploy --ips 192.168.20.101 --force # 稼働中でも上書き
uv run cm4-fleet deploy --ips 192.168.20.101 --rebuild-camera # カメラも再ビルド(ネット到達は自動)
処理内容:
- ホスト側の未コミット差分を検出(デフォルトは拒否、
--allow-dirtyで許可)。 git archive <ref>で tarball 作成(.gitignore対象は自然に除外されます)。- 対象デバイスごとに並列実行: 稼働中ならスキップ(
--forceで上書き可)→ tarball 転送 → 既存ツリーへ展開 → 削除されたファイルのみ個別削除 →cm4/update.sh実行(ブリッジ再ビルド・サービス再起動)→ デプロイ済みバージョン記録 → 起動確認。 - 1 台の失敗は他台に影響しません。成功/失敗をステージ付きでサマリ表示します。
ロールバック¶
専用コマンドはありません。古い ref を指定して deploy を再実行することがロールバックです。
ブリッジは毎回再ビルドするため数秒〜十数秒で戻せます。カメラコードを含む変更を跨ぐ場合のみ --rebuild-camera が必要です。
オンデマンドインターネット到達 (cm4-fleet proxy)¶
ロボット用 LAN は常時インターネットに到達できません。デバッグ用に一時的にインターネットへ出たい場合、cm4-fleet proxy でこの PC 経由の HTTP プロキシトンネルを張れます。
- 実現方式は SSH のリバースポートフォワードです。PC 側で軽量な HTTP フォワードプロキシ(
host/lib/fleet/http_proxy.py)を起動し、paramiko の固定リバースポートフォワード(ssh -R相当、SOCKS 等の追加プロトコル実装は無し)でデバイス側の127.0.0.1:<port>へ中継します。外部のsshバイナリには依存しません。 - オンデマンド専用です。「常時」インターネットに出られるわけではありません。 このコマンドを実行している間・対象デバイスへの SSH セッションが生きている間だけ有効です。PC がスリープ・ネットワーク切断・シャットダウンするとトンネルは切れます。常時稼働のゲートウェイが必要な用途には向きません。
- 前面で動作し続けます。Ctrl+C で全台のトンネルを閉じて終了します。
- デバイス側で使う場合は
http_proxy/https_proxy環境変数にこのプロキシを指定します: aptはAcquire::http::Proxy/Acquire::https::Proxyを設定すればこのプロキシ経由で使えます(実機でapt-get updateの到達を確認済み)。http_proxy/https_proxy環境変数だけでは apt には効かないため、/etc/apt/apt.conf.d/に設定ファイルを置く必要がある点に注意してください:(SOCKS はサポート対象外です。echo 'Acquire::http::Proxy "http://127.0.0.1:18080";' | sudo tee /etc/apt/apt.conf.d/99-orion-fleet-proxy.conf echo 'Acquire::https::Proxy "http://127.0.0.1:18080";' | sudo tee -a /etc/apt/apt.conf.d/99-orion-fleet-proxy.conf/usr/lib/apt/methods/に SOCKS 用メソッドが無く、apt-transport-*系パッケージも未導入のため、reverse dynamic forwarding 方式は使えません。今回 HTTP プロキシ方式を採用したのはこのためです。)pip・curl・git(http.proxy=http://127.0.0.1:<port>)はhttp_proxy/https_proxy環境変数だけで標準の HTTP プロキシとして問題なく使えます(追加パッケージ不要)。cm4-fleet deploy --rebuild-cameraは内部でこの仕組みを自動的に使い、cm4/update.shのpip install pyinstallerにプロキシ環境変数を渡します。手動でcm4-fleet proxyを先に実行しておく必要はありません。
設定配布¶
uv run cm4-fleet push-config --all --target env --file .\fleet-env.txt
uv run cm4-fleet push-config --machines 3 --target hsv --file .\hsv_101.json
uv run cm4-fleet push-config --ips 192.168.20.101 --target authorized-keys --file .\other-dev-key.pub
uv run cm4-fleet push-config --all --target file --file .\local-note.txt --remote-path ".orion_deploy/local-note.txt"
--target hsv のような機体固有ファイルは、誤って全台へ同一内容を配布しないよう --all との併用を拒否します。
--target env は /home/ibis/.orion_deploy/env に配置され、cm4/control_server.service の EnvironmentFile から読み込まれます。反映には sudo systemctl daemon-reload && sudo systemctl restart control_server.service が必要です(次回 cm4-fleet deploy を実行した際にも cm4/update.sh が同じ再起動を行うため自動的に反映されます)。
--target file / --remote-path で git 管理下のパス(Orion_CM4/ 配下でリポジトリに追跡されているファイル)を指定しないでください。次回 cm4-fleet deploy の展開で上書きされ、変更が消えます。機体固有の恒久的な設定は .orion_deploy/ 配下など git 管理外の場所に配置してください。
ステータス確認¶
稼働状態(Running/Stopped/Offline)とデプロイ済み commit を 1 台 1 行で表示します。
制約¶
- デプロイ時はブリッジを毎回ビルドします。
--rebuild-cameraを指定した場合、カメラもフルビルドします。 - 対象デバイスの
sudoがパスワードを要求する設定になっている場合、cm4-fleet deploy(cm4/update.sh内のsystemctl呼び出し)は失敗します。sudoers の自動生成は行わないため、その場合は手動で NOPASSWD 設定を行ってください。 cm4-fleet proxyは常時稼働のインターネットゲートウェイではありません(前述)。デバイスを恒常的にインターネットへ出したい場合は本ツールの対象外です。cm4-fleet proxy経由でaptを使うにはAcquire::http::Proxyの設定が必要です(前述)。http_proxy/https_proxy環境変数だけでは効きません。
トラブルシューティング¶
stage=connectでServer not found in known_hostsのようなエラー: その機体に対してcm4-fleet bootstrapを先に実行してください。stage=buildでそのようなファイルやディレクトリはありません:git archiveは git に追跡されているファイルのみを含みます。新規ファイルを追加した場合はgit addしてから(コミット前でも--allow-dirtyで)デプロイしてください。--rebuild-camera時にpip install pyinstallerが失敗する:cm4-fleet deployは自動でオンデマンドの HTTP プロキシトンネルを張りますが、この PC 自体がインターネットに到達できていることが前提です(PC のネットワーク接続を確認してください)。stage=proxyで失敗する場合はリバースフォワード自体の確立に失敗しています。デバイス側で既に127.0.0.1:18080を使う別プロセスが動いていないか確認してください。