240 lines
8.1 KiB
C#
240 lines
8.1 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public class RobotManager : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
public static RobotManager Instance { get; private set; }
|
|||
|
|
|
|||
|
|
UIManager uiManager => UIManager.Instance;
|
|||
|
|
|
|||
|
|
[Header("MQTT Settings")]
|
|||
|
|
[SerializeField] private MqttManager mqttManager;
|
|||
|
|
|
|||
|
|
[Header("Robot Config")]
|
|||
|
|
[SerializeField] private TextAsset robotIDconfig;
|
|||
|
|
[SerializeField] private TextAsset robotActionTopics;
|
|||
|
|
[SerializeField] private HybridInverseKinematicsNode hybridIKNode;
|
|||
|
|
|
|||
|
|
[Header("UI Settings")]
|
|||
|
|
[Tooltip("<22><> <20>κ<EFBFBD><CEBA><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> UI <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
|
|||
|
|
[SerializeField] private GameObject robotUIPrefab;
|
|||
|
|
[Tooltip("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> UI<55><49><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> <20>θ<EFBFBD> Canvas")]
|
|||
|
|
[SerializeField] private Transform uiParentCanvas;
|
|||
|
|
|
|||
|
|
// --- MQTT Topic <20><><EFBFBD><EFBFBD> ---
|
|||
|
|
private RobotIDConfig idConfigData;
|
|||
|
|
private RobotActionTopics actionTopicsData;
|
|||
|
|
|
|||
|
|
// --- <20>κ<EFBFBD> <20><><EFBFBD><EFBFBD> ---
|
|||
|
|
private readonly Dictionary<string, RobotController> robotRegistry = new Dictionary<string, RobotController>();// <20>κ<EFBFBD> ID<49><44> Ű<><C5B0> <20>Ͽ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
|||
|
|
private string targetRobotId; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD> ID (<28><><EFBFBD><EFBFBD> = <20><><EFBFBD><EFBFBD>)
|
|||
|
|
private Dictionary<string, GameObject> robotUIs = new Dictionary<string, GameObject>();
|
|||
|
|
|
|||
|
|
// --- <20>κ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ---
|
|||
|
|
private RobotController selectedRobot; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD>õ<EFBFBD> <20>κ<EFBFBD>
|
|||
|
|
private Transform RecordingHandleTarget; // Handle(<28><><EFBFBD><EFBFBD> <20>κ<EFBFBD>)<29><> Transform
|
|||
|
|
public static event Action<RobotController> OnRobotSelected; // <20>κ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ
|
|||
|
|
|
|||
|
|
private void Awake()
|
|||
|
|
{
|
|||
|
|
if (Instance == null)
|
|||
|
|
{
|
|||
|
|
Instance = this;
|
|||
|
|
DontDestroyOnLoad(gameObject);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Destroy(gameObject);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
InitializeRobotRegistry();
|
|||
|
|
ManageConfig();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|||
|
|
private void OnEnable()
|
|||
|
|
{
|
|||
|
|
MqttManager.OnMessageReceived += HandleMessage; // <20><EFBFBD><DEBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD>
|
|||
|
|
UIController.OnTransformSendUIClicked += HandlePublishTransformCommand;
|
|||
|
|
UIController.OnKeyframesSendUIClicked += HandlePublishKeyframeListCommand;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnDisable()
|
|||
|
|
{
|
|||
|
|
MqttManager.OnMessageReceived -= HandleMessage;
|
|||
|
|
UIController.OnTransformSendUIClicked -= HandlePublishTransformCommand;
|
|||
|
|
UIController.OnKeyframesSendUIClicked -= HandlePublishKeyframeListCommand;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Start()
|
|||
|
|
{
|
|||
|
|
InstantiateRobotUIs();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void InitializeRobotRegistry()
|
|||
|
|
{
|
|||
|
|
RobotController[] allRobots = FindObjectsByType<RobotController>(FindObjectsSortMode.None); // <20><>Ȱ<EFBFBD><C8B0>ȭ <20><> <20><> <20><><EFBFBD><EFBFBD> ã<><C3A3>
|
|||
|
|
foreach (var robot in allRobots)
|
|||
|
|
{
|
|||
|
|
if (!robotRegistry.ContainsKey(robot.robotId))
|
|||
|
|
{
|
|||
|
|
robotRegistry.Add(robot.robotId, robot);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"<22>κ<EFBFBD> ID {robot.robotId}<7D><> <20>ߺ<EFBFBD><DFBA>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>. ù <20><>° <20>κ<EFBFBD><CEBA><EFBFBD> <20><><EFBFBD>ϵ˴ϴ<CBB4>.");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void InstantiateRobotUIs()
|
|||
|
|
{
|
|||
|
|
if (robotUIPrefab == null || uiParentCanvas == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogError("Robot UI Prefab <20>Ǵ<EFBFBD> UI Parent Canvas<61><73> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>.");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
foreach (var entry in robotRegistry)
|
|||
|
|
{
|
|||
|
|
RobotController robot = entry.Value;
|
|||
|
|
// '<27><><EFBFBD><EFBFBD> <20>κ<EFBFBD> (Ʈ<><C6AE>)'<27><> <20><><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD> UI<55><49> <20><><EFBFBD><EFBFBD>
|
|||
|
|
if (!robot.isLocallyControlled)
|
|||
|
|
{
|
|||
|
|
GameObject uiInstance = Instantiate(robotUIPrefab, uiParentCanvas);
|
|||
|
|
uiInstance.name = $"UI_{robot.robotId}";
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD> UI Prefab<61><62> <20><>Ȱ<EFBFBD><C8B0>ȭ
|
|||
|
|
robotUIPrefab.SetActive(false);
|
|||
|
|
|
|||
|
|
UIController uiController = uiInstance.GetComponent<UIController>();
|
|||
|
|
if (uiController != null)
|
|||
|
|
{
|
|||
|
|
uiController.Initialize(this, uiManager);
|
|||
|
|
robotUIs.Add(robot.robotId, uiInstance);
|
|||
|
|
}
|
|||
|
|
uiInstance.SetActive(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SelectRobot(string robotId)
|
|||
|
|
{
|
|||
|
|
if (robotRegistry.TryGetValue(robotId, out RobotController robot))
|
|||
|
|
{
|
|||
|
|
selectedRobot = robot;
|
|||
|
|
targetRobotId = robotId; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD> ID <20><><EFBFBD><EFBFBD>
|
|||
|
|
Debug.Log($"<22>κ<EFBFBD> '{robotId}' <20><><EFBFBD>õ<EFBFBD>. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD> ID<49><44> <20><><EFBFBD><EFBFBD>.");
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Handle Target <20><><EFBFBD><EFBFBD>
|
|||
|
|
RecordingHandleTarget = GameObject.FindWithTag("Handle")?.transform;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD> UI <20><>Ȱ<EFBFBD><C8B0>ȭ
|
|||
|
|
foreach (var ui in robotUIs.Values) ui.SetActive(false);
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD>õ<EFBFBD> <20>κ<EFBFBD><CEBA><EFBFBD> UI<55><49> Ȱ<><C8B0>ȭ
|
|||
|
|
if (robotUIs.TryGetValue(robotId, out GameObject selectedUI))
|
|||
|
|
{
|
|||
|
|
selectedUI.SetActive(true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
OnRobotSelected?.Invoke(selectedRobot); // UIManager<65><72> HandleRobotSelected <20>̺<EFBFBD>Ʈ ȣ<><C8A3>
|
|||
|
|
SubscribeToTopic(new string[] { $"robots/{targetRobotId}/ {actionTopicsData.Topic1}" }); // Topic1: state
|
|||
|
|
|
|||
|
|
HandlePublishTransformCommand(); // <20><><EFBFBD><EFBFBD> <20><> <20><> <20><> <20><><EFBFBD><EFBFBD>ȭ
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region Publishing Logic
|
|||
|
|
|
|||
|
|
private void ManageConfig()
|
|||
|
|
{
|
|||
|
|
idConfigData = JsonUtility.FromJson<RobotIDConfig>(robotIDconfig.text);
|
|||
|
|
actionTopicsData = JsonUtility.FromJson<RobotActionTopics>(robotActionTopics.text);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD><CEBA><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD><CEBA><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (UI <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>)
|
|||
|
|
public void HandlePublishTransformCommand()
|
|||
|
|
{
|
|||
|
|
Debug.Log("TransformSendUI <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD> HandlePublishTransformCommand <20>ҷ<EFBFBD><D2B7><EFBFBD>");
|
|||
|
|
Vector3 commandPosition = RecordingHandleTarget.transform.localPosition;
|
|||
|
|
List<Vector3> commandJoints = hybridIKNode.GetCurrentJointPositions();
|
|||
|
|
List<Quaternion> commandRotations = hybridIKNode.GetCurrentJointRotations();
|
|||
|
|
|
|||
|
|
string topic = $"robots/{targetRobotId}/{actionTopicsData.Topic2}"; // Topic2: command
|
|||
|
|
Debug.Log($"topic: {topic}");
|
|||
|
|
|
|||
|
|
IKData data = new IKData
|
|||
|
|
{
|
|||
|
|
robotId = targetRobotId, // <20>κ<EFBFBD> ID (<28><><EFBFBD><EFBFBD> = <20><><EFBFBD><EFBFBD>)
|
|||
|
|
position = commandPosition,
|
|||
|
|
nodesPosition = new List<Vector3>(commandJoints),
|
|||
|
|
nodesRotation = new List<Quaternion>(commandRotations)
|
|||
|
|
};
|
|||
|
|
string json = JsonUtility.ToJson(data, true);
|
|||
|
|
mqttManager.PublishMessage(topic, json);
|
|||
|
|
Debug.Log($"<22><>ġ <20><><EFBFBD><EFBFBD>ȭ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {json}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void HandlePublishKeyframeListCommand()
|
|||
|
|
{
|
|||
|
|
Debug.Log("ListSendUI <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD> HandlePublishKeyframeListCommand <20>ҷ<EFBFBD><D2B7><EFBFBD>");
|
|||
|
|
IReadOnlyList<IKData> keyframePositions = UIManager.Instance.KeyframePositions;
|
|||
|
|
|
|||
|
|
|
|||
|
|
//List<Vector3> commandJoints = hybridIKNode.GetJointPositionsForKeyframe();
|
|||
|
|
// <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><EFBFBD><DEBD><EFBFBD><EFBFBD><EFBFBD> publish
|
|||
|
|
if (keyframePositions.Count > 0)
|
|||
|
|
{
|
|||
|
|
string topic = $"robots/{targetRobotId}/{actionTopicsData.Topic2}"; // Topic2: command
|
|||
|
|
Debug.Log($"topic: {topic}");
|
|||
|
|
|
|||
|
|
IKDataListWrapper wrapper = new IKDataListWrapper
|
|||
|
|
{
|
|||
|
|
robotId = targetRobotId,
|
|||
|
|
keyFrameList = new List<IKData>(keyframePositions),
|
|||
|
|
//nodesList = commandJoints
|
|||
|
|
};
|
|||
|
|
string json = JsonUtility.ToJson(wrapper, true);
|
|||
|
|
mqttManager.PublishMessage(topic, json);
|
|||
|
|
Debug.Log($"Ű<><C5B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ʈ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {json}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HandleMessage(string topic, string message)
|
|||
|
|
{
|
|||
|
|
string[] topicLevels = topic.Split('/');
|
|||
|
|
if (topicLevels.Length < 3) return;
|
|||
|
|
|
|||
|
|
string robotId = topicLevels[1];
|
|||
|
|
string messageType = topicLevels[2];
|
|||
|
|
|
|||
|
|
// ID<49><44> <20>ش<EFBFBD><D8B4>ϴ<EFBFBD> <20>κ<EFBFBD><CEBA><EFBFBD> <20>ִ<EFBFBD><D6B4><EFBFBD> Ȯ<><C8AE>
|
|||
|
|
if (!robotRegistry.TryGetValue(robotId, out RobotController targetRobot))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//HandleStateUpdate(targetRobot, message); // TODO. <20><><EFBFBD><EFBFBD> Ʈ<><C6AE><EFBFBD><EFBFBD> <20><>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ -> <20><><EFBFBD><EFBFBD> <20>κ<EFBFBD><CEBA><EFBFBD><EFBFBD><EFBFBD> <20><>ư Ŭ<><C5AC><EFBFBD>ϸ<EFBFBD> <20><><EFBFBD><EFBFBD>ȭ <20>ϱ<EFBFBD><CFB1><EFBFBD>.
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HandleStateUpdate(RobotController twinRobot, string message) // <20><><EFBFBD><EFBFBD> <- <20><><EFBFBD><EFBFBD>
|
|||
|
|
{
|
|||
|
|
IKData data = JsonUtility.FromJson<IKData>(message);
|
|||
|
|
twinRobot.transform.localPosition = data.position;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Subscribing Logic
|
|||
|
|
|
|||
|
|
private void SubscribeToTopic(string[] topics)
|
|||
|
|
{
|
|||
|
|
// MqttManager<65><72><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|||
|
|
mqttManager.SubscribeToTopics(topics);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
}
|