using BestHTTP; using EasyInject.Attributes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.Playables; using UnityEngine.Serialization; /// /// 叉车AGV /// [GameObjectBean(ENameType.GameObjectName)] public class ForkAgvDevice : AbstractDevice, ICar { [Autowired] private AgvPopUI agvPopUI; /// /// 设备位置解析服务 /// [Autowired("DeviceParseService")] private readonly DeviceParseService deviceParseService; /// /// 提供网络服务 /// [Autowired] private readonly NetWorkComponent netWorkComponent; /// /// 车辆管理服务 /// [Autowired] private readonly AgvCarManage carManage; [Autowired] private ContainersManage containersManage; /// /// 路线高亮服务 /// private LineRenderer lineRenderer; [SerializeField] private bool initialize = false; [SerializeField] private float _speed; [Header("货叉")] [SerializeField] private GameObject forkCargo; [Header("申请取货位置")] [SerializeField] private List applyTakePosition = new(); [Header("申请放货位置")] [SerializeField] private List applyPutPosition = new(); [Header("目标是设备角度设置")] [SerializeField] private List forkAgvRotationSets = new(); [Header("目标是库位角度设置")] [SerializeField] public float shelfRotation = -90; public string CarName => name; [Header("可用巷道")] public List _allowRows = new List(); [SerializeField] private bool _hasTask; [SerializeField] private string _region; [Header("路线颜色")] [SerializeField] private Color pathColor; /// /// 代理组件 /// private NavMeshAgent agent; /// /// 时间轴组件 /// private PlayableDirector playable; /// /// 当前agv任务 /// [FormerlySerializedAs("taskList")] [FormerlySerializedAs("taskData")] [SerializeField] private AgvTaskInfo taskInfo; /// /// 当前反馈状态 /// [SerializeField] private AgvCarManage.CarTaskStatusEnum currentFeedBackStatus; private List paths = new List(); public bool hasTask => _hasTask; public string Region => _region; public List AllowRows => _allowRows; public override Transform Transform => transform; public override string DeviceCode => name; public override string DeviceType => "AGV"; public bool Initialize => initialize; public bool HasGood{ get{ return forkCargo.GetComponentInChildren() != null;} } float ICar.Speed { get => _speed; set { agent.speed = value; _speed = value; } } public override DeviceData DeviceData => throw new NotImplementedException(); private AgvData _data = new(); private bool isOpenPop; [Header("模拟反馈")] [SerializeField] private bool debugFeedBack; //保存当前动画状态 public double animationTime; public double animationSpeed; public PlayState playState; public Boolean agentIsStoping; public Boolean agentRotationUpdate; public Vector3 agentTarget; [System.Serializable] public class ForkAgvRotationSet { //设备 public List device; //非库位取或放,agv保持的角度 public float deviceRotation; } private void Start() { agent = GetComponent(); agent.speed = _speed; playable = GetComponent(); playable.Pause(); lineRenderer = transform.GetOrAddComponent(); lineRenderer.positionCount = 0; lineRenderer.startColor = pathColor; lineRenderer.endColor = pathColor; _data.deviecCode = name; } // private void FixedUpdate() // { // //设备没初始化 // if (!initialize) // { // return; // } // // if (!hasTask) // { // return; // } // UpdateTask(); // //当任务状态是下发状态是,执行 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.SENT) // { // if (currentFeedBackStatus != AgvCarManage.CarTaskStatusEnum.TAKING) // { // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKING; // } // //多次申请 // FeedBackTaskStatus(currentFeedBackStatus); // } // //取货中 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.TAKING) // { // agent.isStopped = false; // //开始代理 // StartAgent(taskInfo.fromLocation); // // 起点旋转位置 // if (applyTakePosition.Count > 0) // { // Vector3 applyTakeVector = LastPosition(applyTakePosition,taskInfo.fromLocation); // //抵达后,申请取货流程 // Vector3 targetPosition = new Vector3(applyTakeVector.x, transform.position.y, applyTakeVector.z); // if (Vector3.Distance(transform.position, targetPosition) <= 0.1f) // { // agent.isStopped = true; // agent.updateRotation = false; // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.APPLY_TAKE; // FeedBackTaskStatus(currentFeedBackStatus); // } // } // } // //申请取货 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.APPLY_TAKE) // { // //抵达终点 // Vector3 targetPosition = new Vector3(transform.position.x, agent.destination.y, transform.position.z); // if (Vector3.Distance(targetPosition, agent.destination) <= 0.1f) // { // //获取库位容器模型,绑定到货叉上 // GameObject game = deviceParseService.GameObjectByDevice(taskInfo.fromLocation); // if (game != null) // { // Container container = game.GetComponentInChildren(); // if (container != null) // { // container.transform.parent = forkCargo.transform; // container.Agent.enabled = false; // container.Agent.isStopped = true; // playable.Play(); // } // } // //反馈取货完成 // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED; // FeedBackTaskStatus(currentFeedBackStatus); // } // Quaternion targetRotation = RotationByDevice(taskInfo.fromDevice); // if (transform.localRotation == targetRotation) // { // //校验起点是设备,需要提升货叉到高位 // if (!IsShelf(taskInfo.fromLocation)) // { // if(playable.time <= 1.3) // { // playable.Play(); // } // else // { // playable.Pause(); // } // } // if(playable.state == PlayState.Paused) // { // agent.isStopped = false; // } // } // else // { // transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, _speed * 2); // } // } // // // //取货完成 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED) // { // if (HasGood) // { // //是库位取货方式 // if (IsShelf(taskInfo.fromDevice)) // { // if (playable.time >= 0.4) // { // OnMinFPS(); // } // if (playable.state == PlayState.Paused) // { // agent.updateRotation = true; // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUTTING; // FeedBackTaskStatus(currentFeedBackStatus); // } // } // else // { // //接驳点取货方式 // //需要回退到指定位置做货叉下降动作 // Vector3 target = LastPosition(applyTakePosition, taskInfo.fromDevice); // agent.isStopped = false; // //开始代理 // StartAgent(target); // Vector3 targetPosition = new Vector3(target.x, transform.position.y, target.z); // //到位后,开始下降货叉 // if (Vector3.Distance(transform.position, targetPosition) <= 0.1f) // { // if (playable.time >= 0.6) // { // playable.playableGraph.GetRootPlayable(0).SetSpeed(-1); // playable.Play(); // } // else // { // playable.Pause(); // agent.updateRotation = true; // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUTTING; // FeedBackTaskStatus(currentFeedBackStatus); // } // } // else // { // //货叉升到满叉才执行后续动作 // if (playable.time < 1.99) // { // playable.Play(); // } // } // // } // // } // else // { // GameObject game = deviceParseService.GameObjectByDevice(taskInfo.fromLocation); // if (game != null) // { // Container container = game.GetComponentInChildren(); // // if (container != null) // { // container.isAwke = false; // container.transform.parent = forkCargo.transform; // playable.Play(); // } // } // } // return; // } // //放货中 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.PUTTING) // { // //未代理开始代理 // StartAgent(taskInfo.toLocation); // // // 起点旋转位置 // if (applyPutPosition.Count > 0) // { // Vector3 applyPutVector = LastPosition(applyPutPosition, taskInfo.toLocation); // //抵达后,申请取货流程 // Vector3 targetPosition = new Vector3(applyPutVector.x, transform.position.y, applyPutVector.z); // if (Vector3.Distance(transform.position, targetPosition) <= 0.1f) // { // agent.isStopped = true; // agent.updateRotation = false; // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.APPLY_PUT; // FeedBackTaskStatus(currentFeedBackStatus); // } // // } // // } // //申请放货 // if (taskInfo.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.APPLY_PUT && currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.APPLY_PUT) // { // //抵达终点 // if (Vector3.Distance(transform.position, agent.destination) <= 0.1f) // { // currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUT_FINISHED; // // } // Quaternion targetRotation = RotationByDevice(taskInfo.toDevice); // if (transform.localRotation == targetRotation) // { // //启用代理 // agent.isStopped = false; // //如果是设备将货叉提升完 // if(!IsShelf(taskInfo.toLocation)) // { // playable.Play(); // } // } // else // { // transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, _speed * 2); // } // } // // if (currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.PUT_FINISHED) // { // if (HasGood) // { // //校验是库位还是设备 // // if(IsShelf(taskInfo.toLocation)) // { // Debug.LogWarning("放货持续"); // if (playable.time > 0) // { // playable.playableGraph.GetRootPlayable(0).SetSpeed(-1); // playable.Play(); // } // else // { // //暂停播放 // //playable.Pause(); // ////解绑容器 // //Container container = forkCargo.transform.GetComponentInChildren(); // //container.transform.parent = null; // OnMaxFPS(); // } // } // else // { // if (playable.time > 1.5f) // { // playable.playableGraph.GetRootPlayable(0).SetSpeed(-1); // playable.Play(); // } // else // { // OnMaxFPS(); // } // } // // } // else // { // if(!IsShelf(taskInfo.toLocation)) // { // //当后退完成后最终下降完货叉,并重置agv状态 // Vector3 position = LastPosition(applyPutPosition, taskInfo.toLocation); // Vector3 targetPosition = new Vector3(position.x, transform.position.y, position.z); // // if (Vector3.Distance(transform.position, targetPosition) <= 0.1f) // { // if(playable.time > 0) // { // playable.Play(); // } // else // { // playable.Pause(); // FeedBackTaskStatus(currentFeedBackStatus); // Rest(); // } // } // } // else // { // Vector3 position = LastPosition(applyPutPosition, taskInfo.toLocation); // Vector3 targetPosition = new Vector3(position.x, transform.position.y, position.z); // if (Vector3.Distance(transform.position, targetPosition) <= 0.1f) // { // GameObject game = deviceParseService.GameObjectByDevice(taskInfo.toLocation); // Container container = containersManage.GetContainerByCode(taskInfo.containerCode); // container.transform.parent = game.transform; // container.transform.localPosition = new Vector3(0, -0.2472343f, 0.0006999969f); // container.Agent.enabled = true; // FeedBackTaskStatus(currentFeedBackStatus); // Rest(); // } // } // } // } // } /// /// 重置设备状态 /// public void Rest() { taskInfo = new AgvTaskInfo(); _hasTask = false; paths.Clear(); currentFeedBackStatus =AgvCarManage.CarTaskStatusEnum.STANDBY; agent.ResetPath(); agent.isStopped = false; agent.updateRotation = true; playable.playableGraph.GetRootPlayable(0).SetSpeed(1); playable.time = 0; playable.Pause(); } /// /// 反馈任务状态 /// public void FeedBackTaskStatus(AgvCarManage.CarTaskStatusEnum status,string feedBacklocation = "") { if(debugFeedBack) { // taskInfo.agvTaskStatus = status; } FeedBackEntity feedBackDTO = new FeedBackEntity(); feedBackDTO.feedbackStatus = status.ToString(); feedBackDTO.feedbackLocation = feedBacklocation; feedBackDTO.taskCode = taskInfo.instructionCode; feedBackDTO.carId = taskInfo.carId; netWorkComponent.RemoteFeedBackAgvTaskStatus(feedBackDTO, OnFeedBack); } /// /// 接受反馈回调信息 /// private void OnFeedBack(HTTPRequest originalRequest, HTTPResponse response) { if(response == null) { return; } //请求成功 if (response.IsSuccess) { try { //解析反馈 JObject result = JObject.Parse(response.DataAsText); bool isSuccesss = bool.Parse(result["success"].ToString()); //后台处理反馈成功 if (isSuccesss) { //更新当前任务状态,懒更新 // taskData.agvTaskStatus = currentFeedBackStatus; //agent.isStopped = true; } else { Debug.LogError(name + " 反馈 =" + response.DataAsText); } } catch(Exception ex) { } } } private void Reset() { taskInfo = null; _hasTask = false; agent.ResetPath(); } public void SendTask(AgvTaskInfo taskInfo) { //if (!Initialize) //{ // return; //} this.taskInfo = taskInfo; _hasTask = true; } /// /// 检查数据并初始化 /// private void CheckValueAndInit(HTTPRequest originalRequest, HTTPResponse response) { //响应成功 if (response.IsSuccess) { try { JObject result = JObject.Parse(response.DataAsText); if (result["object"] == null) { Debug.LogWarning("检查数据并初始化" + $"{response.DataAsText}"); return; } string json = result["object"].ToString(); CarStatusEntity statusEntity = JsonConvert.DeserializeObject(json); if (statusEntity != null && statusEntity.task != null) { //任务存在的时候才运行初始位置 if (carManage.Contains(statusEntity.task)) { } Debug.LogWarning(name + "agv 初始化赋值 =" + JsonConvert.SerializeObject(statusEntity.task)); //agv本体 this.SendTask(statusEntity.task); this.transform.localPosition = statusEntity.posistion.ToVector(); this.transform.localRotation = statusEntity.roation.ToQuaternion(); this.transform.localScale = statusEntity.scale.ToVector(); this.currentFeedBackStatus = statusEntity.currentFeedBackStatus; //货叉 if (statusEntity.cargoStatus != null) { //forkCargo.transform.localPosition = statusEntity.cargoStatus.posistion.ToVector(); //forkCargo.transform.localRotation = statusEntity.cargoStatus.roation.ToQuaternion(); //forkCargo.transform.localScale = statusEntity.cargoStatus.scale.ToVector(); playable.time = statusEntity.cargoStatus.animationTime; if (statusEntity.cargoStatus.playState == PlayState.Playing) { playable.Play(); } if (statusEntity.cargoStatus.playState == PlayState.Paused) { playable.Pause(); } playable.RebuildGraph(); playable.playableGraph.GetRootPlayable(0).SetSpeed(statusEntity.cargoStatus.animationSpeed); } //容器 if (statusEntity.containerStatus != null) { ContainerEntity containerEntity = new ContainerEntity(); containerEntity.containerCode = statusEntity.containerStatus.deviceCode; containerEntity.containerType = statusEntity.containerStatus.type; Container container = containersManage.CreateContainer(forkCargo.transform,containerEntity); container.transform.localPosition = statusEntity.containerStatus.posistion.ToVector(); container.transform.localRotation = statusEntity.containerStatus.roation.ToQuaternion(); container.transform.localScale = statusEntity.containerStatus.scale.ToVector(); container.transform.parent = forkCargo.transform; } initialize = true; } }catch(Exception x) { } } else { // Debug.LogWarning(name + ":获取缓存数据响应=" + response.DataAsText); // Debug.LogWarning(string.Format("【url:{0}】", originalRequest.CurrentUri)); } initialize = true; } private void OnDestroy() { Shutdown(); } public void Shutdown() { //当前agv的设备信息 CarStatusEntity carStatus = new(); carStatus.scale = Utils.ToSerializationVectorByVector(transform.localScale); carStatus.posistion = Utils.ToSerializationVectorByVector(transform.localPosition); carStatus.roation = Utils.ToSerializationVectorByVector(transform.localRotation.eulerAngles); carStatus.deviceCode = DeviceCode; carStatus.modelId = GetInstanceID(); carStatus.currentFeedBackStatus = currentFeedBackStatus; carStatus.agentIsStoping = this.agentIsStoping; carStatus.agentRotationUpdate = this.agentRotationUpdate; carStatus.target = Utils.ToSerializationVectorByVector(this.agentTarget); //货叉设备信息 CarStatusEntity cargo = new() { scale = Utils.ToSerializationVectorByVector(forkCargo.transform.localScale), posistion = Utils.ToSerializationVectorByVector(forkCargo.transform.localPosition), roation = Utils.ToSerializationVectorByVector(forkCargo.transform.localRotation.eulerAngles), modelId = forkCargo.GetInstanceID(), deviceCode = forkCargo.name, animationTime = animationTime, animationSpeed = animationSpeed, playState = this.playState }; //有货 if (HasGood) { CarStatusEntity containerStatus = new(); Container container = forkCargo.GetComponentInChildren(); containerStatus.scale = Utils.ToSerializationVectorByVector(container.transform.localScale); containerStatus.posistion = Utils.ToSerializationVectorByVector(container.transform.localPosition); containerStatus.roation = Utils.ToSerializationVectorByVector(container.transform.localRotation.eulerAngles); carStatus.containerStatus = containerStatus; } carStatus.cargoStatus = cargo; if(taskInfo != null && taskInfo.instructionId != 0) { carStatus.task = taskInfo; } //保存当前设备数据 netWorkComponent.RemoteSaveData(name, carStatus, SaveResult); } private void SaveResult(HTTPRequest originalRequest, HTTPResponse response) { if (response == null) { return; } if (response.IsSuccess) { Debug.Log("保存返回= " + response.DataAsText); } else { Debug.Log("保存返回= " + response.DataAsText); } } /// /// 开始代理 /// /// public void StartAgent(string deviceName) { //未代理开始代理 if (!paths.Contains(deviceName)) { Vector3 targetPosistion = deviceParseService.PositionByDevice(deviceName); agent.SetDestination(targetPosistion); lineRenderer.positionCount = 0; lineRenderer.SetPositions(agent.path.corners); paths.Add(taskInfo.fromLocation); } } /// /// 开始代理 /// /// public void StartAgent(Vector3 target) { agent.SetDestination(target); } /// /// 取货完成 /// public void OnTakeFinish() { currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED; } public void MouseLeftDown() { CameraFollow cameraFollow = transform.GetComponent(); if (cameraFollow) { cameraFollow.OnEnter(); } } /// /// 更新任务 /// public void UpdateTask() { _data.feedBack = currentFeedBackStatus.ToString(); if(taskInfo != null) { AgvTaskInfo task = carManage.GetTaskByCode(taskInfo.instructionCode); try { animationSpeed = playable.playableGraph.GetRootPlayable(0).GetSpeed(); } catch (Exception e) { } animationTime = playable.time; playState = playable.state; agentIsStoping = agent.isStopped; agentRotationUpdate = agent.updateRotation; agentTarget = agent.destination; if (task != null) { taskInfo = task; _data.container = taskInfo.containerCode; _data.startDevice = taskInfo.fromLocation; _data.endDevice = taskInfo.toLocation; _data.currentAction = taskInfo.agvTaskStatus.ToString(); } else { Rest(); } } } public void OnInit() { //获取远程缓存 netWorkComponent.RemoteGetDataByLable(name, CheckValueAndInit); } /// /// 任务状态反馈实体 /// private class FeedBackEntity { public string systemCode = "DT"; public string houseCode = "DT"; public long taskCode; public string carId; public string taskType; public string feedbackStatus; public string feedbackLocation; } /// /// 车辆状态实体 /// [System.Serializable] private class CarStatusEntity : DeviceStatus { public AgvTaskInfo task; public AgvCarManage.CarTaskStatusEnum currentFeedBackStatus; public Boolean agentIsStoping; public Boolean agentRotationUpdate; public SerializationVector target; public DeviceStatus cargoStatus; public DeviceStatus containerStatus; } /// /// 解析申请取放货坐标 /// /// /// /// /// public Vector3 LastPosition(List objects, string name) { //如果的库位 if (name.Contains("-")) { string[] str = name.Split('-'); GameObject game = objects.Find(v => string.Equals(v.name, "row_" + str[0])); if (game != null) { return new Vector3(game.transform.position.x, transform.position.y, game.transform.position.z); } } else { //设备 GameObject game = objects.Find(v => string.Equals(v.name, "device_" +name)); if (game != null) { return new Vector3(game.transform.position.x,transform.position.y,game.transform.position.z); } } throw new Exception(string.Format("【{0}】未配置申请取放货坐标【{1}】",this.name,name)); } private Quaternion RotationByDevice(string name) { if(name.Contains("shelf")) { return Quaternion.Euler(0,shelfRotation , 0); } else { foreach (var itme in forkAgvRotationSets) { GameObject obj = itme.device.Find(v => string.Equals(v.name, name)); if (obj != null) { return Quaternion.Euler(0, itme.deviceRotation, 0); } } } throw new Exception(string.Format("未找到该设备【{0}】旋转角度",name)); } /// /// 在动画指定最小帧时触发 /// public void OnMinFPS() { //有货停止播放 if (HasGood) { playable.Pause(); } } public void OnMaxFPS() { if (currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.PUT_FINISHED) { //暂停播放 playable.Pause(); //解绑容器 Container container = forkCargo.transform.GetComponentInChildren(); container.transform.parent = null; container.Agent.enabled = true; //agv得退出一段距离 //倒退位置坐标 Vector3 applyPutVector = LastPosition(applyPutPosition, taskInfo.toLocation); //开始代理 StartAgent(applyPutVector); } } /// /// 校验当前目标是否是库位 /// /// public bool IsShelf(string name) { return name.Contains("-") || name.Contains("shelf"); } public override void DataHandle(object data, object other = null) { } public override void ProcessCompleted() { } public override T DynamicData() { return (T)(object) _data; } public override void MouseSingleClick() { base.MouseSingleClick(); isOpenPop = !isOpenPop; agvPopUI.Open(this, isOpenPop); } }