ハコブくんの「心」をUnityで可視化する|HRIデザインの実装記録
協働ロボットが「今、どれくらい自信を持って動いているか」。それをオペレーターに一瞬で伝えるための「確信度ゲージ」の実装に挑みました。デザイナーがCursor(AIエディタ)を相棒に、技術の壁をどう乗り越えたかの記録です。
※本プロジェクトの目的:実機「mechArm 270 M5」の制御を通じて、AIの判断をいかに物理的な動きへ変換するか。そのロボット制御の仕組みを理解するプロセスを記録・検証するものです。
デザインの意図:周辺視野で「異変」を伝える

人間は数値の変化よりも、視界の端(周辺視野)での「色の変化」に敏感です。そこで、確信度に応じてバーの色が緑(安心)→ 黄(注意)→ 赤(警告)と自動で切り替わるロジックを設計しました。
実装したコード:HudManager.cs
当初は角度を表示するだけだったスクリプトを、Cursorを使って「確信度(Confidence)」を扱えるように大幅に拡張しました。
C#
using UnityEngine;
using UnityEngine.UI; // UI要素(Slider, Image)を扱うために追加
using TMPro;
public class HudManager : MonoBehaviour
{
[Header("UI Components")]
[SerializeField] private TextMeshProUGUI jointInfoText; // 角度表示用
[SerializeField] private Slider confidenceGauge; // 確信度バー本体
[SerializeField] private Image fillImage; // バーの色を変えるための画像要素
// デザイナー用:Unityエディタ上で値を動かした時にリアルタイムで色を確認するための魔法
private void Update()
{
if (confidenceGauge != null && fillImage != null)
{
UpdateGaugeColor(confidenceGauge.value);
}
}
// ROS 2(Python)から届いたデータでHUDを更新する中心的な関数
public void UpdateHud(float[] positions, float confidence = 1.0f)
{
if (jointInfoText == null) return;
// 1. テキスト表示の更新(小数第2位まで表示)
string displayMessage = "<color=#00FF00>ROS2 SYSTEM: CONNECTED</color>\n";
displayMessage += "------------------------------\n";
for (int i = 0; i < positions.Length; i++)
{
displayMessage += $"Link {i + 1}: {positions[i]:F2} rad\n";
}
jointInfoText.text = displayMessage;
// 2. ゲージの長さを更新
if (confidenceGauge != null)
{
confidenceGauge.value = confidence;
}
}
// 3. 【HRI核心部】確信度に応じたカラーフィードバック
private void UpdateGaugeColor(float value)
{
if (fillImage == null) return;
if (value >= 0.7f)
fillImage.color = Color.green; // 70%以上は「順調」
else if (value >= 0.4f)
fillImage.color = Color.yellow; // 40%〜70%は「迷い」
else
fillImage.color = Color.red; // 40%未満は「警告」
}
}ぶつかった壁と「開示」するプロセス
① 「見えないオブジェクト」の正体

スクリプトの空枠に「テキストオブジェクト」を紐付ける際、New Text という名前が見当たらず足踏みしました。
原因: 以前の自分が、管理しやすいように
robot2_infoと名前を変えていたから。学び: 「名前」が変わっても「中身(コンポーネント)」は自分自身にある。自分自身をドラッグ&ドロップするというUnityの基本構造を体得しました。
② 届かない「色の変化」
最初は再生ボタンを押してSliderを動かしても色が変わりませんでした。
解決: プログラムは「Pythonからデータが来た時」だけ動くようになっていたため、
Update()関数を追加してエディタ上の操作も常時監視するように改良しました。
③ 通信の混線を断つ
2台のロボットが同じ /joint_states という名前でデータを送ろうとして警告が出ていました。
解決: 先頭のスラッシュ
/を外して相対パスにし、robot1/joint_statesのように「名前空間(Namespace)」を分けることで、情報の衝突を解消しました。
今回のミッションで、UIは単なる装飾ではなく、「システムの論理」と「人間の感覚」を繋ぐ翻訳機なのだと深く理解しました。次はPythonから、本物の「AIの迷い」をこのゲージに流し込みます。
