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 } }