非標框架(6)-軸類

using System;
using System.Threading;
using LaserWelder.Base;
using LaserWelder.Util;

namespace LaserWelder.Motion
{
    /// <summary>
    /// 軸
    /// </summary>
    public partial class Axis : EntityBase<AxisKey>
    {
        /// <summary>
        /// 基於軸參數的軸構造函數
        /// </summary>
        /// <param name="prm"></param>
        public Axis(AxisPrm prm)
        {
            Prm = prm;
            Key = prm.Key;
            switch (Prm.Type)
            {
                case AxisType.Reverse:
                    ReverseAxis = AxisMgr.Instance.FindBy(Prm.ReverseAxisKey);
                    break;
                case AxisType.Cylinder_TwoPos:
                    break;
            }
            if (Prm.Type == AxisType.Common || Prm.Type == AxisType.Master || Prm.Type == AxisType.Reverse)
            {
                Card.Executer.SetScale(prm.Code, prm.PulseEquiv, Card.Key);
            }
        }
        /// <summary>
        /// 參數
        /// </summary>
        public AxisPrm Prm { get; set; }
        /// <summary>
        /// 軸需要用到的控制卡
        /// </summary>
        public Card Card
        {
            get
            {
                return CardMgr.Instance[Prm.CardNum];
            }
        }
        /// <summary>
        /// Reverse軸所關聯的其它軸
        /// </summary>
        public Axis ReverseAxis { get; private set; }
        private bool isHomed;
        public bool IsHomed
        {
            get
            {
                if (Prm.Type == AxisType.Reverse)
                {
                    return ReverseAxis.IsHomed;
                }
                return isHomed;
            }
        }

