unity2moveit2/unity-project/Assets/Scripts/Core/RobotAutoConfigurator.cs
ayuan9957 fe15edcbd5 Initial commit: Unity-MoveIt2 integrated robotic arm simulation system
- Unity frontend with ROS-TCP-Connector for ROS2 communication
- Docker-based ROS2 Jazzy backend with MoveIt2 integration
- Support for 1-9 DOF manipulators
- UR5 robot configuration and URDF files
- Assembly task feasibility analysis tools
- Comprehensive documentation and deployment guides

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-13 12:08:34 +08:00

301 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
namespace UnityMoveIt2.Core
{
/// <summary>
/// 机器人自动配置器 / Robot Auto Configurator
/// 运行时自动检测并配置机器人组件 / Auto-detect and configure robot components at runtime
/// </summary>
[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<UniversalRobotAdapter>();
if (Application.isPlaying && autoConfigureAtRuntime && !isConfigured)
{
ConfigureRobot();
}
}
private void OnValidate()
{
if (!Application.isPlaying && autoConfigureInEditor)
{
// 在编辑器模式下延迟配置
UnityEditor.EditorApplication.delayCall += () =>
{
if (this != null)
ConfigureRobot();
};
}
}
#endregion
#region Auto Configuration
/// <summary>
/// 配置机器人 / Configure Robot
/// </summary>
[ContextMenu("自动配置机器人 / Auto Configure Robot")]
public void ConfigureRobot()
{
if (robotAdapter == null)
{
robotAdapter = GetComponent<UniversalRobotAdapter>();
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
}
}
/// <summary>
/// 配置基座链接 / Configure Base Link
/// </summary>
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;
}
/// <summary>
/// 配置末端执行器 / Configure End Effector
/// </summary>
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;
}
/// <summary>
/// 配置其他参数 / Configure Additional Parameters
/// </summary>
private void ConfigureAdditionalParameters()
{
// 统计关节数量
ArticulationBody[] articulationBodies = GetComponentsInChildren<ArticulationBody>();
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
/// <summary>
/// 递归查找子对象 / Find Child Recursively
/// </summary>
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;
}
/// <summary>
/// 验证配置 / Validate Configuration
/// </summary>
[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<ArticulationBody>();
Debug.Log($"✓ 找到 {joints.Length} 个 Articulation Body");
// 检查Adapter
if (robotAdapter != null)
Debug.Log("✓ UniversalRobotAdapter 组件存在");
else
Debug.LogError("✗ UniversalRobotAdapter 组件不存在");
Debug.Log("====================================");
}
/// <summary>
/// 显示层级结构 / Show Hierarchy
/// </summary>
[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<ArticulationBody>() != null)
components += "[AB] ";
if (parent.GetComponent<MeshRenderer>() != null)
components += "[MR] ";
if (parent.GetComponent<Collider>() != null)
components += "[Col] ";
Debug.Log($"{indent}└─ {parent.name} {components}");
foreach (Transform child in parent)
{
PrintHierarchy(child, level + 1);
}
}
#endregion
}
}