using FLY.Thick.Base.Common; using FLY.Thick.Base.IService; using FlyADBase; using FObjBase; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; namespace FLY.Thick.Base.Server { /// /// 膜位置检测; /// 通过辊接近开关,或者编码器2; /// 可以用于2台测厚仪同步主轴位置 /// public class FilmPositionDetect : IFilmPositionDetectService { const int MARKNO_SYNC_HIGH = 1; public event PropertyChangedEventHandler PropertyChanged; #region 状态 /// /// 线速度 m/min /// public double FilmVelocity { get; private set; } /// /// 膜位置, m /// public double FilmPosition { get; private set; } /// /// 复位标识,从同步服务器发送过来的 /// public int ResetMark { get; private set; } #endregion #region 参数 /// /// 线速度阀值,低于阀值,速度直接变为0 /// public double FilmVThreshold { get; set; } = 2; /// /// 线速度来源 /// public FilmVSRC FilmVSrc { get; set; } = FilmVSRC.ROUND; /// /// 线速度:编码器2 mm/pulse /// public double Encoder2_mmpp { get; set; } = 0.1; /// /// 线速度:1圈多少mm /// public double MmOfR { get; set; } = 314; #endregion /// /// 纵向光纤传感器检测到 0到1 变化 事件 /// 或 /// sysTime同步信号触发 0到1 变化 事件 /// public event EventHandler SysTimeFilmPosEvent; /// /// /// double reset_filmPos; /// /// 复位时,对应的pos2脉冲 /// int reset_pos2; FlyAD7 flyAd; /// /// /// /// public void Init(FlyAD7 flyAd) { this.flyAd = flyAd; //------------------------------------------------------------------------------------------------------------------------------------ //线速度------------------------------------------------------------------------------------------------------------------------------ this.flyAd.PropertyChanged += FlyAd_PropertyChanged_EN2; //------------------------------------------------------------------------------------------------------------------------------------ //辊信号生成线速度----------------------------------------------------------------------------------------------------------------------------- InitRoundFilmVelocity(); flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent; //复位 Misc.BindingOperations.SetBinding(this.flyAd, nameof(this.flyAd.IsReady), () => { //刚连接上,复位 ResetMark = 0; Reset(0); }); } private void FlyAd_PropertyChanged_EN2(object sender, PropertyChangedEventArgs e) { if (FilmVSrc != FilmVSRC.EN2) return; if (e.PropertyName == nameof(flyAd.Speed2)) { double speed = flyAd.Speed2 * Encoder2_mmpp / 1000.0;// m/s speed *= 60;//m/min FilmVelocity = speed; } else if (e.PropertyName == nameof(flyAd.Position2)) { double filmPos = Pos2ToFilmPos(flyAd.Position2); FilmPosition = filmPos; } } class DateTimeUnit { public DateTime dt { get; set; } public int data; } List pos2Pool = new List(); void AddPos2(DateTime time, int pos2) { pos2Pool.Add(new DateTimeUnit() { dt = time, data = pos2 }); if (pos2Pool.Last().dt - pos2Pool.First().dt > TimeSpan.FromMinutes(1)) { pos2Pool.RemoveAt(0); } } bool FindPos2(DateTime time, out int pos2) { pos2 = 0; var unit = pos2Pool.Find(u => u.dt == time); if (unit == null) return false; pos2 = unit.data; return true; } void mFlyAD_IStatusChangedEvent(object sender, IStatusChangedEventArgs e) { if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_VSign)) { if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_VSign)) { if (FilmVSrc == FilmVSRC.EN2)//不是用编码器, 纵向光纤也不会安装 { SysTimeFilmPosEvent?.Invoke(this, new SysTimeFilmPosEventArgs() { IsSysTimeSync = false, SysTime = e.Time, FilmPos = Pos2ToFilmPos(e.Position2) }); AddPos2(e.Time, e.Position2); } } } else if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_Sync)) { if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_Sync)) { if (FilmVSrc == FilmVSRC.EN2) { AddPos2(e.Time, e.Position2); FilmPosition = Pos2ToFilmPos(e.Position2); } SysTimeFilmPosEvent?.Invoke(this, new SysTimeFilmPosEventArgs() { IsSysTimeSync = true, SysTime = e.Time, FilmPos = FilmPosition }); } } } #region 辊信号生成 线速度 DispatcherTimer round_t; DateTime dtRound; int RCnt = 0; double BaseFilmPosition = 0; void InitRoundFilmVelocity() { round_t = new DispatcherTimer(); round_t.Interval = TimeSpan.FromSeconds(1); round_t.Tick += new EventHandler(round_t_Tick); flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent_round; } void mFlyAD_IStatusChangedEvent_round(object sender, IStatusChangedEventArgs e) { if (FilmVSrc != FilmVSRC.ROUND) return; if (!Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_Roll)) return; if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_Roll)) return; //1->0 DateTime dt = e.Time; if (dt <= dtRound) return; if (dtRound != DateTime.MinValue) { double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes; if (v < 2)//太慢了 { dt = DateTime.MinValue; v = 0; } FilmVelocity = v; if (v > 0) { RCnt++; FilmPosition = RCnt * MmOfR / 1000.0 + BaseFilmPosition; } } dtRound = dt; if (dtRound != DateTime.MinValue) { if (!round_t.IsEnabled) round_t.Start(); } } void round_t_Tick(object sender, EventArgs e) { if (FilmVSrc != FilmVSRC.ROUND) { round_t.Stop(); return; } if (dtRound == DateTime.MinValue) { round_t.Stop(); return; } //1->0 DateTime dt = flyAd.Now; if (dt <= dtRound) return; double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes; if (v < (FilmVelocity - 1)) FilmVelocity = v; double p1 = RCnt * MmOfR / 1000.0; double p2 = (dt - dtRound).TotalMinutes * FilmVelocity; if (p2 > MmOfR / 1000.0) p2 = MmOfR / 1000.0; p1 += p2; if (FilmPosition < p1) FilmPosition = p1; if (FilmVelocity <= FilmVThreshold) { dtRound = DateTime.MinValue; FilmVelocity = 0; round_t.Stop(); return; } } #endregion /// /// 设置膜位置为某值 /// /// 极片位置m public void Reset(double filmPos) { if (FilmVSrc == FilmVSRC.EN2) { reset_pos2 = flyAd.Position2; reset_filmPos = filmPos; } else { RCnt = 0; BaseFilmPosition = filmPos; } FilmPosition = filmPos; } /// /// 让同步信号输出 1到0 1秒后, 0到1 /// public void SyncSysTime() { flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Sync, false); //1秒后,复位同步信号 PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, () => { flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Sync, true); }, TimeSpan.FromSeconds(1), true, false, this, MARKNO_SYNC_HIGH, true); } /// /// 设置膜位置为某值; 同步服务器调用的 /// /// 极片位置m /// AD盒sysTime /// 复位标识 public void Reset(double filmPos, DateTime sysTime, int resetMark) { ResetMark = resetMark; if (FilmVSrc == FilmVSRC.EN2) { reset_filmPos = filmPos; //找回 sysTime 时,对应的flyAd.Position2 if (FindPos2(sysTime, out int pos2)) { reset_pos2 = pos2; } else { reset_pos2 = flyAd.Position2; } } else { RCnt = 0; BaseFilmPosition = filmPos; } FilmPosition = filmPos; } double Pos2ToFilmPos(int pos2) { int distance_p = pos2 - reset_pos2; double distance_m = distance_p * Encoder2_mmpp / 1000.0; double filmPos = distance_m + reset_filmPos; if (Math.Abs(distance_p) > 1000000)//不让它太大,不然乘法会溢出 { //当距离很远,需要复位一下 reset_pos2 = pos2; reset_filmPos = filmPos; } return filmPos; } } }