Unityでデジタルツインに「解析の眼」を授ける|mechArm 270データ可視化
ロボットアームとの双方向通信に成功した喜びも束の間、新たな課題に直面しました。ターミナルを高速で流れる数値の滝を見ていても、ロボットが本当に正しく、効率的に動いているのかが直感的にわからなかったのです。
そこでリアルタイム・データモニターの自作に挑みました。
※本プロジェクトの目的:実機「mechArm 270 M5」の制御を通じて、AIの判断をいかに物理的な動きへ変換するか。そのロボット制御の仕組みを理解するプロセスを記録・検証するものです。
リアルタイム・グラフ化ツール
このスクリプトは、実験2で成功した /joint_states トピックを監視し、関節1(link1)の動きをリアルタイムで波形として描き出します。
保存方法: unity_ws/scripts フォルダの中に、標準テキスト形式で joint_monitor.py として保存してください。
Python
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import JointState
import matplotlib.pyplot as plt
from collections import deque
class JointVisualizer(Node):
def __init__(self):
super().__init__('joint_visualizer')
# 実験2で確認したトピックを購読
self.subscription = self.create_subscription(
JointState, '/joint_states', self.listener_callback, 10)
# 過去100データ分のバッファを用意
self.data_buffer = deque(maxlen=100)
self.time_buffer = deque(maxlen=100)
self.counter = 0
# グラフの初期設定
plt.ion() # インタラクティブモードON
self.fig, self.ax = plt.subplots()
self.line, = self.ax.plot([], [], 'r-')
self.ax.set_ylim(-2.0, 2.0) # ラジアンの範囲
self.ax.set_title('Real-time Joint 1 Position')
self.ax.set_xlabel('Time Steps')
self.ax.set_ylabel('Angle (rad)')
def listener_callback(self, msg):
# link1 の角度(index 0)を取得
joint_pos = msg.position[0]
self.data_buffer.append(joint_pos)
self.counter += 1
self.time_buffer.append(self.counter)
# グラフの更新
self.line.set_data(list(self.time_buffer), list(self.data_buffer))
self.ax.set_xlim(max(0, self.counter - 100), self.counter + 5)
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def main():
rclpy.init()
node = JointVisualizer()
try:
print("グラフ表示中... (Ctrl+Cで停止)")
rclpy.spin(node)
except KeyboardInterrupt:
pass
rclpy.shutdown()
if __name__ == '__main__':
main()実行の準備:ライブラリのインストール
グラフを描画するために、matplotlib というライブラリが必要です。ターミナルで以下のコマンドを 1 回だけ実行してください。
conda activate ros_env
pip install matplotlib実験の進め方(3枚のターミナルを使いこなす!)
デジタルツインらしくなってきました。以下の順に起動してください。
Unityを再生(▶︎)する: 青いHUDを確認。
ターミナル1(送信):
python3 robot_dance.pyでロボットを動かす。ターミナル2(可視化): ここで今回のツールを起動!
cd ~/unity_ws/scripts
conda activate ros_env
source ~/unity_ws/install/setup.zsh
python3 joint_monitor.pyこの実験で「見える」こと

キレの視覚化: 実験1で設定した1.0秒ごとのポーズ遷移が、グラフ上でカクカクとした波形として現れます。
物理挙動の確認: ロボットが目標角度に到達した際、少しだけ揺れているような物理エンジンの細かい挙動も、グラフなら捉えることができます。
システム遅延の把握: プログラムで送った瞬間と、グラフの山が動く瞬間のズレを見ることで、通信環境の健康診断ができます。
意外な「落とし穴」たち
ツール制作の序盤、いくつかの初歩的な、しかし厄介な壁にぶつかりました。
ファイル名の罠: プログラムを保存する際、無意識に
.txtが末尾についてしまい、python3コマンドでファイルが見つからないと怒られる事態に。フォーマットの罠: Macのテキストエディットが標準で「リッチテキスト(.rtf)」になっていたため、コードの中に余計な装飾情報が混じり、実行エラーが発生。
ターミナル管理の混乱: 通信サーバー(Endpoint)、ダンス指令(Dance Script)、生データ表示(Echo)、そしてグラフツール。気づけば4枚ものターミナルが画面を埋め尽くし、どれがどれか分からなくなるマルチターミナル迷子になりました。
これらを一つずつ整理し、iCloud同期外のローカルフォルダ(unity_ws)に正しく配置することで、開発環境は劇的に安定しました。
疑問:「Joint 1」の正体を探る
最初に赤い線が一本、グラフ上に現れたとき、一つの疑問が湧きました。このJoint 1というのは、Unityのどの部分のことなのか?
データのインデックス(並び順)を紐解くと、以下の事実が判明しました。
ROS 2のメッセージには
link1からlink6が順番に格納されている。プログラムで index[0] を指定して描画していたのは、紛れもなくロボットの土台となる link1 の回転角だったのです。
この発見により、プログラム上の数値と3Dモデルの挙動が、頭の中で完全に一致しました。
全6軸の同時監視へ:データを丸裸にする
「他の関節も同時に見たい」という好奇心から、ツールをさらに改良しました。6本の異なる色の線が、ダンスのリズムに合わせて一斉に波打つ光景は圧巻です(サムネイルの画像がまさにソレです)
2倍速の検証: 昨日作成したキレキレダンスを動かすと、1.0秒間隔で送られる指令に対してグラフが鋭い矩形波(くけいは)を描きました。
物理挙動の視覚化: 数値だけでは見落としていた、微細な物理エンジンの揺れまでが波形として可視化されました。
解析フェーズ | 状態 | 達成したこと |
|---|---|---|
単軸モニタリング | 成功 | 基本的な描画ロジックの確立 |
全6軸同時モニタリング | 成功 | 腕全体の連動性の視覚化 |
マルチタスク運用 | 確立 | 4枚のターミナルによる監視体制 |
デジタルツインは「知能」への準備を終えた
デジタルツインは単に繋がっているだけの状態から、挙動を精密に監視・解析できる研究用プラットフォームへと進化しました。
失敗から学んだ環境構築の厳格さと、疑問から得たデータ構造の理解。これらがあるからこそ、次なるステップである実験3:テレオペレーション(自由操作)にも自信を持って挑めます。
