using UnityEngine;
namespace UnityMoveIt2.Core
{
///
/// 机器人自动配置器 / Robot Auto Configurator
/// 运行时自动检测并配置机器人组件 / Auto-detect and configure robot components at runtime
///
[RequireComponent(typeof(UniversalRobotAdapter))]
[ExecuteInEditMode]
public class RobotAutoConfigurator : MonoBehaviour
{
[Header("自动配置设置 / Auto Configuration Settings")]
[SerializeField]
[Tooltip("是否在编辑器模式下自动配置")]
private bool autoConfigureInEditor = true;
[SerializeField]
[Tooltip("是否在Play模式下自动配置")]
private bool autoConfigureAtRuntime = true;
[SerializeField]
[Tooltip("基座链接名称 / Base Link Name")]
private string baseLinkName = "base_link";
[SerializeField]
[Tooltip("末端执行器名称 / End Effector Name")]
private string endEffectorName = "tool0";
[Header("配置状态 / Configuration Status")]
[SerializeField]
private bool isConfigured = false;
private UniversalRobotAdapter robotAdapter;
#region Unity Lifecycle
private void Awake()
{
robotAdapter = GetComponent();
if (Application.isPlaying && autoConfigureAtRuntime && !isConfigured)
{
ConfigureRobot();
}
}
private void OnValidate()
{
if (!Application.isPlaying && autoConfigureInEditor)
{
// 在编辑器模式下延迟配置
UnityEditor.EditorApplication.delayCall += () =>
{
if (this != null)
ConfigureRobot();
};
}
}
#endregion
#region Auto Configuration
///
/// 配置机器人 / Configure Robot
///
[ContextMenu("自动配置机器人 / Auto Configure Robot")]
public void ConfigureRobot()
{
if (robotAdapter == null)
{
robotAdapter = GetComponent();
if (robotAdapter == null)
{
Debug.LogError("[RobotAutoConfigurator] 未找到 UniversalRobotAdapter 组件");
return;
}
}
Debug.Log("[RobotAutoConfigurator] 开始自动配置机器人...");
bool success = true;
// 查找并设置 Base Link
if (!ConfigureBaseLink())
{
success = false;
}
// 查找并设置 End Effector
if (!ConfigureEndEffector())
{
success = false;
}
// 配置其他参数
ConfigureAdditionalParameters();
if (success)
{
isConfigured = true;
Debug.Log("[RobotAutoConfigurator] ✓ 机器人自动配置成功!");
}
else
{
Debug.LogWarning("[RobotAutoConfigurator] 机器人配置不完整,请检查Hierarchy结构");
}
// 标记为已修改(仅编辑器模式)
if (!Application.isPlaying)
{
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(robotAdapter);
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
}
///
/// 配置基座链接 / Configure Base Link
///
private bool ConfigureBaseLink()
{
Transform baseLink = FindChildRecursive(transform, baseLinkName);
if (baseLink != null)
{
// 使用反射设置私有字段
var baseLinkField = typeof(UniversalRobotAdapter).GetField("baseLink",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (baseLinkField != null)
{
baseLinkField.SetValue(robotAdapter, baseLink);
Debug.Log($"[RobotAutoConfigurator] ✓ 设置 Base Link: {baseLink.name}");
return true;
}
}
else
{
Debug.LogWarning($"[RobotAutoConfigurator] ✗ 未找到 Base Link: {baseLinkName}");
Debug.LogWarning("[RobotAutoConfigurator] 提示: 请确保机器人结构中包含名为 'base_link' 的对象");
}
return false;
}
///
/// 配置末端执行器 / Configure End Effector
///
private bool ConfigureEndEffector()
{
Transform endEffector = FindChildRecursive(transform, endEffectorName);
if (endEffector != null)
{
// 使用反射设置私有字段
var endEffectorField = typeof(UniversalRobotAdapter).GetField("endEffector",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (endEffectorField != null)
{
endEffectorField.SetValue(robotAdapter, endEffector);
Debug.Log($"[RobotAutoConfigurator] ✓ 设置 End Effector: {endEffector.name}");
return true;
}
}
else
{
Debug.LogWarning($"[RobotAutoConfigurator] ✗ 未找到 End Effector: {endEffectorName}");
Debug.LogWarning("[RobotAutoConfigurator] 提示: 请确保机器人结构中包含名为 'tool0' 的对象");
}
return false;
}
///
/// 配置其他参数 / Configure Additional Parameters
///
private void ConfigureAdditionalParameters()
{
// 统计关节数量
ArticulationBody[] articulationBodies = GetComponentsInChildren();
int jointCount = articulationBodies.Length - 1; // 减去root body
// 使用反射设置DOF
var dofField = typeof(UniversalRobotAdapter).GetField("degreesOfFreedom",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (dofField != null && jointCount > 0 && jointCount <= 9)
{
dofField.SetValue(robotAdapter, jointCount);
Debug.Log($"[RobotAutoConfigurator] ✓ 检测到 {jointCount} 个关节");
}
// 设置机器人名称
var robotNameField = typeof(UniversalRobotAdapter).GetField("robotName",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (robotNameField != null)
{
robotNameField.SetValue(robotAdapter, gameObject.name);
}
}
#endregion
#region Helper Methods
///
/// 递归查找子对象 / Find Child Recursively
///
private Transform FindChildRecursive(Transform parent, string childName)
{
// 先检查直接子对象
Transform result = parent.Find(childName);
if (result != null)
return result;
// 递归查找所有子对象
foreach (Transform child in parent)
{
result = FindChildRecursive(child, childName);
if (result != null)
return result;
}
return null;
}
///
/// 验证配置 / Validate Configuration
///
[ContextMenu("验证配置 / Validate Configuration")]
public void ValidateConfiguration()
{
Debug.Log("========== 机器人配置验证 ==========");
// 检查Base Link
Transform baseLink = FindChildRecursive(transform, baseLinkName);
if (baseLink != null)
Debug.Log($"✓ Base Link 存在: {baseLink.name}");
else
Debug.LogError($"✗ Base Link 不存在: {baseLinkName}");
// 检查End Effector
Transform endEffector = FindChildRecursive(transform, endEffectorName);
if (endEffector != null)
Debug.Log($"✓ End Effector 存在: {endEffector.name}");
else
Debug.LogError($"✗ End Effector 不存在: {endEffectorName}");
// 统计关节
ArticulationBody[] joints = GetComponentsInChildren();
Debug.Log($"✓ 找到 {joints.Length} 个 Articulation Body");
// 检查Adapter
if (robotAdapter != null)
Debug.Log("✓ UniversalRobotAdapter 组件存在");
else
Debug.LogError("✗ UniversalRobotAdapter 组件不存在");
Debug.Log("====================================");
}
///
/// 显示层级结构 / Show Hierarchy
///
[ContextMenu("显示层级结构 / Show Hierarchy")]
public void ShowHierarchy()
{
Debug.Log("========== 机器人层级结构 ==========");
PrintHierarchy(transform, 0);
Debug.Log("====================================");
}
private void PrintHierarchy(Transform parent, int level)
{
string indent = new string(' ', level * 2);
string components = "";
if (parent.GetComponent() != null)
components += "[AB] ";
if (parent.GetComponent() != null)
components += "[MR] ";
if (parent.GetComponent() != null)
components += "[Col] ";
Debug.Log($"{indent}└─ {parent.name} {components}");
foreach (Transform child in parent)
{
PrintHierarchy(child, level + 1);
}
}
#endregion
}
}