        /// <summary>
        /// 等待軸使能成功
        /// </summary>
        /// <param name="maxDelay">最大等待時間/ms</param>
        /// <param name="code">軸編號</param>
        private bool waitAxisOn(int maxDelay, short code)
        {
            Result rtn;
            bool isServo;
            int num = maxDelay / 5; //允許的最大循環次數
            int i = 0; //已循環的次數
            while (true)
            {
                rtn = Card.Executer.GetIsServo(code, out isServo, Card.Key);
                if (!rtn.IsOk)
                {
                    return false;
                }
                else if (isServo)
                {
                    return true;
                }
                if (i > num)
                    break;
                i++;
                Thread.Sleep(3);
            }
            return false;
        }
        private bool isServo(short code)
        {
            bool isServo;
            Card.Executer.GetIsServo(code, out isServo, Card.Key);
            return isServo;
        }
        public bool Alarm
        {
            get
            {
                bool isAlarm;
                Result rst;
                if (Prm.Type == AxisType.Master)
                {
                    rst = Card.Executer.GetIsAlarm(Prm.FollowAxisCode, out isAlarm, Card.Key);
                    if (!rst.IsOk || !isAlarm)
                    {
                        return false;
                    }
                }
                rst = Card.Executer.GetIsAlarm(Prm.Code, out isAlarm, Card.Key);
                if (!rst.IsOk || !isAlarm)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            set
            {
                if (!value)
                {
                    if (Prm.Type == AxisType.Master)
                    {
                        Card.Executer.ClearAlarm(Prm.FollowAxisCode, Card.Key);
                    }
                    Card.Executer.ClearAlarm(Prm.Code, Card.Key);
                }
            }
        }
        /// <summary>
        /// 獲得絕對座標
        /// </summary>
        public double Position
        {
            get
            {
                switch (Prm.Type)
                {
                    case AxisType.Reverse:
                        return ReverseAxis.Position * (-1);
                    case AxisType.Cylinder_TwoPos:
                        return 0;
                }
                double pos = 0;
                int enc, ele;
                Card.Executer.GetEncPos(Prm.Code, out pos, Card.Key);
                Card.Executer.GetGear(Prm.Code, out enc, out ele, Card.Key);
                return pos * ele / enc / Prm.PulseEquiv;
            }
        }
        public bool PosHardLimit
        {
            get
            {
                int status;
                Card.Executer.GetLmtsSts(Prm.Code, Prm.PosLimitNum, out status, Card.Key);
                if (status == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
        public bool NegHardLimit
        {
            get
            {
                int status;
                Card.Executer.GetLmtsSts(Prm.Code, Prm.NegLimitNum, out status, Card.Key);
                if (status == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
        public Result SetSoftLimitOn()
        {
            //Prm.IsSoftLimit = true;
            return Card.Executer.SetSoftLimit(Prm.Code, 1, Prm.SoftPosLimit, Prm.SoftNegLimit, Card.Key);
        }
        public Result SetSoftLimitOff()
        {
            //Prm.IsSoftLimit = false;
            return Card.Executer.SetSoftLimit(Prm.Code, 0, Prm.SoftPosLimit, Prm.SoftNegLimit, Card.Key);
        }
        public Result GetSoftLimit(out int enable, out int positive, out int negative)
        {
            int mode;
            return Card.Executer.GetSoftLimit(Prm.Code, out enable, out positive, out negative, out mode, Card.Key);
        }
        /// <summary>
        /// 設置或獲得上電狀態
        /// </summary>
        public bool Servo
        {
            get
            {
                switch (Prm.Type)
                {
                    case AxisType.Common:
                    case AxisType.Master:
                        bool isServo;
                        Card.Executer.GetIsServo(Prm.Code, out isServo, Card.Key);
                        return isServo;
                    case AxisType.Reverse:
                        return ReverseAxis.Servo;
                }
                return true;
            }
            set
            {
                switch (Prm.Type)
                {
                    case AxisType.Common:
                    case AxisType.Master:
                        if (value) //上電
                        {
                            switch (Prm.Type)
                            {
                                case AxisType.Common:
                                    Card.Executer.AxisOn(Prm.Code, Card.Key);
                                    waitAxisOn(500, Prm.Code);
                                    break;
                                case AxisType.Master:

                                    break;
                            }
                            Thread.Sleep(200);
                        }
                        else //斷電
                        {
                            switch (Prm.Type)
                            {
                                case AxisType.Common:
                                    Card.Executer.AxisOff(Prm.Code, Card.Key);
                                    break;
                                case AxisType.Master:
                                    Card.Executer.SetFollowAxis(0, Prm.FollowAxisCode, Card.Key);
                                    Thread.Sleep(500);
                                    Card.Executer.AxisOff(Prm.Code, Card.Key);
                                    Card.Executer.AxisOff(Prm.FollowAxisCode, Card.Key);
                                    break;
                            }
                        }
                        break;
                    case AxisType.Reverse:
                        ReverseAxis.Servo = value;
                        break;
                }
            }
        }
        /// <summary>
        /// 清零
        /// </summary>
        /// <returns></returns>
        public Result Zero()
        {
            switch (Prm.Type)
            {
                case AxisType.Common:
                case AxisType.Master:
                    return Card.Zero(Prm.Code);
                case AxisType.Reverse:
                    return ReverseAxis.Zero();
            }
            return Result.OK;
        }
        /// <summary>
        /// 回原點,不阻塞不清零
        /// </summary>
        /// <returns></returns>
        public Result GoHome()
        {
            Result rtn = Result.OK;
            switch (Prm.Type)
            {
                case AxisType.Common:
                    int enc, ele;
                    Card.Executer.GetGear(Prm.Code, out enc, out ele, Card.Key);
                    rtn = Card.GoHome
                      (Prm.Code, Prm.HomeMode, Prm.HomeVel * enc / ele * Prm.PulseEquiv, Prm.HomeAcc * enc / ele * Prm.PulseEquiv,
                      (int)(Prm.HomeOffset * enc / ele * Prm.PulseEquiv), Prm.HomeLowVel * enc / ele * Prm.PulseEquiv);
                    break;
                case AxisType.Master:
                case AxisType.Reverse:
                    rtn = ReverseAxis.GoHome();
                    break;
                case AxisType.Cylinder_TwoPos:
                    //rtn = ioAxisHome();
                    break;
            }
            if (rtn.IsOk)
            {
                isHomed = true;
            }
            else
            {
                DebugMsg.SendMsg($"{Prm.Key}回原點失敗, {rtn.ErrCode} + {rtn.ErrMsg}");
            }
            return rtn;
        }
        /// <summary>
        /// 回原點並阻塞,清零
        /// </summary>
        /// <returns></returns>
        public Result GoHomeAndReply(bool isHomeOffset = false)
        {
            switch (Prm.Type)
            {
                case AxisType.Common:
                case AxisType.Master:
                    var rtn = GoHome();
                    if (!rtn.IsOk)
                    {
                        return rtn;
                    }
                    Thread.Sleep(50);
                    WaitAxisHomeEndAndZero(isHomeOffset);
                    return rtn;
                case AxisType.Reverse:
                    return ReverseAxis.GoHomeAndReply();
                case AxisType.Cylinder_TwoPos:
                    var ta = GoHome();
                    Thread.Sleep(200);
                    return ta;
            }
            isHomed = true;
            //SetPosSoftLimit(1, Prm.SoftPosLimit, Prm.SoftNegLimit);
            return Result.OK;
        }
        /// <summary>
        /// 等待軸回原點結束並清零
        /// </summary>
        /// <param name="axis"></param>
        /// <param name="delay">最大等待回原點時間ms</param>
        /// <returns></returns>
        public void WaitAxisHomeEndAndZero(bool isHomeOffset = false)
        {
            WaitAxisHomeEnd();
            var rtn = Card.Executer.ZeroPos(Prm.Code, Card.Key);
            rtn += Card.Executer.ZeroBoardPos(Prm.Code, Card.Key);
            rtn += Card.Executer.SetBoardMode(Prm.Code, 0); //默認正向
            if (Prm.IsSoftLimit)
            {
                rtn += SetSoftLimitOn();
            }
            else
            {
                rtn += SetSoftLimitOff();
            }
            isHomed = true;
            return;
        }
        /// <summary>
        /// 等待軸回原點結束
        /// </summary>
        public void WaitAxisHomeEnd()
        {
            WaitAxisHomeEnd(Prm.Code);
        }
        private void WaitAxisHomeEnd(short axisCode)
        {
            bool isMove;
            //正在回原點中
            while (Card.Executer.GetIsHoming(axisCode, Card.Key))
            {
                //如果已經停止回原點
                Card.Executer.GetIsMove(axisCode, out isMove, Card.Key);
                if (isMove)
                {
                    return;
                }
                Thread.Sleep(10);
            }
            //等待停穩
            Thread.Sleep(300);
            isHomed = true;
        }
        /// <summary>
        /// 移動到某座標並阻塞,默認爲絕對座標
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        public Result MovAndReply(double pos, bool isAbs = true, double percent = 100)
        {
            Mov(pos, isAbs, percent);
            var rtn = WaitUnMove();
            if (rtn.IsOk)
            {
                Thread.Sleep(10);
                return WaitArrived();
            }
            return rtn;
        }
        public Result MovByJogVelAndReply(double pos, bool isAbs = true)
        {
            //switch (Prm.Type)
            //{
            //    case AxisType.Reverse:
            //        return ReverseAxis.MovByJogVelAndReply((-1) * pos, isAbs);
            //    case AxisType.Cylinder_TwoPos:
            //        return ioAxisMovAndReply(pos, isAbs);
            //}
            MovByJogVel(pos, isAbs);
            WaitUnMove();
            Thread.Sleep(10);
            return WaitArrived();
        }
        public Result Mov(double pos, bool isAbs = true, double percent = 100)
        {     //if (IsTrigSoftLimit(pos))
            //{
            //    return new Result(false, null, $"{Prm.Code}Axis has trigger the SoftLimit");
            //}
            if (percent > 120)
            {
                percent = 100;
            }
            double scale = percent / 100.0;
            Result rtn;
            if (isAbs)
            {
                rtn = Card.Executer.AbsMov(Prm.Code, pos, Prm.DefAcc * scale, Prm.DefDec * scale, Prm.DefVel * scale,
                    Prm.DefStartVel * scale, Prm.SmoothTime, Card.Key);
            }
            else
            {
                rtn = Card.Executer.RelMov(Prm.Code, pos, Prm.DefAcc * scale, Prm.DefDec * scale, Prm.DefVel * scale,
                    Prm.DefStartVel * scale, Prm.SmoothTime, Card.Key);
            }
            return rtn;
        }
        public Result MovByJogVel(double pos, bool isAbs = true)
        {
            Result rtn;
            if (isAbs)
            {
                rtn = Card.Executer.AbsMov(Prm.Code, pos, Prm.DefJogAcc, Prm.DefJogDec, Prm.DefJogVel,
                    Prm.DefJogStartVel, Prm.SmoothTime, Card.Key);
            }
            else
            {
                rtn = Card.Executer.RelMov(Prm.Code, pos, Prm.DefJogAcc, Prm.DefJogDec, Prm.DefJogVel,
                    Prm.DefJogStartVel, Prm.SmoothTime, Card.Key);
            }
            return rtn;
        }
        /// <summary>
        /// 等待軸運動到位
        /// </summary>
        /// <returns></returns>
        public Result WaitArrived()
        {
            if (Prm.Type == AxisType.Cylinder_TwoPos || Prm.Type == AxisType.Reverse)
            {
                return Result.OK;
            }
            Result rtn = Result.FAILED;
            bool isArrive = false;
            while (!isArrive)
            {
                rtn = Card.Executer.GetIsArrive(Prm.Code, out isArrive, Card.Key);
                if (!rtn.IsOk)
                {
                    return rtn;
                }
                Thread.Sleep(2);
            }
            return rtn;
        }
        /// <summary>
        /// 等待軸停止運動
        /// </summary>
        /// <returns></returns>
        public Result WaitUnMove()
        {
            switch (Prm.Type)
            {
                case AxisType.Common:
                case AxisType.Master:
                    Result rtn = Result.FAILED;
                    bool isMove = true;
                    while (isMove)
                    {
                        rtn = Card.Executer.GetIsMove(Prm.Code, out isMove, Card.Key);
                        if (!rtn.IsOk)
                        {
                            return rtn;
                        }
                        Thread.Sleep(2);
                    }
                    return rtn;
                case AxisType.Reverse:
                    return ReverseAxis.WaitUnMove();
            }
            return Result.OK;
        }
        public Result IsMove(out bool isMove)
        {
            return Card.Executer.GetIsMove(Prm.Code, out isMove, Card.Key);
        }
        /// <summary>
        /// Jog移動,速度爲正則爲正方向,負則爲負方向
        /// </summary>
        /// <param name="vel"></param>
        /// <returns></returns>
        public Result JogMove(double vel)
        {
            if (vel > -0.0001 && vel < 0.0001)
            {
                return Result.OK;
            }
 
            bool isPos;
            if (vel > 0)
            {
                isPos = true;
            }
            else
            {
                isPos = false;
            }
            return Card.Executer.JogMov(Prm.Code, isPos, Prm.DefJogAcc,
                Prm.DefJogDec, Math.Abs(vel), Prm.DefJogStartVel, Prm.SmoothTime, Card.Key);       
        }
        /// <summary>
        /// 以默認速度Jog移動,isPos = true 時正向運動
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public Result JogMove(bool isPos, double percent = 1)
        {       
            return Card.Executer.JogMov(Prm.Code, isPos, Prm.DefJogAcc,
                Prm.DefJogDec, Prm.DefJogVel * percent, Prm.DefJogStartVel, Prm.SmoothTime, Card.Key);

        }
        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="isAbout">是否急停</param>
        /// <returns></returns>
        public Result Stop(bool isAbout = false)
        {
            if (Prm.Type == AxisType.Cylinder_TwoPos)
            {
                return Result.OK;
            }
            else if (Prm.Type == AxisType.Reverse)
            {
                return ReverseAxis.Stop(isAbout);
            }
            return Card.StopAxis(Prm.Code, isAbout);
        }
        public Result StopGoHome()
        {
            if (Prm.Type == AxisType.Cylinder_TwoPos)
            {
                return Result.OK;
            }
            else if (Prm.Type == AxisType.Reverse)
            {
                return ReverseAxis.StopGoHome();
            }
            return Card.StopGoHome(Prm.Code);
        }
        /// <summary>
        /// 是否觸發軟限位
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        public bool IsTrigSoftLimit(double pos)
        {
            if (pos < Prm.SoftNegLimit || pos > Prm.SoftPosLimit)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    /// <summary>
    /// 軸的類型
    /// </summary>
    public enum AxisType
    {
        /// <summary>
        /// 普通軸
        /// </summary>
        Common,
        /// <summary>
        /// IO控制的兩位置氣缸軸
        /// </summary>
        Cylinder_TwoPos,
        /// <summary>
        /// 與某軸運動方向相反的反向軸
        /// </summary>
        Reverse,
        /// <summary>
        /// 龍門主軸
        /// </summary>
        Master,
    }
}
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章