using FObjBase; using Misc; using NLog.Fluent; using System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.Remoting.Channels; namespace FlyADBase { public partial class FlyAd2021B2 : IFlyADClientAdv { #region IFlyADClientAdv property /// /// grid数据平滑 /// public int GridSmooth { get; set; } /// /// 机架总长 /// public int PosLen { get; set; } = 8900; /// /// 使用独立的脉冲最大最小值 /// public bool HasPosMaxMin { get; set; } /// /// 最小脉冲,默认是0 /// public int PosMin { get; set; } = 0; /// /// 最大脉冲,默认于PosLen 一样 /// public int PosMax { get; set; } = 8900; public int GridLen => PosLen / PosOfGrid; /// /// Speed1 = Velocity * Speed1Scale /// public double Speed1Scale => (double)Ratio02 / Ratio01; /// /// 动作完成 /// public bool IsFinish { get; set; } /// /// ad滞后修正 单位ms /// public int ADLag { get; set; } /// /// ad2滞后修正 单位ms /// public int AD2Lag { get; set; } //一共有1.AD数据池(由timegrid提供) 1min //2.pos数据池(pos推送提供) 1min //4.当接收的grid事件数据。它有 (direction, grid_start,grid_len, systick ) //systick 就是结束的时间点。 当AD数据池出现了这个时间点 //pos数据池向前找。 pos 在 grid_start*posOfGrid 范围的数据。 //找到开始的systick 后,整合3个数据池的数据。 //5.最后代替 grid 推送出去。 public TimeGridAdvHelper mTimeGridAdvHelper { get; } = new TimeGridAdvHelper(); /// /// 动作指令完成,准备推送 timegridadv 事件 /// public bool IsTimeToPushTimeGridAdv { get; private set; } = false; /// /// 以timegrid 为单位,推送数据 /// public event TimeGridAdv2EventHandler TimeGridAdv2Event; #endregion DateTime lastUpdateADTime; int lastGrid = Misc.MyBase.NULL_VALUE; DateTime lastGridTime; Stopwatch stopwatch_gridTime = new Stopwatch(); void advConstructor() { mTimeGridAdvHelper.Init(); this.PropertyChanged += FlyAD7_PropertyChanged1; //轮询事件触发 PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, OnPoll); } private void FlyAD7_PropertyChanged1(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == nameof(DriveStatus)) { switch (DriveStatus) { case DRIVE_MAN_STATUS.STOP_MANUAL: case DRIVE_MAN_STATUS.STOP: case DRIVE_MAN_STATUS.LIMIT: IsFinish = true; break; case DRIVE_MAN_STATUS.RUNNING: IsFinish = false; break; } } } void advAfterContected() { mTimeGridAdvHelper.Clear(); lastUpdateADTime = DateTime.MinValue; lastGrid = Misc.MyBase.NULL_VALUE; lastGridTime = DateTime.MinValue; } #region IFlyADClientAdv function /// /// Runto(0), 不同于 Backward /// public void RuntoMin() { if (HasPosMaxMin) Runto(PosMin); else Runto(0); } /// /// Runto(PosLen), 不同于 Forward /// public void RuntoMax() { if (HasPosMaxMin) Runto(PosMax); else Runto(PosLen); } /// /// 设置输出 /// /// /// public void SetOutputBit(int index, bool is1) { if (index > 15)//4) return; if (index < 0) return; if (is1) { SetOutput( (UInt16)Misc.MyBase.BIT(index), (UInt16)Misc.MyBase.BIT(index)); } else { SetOutput( (UInt16)Misc.MyBase.BIT(index), (UInt16)~Misc.MyBase.BIT(index)); } } #endregion void advPushData(DateTime dt, int ad, int ad2) { var ret = mTimeGridAdvHelper.AddData(dt, ad, ad2, Position, Position2, IStatus); if (ret.isChanged) { if (ret.isIstatusChanged) { IStatusChangedEvent?.Invoke(this, new IStatusChangedEventArgs(Now, IStatus, ret.ichanged, Position, Position2)); } if (ret.isPosChanged) { PositionChangedEvent?.Invoke(this, new PositionChangedEventArgs() { Time = Now, Position = Position }); } if (ret.isPos2Changed) { Position2ChangedEvent?.Invoke(this, new PositionChangedEventArgs() { Time = Now, Position = Position2 }); } } } void advPushStatus() { if (mTimeGridAdvHelper.AddDriveStatus(Now, DriveOrder, DriveStatus)) { //状态变了 if (DriveStatus != DRIVE_MAN_STATUS.RUNNING) { //通知 mTimeGridAdvHelper 下次触发 timegridadv IsTimeToPushTimeGridAdv = true; } DriveStatusChangedEvent?.Invoke(this, new DriveStatusChangedEventArgs() { Time = Now, DriveOrder = DriveOrder, DriveStatus = DriveStatus }); } } /// /// ScanMotion 使用。 /// 给定按扫描的时间点。当探头停下来后,获取数据。 /// 数据带滞后修正,带运动方向。 /// /// /// public TimeGridAdv2EventArgs GetTimeGridAdv2Event(DateTime beginTime) { //获取ad列表 var dataList = mTimeGridAdvHelper.GetData(beginTime); if (dataList.Count() == 0) return null; DateTime endTime = mTimeGridAdvHelper.NewestTime; Misc.DIRECTION direction; //判断运动方向 if (dataList.Last().pos > dataList.First().pos) { //正向 direction = DIRECTION.FORWARD; } else { direction = DIRECTION.BACKWARD; } //数据滞后 if(!TimeGridAdvHelperExt.AdLagCorr(dataList, ref endTime, ADLag, AD2Lag)) { throw new Exception("数据量太少,无法滞后修正"); } TimeGridAdv2EventArgs eventArgs = new TimeGridAdv2EventArgs(); eventArgs.Direction = direction; eventArgs.EndTime = endTime; eventArgs.DataList = dataList; return eventArgs; } void OnPoll() { if (!IsConnected) return; if (!IsReady) return; OnPoll_TimeGrid(); OnPoll_TimeGridAdv(); OnPoll_miniGrid(); } //没有滞后处理,没有机架修正 void OnPoll_TimeGrid() { if (lastUpdateADTime == DateTime.MinValue) { lastUpdateADTime = Now; return; } if (Now - lastUpdateADTime < TimeSpan.FromSeconds(0.1)) return; //获取0.1s到现在的数据 var dataList = mTimeGridAdvHelper.GetData(lastUpdateADTime); //算AD均值 int[] ad1s = dataList.Select(d => d.ad).ToArray(); int[] ad2s = dataList.Select(d => d.ad2).ToArray(); int ad = (int)ad1s.Average(); AD = ad; int ad2 = (int)ad2s.Average(); AD2 = ad2; //推送timegrid事件 TimeGridEvent?.Invoke(this, new TimeGridEventArgs() { Time = lastUpdateADTime, Ad1s = ad1s, Ad2s = ad2s }); lastUpdateADTime = Now; } //没有滞后处理,没有机架修正 void OnPoll_miniGrid() { int grid = Position / PosOfGrid; if (!Misc.MyBase.ISVALIDATA(lastGrid)) { lastGrid = grid; lastGridTime = Now; stopwatch_gridTime.Restart(); return; } if (lastGrid == grid) { if (Now - lastGridTime > TimeSpan.FromSeconds(2)) { //太慢,超过2秒还没走完一个grid //强制缩少数据 lastGridTime = Now; } return; } if (stopwatch_gridTime.Elapsed < TimeSpan.FromSeconds(0.1)) { //太快,控制推送频率 return; } stopwatch_gridTime.Restart(); //方向 Misc.DIRECTION direction; if (lastGrid < grid) direction = Misc.DIRECTION.FORWARD; else direction = Misc.DIRECTION.BACKWARD; var dataList = mTimeGridAdvHelper.GetData(lastGridTime); var endTime = mTimeGridAdvHelper.NewestTime; //数据滞后 if (!TimeGridAdvHelperExt.AdLagCorr(dataList, ref endTime, ADLag, AD2Lag)) { //throw new Exception("数据量太少,无法滞后修正"); return; } //获取grid图 TimeGridAdvHelperExt.ToGrid(dataList, PosOfGrid, GridLen, out int grid_start, out int grid_end, out int[] gridsOfAd1, out int[] gridsOfAd2, isMiniGrid: true); if (gridsOfAd1 == null) return; if (grid_start >= GridLen) return; //需要推送grid MiniGridEvent?.Invoke(this, new MiniGridEventArgs() { direction = direction, grid_start = grid_start, posOfGrid = PosOfGrid, buf = gridsOfAd1, buf2= gridsOfAd2, }); lastGrid = grid; lastGridTime = Now; } void OnPoll_TimeGridAdv() { if (!IsTimeToPushTimeGridAdv) return; IsTimeToPushTimeGridAdv = false; if (TimeGridAdv2Event == null) return; //触发全部高级版的 timegrid bool ret = mTimeGridAdvHelper.GetLastRunningTime(out DateTime beginTime, out DateTime endTime, out DRIVE_MAN_ORDER order); if (!ret) return; var eventArgs = GetTimeGridAdv2Event(beginTime); //获取ad列表 var dataList = eventArgs.DataList; int dataCnt = dataList.Count(); if (dataCnt == 0) return; endTime = eventArgs.EndTime; var direction = eventArgs.Direction; //生成grid图 TimeGridAdvHelperExt.ToGrid(dataList, PosOfGrid, GridLen, out int grid_start, out int grid_end, out int[] gridsOfAd1, out int[] gridsOfAd2); //触发事件 TimeGridAdv2Event?.Invoke(this, new TimeGridAdv2EventArgs { Direction = direction, EndTime = endTime, DataList= dataList }); } } class CalSpeed { DateTime last_now; DateTime pos1_changed_time; DateTime pos2_changed_time; DateTime last_pos1_changed_time; DateTime last_pos2_changed_time; int last_pos1; int last_pos2; int pos1; int pos2; public bool Cal(DateTime now, out int speed1, out int speed2) { speed1 = 0; speed2 = 0; if (last_now == DateTime.MinValue && now != DateTime.MinValue) { last_now = now; last_pos1_changed_time = pos1_changed_time; last_pos2_changed_time = pos2_changed_time; last_pos1 = pos1; last_pos2 = pos2; return false; } if (now - last_now < TimeSpan.FromSeconds(0.5)) return false; bool isInvalid = false; if (pos1_changed_time != last_pos1_changed_time && last_pos1_changed_time != DateTime.MinValue) { var spd = (int)((pos1 - last_pos1) / (pos1_changed_time - last_pos1_changed_time).TotalSeconds); if (Math.Abs(spd) > 100000) { //肯定是溢出了, isInvalid = true; } else { speed1 = spd; } } else { //停了 speed1 = 0; } if (pos2_changed_time != last_pos2_changed_time && last_pos2_changed_time != DateTime.MinValue) { var spd= (int)((pos2 - last_pos2) / (pos2_changed_time - last_pos2_changed_time).TotalSeconds); if (Math.Abs(spd) > 100000) { //肯定是溢出了, isInvalid = true; } else { speed2 = spd; } } else { //停了 speed2 = 0; } last_now = now; last_pos1_changed_time = pos1_changed_time; last_pos2_changed_time = pos2_changed_time; last_pos1 = pos1; last_pos2 = pos2; if (isInvalid) return false; else return true; } public void SetPos1(DateTime changedTime, int pos) { pos1_changed_time = changedTime; pos1 = pos; } public void SetPos2(DateTime changedTime, int pos) { pos2_changed_time = changedTime; pos2 = pos; } public void Reset() { last_now = DateTime.MinValue; pos1_changed_time = DateTime.MinValue; pos1 = 0; last_pos1_changed_time = DateTime.MinValue; last_pos1 = 0; pos2_changed_time = DateTime.MinValue; pos2 = 0; last_pos2_changed_time = DateTime.MinValue; last_pos2 = 0; } } /// /// 正反转 grid数据 缓存区 /// class SGrid { public const int GRID_MAX_SIZE = 1000; int size; public int[][] data = new int[2][];//data[0]=forword, data[1]=backward public SGrid() { //清空所有数据 SetSize(GRID_MAX_SIZE); } public void SetSize(int size) { this.size = size; data[0] = new int[size]; data[1] = new int[size]; Clear(); } public void Clear() { //清空所有数据 for (int i = 0; i < size; i++) { data[0][i] = Misc.MyBase.NULL_VALUE; data[1][i] = Misc.MyBase.NULL_VALUE; } } } }