unity2moveit2/unity-project/Assets/Scripts/Tests/SimpleROSConnectionTester.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

369 lines
13 KiB
C#

using UnityEngine;
using Unity.Robotics.ROSTCPConnector;
using System;
namespace UnityMoveIt2.Tests
{
/// <summary>
/// 简单ROS连接测试器 / Simple ROS Connection Tester
/// 可以直接附加到Unity场景中的GameObject进行手动测试
/// Can be attached to a GameObject in Unity scene for manual testing
/// </summary>
public class SimpleROSConnectionTester : MonoBehaviour
{
[Header("连接配置 / Connection Configuration")]
[Tooltip("ROS2服务器IP地址 / ROS2 Server IP Address")]
public string rosIP = "127.0.0.1";
[Tooltip("ROS2服务器端口 / ROS2 Server Port")]
public int rosPort = 10000;
[Tooltip("启动时自动连接 / Auto connect on start")]
public bool autoConnectOnStart = true;
[Header("测试配置 / Test Configuration")]
[Tooltip("显示详细日志 / Show verbose logs")]
public bool verboseLogging = true;
[Tooltip("连接保持时间(秒) / Connection keep-alive duration (seconds)")]
public float keepAliveDuration = 10f;
[Header("状态显示 / Status Display")]
[SerializeField]
private bool isConnected = false;
[SerializeField]
private float connectionTime = 0f;
[SerializeField]
private string lastError = "";
private ROSConnection rosConnection;
private float connectedSince = 0f;
#region Unity生命周期 / Unity Lifecycle
private void Awake()
{
Log("=== SimpleROSConnectionTester 初始化 / Initialized ===");
Log($"目标服务器 / Target Server: {rosIP}:{rosPort}");
}
private void Start()
{
if (autoConnectOnStart)
{
ConnectToROS();
}
else
{
Log("自动连接已禁用,请手动调用ConnectToROS() / Auto-connect disabled, call ConnectToROS() manually");
}
}
private void Update()
{
// 更新连接时间 / Update connection time
if (isConnected)
{
connectionTime = Time.time - connectedSince;
}
}
private void OnDestroy()
{
DisconnectFromROS();
}
#endregion
#region / Public Methods
/// <summary>
/// 连接到ROS2服务器 / Connect to ROS2 Server
/// </summary>
[ContextMenu("连接到ROS / Connect to ROS")]
public void ConnectToROS()
{
Log("======================================");
Log("开始连接到ROS2 / Starting connection to ROS2");
Log($"服务器地址 / Server Address: {rosIP}:{rosPort}");
Log("======================================");
try
{
// 获取或创建ROSConnection实例 / Get or create ROSConnection instance
if (rosConnection == null)
{
GameObject rosGO = GameObject.Find("ROSConnection");
if (rosGO == null)
{
rosGO = new GameObject("ROSConnection");
}
rosConnection = rosGO.GetComponent<ROSConnection>();
if (rosConnection == null)
{
rosConnection = rosGO.AddComponent<ROSConnection>();
}
}
// 配置连接参数 / Configure connection parameters
rosConnection.RosIPAddress = rosIP;
rosConnection.RosPort = rosPort;
rosConnection.ConnectOnStart = false;
// 执行连接 / Execute connection
rosConnection.Connect();
// 等待一小段时间验证连接 / Wait a moment to verify connection
Invoke(nameof(CheckConnectionStatus), 1f);
}
catch (Exception ex)
{
LogError($"连接异常 / Connection Exception: {ex.Message}");
lastError = ex.Message;
isConnected = false;
}
}
/// <summary>
/// 断开ROS2连接 / Disconnect from ROS2
/// </summary>
[ContextMenu("断开连接 / Disconnect")]
public void DisconnectFromROS()
{
if (rosConnection != null)
{
Log("正在断开ROS连接... / Disconnecting from ROS...");
rosConnection.Disconnect();
isConnected = false;
connectionTime = 0f;
Log("✓ 已断开连接 / ✓ Disconnected");
}
}
/// <summary>
/// 重新连接 / Reconnect
/// </summary>
[ContextMenu("重新连接 / Reconnect")]
public void Reconnect()
{
DisconnectFromROS();
Invoke(nameof(ConnectToROS), 1f);
}
/// <summary>
/// 发送测试数据 / Send Test Data
/// </summary>
[ContextMenu("发送测试数据 / Send Test Data")]
public void SendTestData()
{
if (!isConnected || rosConnection == null)
{
LogWarning("未连接,无法发送数据 / Not connected, cannot send data");
return;
}
try
{
// 创建简单的测试数据 / Create simple test data
byte[] testData = System.Text.Encoding.UTF8.GetBytes("Hello from Unity!");
Log($"发送测试数据: {testData.Length} 字节 / Sending test data: {testData.Length} bytes");
rosConnection.SendMessage(testData);
Log("✓ 测试数据已发送 / ✓ Test data sent");
}
catch (Exception ex)
{
LogError($"发送数据失败 / Send data failed: {ex.Message}");
}
}
/// <summary>
/// 运行完整测试套件 / Run Full Test Suite
/// </summary>
[ContextMenu("运行完整测试 / Run Full Test")]
public void RunFullTest()
{
StartCoroutine(FullTestCoroutine());
}
#endregion
#region / Private Methods
private void CheckConnectionStatus()
{
if (rosConnection != null)
{
bool hasError = rosConnection.HasConnectionError;
if (!hasError)
{
isConnected = true;
connectedSince = Time.time;
connectionTime = 0f;
lastError = "";
Log("======================================");
Log("✓✓✓ 连接成功! / Connection Successful! ✓✓✓");
Log("======================================");
Log($"服务器: {rosIP}:{rosPort}");
Log($"连接时间: {DateTime.Now:HH:mm:ss}");
Log("======================================");
// 自动断开连接(如果设置了保持时间)
// Auto-disconnect after keep-alive duration
if (keepAliveDuration > 0)
{
Log($"将在 {keepAliveDuration} 秒后自动断开 / Will auto-disconnect after {keepAliveDuration} seconds");
Invoke(nameof(DisconnectFromROS), keepAliveDuration);
}
}
else
{
isConnected = false;
lastError = "Connection failed";
Log("======================================");
Log("✗✗✗ 连接失败! / Connection Failed! ✗✗✗");
Log("======================================");
LogError("可能的原因 / Possible reasons:");
LogError("1. ROS2服务未启动 / ROS2 service not started");
LogError("2. IP地址或端口错误 / Wrong IP or port");
LogError("3. 防火墙阻止连接 / Firewall blocking connection");
LogError("4. Docker容器未运行 / Docker container not running");
Log("======================================");
LogError("解决方案 / Solutions:");
LogError("运行: cd docker && docker-compose up -d");
LogError("检查: docker-compose ps");
LogError("日志: docker-compose logs ros2-unity");
Log("======================================");
}
}
}
private System.Collections.IEnumerator FullTestCoroutine()
{
Log("\n\n");
Log("██████████████████████████████████████████████████");
Log("█ 开始完整测试套件 / Starting Full Test Suite █");
Log("██████████████████████████████████████████████████");
// 测试1: 连接
Log("\n[测试 1/3] 连接测试 / Connection Test");
ConnectToROS();
yield return new UnityEngine.WaitForSeconds(2f);
if (!isConnected)
{
LogError("✗ 测试失败: 无法连接 / Test Failed: Cannot connect");
yield break;
}
Log("✓ 测试1通过: 连接成功 / Test 1 Passed: Connected");
// 测试2: 保持连接
Log("\n[测试 2/3] 连接保持测试 / Keep-Alive Test");
Log("保持连接3秒... / Keeping connection for 3 seconds...");
yield return new UnityEngine.WaitForSeconds(3f);
if (isConnected)
{
Log("✓ 测试2通过: 连接保持成功 / Test 2 Passed: Connection kept alive");
}
else
{
LogError("✗ 测试2失败: 连接断开 / Test 2 Failed: Connection dropped");
}
// 测试3: 发送数据
Log("\n[测试 3/3] 数据发送测试 / Data Send Test");
SendTestData();
yield return new UnityEngine.WaitForSeconds(1f);
Log("✓ 测试3完成: 数据已发送 / Test 3 Complete: Data sent");
// 断开连接
Log("\n[清理] 断开连接 / Cleanup: Disconnecting");
DisconnectFromROS();
yield return new UnityEngine.WaitForSeconds(0.5f);
Log("\n");
Log("██████████████████████████████████████████████████");
Log("█ 测试套件完成! / Test Suite Complete! █");
Log("██████████████████████████████████████████████████");
Log($"总测试时间 / Total test time: {Time.time - (connectedSince - 6f):F2}秒 / seconds");
Log("\n\n");
}
#endregion
#region / Logging Methods
private void Log(string message)
{
if (verboseLogging)
{
Debug.Log($"[ROS连接测试器] {message}");
}
}
private void LogWarning(string message)
{
Debug.LogWarning($"[ROS连接测试器] {message}");
}
private void LogError(string message)
{
Debug.LogError($"[ROS连接测试器] {message}");
}
#endregion
#region Inspector辅助 / Inspector Helpers
private void OnGUI()
{
// 在Game视图显示状态 / Display status in Game view
if (!verboseLogging) return;
GUIStyle style = new GUIStyle(GUI.skin.box);
style.alignment = TextAnchor.UpperLeft;
style.fontSize = 14;
style.normal.textColor = isConnected ? Color.green : Color.red;
string statusText = $"ROS连接状态 / ROS Connection Status\n" +
$"----------------------------\n" +
$"服务器 / Server: {rosIP}:{rosPort}\n" +
$"状态 / Status: {(isConnected ? " / Connected" : " / Disconnected")}\n" +
$"连接时长 / Duration: {connectionTime:F1}s\n";
if (!string.IsNullOrEmpty(lastError))
{
statusText += $"错误 / Error: {lastError}\n";
}
GUI.Box(new Rect(10, 10, 350, 100), statusText, style);
// 添加按钮 / Add buttons
if (GUI.Button(new Rect(10, 120, 100, 30), "连接 / Connect"))
{
ConnectToROS();
}
if (GUI.Button(new Rect(120, 120, 100, 30), "断开 / Disconnect"))
{
DisconnectFromROS();
}
if (GUI.Button(new Rect(230, 120, 130, 30), "完整测试 / Full Test"))
{
RunFullTest();
}
}
#endregion
}
}