<fix> 로봇 Grab하는 동안 생긴 버그 해결, 놓으면 바로 멈추도록 변경, 프로그램 재생 시에도 사운드 재생하도록 변경
This commit is contained in:
@@ -134,7 +134,7 @@ Transform:
|
||||
m_GameObject: {fileID: 9153036347640126610}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -0.8996404, y: 1.4682918, z: 1.5212109}
|
||||
m_LocalPosition: {x: -6.382849, y: 7.971563, z: 6.985526}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
|
||||
@@ -43836,6 +43836,7 @@ MonoBehaviour:
|
||||
robotInfoView: {fileID: 873227714}
|
||||
programInfoView: {fileID: 1807992934}
|
||||
envView: {fileID: 971773399}
|
||||
gripperCollide: {fileID: 2809842780563999912}
|
||||
robotController: {fileID: 806304512143720359}
|
||||
pointManagerView: {fileID: 1299890574}
|
||||
pathLineView: {fileID: 1299890572}
|
||||
@@ -75135,9 +75136,10 @@ GameObject:
|
||||
- component: {fileID: 7750953148055529459}
|
||||
- component: {fileID: 7899423492771922356}
|
||||
- component: {fileID: 7899423492771922357}
|
||||
- component: {fileID: 7899423492771922358}
|
||||
m_Layer: 0
|
||||
m_Name: "\uB85C\uBD07\uD314_06"
|
||||
m_TagString: Untagged
|
||||
m_TagString: Robot
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
@@ -75396,6 +75398,9 @@ GameObject:
|
||||
- component: {fileID: 2809842780563999911}
|
||||
- component: {fileID: 1878676147561002156}
|
||||
- component: {fileID: 2580099376798576862}
|
||||
- component: {fileID: 2809842780563999914}
|
||||
- component: {fileID: 2809842780563999913}
|
||||
- component: {fileID: 2809842780563999912}
|
||||
m_Layer: 0
|
||||
m_Name: "\uADF8\uB9AC\uD37C_1"
|
||||
m_TagString: Untagged
|
||||
@@ -75505,6 +75510,68 @@ Transform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6476108356885335244}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2809842780563999912
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2254038508360166054}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c1c9958a493b1e042bf5480ca2d9f3af, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
robotBodyTag: Robot
|
||||
isTriggerRobot: 0
|
||||
--- !u!65 &2809842780563999913
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2254038508360166054}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 1
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.0030580568, y: 0.0030454502, z: 0.001771739}
|
||||
m_Center: {x: -0.00000038708095, y: 0.000021483833, z: -0.000944237}
|
||||
--- !u!54 &2809842780563999914
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2254038508360166054}
|
||||
serializedVersion: 4
|
||||
m_Mass: 1
|
||||
m_Drag: 0
|
||||
m_AngularDrag: 0.05
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ImplicitCom: 1
|
||||
m_ImplicitTensor: 1
|
||||
m_UseGravity: 0
|
||||
m_IsKinematic: 1
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!1 &3269629316409468015
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -75516,7 +75583,6 @@ GameObject:
|
||||
- component: {fileID: 1034940619344592870}
|
||||
- component: {fileID: 8348283317296094972}
|
||||
- component: {fileID: 8218048649755986071}
|
||||
- component: {fileID: 8348283317296094973}
|
||||
m_Layer: 6
|
||||
m_Name: "\uADF8\uB9AC\uD37C_2"
|
||||
m_TagString: Gripper
|
||||
@@ -75545,9 +75611,10 @@ GameObject:
|
||||
- component: {fileID: 7875942327570384369}
|
||||
- component: {fileID: 8980508415438906781}
|
||||
- component: {fileID: 8980508415438906782}
|
||||
- component: {fileID: 8980508415438906783}
|
||||
m_Layer: 0
|
||||
m_Name: "\uB85C\uBD07\uD314_05"
|
||||
m_TagString: Untagged
|
||||
m_TagString: Robot
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
@@ -75947,6 +76014,27 @@ MeshCollider:
|
||||
m_Convex: 0
|
||||
m_CookingOptions: 30
|
||||
m_Mesh: {fileID: -2328343405082307496, guid: f8e1d25363bc3264ead6a2d4dba3d589, type: 3}
|
||||
--- !u!65 &7899423492771922358
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1019155422019270077}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 1
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.0031899994, y: 0.003175993, z: 0.003566943}
|
||||
m_Center: {x: 0.00024499983, y: 0.00034892443, z: 0.0014505462}
|
||||
--- !u!33 &7939903229847774538
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -76106,27 +76194,6 @@ MeshFilter:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3269629316409468015}
|
||||
m_Mesh: {fileID: 3108956238139520217, guid: f8e1d25363bc3264ead6a2d4dba3d589, type: 3}
|
||||
--- !u!65 &8348283317296094973
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3269629316409468015}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.0029685243, y: 0.002955866, z: 0.0010668265}
|
||||
m_Center: {x: -0.0000137486595, y: 0.0000029048076, z: -0.00037045297}
|
||||
--- !u!23 &8380366081719268712
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -76285,6 +76352,27 @@ MeshCollider:
|
||||
m_Convex: 0
|
||||
m_CookingOptions: 30
|
||||
m_Mesh: {fileID: 1644276158865073351, guid: f8e1d25363bc3264ead6a2d4dba3d589, type: 3}
|
||||
--- !u!65 &8980508415438906783
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3543066072088338770}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 1
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 0.0022507885, y: 0.0021192858, z: 0.008971175}
|
||||
m_Center: {x: -0.000027214437, y: 0.00081971334, z: 0.0041109337}
|
||||
--- !u!4 &9208936240245234726
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -15,6 +15,7 @@ public class AppManager : MonoBehaviour
|
||||
[SerializeField] private RobotInfoView robotInfoView;
|
||||
[SerializeField] private ProgramInfoView programInfoView;
|
||||
[SerializeField] private EnvView envView;
|
||||
[SerializeField] private GripperCollide gripperCollide;
|
||||
[SerializeField] private RobotController robotController;
|
||||
|
||||
private InteractionView leftInteractionView;
|
||||
@@ -109,6 +110,7 @@ public class AppManager : MonoBehaviour
|
||||
robotInfoView,
|
||||
programInfoView,
|
||||
envView,
|
||||
gripperCollide,
|
||||
leftInteractionView, rightInteractionView,
|
||||
pointManagerView,
|
||||
popupView,
|
||||
|
||||
25
Assets/Scripts/GripperCollide.cs
Normal file
25
Assets/Scripts/GripperCollide.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GripperCollide : MonoBehaviour
|
||||
{
|
||||
[Tooltip("·Îº¿ ¸öÅë¿¡ »ç¿ëµÉ ű×")]
|
||||
[SerializeField] private string robotBodyTag = "Robot";
|
||||
|
||||
public bool isTriggerRobot = false;
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.CompareTag(robotBodyTag))
|
||||
{
|
||||
isTriggerRobot = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (other.CompareTag(robotBodyTag))
|
||||
{
|
||||
isTriggerRobot = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/GripperCollide.cs.meta
Normal file
2
Assets/Scripts/GripperCollide.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c9958a493b1e042bf5480ca2d9f3af
|
||||
@@ -470,6 +470,7 @@ public class ProgramModel
|
||||
{
|
||||
Debug.Log("TCP POST (Move) 명령 전송 성공");
|
||||
IsMoving = true;
|
||||
Debug.DrawLine(Camera.main.transform.position, position, Color.red, 0.1f);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -497,9 +498,9 @@ public class ProgramModel
|
||||
// TCP POST 이동 명령 체크
|
||||
public async Task StartMovementCheckLoopAsync(CancellationToken token)
|
||||
{
|
||||
try
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
if (IsMoving)
|
||||
{
|
||||
@@ -525,14 +526,14 @@ public class ProgramModel
|
||||
await Task.Delay(500, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
Debug.Log("MovementCheckLoopAsync Canceled.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"MovementCheckLoopAsync Error: {e.Message}\n{e.StackTrace}");
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
Debug.Log("MovementCheckLoopAsync Canceled.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"MovementCheckLoopAsync Error: {e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +557,7 @@ public class ProgramModel
|
||||
{
|
||||
this.isError = newErrorState;
|
||||
OnRobotErrorStateChanged?.Invoke(this.isError);
|
||||
Debug.Log($"[이동범위] 이동 가능 상태: {newErrorState}");
|
||||
//Debug.Log($"[이동범위] 이동 가능 상태: {newErrorState}");
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
@@ -573,7 +574,7 @@ public class ProgramModel
|
||||
{
|
||||
this.isError = false;
|
||||
OnRobotErrorStateChanged?.Invoke(this.isError);
|
||||
Debug.Log("로컬 에러 상태 강제 해제 (재시도 준비)");
|
||||
//Debug.Log("로컬 에러 상태 강제 해제 (재시도 준비)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public enum PopupState
|
||||
{
|
||||
@@ -22,6 +23,7 @@ public class ProgramPresenter
|
||||
private RobotInfoView robotInfoView;
|
||||
private ProgramInfoView programInfoView;
|
||||
private EnvView envView;
|
||||
private GripperCollide gripperCollide;
|
||||
private RobotController controlledRobot;
|
||||
private string _programId;
|
||||
private bool lastKnownMotorState = false;
|
||||
@@ -41,12 +43,12 @@ public class ProgramPresenter
|
||||
private RobotData pendingPointData; // 팝업창에 대한 응답을 기다리는 임시 데이터
|
||||
private int activePointIndex = -1; // 현재 수정/삭제 중인 포인트의 인덱스
|
||||
|
||||
private CancellationTokenSource appCts;
|
||||
private CancellationTokenSource dragLoopCts;
|
||||
private RobotData latestTargetPose; // 뷰가 갱신할 최신 목표 지점
|
||||
private bool IsDragging = false;
|
||||
private bool IsStopped = false; // 에러 나서 멈췄는지 여부
|
||||
private bool errMatChanged = false; // 에러 시 로봇 mat을 빨간색으로 한 번만 바뀌도록
|
||||
private bool isHovering = false;
|
||||
private bool isProgramStarted = false;
|
||||
private RobotData originalDragPose; // 취소 시 돌아갈 원본 위치
|
||||
private float lastMoveSendTime = 0f;
|
||||
private const float MOVE_SEND_INTERVAL = 0.1f; // 0.1초(100ms)마다 한 번만 전송 (초당 10회)
|
||||
@@ -57,7 +59,7 @@ public class ProgramPresenter
|
||||
private AudioSource robotMovingAudioSource;
|
||||
private bool isFeedbackLoopRunning = false;
|
||||
|
||||
public ProgramPresenter(ProgramModel model, ProgramView view, TCPView tcpView, RobotInfoView robotInfoView, ProgramInfoView programInfoView, EnvView envView,
|
||||
public ProgramPresenter(ProgramModel model, ProgramView view, TCPView tcpView, RobotInfoView robotInfoView, ProgramInfoView programInfoView, EnvView envView, GripperCollide gripperCollide,
|
||||
InteractionView leftView, InteractionView rightView, PointManagerView pmView, PopupView popView, PathLineView pathLineView, AudioSource robotAudio, CancellationTokenSource cts)
|
||||
{
|
||||
this.model = model;
|
||||
@@ -68,6 +70,7 @@ public class ProgramPresenter
|
||||
this.robotInfoView = robotInfoView;
|
||||
this.programInfoView = programInfoView;
|
||||
this.envView = envView;
|
||||
this.gripperCollide = gripperCollide;
|
||||
this.pointManagerView = pmView;
|
||||
this.popupView = popView;
|
||||
this.pathLineView = pathLineView;
|
||||
@@ -90,7 +93,7 @@ public class ProgramPresenter
|
||||
this.envView.OnLoadProgramListRequested += HandleLoadProgramList;
|
||||
|
||||
this.leftInteractionView.OnRobotHoverStateChanged += (state) => HandleRobotHover(state);
|
||||
this.leftInteractionView.OnRobotGrabStart += () => HandleRobotGrabStart(leftView);
|
||||
this.leftInteractionView.OnRobotGrabStart += (pos) => HandleRobotGrabStart(leftView, pos);
|
||||
this.leftInteractionView.OnRobotGrabbed += (pos, rot) => HandleRobotGrabbed(leftView, pos, rot);
|
||||
this.leftInteractionView.OnRobotReleased += (data) => HandleRobotReleased(leftView, data);
|
||||
this.leftInteractionView.OnPointClicked += (index, pos) => HandlePointClicked(leftView, index, pos);
|
||||
@@ -99,7 +102,7 @@ public class ProgramPresenter
|
||||
this.leftInteractionView.OnPointDragEnd += (index) => HandlePointDragEnd(leftView, index);
|
||||
|
||||
this.rightInteractionView.OnRobotHoverStateChanged += (state) => HandleRobotHover(state);
|
||||
this.rightInteractionView.OnRobotGrabStart += () => HandleRobotGrabStart(rightView);
|
||||
this.rightInteractionView.OnRobotGrabStart += (pos) => HandleRobotGrabStart(rightView, pos);
|
||||
this.rightInteractionView.OnRobotGrabbed += (pos, rot) => HandleRobotGrabbed(rightView, pos, rot);
|
||||
this.rightInteractionView.OnRobotReleased += (data) => HandleRobotReleased(rightView, data);
|
||||
this.rightInteractionView.OnPointClicked += (index, pos) => HandlePointClicked(rightView, index, pos);
|
||||
@@ -117,7 +120,7 @@ public class ProgramPresenter
|
||||
this.robotMovingAudioSource.playOnAwake = false;
|
||||
}
|
||||
|
||||
this.appCts = cts;
|
||||
this.dragLoopCts = cts;
|
||||
}
|
||||
|
||||
public void RegisterControlledRobot(RobotController robot)
|
||||
@@ -163,7 +166,10 @@ public class ProgramPresenter
|
||||
|
||||
private IEnumerator UpdateRobotMovingStateCoroutine()
|
||||
{
|
||||
var waitForOneSecond = new WaitForSeconds(1.0f);
|
||||
var waitForInterval = new WaitForSeconds(0.2f);
|
||||
float lastMovingTime = 0f;
|
||||
float offDelay = 0.5f; // 0.5초 동안은 '0'이 나와도 넘어감 (유예 시간)
|
||||
|
||||
while (true)
|
||||
{
|
||||
Task<string> getTask = model.GetMovingState();
|
||||
@@ -172,23 +178,39 @@ public class ProgramPresenter
|
||||
|
||||
try
|
||||
{
|
||||
if (getTask.IsFaulted)
|
||||
if (!getTask.IsFaulted)
|
||||
{
|
||||
string currentState = getTask.Result;
|
||||
|
||||
if (currentState == "1")
|
||||
{
|
||||
if (pointManagerView.movingAlert != null)
|
||||
pointManagerView.movingAlert.SetActive(true);
|
||||
|
||||
lastMovingTime = Time.time;
|
||||
if(!isProgramStarted) isProgramStarted = true; // 프로그램 실행 도중 GetMovingState가 0이 되는 찰나 isProgramStarted가 false가 되어서 추가한 코드
|
||||
}
|
||||
else
|
||||
{
|
||||
// 마지막으로 움직인 지 0.5초가 지났는지 확인 (유예 시간)
|
||||
if (Time.time - lastMovingTime > offDelay)
|
||||
{
|
||||
if (pointManagerView.movingAlert != null)
|
||||
pointManagerView.movingAlert.SetActive(false);
|
||||
if(isProgramStarted) isProgramStarted = false; // 프로그램 실행 후 정지했을 경우
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw getTask.Exception.InnerException;
|
||||
}
|
||||
|
||||
string currentState = getTask.Result;
|
||||
|
||||
if (pointManagerView.movingAlert != null)
|
||||
{
|
||||
pointManagerView.movingAlert.SetActive(currentState == "1");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"로봇 moving 상태 업데이트 실패: {e.Message}");
|
||||
}
|
||||
yield return waitForOneSecond;
|
||||
yield return waitForInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +227,7 @@ public class ProgramPresenter
|
||||
|
||||
if (!isFeedbackLoopRunning)
|
||||
{
|
||||
_ = CheckRobotMovementFeedbackLoop(appCts.Token);
|
||||
_ = CheckRobotMovementFeedbackLoop(dragLoopCts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +244,7 @@ public class ProgramPresenter
|
||||
{
|
||||
if (model.IsMoving)
|
||||
{
|
||||
// 로봇이 움직이는데 소리가 안 나면 킴
|
||||
// 로봇이 움직이는데 소리가 안 나면 켬
|
||||
if (!robotMovingAudioSource.isPlaying)
|
||||
{
|
||||
robotMovingAudioSource.Play();
|
||||
@@ -237,8 +259,13 @@ public class ProgramPresenter
|
||||
}
|
||||
else
|
||||
{
|
||||
// 프로그램 시작 시에만 켬
|
||||
if (isProgramStarted && !robotMovingAudioSource.isPlaying)
|
||||
{
|
||||
robotMovingAudioSource.Play();
|
||||
}
|
||||
// 로봇이 멈췄는데 소리가 나면 끔
|
||||
if (robotMovingAudioSource.isPlaying)
|
||||
else if (!isProgramStarted && robotMovingAudioSource.isPlaying)
|
||||
{
|
||||
robotMovingAudioSource.Stop();
|
||||
}
|
||||
@@ -265,7 +292,7 @@ public class ProgramPresenter
|
||||
{
|
||||
if (isError)
|
||||
{
|
||||
_ = model.stopProgram(); // 프로그램 실행 중인 경우면 정지
|
||||
//_ = model.stopProgram(); // 프로그램 실행 중인 경우면 정지
|
||||
|
||||
popupView.ShowErrorAlert(true, 2.0f);
|
||||
Debug.LogError("로봇 에러 발생 (범위 초과 등)");
|
||||
@@ -355,11 +382,13 @@ public class ProgramPresenter
|
||||
|
||||
private async Task HandleProgramStart()
|
||||
{
|
||||
isProgramStarted = true;
|
||||
await model.startProgram();
|
||||
}
|
||||
|
||||
private async Task HandleProgramStop()
|
||||
{
|
||||
robotMovingAudioSource.Stop();
|
||||
await model.stopProgram();
|
||||
}
|
||||
|
||||
@@ -403,7 +432,7 @@ public class ProgramPresenter
|
||||
}
|
||||
|
||||
// --- 실시간 동기화(3d->제어기) ---
|
||||
private RobotData ConvertPoseToRobotData(Vector3 newWorldPos, Quaternion newWorldRot)
|
||||
private RobotData ConvertPoseToRobotData(Vector3 newWorldPos)
|
||||
{
|
||||
RobotData targetPose = new RobotData();
|
||||
|
||||
@@ -411,11 +440,11 @@ public class ProgramPresenter
|
||||
targetPose.y = Convert.ToSingle(Math.Round(-1 * newWorldPos.z * 1000, 2));
|
||||
targetPose.z = Convert.ToSingle(Math.Round(newWorldPos.y * 1000, 2));
|
||||
|
||||
Vector3 eulerAngles = newWorldRot.eulerAngles;
|
||||
//Vector3 eulerAngles = newWorldRot.eulerAngles;
|
||||
|
||||
targetPose.rx = Convert.ToSingle(Math.Round(eulerAngles.x, 2));
|
||||
targetPose.ry = Convert.ToSingle(Math.Round(eulerAngles.y, 2));
|
||||
targetPose.rz = Convert.ToSingle(Math.Round(eulerAngles.z, 2));
|
||||
//targetPose.rx = Convert.ToSingle(Math.Round(eulerAngles.x, 2));
|
||||
//targetPose.ry = Convert.ToSingle(Math.Round(eulerAngles.y, 2));
|
||||
//targetPose.rz = Convert.ToSingle(Math.Round(eulerAngles.z, 2));
|
||||
|
||||
return targetPose;
|
||||
}
|
||||
@@ -445,7 +474,7 @@ public class ProgramPresenter
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRobotGrabStart(InteractionView view)
|
||||
private void HandleRobotGrabStart(InteractionView view, Vector3 newWorldPos)
|
||||
{
|
||||
activeInteractionView = view;
|
||||
|
||||
@@ -456,8 +485,12 @@ public class ProgramPresenter
|
||||
Debug.Log("로봇 잡음: 에러 상태 해제");
|
||||
}
|
||||
model.ResetLocalErrorState();
|
||||
IsStopped = false;
|
||||
dragLoopCts = new CancellationTokenSource();
|
||||
IsDragging = true;
|
||||
errMatChanged = false;
|
||||
gripperCollide.isTriggerRobot = false;
|
||||
|
||||
if (model != null) model.IsMoving = false;
|
||||
}
|
||||
|
||||
private async void HandleRobotGrabbed(InteractionView view, Vector3 newWorldPos, Quaternion newWorldRot)
|
||||
@@ -469,17 +502,20 @@ public class ProgramPresenter
|
||||
|
||||
if (model.isError)
|
||||
{
|
||||
IsStopped = true;
|
||||
if (!errMatChanged) // 제어기에서 에러가 false인 경우는 알려주지 않아서 계속 model.isError가 true로 실행되어 넣은 조건문
|
||||
{
|
||||
controlledRobot.toolEndpoint.GetComponent<MeshRenderer>().material = controlledRobot.toolEndpointErrorHighlight;
|
||||
errMatChanged = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
controlledRobot.toolEndpoint.GetComponent<MeshRenderer>().material = controlledRobot.toolEndpointHighlight;
|
||||
}
|
||||
controlledRobot.toolEndpoint.GetComponent<MeshRenderer>().material = controlledRobot.toolEndpointErrorHighlight;
|
||||
errMatChanged = true;
|
||||
model.IsMoving = false;
|
||||
StopDragMoveLoop();
|
||||
//await Task.Delay(100);
|
||||
Debug.Log("에러로 잠시 멈추고 빨간 mat설정");
|
||||
}
|
||||
controlledRobot.toolEndpoint.GetComponent<MeshRenderer>().material = controlledRobot.toolEndpointHighlight;
|
||||
|
||||
if (gripperCollide.isTriggerRobot)
|
||||
{
|
||||
model.IsMoving = false;
|
||||
StopDragMoveLoop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDragging)
|
||||
@@ -488,26 +524,17 @@ public class ProgramPresenter
|
||||
return;
|
||||
}
|
||||
|
||||
this.latestTargetPose = ConvertPoseToRobotData(newWorldPos, newWorldRot);
|
||||
|
||||
// 동기화 속도를 늘리기 위해 명령 횟수 줄임
|
||||
if (!model.isError)
|
||||
this.latestTargetPose = ConvertPoseToRobotData(newWorldPos);
|
||||
|
||||
try
|
||||
{
|
||||
// 시간 체크: 마지막 전송 후 0.1초가 지났는가?
|
||||
bool isTimeToSend = (Time.time - lastMoveSendTime) >= MOVE_SEND_INTERVAL;
|
||||
|
||||
// 거리 체크: 이전 전송 위치보다 유의미하게(1cm 이상) 움직였는가?
|
||||
bool isDistToSend = Vector3.Distance(lastSentPosition, newWorldPos) >= MIN_MOVE_DISTANCE;
|
||||
|
||||
if (isTimeToSend && isDistToSend)
|
||||
{
|
||||
// 전송
|
||||
_ = await model.MoveToPoseTcpAsync(newWorldPos);
|
||||
|
||||
// 시간 및 위치 갱신
|
||||
lastMoveSendTime = Time.time;
|
||||
lastSentPosition = newWorldPos;
|
||||
}
|
||||
// 전송
|
||||
_ = await model.MoveToPoseTcpAsync(newWorldPos);
|
||||
Debug.Log($"로봇 Grabbed 상태, TCP업데이트 : {newWorldPos}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -521,20 +548,63 @@ public class ProgramPresenter
|
||||
{
|
||||
if (view != activeInteractionView) return;
|
||||
IsDragging = false;
|
||||
model.IsMoving = false;
|
||||
StopDragMoveLoop();
|
||||
|
||||
//pendingPointData = this.latestTargetPose; // 임시 저장
|
||||
pendingPointData = pose;
|
||||
controlledRobot.toolEndpoint.GetComponent<MeshRenderer>().material = controlledRobot.toolEndpointOriginal;
|
||||
|
||||
//if (!IsStopped)
|
||||
//{
|
||||
currentPopupState = PopupState.ConfirmAddPoint; // 상태 설정
|
||||
_ = WaitForRobotToStopAndShowPopup(currentPopupState);
|
||||
//}
|
||||
currentPopupState = PopupState.ConfirmAddPoint; // 상태 설정
|
||||
_ = WaitForRobotToStopAndShowPopup(currentPopupState);
|
||||
|
||||
activeInteractionView = null;
|
||||
}
|
||||
|
||||
private void StopDragMoveLoop()
|
||||
{
|
||||
if (dragLoopCts != null)
|
||||
{
|
||||
dragLoopCts.Cancel();
|
||||
dragLoopCts.Dispose();
|
||||
dragLoopCts = null;
|
||||
Debug.Log("dragLoop 토큰 cancel");
|
||||
}
|
||||
}
|
||||
|
||||
private void StartDragMoveLoop(Vector3 dragPosition)
|
||||
{
|
||||
StopDragMoveLoop(); // 중복 방지
|
||||
dragLoopCts = new CancellationTokenSource();
|
||||
_ = DragMoveLoopAsync(dragLoopCts.Token, dragPosition);
|
||||
}
|
||||
|
||||
private async Task DragMoveLoopAsync(CancellationToken token, Vector3 dragPosition)
|
||||
{
|
||||
// 드래그 동안 100ms 주기로 전송
|
||||
while (!token.IsCancellationRequested && IsDragging)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 로봇이 아직 이동 중이 아니라면(대기 상태) 최신 dragPosition으로 지령 전송
|
||||
if (model != null && !model.IsMoving)
|
||||
{
|
||||
await MovingTask(dragPosition); // 내부에서 StratMovement(dragPosition) 호출 및 isMoving 갱신 :contentReference[oaicite:4]{index=4}
|
||||
}
|
||||
|
||||
await Task.Delay(10, token); // 100ms 주기
|
||||
}
|
||||
catch (TaskCanceledException) { /* 정상 취소 */ }
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MovingTask(Vector3 dragPosition)
|
||||
{
|
||||
if (model == null) return;
|
||||
bool ok = await model.MoveToPoseTcpAsync(dragPosition); // 기존 호출 그대로 사용
|
||||
if (ok) model.IsMoving = true;
|
||||
}
|
||||
|
||||
// --- 포인트 클릭 ---
|
||||
private void HandlePointClicked(InteractionView view, int index, Vector3 newWorldPos)
|
||||
{
|
||||
@@ -558,8 +628,6 @@ public class ProgramPresenter
|
||||
// --- 포인트 드래그 ---
|
||||
private void HandlePointDragStart(InteractionView view, int index)
|
||||
{
|
||||
IsDragging = true;
|
||||
|
||||
activePointIndex = index;
|
||||
activeInteractionView = view;
|
||||
|
||||
@@ -573,6 +641,11 @@ public class ProgramPresenter
|
||||
// 반투명 로봇의 위치를 마우스 위치와 같도록 설정
|
||||
pointManagerView.kinematicsNode.targetTransform.position = startPos;
|
||||
originalDragPose = model.CurrentProgram.GetStepPose(index);
|
||||
|
||||
model.ResetLocalErrorState();
|
||||
IsDragging = true;
|
||||
dragLoopCts = new CancellationTokenSource();
|
||||
gripperCollide.isTriggerRobot = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,12 +654,12 @@ public class ProgramPresenter
|
||||
if (!IsDragging) return;
|
||||
if (view != activeInteractionView) return;
|
||||
pointManagerView.kinematicsNode.targetTransform.position = newWorldPos;
|
||||
pointManagerView.kinematicsNode.targetTransform.rotation = newWorldRot;
|
||||
//pointManagerView.kinematicsNode.targetTransform.rotation = newWorldRot;
|
||||
|
||||
Vector3 ghostRobotPos = pointManagerView.kinematicsNode.nodes[5].jointTransform.position;
|
||||
Quaternion ghostRobotRot = pointManagerView.kinematicsNode.nodes[5].jointTransform.rotation;
|
||||
//Quaternion ghostRobotRot = pointManagerView.kinematicsNode.nodes[5].jointTransform.rotation;
|
||||
|
||||
this.latestTargetPose = ConvertPoseToRobotData(ghostRobotPos, ghostRobotRot);
|
||||
this.latestTargetPose = ConvertPoseToRobotData(ghostRobotPos);
|
||||
activeInteractionView.ShowDragArrow(newWorldPos); // 마우스 이미지 변경
|
||||
|
||||
// 고스트 로봇, 포인트, 경로 실시간 이동
|
||||
@@ -607,6 +680,7 @@ public class ProgramPresenter
|
||||
|
||||
Vector3 popupWorldPos = ConvertRobotDataToVector3(pendingPointData);
|
||||
await model.MoveToPoseTcpAsync(popupWorldPos);
|
||||
//StartDragMoveLoop(popupWorldPos);
|
||||
|
||||
currentPopupState = PopupState.ConfirmModifyPoint; // 상태 설정
|
||||
|
||||
@@ -679,25 +753,31 @@ public class ProgramPresenter
|
||||
|
||||
private async Task WaitForRobotToStopAndShowPopup(PopupState nextState)
|
||||
{
|
||||
await Task.Delay(200);
|
||||
while (await model.GetMovingState() == "1")
|
||||
{
|
||||
Debug.Log("로봇이 멈추기를 기다리는 중...");
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
Debug.Log("로봇 정지 완료. 팝업 표시.");
|
||||
currentPopupState = nextState;
|
||||
|
||||
Vector3 popupWorldPos = Vector3.zero;
|
||||
currentPopupState = nextState;
|
||||
|
||||
if (nextState == PopupState.ConfirmAddPoint)
|
||||
{
|
||||
if(!IsDragging) StopDragMoveLoop();
|
||||
while (await model.GetMovingState() == "1")
|
||||
{
|
||||
Debug.Log("로봇이 멈추기를 기다리는 중...");
|
||||
await Task.Delay(100);
|
||||
}
|
||||
model.IsMoving = false;
|
||||
StopDragMoveLoop();
|
||||
Debug.Log("로봇 정지 완료. 팝업 표시.");
|
||||
popupWorldPos = ConvertRobotDataToVector3(pendingPointData);
|
||||
popupView.ShowConfirmPopupFromPoint(popupWorldPos); // 새 포인트 위치
|
||||
}
|
||||
else if(nextState == PopupState.ConfirmModifyPoint)
|
||||
{
|
||||
while (await model.GetMovingState() == "1")
|
||||
{
|
||||
Debug.Log("로봇이 멈추기를 기다리는 중...");
|
||||
await Task.Delay(100);
|
||||
}
|
||||
Debug.Log("로봇 정지 완료. 팝업 표시.");
|
||||
popupWorldPos = ConvertRobotDataToVector3(pendingPointData);
|
||||
popupView.ShowModifyPopup(popupWorldPos);
|
||||
}
|
||||
@@ -773,6 +853,7 @@ public class ProgramPresenter
|
||||
this.envView.OnLoadProgramListRequested -= HandleLoadProgramList;
|
||||
|
||||
this.leftInteractionView.OnRobotHoverStateChanged -= (state) => HandleRobotHover(state);
|
||||
this.leftInteractionView.OnRobotGrabStart -= (pos) => HandleRobotGrabStart(leftInteractionView, pos);
|
||||
this.leftInteractionView.OnRobotGrabbed -= (pos, rot) => HandleRobotGrabbed(leftInteractionView, pos, rot);
|
||||
this.leftInteractionView.OnRobotReleased -= (data) => HandleRobotReleased(leftInteractionView, data);
|
||||
this.leftInteractionView.OnPointClicked -= (index, pos) => HandlePointClicked(leftInteractionView, index, pos);
|
||||
@@ -781,6 +862,7 @@ public class ProgramPresenter
|
||||
this.leftInteractionView.OnPointDragEnd -= (index) => HandlePointDragEnd(leftInteractionView, index);
|
||||
|
||||
this.rightInteractionView.OnRobotHoverStateChanged -= (state) => HandleRobotHover(state);
|
||||
this.rightInteractionView.OnRobotGrabStart -= (pos) => HandleRobotGrabStart(rightInteractionView, pos);
|
||||
this.rightInteractionView.OnRobotGrabbed -= (pos, rot) => HandleRobotGrabbed(this.rightInteractionView, pos, rot);
|
||||
this.rightInteractionView.OnRobotReleased -= (data) => HandleRobotReleased(this.rightInteractionView, data);
|
||||
this.rightInteractionView.OnPointClicked -= (index, pos) => HandlePointClicked(this.rightInteractionView, index, pos);
|
||||
|
||||
@@ -10,7 +10,7 @@ public enum HandSide { Left, Right }
|
||||
public class InteractionView : MonoBehaviour
|
||||
{
|
||||
public event Action<bool> OnRobotHoverStateChanged;
|
||||
public event Action OnRobotGrabStart;
|
||||
public event Action<Vector3> OnRobotGrabStart;
|
||||
public event Action<Vector3, Quaternion> OnRobotGrabbed;
|
||||
public event Action<RobotData> OnRobotReleased;
|
||||
public event Action<int, Vector3> OnPointClicked;
|
||||
@@ -173,7 +173,7 @@ public class InteractionView : MonoBehaviour
|
||||
isGrabbingRobot = true;
|
||||
currentGrabbedPointIndex = -1;
|
||||
|
||||
OnRobotGrabStart?.Invoke();
|
||||
OnRobotGrabStart?.Invoke(startGrabPosition);
|
||||
OnPointDragStart?.Invoke(currentGrabbedPointIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
// 인터페이스
|
||||
public interface IPathLineView
|
||||
{
|
||||
}
|
||||
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class PathLineView : MonoBehaviour, IPathLineView
|
||||
public class PathLineView : MonoBehaviour
|
||||
{
|
||||
private LineRenderer lineRenderer;
|
||||
|
||||
|
||||
@@ -21,21 +21,43 @@ public class PointManagerView : MonoBehaviour
|
||||
|
||||
private Vector3 ConvertRobotDataToVector3(RobotData pose)
|
||||
{
|
||||
float x = Convert.ToSingle(pose.x / -1000.0); // mm -> m
|
||||
float x = Convert.ToSingle(pose.x / -1000.0); // Robot X(mm) -> Unity X(m)
|
||||
float y = Convert.ToSingle(pose.z / 1000.0); // Robot Z(mm) -> Unity Y(m)
|
||||
float z = Convert.ToSingle(pose.y / -1000.0); // Robot Y(mm) -> Unity Z(m)
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
private Quaternion ConvertRobotDataToQuaternion(RobotData pose)
|
||||
{
|
||||
float rx = pose.rx;
|
||||
float ry = pose.z;
|
||||
float rz = pose.y;
|
||||
|
||||
return Quaternion.Euler(pose.rx, -pose.rz, pose.ry);
|
||||
}
|
||||
|
||||
public void CreatePoint(RobotData pose, int index)
|
||||
{
|
||||
if(pointPrefab == null)
|
||||
{
|
||||
Debug.Log("마커 프리팹이 할당되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
Vector3 localPos = ConvertRobotDataToVector3(pose);
|
||||
Vector3 worldPos = localPos;
|
||||
//Quaternion localRot = ConvertRobotDataToQuaternion(pose);
|
||||
|
||||
//Vector3 toolOffset = new Vector3(0.681004044f, -0.221942063f, -0.447616011f);
|
||||
//Vector3 rotatedOffset = localRot * toolOffset;
|
||||
//Vector3 finalLocalPos = localPos + rotatedOffset;
|
||||
|
||||
Vector3 worldPos = localPos;
|
||||
//Quaternion worldRot = localRot;
|
||||
|
||||
// 로봇 Base가 있다면, 로컬 좌표를 월드 좌표로 변환
|
||||
if (robotBaseTransform != null)
|
||||
{
|
||||
worldPos = robotBaseTransform.TransformPoint(localPos);
|
||||
//worldRot = robotBaseTransform.rotation * localRot;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -44,6 +66,9 @@ public class PointManagerView : MonoBehaviour
|
||||
|
||||
// 변환된 월드 좌표에 생성
|
||||
GameObject pointObj = Instantiate(pointPrefab, worldPos, Quaternion.identity, this.transform);
|
||||
Debug.Log($"마커 프리팹 생성됨, 위치: {worldPos}");
|
||||
|
||||
//pointObj.transform.localRotation = Quaternion.identity;
|
||||
activePoints.Add(pointObj);
|
||||
|
||||
RobotPoint pointComponent = pointObj.GetComponent<RobotPoint>();
|
||||
|
||||
@@ -122,7 +122,7 @@ public class ProgramInfoView : MonoBehaviour
|
||||
private void ShowProgramInfoPanel(InputAction.CallbackContext obj)
|
||||
{
|
||||
isPressingX = !isPressingX;
|
||||
if (!isPressingX)
|
||||
if (isPressingX)
|
||||
{
|
||||
infoPanel.transform.SetParent(leftControllerTransform);
|
||||
infoPanel.transform.localPosition = new Vector3(0f, 0.2f, 0f);
|
||||
@@ -143,7 +143,7 @@ public class ProgramInfoView : MonoBehaviour
|
||||
private void PlayProgram(InputAction.CallbackContext obj)
|
||||
{
|
||||
isPressingAorB = !isPressingAorB;
|
||||
if (!isPressingAorB)
|
||||
if (isPressingAorB)
|
||||
{
|
||||
OnStartClicked?.Invoke();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ TagManager:
|
||||
- Point
|
||||
- DropZone
|
||||
- Gripper
|
||||
- Robot
|
||||
layers:
|
||||
- Default
|
||||
- TransparentFX
|
||||
|
||||
Reference in New Issue
Block a user