Axis-Control-API.md 41.1 KB

轴控制 API 文档

文档信息

项目 内容
版本 1.1.0
状态 正式版
编写日期 2025-12-18
最后更新 2025-12-18
编写人 MIMO 开发团队

更新日志

版本 日期 更新内容 编写人
1.1.0 2025-12-18 根据实际代码更新接口定义和AxisBean说明 MIMO 开发团队
1.0.0 2025-12-16 初始版本 MIMO 开发团队

1. 概述

本文档详细介绍了 MIMO 系统中轴控制相关的 API 接口,主要包括 IAxisManager 接口和 AxisBean 封装类。这些 API 提供了对运动轴的初始化、控制、状态监控等功能的抽象和实现。

2. 轴管理器接口

2.1 IAxisManager 接口

IAxisManager 是轴控制模块的核心接口,定义了对运动轴进行底层控制的基本操作。

namespace DeviceLibrary
{
    public interface IAxisManager
    {
        /// <summary>
        /// 检查轴是否使能
        /// </summary>
        bool IsServeoOn(string portName, short slvAddr);

        /// <summary>
        /// 打开板卡/控制器
        /// </summary>
        bool OpenCard();

        /// <summary>
        /// 关闭板卡/控制器
        /// </summary>
        bool CloseCard();

        /// <summary>
        /// 检查回零是否完成
        /// </summary>
        bool IsHomeMoveEnd(string portName, short slvAddr);

        /// <summary>
        /// 检查绝对运动是否完成
        /// </summary>
        bool AbsMoveIsEnd(string portName, short axisNo, int targetPosition, int canErrorCount, out bool countError);

        /// <summary>
        /// 伺服开启
        /// </summary>
        void ServoOn(string portName, short slvAddr);

        /// <summary>
        /// 伺服关闭
        /// </summary>
        void ServoOff(string portName, short slvAddr); 

        /// <summary>
        /// 相对运动
        /// </summary>
        void RelMove(string portName, short slvAddr, int position, int targetSpeed, int ptpAcc, int ptpDec); 

        /// <summary>
        /// 回零运动
        /// </summary>
        bool HomeMove(string portName, short slvAddr, int highVel, int lowVel, int acc);

        /// <summary>
        /// 速度模式运动
        /// </summary>
        void SpeedMove(string portName, short slvAddr, int speed, int acc, int dec);

        /// <summary>
        /// 急停
        /// </summary>
        void SuddenStop(string portName, short slvAddr);

        /// <summary>
        /// 判断是否到位
        /// </summary>
        bool isInPosition(string portName, short slvAddr, int PPosition, int canErrorCount, bool isLog = false);

        /// <summary>
        /// 绝对运动
        /// </summary>
        void AbsMove(string portName, short slvAddr, int targetPosition, int targetSpeed, int ptpAcc, int ptpDec);

        /// <summary>
        /// 清除报警
        /// </summary>
        void AlarmClear(string portName, short slvAddr);

        /// <summary>
        /// 获取目标位置
        /// </summary>
        int GetTargetPosition(string portName, short slvAddr);

        /// <summary>
        /// 获取实际位置
        /// </summary>
        int GetActualtPosition(string portName, short slvAddr); 

        /// <summary>
        /// 获取报警状态
        /// </summary>
        int GetAlarmStatus(string portName, short slvAddr);

        /// <summary>
        /// 获取忙状态
        /// </summary>
        int GetBusyStatus(string portName, short slvAddr);

        /// <summary>
        /// 获取回零结束状态
        /// </summary>
        int GetHomeEndStatus(string portName, short slvAddr);

        /// <summary>
        /// 获取原点信号
        /// </summary>
        int GetHomeSingle(string portName, short slvAddr);

        /// <summary>
        /// 获取负极限信号
        /// </summary> 
        int GetLimitNegativeSingle(string portName, short slvAddr);

        /// <summary>
        /// 获取正极限信号
        /// </summary> 
        int GetLimitPositiveSingle(string portName, short slvAddr);

        int AxisStsINP(string portName, short slvAddr);

        short GetErrorCode(string portName, short slvAddr);
    }
}

3. 轴对象封装 (AxisBean)

AxisBean 类是对 IAxisManager 的高级封装,提供了更易用的面向对象接口,包含了轴的配置信息和状态管理。

3.1 核心属性

  • ConfigMoveAxis Config: 轴配置信息对象
  • string AxisName: 轴名称
  • int LastPosition: 上次记录的位置
  • bool IsBusy: 轴是否忙碌
  • bool IsServeoOn: 轴是否使能

3.2 主要方法

public class AxisBean
{
    // 构造函数
    public AxisBean(ConfigMoveAxis axisConfig, string deviceName, int maxSensorValue = 0);

    // 打开轴(使能)
    public bool Open(bool isCheck, out string Msg);

    // 关闭轴(去使能)
    public void ServoOff();

    // 回零运动
    public void HomeMove(MoveInfo MoveInfo, bool force = true);

    // 绝对运动
    public void AbsMove(MoveInfo MoveInfo, int targetPosition, int targetSpeed);

    // 速度运动
    public void SpeedMove(int targetSpeed);

    // 急停
    public void SuddenStop();

    // 检查是否到位
    public bool IsInPosition(int targetP);

    // 获取当前位置
    public int GetAclPosition();
}

3.2 枚举类型

3.2.1 AxisStatus 枚举

表示轴的运行状态。

public enum AxisStatus
{
    /// <summary>
    /// 未知状态
    /// </summary>
    Unknown = 0,

    /// <summary>
    /// 空闲状态
    /// </summary>
    Idle = 1,

    /// <summary>
    /// 运动中
    /// </summary>
    Moving = 2,

    /// <summary>
    /// 回零中
    /// </summary>
    Homing = 3,

    /// <summary>
    /// 已回零
    /// </summary>
    Homed = 4,

    /// <summary>
    /// 报警状态
    /// </summary>
    Alarm = 5,

    /// <summary>
    /// 错误状态
    /// </summary>
    Error = 6,

    /// <summary>
    /// 限位状态
    /// </summary>
    InLimit = 7
}

3.2.2 HomeMode 枚举

表示回零模式。

public enum HomeMode
{
    /// <summary>
    /// 主动回零(向限位方向运动找原点)
    /// </summary>
    ActiveHome = 0,

    /// <summary>
    /// 被动回零(等待外部触发回零信号)
    /// </summary>
    PassiveHome = 1,

    /// <summary>
    /// 感应回零(通过原点传感器信号回零)
    /// </summary>
    SensorHome = 2
}

4. 具体实现类

4.1 AxisManager 类

AxisManagerIAxisManager 接口的具体实现类,负责实际的轴控制操作。

public class AxisManager : IAxisManager
{
    #region 成员变量

    private bool _isInitialized = false;
    private Dictionary<int, AxisBean> _axisMap = new Dictionary<int, AxisBean>();
    private Dictionary<int, Action<int, AxisStatus>> _statusChangeHandlers = new Dictionary<int, Action<int, AxisStatus>>();
    private Dictionary<int, Action<int>> _positionReachedHandlers = new Dictionary<int, Action<int>>();
    private object _lockObj = new object();

    #endregion

    #region 构造函数

    /// <summary>
    /// 默认构造函数
    /// </summary>
    public AxisManager()
    {
        // 初始化默认配置
        InitializeDefaultConfig();
    }

    /// <summary>
    /// 使用配置文件路径构造
    /// </summary>
    /// <param name="configPath">配置文件路径</param>
    public AxisManager(string configPath)
    {
        if (string.IsNullOrEmpty(configPath))
        {
            throw new ArgumentNullException(nameof(configPath));
        }
        Initialize(configPath);
    }

    #endregion

    #region IAxisManager 接口实现

    /// <summary>
    /// 初始化轴管理器
    /// </summary>
    /// <returns>初始化是否成功</returns>
    public bool Initialize()
    {
        return Initialize("DefaultAxisConfig.xml");
    }

    /// <summary>
    /// 使用指定配置初始化轴管理器
    /// </summary>
    /// <param name="configPath">配置文件路径</param>
    /// <returns>初始化是否成功</returns>
    public bool Initialize(string configPath)
    {
        lock (_lockObj)
        {
            if (_isInitialized)
            {
                return true;
            }

            try
            {
                // 加载配置文件
                var config = LoadConfig(configPath);

                // 初始化轴映射
                InitializeAxisMap(config);

                // 初始化硬件连接
                InitializeHardware();

                _isInitialized = true;
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"初始化轴管理器失败: {ex.Message}");
                return false;
            }
        }
    }

    /// <summary>
    /// 关闭轴管理器,释放资源
    /// </summary>
    public void Close()
    {
        lock (_lockObj)
        {
            if (!_isInitialized)
            {
                return;
            }

            try
            {
                // 停止所有轴运动
                StopAllAxes();

                // 释放硬件资源
                ReleaseHardware();

                // 清空事件处理器
                _statusChangeHandlers.Clear();
                _positionReachedHandlers.Clear();

                // 清空轴映射
                _axisMap.Clear();

                _isInitialized = false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"关闭轴管理器失败: {ex.Message}");
            }
        }
    }

    /// <summary>
    /// 获取所有轴的信息
    /// </summary>
    /// <returns>轴信息列表</returns>
    public List<AxisBean> GetAllAxes()
    {
        lock (_lockObj)
        {
            if (!_isInitialized)
            {
                throw new AxisInitializationException("轴管理器尚未初始化");
            }

            return _axisMap.Values.ToList();
        }
    }

    /// <summary>
    /// 根据轴ID获取轴信息
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <returns>轴信息对象,如果未找到返回null</returns>
    public AxisBean GetAxisById(int axisId)
    {
        lock (_lockObj)
        {
            if (!_isInitialized)
            {
                throw new AxisInitializationException("轴管理器尚未初始化");
            }

            _axisMap.TryGetValue(axisId, out var axis);
            return axis;
        }
    }

    /// <summary>
    /// 获取轴的当前状态
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <returns>轴状态枚举值</returns>
    public AxisStatus GetAxisStatus(int axisId)
    {
        var axis = GetAxisById(axisId);
        if (axis == null)
        {
            throw new AxisOperationException($"未找到ID为{axisId}的轴");
        }

        // 实时更新轴状态
        UpdateAxisStatus(axis);
        return axis.Status;
    }

    /// <summary>
    /// 获取轴的当前位置
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <returns>轴的当前位置值</returns>
    public double GetAxisCurrentPosition(int axisId)
    {
        var axis = GetAxisById(axisId);
        if (axis == null)
        {
            throw new AxisOperationException($"未找到ID为{axisId}的轴");
        }

        // 实时更新轴位置
        UpdateAxisPosition(axis);
        return axis.CurrentPosition;
    }

    /// <summary>
    /// 获取轴的当前速度
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <returns>轴的当前速度值</returns>
    public double GetAxisCurrentSpeed(int axisId)
    {
        var axis = GetAxisById(axisId);
        if (axis == null)
        {
            throw new AxisOperationException($"未找到ID为{axisId}的轴");
        }

        // 实时更新轴速度
        UpdateAxisSpeed(axis);
        return axis.CurrentSpeed;
    }

    /// <summary>
    /// 控制轴点动
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="speed">点动速度</param>
    /// <param name="isPositive">是否正方向</param>
    /// <returns>操作是否成功</returns>
    public bool MoveAxisJog(int axisId, double speed, bool isPositive)
    {
        var axis = GetAxisById(axisId);
        if (axis == null)
        {
            throw new AxisOperationException($"未找到ID为{axisId}的轴");
        }

        if (speed <= 0)
        {
            throw new ArgumentException("速度必须大于0", nameof(speed));
        }

        lock (_lockObj)
        {
            try
            {
                // 发送点动命令到硬件
                SendJogCommandToHardware(axis, speed, isPositive);

                // 更新轴状态
                axis.Status = AxisStatus.Moving;
                OnAxisStatusChanged(axisId, axis.Status);

                return true;
            }
            catch (Exception ex)
            {
                throw new AxisOperationException($"轴{axisId}点动失败: {ex.Message}", ex);
            }
        }
    }

    // 其他IAxisManager接口方法的实现...
    // 由于篇幅限制,此处省略部分实现代码
    // 完整实现请参考源代码

    /// <summary>
    /// 多轴同步运动(绝对位置)
    /// </summary>
    /// <param name="targetPositions">各轴目标位置映射表,key为轴ID,value为目标位置</param>
    /// <param name="speed">运动速度</param>
    /// <returns>操作是否成功</returns>
    public bool MoveMultipleAxesSynchronously(Dictionary<int, double> targetPositions, double speed)
    {
        return MoveMultipleAxesSynchronously(targetPositions, speed, 0, 0);
    }

    /// <summary>
    /// 多轴同步运动(绝对位置,带加速度和减速度)
    /// </summary>
    /// <param name="targetPositions">各轴目标位置映射表,key为轴ID,value为目标位置</param>
    /// <param name="speed">运动速度</param>
    /// <param name="acceleration">加速度</param>
    /// <param name="deceleration">减速度</param>
    /// <returns>操作是否成功</returns>
    public bool MoveMultipleAxesSynchronously(Dictionary<int, double> targetPositions, double speed, double acceleration, double deceleration)
    {
        if (targetPositions == null || targetPositions.Count == 0)
        {
            throw new ArgumentException("目标位置映射表不能为空", nameof(targetPositions));
        }

        if (speed <= 0)
        {
            throw new ArgumentException("速度必须大于0", nameof(speed));
        }

        lock (_lockObj)
        {
            try
            {
                // 验证所有轴是否存在
                foreach (int axisId in targetPositions.Keys)
                {
                    if (!_axisMap.ContainsKey(axisId))
                    {
                        throw new AxisOperationException(axisId, "MoveMultiple", $"未找到ID为{axisId}的轴");
                    }
                }

                // 计算各轴运动参数
                Dictionary<int, MotionParams> motionParams = CalculateMotionParams(targetPositions, speed, acceleration, deceleration);

                // 发送同步运动命令到硬件
                SendSyncMotionCommandToHardware(motionParams);

                // 更新各轴状态
                foreach (int axisId in targetPositions.Keys)
                {
                    _axisMap[axisId].Status = AxisStatus.Moving;
                    _axisMap[axisId].TargetPosition = targetPositions[axisId];
                    OnAxisStatusChanged(axisId, AxisStatus.Moving);
                }

                return true;
            }
            catch (Exception ex)
            {
                throw new AxisOperationException(0, "MoveMultiple", $"多轴同步运动失败: {ex.Message}", ex);
            }
        }
    }

    /// <summary>
    /// 多轴同步相对运动
    /// </summary>
    /// <param name="relativeDistances">各轴相对运动距离映射表,key为轴ID,value为相对距离</param>
    /// <param name="speed">运动速度</param>
    /// <returns>操作是否成功</returns>
    public bool MoveMultipleAxesSynchronouslyRelative(Dictionary<int, double> relativeDistances, double speed)
    {
        if (relativeDistances == null || relativeDistances.Count == 0)
        {
            throw new ArgumentException("相对距离映射表不能为空", nameof(relativeDistances));
        }

        // 计算绝对目标位置
        Dictionary<int, double> targetPositions = new Dictionary<int, double>();
        foreach (var kvp in relativeDistances)
        {
            int axisId = kvp.Key;
            double distance = kvp.Value;

            if (!_axisMap.ContainsKey(axisId))
            {
                throw new AxisOperationException(axisId, "MoveMultipleRelative", $"未找到ID为{axisId}的轴");
            }

            double currentPos = _axisMap[axisId].CurrentPosition;
            targetPositions[axisId] = currentPos + distance;
        }

        // 调用绝对运动方法
        return MoveMultipleAxesSynchronously(targetPositions, speed);
    }

    /// <summary>
    /// 等待所有指定轴运动完成
    /// </summary>
    /// <param name="axisIds">轴ID列表,若为null或空则等待所有轴</param>
    /// <param name="timeout">超时时间(毫秒),0表示无限等待</param>
    /// <returns>是否在超时前完成运动</returns>
    public bool WaitForMotionCompletion(List<int> axisIds = null, int timeout = 0)
    {
        if (!_isInitialized)
        {
            throw new AxisInitializationException("轴管理器尚未初始化");
        }

        List<int> axesToWait = axisIds;
        if (axesToWait == null || axesToWait.Count == 0)
        {
            axesToWait = _axisMap.Keys.ToList();
        }

        long startTime = DateTime.Now.Ticks;
        long timeoutTicks = timeout * 10000; // 转换为 ticks

        while (true)
        {
            bool allCompleted = true;

            // 检查所有指定轴的状态
            foreach (int axisId in axesToWait)
            {
                if (!_axisMap.ContainsKey(axisId))
                {
                    continue;
                }

                // 实时更新轴状态
                UpdateAxisStatus(_axisMap[axisId]);

                // 检查轴是否不在运动状态
                if (_axisMap[axisId].Status == AxisStatus.Moving || _axisMap[axisId].Status == AxisStatus.Homing)
                {
                    allCompleted = false;
                    break;
                }
            }

            if (allCompleted)
            {
                return true;
            }

            // 检查是否超时
            if (timeout > 0)
            {
                long elapsedTicks = DateTime.Now.Ticks - startTime;
                if (elapsedTicks > timeoutTicks)
                {
                    throw new AxisTimeoutException(0, timeout, "多轴运动等待超时");
                }
            }

            // 短暂休眠,避免CPU占用过高
            Thread.Sleep(50);
        }
    }

    #endregion

    #region 内部辅助方法

    /// <summary>
    /// 运动参数类
    /// </summary>
    private class MotionParams
    {
        /// <summary>
        /// 轴ID
        /// </summary>
        public int AxisId { get; set; }

        /// <summary>
        /// 目标位置
        /// </summary>
        public double TargetPosition { get; set; }

        /// <summary>
        /// 运动速度
        /// </summary>
        public double Speed { get; set; }

        /// <summary>
        /// 加速度
        /// </summary>
        public double Acceleration { get; set; }

        /// <summary>
        /// 减速度
        /// </summary>
        public double Deceleration { get; set; }

        /// <summary>
        /// 运动距离
        /// </summary>
        public double Distance { get; set; }

        /// <summary>
        /// 运动时间
        /// </summary>
        public double MotionTime { get; set; }
    }

    /// <summary>
    /// 初始化默认配置
    /// </summary>
    private void InitializeDefaultConfig()
    {
        // 初始化默认轴配置
        // ...
    }

    /// <summary>
    /// 加载配置文件
    /// </summary>
    /// <param name="configPath">配置文件路径</param>
    /// <returns>配置对象</returns>
    private AxisConfig LoadConfig(string configPath)
    {
        // 加载并解析配置文件
        // ...
        return new AxisConfig();
    }

    /// <summary>
    /// 初始化轴映射
    /// </summary>
    /// <param name="config">轴配置对象</param>
    private void InitializeAxisMap(AxisConfig config)
    {
        // 根据配置初始化轴映射
        // ...
    }

    /// <summary>
    /// 初始化硬件连接
    /// </summary>
    private void InitializeHardware()
    {
        // 初始化硬件驱动和连接
        // ...
    }

    /// <summary>
    /// 释放硬件资源
    /// </summary>
    private void ReleaseHardware()
    {
        // 释放硬件驱动和连接
        // ...
    }

    /// <summary>
    /// 实时更新轴状态
    /// </summary>
    /// <param name="axis">轴对象</param>
    private void UpdateAxisStatus(AxisBean axis)
    {
        // 从硬件获取最新状态并更新
        // ...
    }

    /// <summary>
    /// 实时更新轴位置
    /// </summary>
    /// <param name="axis">轴对象</param>
    private void UpdateAxisPosition(AxisBean axis)
    {
        // 从硬件获取最新位置并更新
        // ...
    }

    /// <summary>
    /// 实时更新轴速度
    /// </summary>
    /// <param name="axis">轴对象</param>
    private void UpdateAxisSpeed(AxisBean axis)
    {
        // 从硬件获取最新速度并更新
        // ...
    }

    /// <summary>
    /// 发送点动命令到硬件
    /// </summary>
    /// <param name="axis">轴对象</param>
    /// <param name="speed">点动速度</param>
    /// <param name="isPositive">是否正方向</param>
    private void SendJogCommandToHardware(AxisBean axis, double speed, bool isPositive)
    {
        // 实际的硬件通信代码
        // ...
    }

    /// <summary>
    /// 计算运动参数
    /// </summary>
    /// <param name="targetPositions">目标位置映射表</param>
    /// <param name="speed">运动速度</param>
    /// <param name="acceleration">加速度</param>
    /// <param name="deceleration">减速度</param>
    /// <returns>运动参数映射表</returns>
    private Dictionary<int, MotionParams> CalculateMotionParams(Dictionary<int, double> targetPositions, double speed, double acceleration, double deceleration)
    {
        Dictionary<int, MotionParams> motionParamsMap = new Dictionary<int, MotionParams>();
        double maxMotionTime = 0;

        // 第一遍计算:计算各轴运动距离和所需时间
        foreach (int axisId in targetPositions.Keys)
        {
            AxisBean axis = _axisMap[axisId];
            double currentPos = axis.CurrentPosition;
            double targetPos = targetPositions[axisId];
            double distance = Math.Abs(targetPos - currentPos);

            // 使用默认加速度和减速度(如果未指定)
            double axisAcc = acceleration > 0 ? acceleration : axis.Acceleration;
            double axisDec = deceleration > 0 ? deceleration : axis.Deceleration;

            // 计算运动时间
            double motionTime = CalculateMotionTime(distance, speed, axisAcc, axisDec);

            MotionParams params = new MotionParams
            {
                AxisId = axisId,
                TargetPosition = targetPos,
                Speed = speed,
                Acceleration = axisAcc,
                Deceleration = axisDec,
                Distance = distance,
                MotionTime = motionTime
            };

            motionParamsMap.Add(axisId, @params);

            // 更新最大运动时间
            if (motionTime > maxMotionTime)
            {
                maxMotionTime = motionTime;
            }
        }

        // 第二遍计算:调整各轴速度,确保同步完成
        foreach (var kvp in motionParamsMap)
        {
            MotionParams @params = kvp.Value;

            // 如果轴的运动时间小于最大时间,调整其速度以匹配最大时间
            if (@params.MotionTime < maxMotionTime && @params.MotionTime > 0)
            {
                double speedRatio = @params.MotionTime / maxMotionTime;
                @params.Speed = speed * speedRatio;

                // 重新计算加速度和减速度,保持比例
                @params.Acceleration *= speedRatio;
                @params.Deceleration *= speedRatio;

                // 更新运动时间
                @params.MotionTime = maxMotionTime;
            }
        }

        return motionParamsMap;
    }

    /// <summary>
    /// 计算运动时间
    /// </summary>
    /// <param name="distance">运动距离</param>
    /// <param name="speed">运动速度</param>
    /// <param name="acceleration">加速度</param>
    /// <param name="deceleration">减速度</param>
    /// <returns>运动时间(秒)</returns>
    private double CalculateMotionTime(double distance, double speed, double acceleration, double deceleration)
    {
        // 计算运动时间的公式
        // ...
        return distance / speed;
    }

    /// <summary>
    /// 发送同步运动命令到硬件
    /// </summary>
    /// <param name="motionParams">运动参数映射表</param>
    private void SendSyncMotionCommandToHardware(Dictionary<int, MotionParams> motionParams)
    {
        // 发送同步运动命令到硬件
        // ...
    }

    /// <summary>
    /// 触发轴状态变化事件
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="status">新状态</param>
    private void OnAxisStatusChanged(int axisId, AxisStatus status)
    {
        // 触发状态变化事件
        // ...
    }

    /// <summary>
    /// 触发轴位置到达事件
    /// </summary>
    /// <param name="axisId">轴ID</param>
    private void OnAxisPositionReached(int axisId)
    {
        // 触发位置到达事件
        // ...
    }

    #endregion
}

4.2 AxisConfig 类

AxisConfig 类用于存储轴管理器的配置信息。

public class AxisConfig
{
    /// <summary>
    /// 轴配置列表
    /// </summary>
    public List<SingleAxisConfig> AxesConfig { get; set; }

    /// <summary>
    /// 通信超时时间(毫秒)
    /// </summary>
    public int CommunicationTimeout { get; set; } = 5000;

    /// <summary>
    /// 状态更新间隔(毫秒)
    /// </summary>
    public int StatusUpdateInterval { get; set; } = 100;

    /// <summary>
    /// 是否启用日志
    /// </summary>
    public bool EnableLogging { get; set; } = true;
}

/// <summary>
/// 单轴配置类
/// </summary>
public class SingleAxisConfig
{
    /// <summary>
    /// 轴ID
    /// </summary>
    public int AxisId { get; set; }

    /// <summary>
    /// 轴名称
    /// </summary>
    public string AxisName { get; set; }

    /// <summary>
    /// 最大速度
    /// </summary>
    public double MaxSpeed { get; set; }

    /// <summary>
    /// 加速度
    /// </summary>
    public double Acceleration { get; set; }

    /// <summary>
    /// 减速度
    /// </summary>
    public double Deceleration { get; set; }

    /// <summary>
    /// 回零模式
    /// </summary>
    public HomeMode HomeMode { get; set; }

    /// <summary>
    /// 回零速度
    /// </summary>
    public double HomeSpeed { get; set; }
}

5. 异常处理

轴控制模块定义了特定的异常类型,用于表示不同类型的轴操作异常。所有轴相关异常都继承自 DeviceException 基类,提供统一的异常处理机制。

5.1 异常类层次结构

DeviceException
└── AxisException
    ├── AxisInitializationException
    ├── AxisCommunicationException
    ├── AxisOperationException
    ├── AxisTimeoutException
    ├── AxisLimitException
    └── AxisAlarmException

5.2 异常类具体定义

/// <summary>
/// 轴异常基类
/// </summary>
public class AxisException : DeviceException
{
    /// <summary>
    /// 轴ID
    /// </summary>
    public int? AxisId { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="message">异常消息</param>
    public AxisException(string message) : base(message)
    {}

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="message">异常消息</param>
    /// <param name="innerException">内部异常</param>
    public AxisException(string message, Exception innerException) : base(message, innerException)
    {}

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="message">异常消息</param>
    public AxisException(int axisId, string message) : base(message)
    {
        AxisId = axisId;
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="message">异常消息</param>
    /// <param name="innerException">内部异常</param>
    public AxisException(int axisId, string message, Exception innerException) : base(message, innerException)
    {
        AxisId = axisId;
    }
}

/// <summary>
/// 轴初始化异常
/// </summary>
public class AxisInitializationException : AxisException
{
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="message">异常消息</param>
    public AxisInitializationException(string message) : base(message) {}

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="message">异常消息</param>
    /// <param name="innerException">内部异常</param>
    public AxisInitializationException(string message, Exception innerException) : base(message, innerException) {}
}

/// <summary>
/// 轴通信异常
/// </summary>
public class AxisCommunicationException : AxisException
{
    /// <summary>
    /// 通信端口
    /// </summary>
    public string Port { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="port">通信端口</param>
    /// <param name="message">异常消息</param>
    public AxisCommunicationException(int axisId, string port, string message) : base(axisId, message)
    {
        Port = port;
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="port">通信端口</param>
    /// <param name="message">异常消息</param>
    /// <param name="innerException">内部异常</param>
    public AxisCommunicationException(int axisId, string port, string message, Exception innerException) 
        : base(axisId, message, innerException)
    {
        Port = port;
    }
}

/// <summary>
/// 轴操作异常
/// </summary>
public class AxisOperationException : AxisException
{
    /// <summary>
    /// 操作类型
    /// </summary>
    public string OperationType { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="operationType">操作类型</param>
    /// <param name="message">异常消息</param>
    public AxisOperationException(int axisId, string operationType, string message) : base(axisId, message)
    {
        OperationType = operationType;
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="operationType">操作类型</param>
    /// <param name="message">异常消息</param>
    /// <param name="innerException">内部异常</param>
    public AxisOperationException(int axisId, string operationType, string message, Exception innerException) 
        : base(axisId, message, innerException)
    {
        OperationType = operationType;
    }
}

/// <summary>
/// 轴操作超时异常
/// </summary>
public class AxisTimeoutException : AxisException
{
    /// <summary>
    /// 超时时间(毫秒)
    /// </summary>
    public int Timeout { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="timeout">超时时间(毫秒)</param>
    /// <param name="message">异常消息</param>
    public AxisTimeoutException(int axisId, int timeout, string message) : base(axisId, message)
    {
        Timeout = timeout;
    }
}

/// <summary>
/// 轴限位异常
/// </summary>
public class AxisLimitException : AxisException
{
    /// <summary>
    /// 是否为正向限位
    /// </summary>
    public bool IsPositiveLimit { get; private set; }

    /// <summary>
    /// 当前位置
    /// </summary>
    public double CurrentPosition { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="isPositiveLimit">是否为正向限位</param>
    /// <param name="currentPosition">当前位置</param>
    /// <param name="message">异常消息</param>
    public AxisLimitException(int axisId, bool isPositiveLimit, double currentPosition, string message) 
        : base(axisId, message)
    {
        IsPositiveLimit = isPositiveLimit;
        CurrentPosition = currentPosition;
    }
}

/// <summary>
/// 轴报警异常
/// </summary>
public class AxisAlarmException : AxisException
{
    /// <summary>
    /// 报警代码
    /// </summary>
    public int AlarmCode { get; private set; }

    /// <summary>
    /// 报警描述
    /// </summary>
    public string AlarmDescription { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="axisId">轴ID</param>
    /// <param name="alarmCode">报警代码</param>
    /// <param name="alarmDescription">报警描述</param>
    /// <param name="message">异常消息</param>
    public AxisAlarmException(int axisId, int alarmCode, string alarmDescription, string message) 
        : base(axisId, message)
    {
        AlarmCode = alarmCode;
        AlarmDescription = alarmDescription;
    }
}

5.3 异常使用示例

// 异常捕获和处理示例
IAxisManager axisManager = new AxisManager();
try
{
    // 初始化轴管理器
    if (!axisManager.Initialize())
    {
        throw new AxisInitializationException("轴管理器初始化失败");
    }

    // 回零操作
    if (!axisManager.HomeAxis(1))
    {
        throw new AxisOperationException(1, "Home", "轴1回零失败");
    }

    // 绝对运动
    if (!axisManager.MoveAxisAbsolute(1, 100.0, 10.0))
    {
        throw new AxisOperationException(1, "MoveAbsolute", "轴1绝对运动失败");
    }

    // 等待运动完成
    Thread.Sleep(2000);

    // 获取当前位置
    double currentPosition = axisManager.GetAxisCurrentPosition(1);
    Console.WriteLine($"轴1当前位置: {currentPosition}");
}
catch (AxisTimeoutException ex)
{
    Console.WriteLine($"轴{ex.AxisId}操作超时: {ex.Message}, 超时时间: {ex.Timeout}ms");
    // 处理超时异常,例如重试操作
}
catch (AxisLimitException ex)
{
    Console.WriteLine($"轴{ex.AxisId}限位异常: {ex.Message}, 方向: {(ex.IsPositiveLimit ? "正向" : "负向")}, 当前位置: {ex.CurrentPosition}");
    // 处理限位异常,例如反向运动解除限位
}
catch (AxisAlarmException ex)
{
    Console.WriteLine($"轴{ex.AxisId}报警: {ex.Message}, 报警代码: {ex.AlarmCode}, 报警描述: {ex.AlarmDescription}");
    // 处理报警异常,例如重置报警
}
catch (AxisException ex)
{
    Console.WriteLine($"轴{ex.AxisId}异常: {ex.Message}");
    // 处理其他轴异常
}
catch (Exception ex)
{
    Console.WriteLine($"未知异常: {ex.Message}");
    // 处理其他非轴异常
}
finally
{
    // 关闭轴管理器,释放资源
    axisManager?.Close();
}

5.4 异常处理最佳实践

  1. 分层捕获:根据异常类型进行分层捕获,优先处理特定类型的异常,再处理通用异常。

  2. 详细日志:在捕获异常时,记录详细的异常信息,包括轴ID、操作类型、错误代码等,便于问题定位。

  3. 合理重试:对于通信异常或超时异常,可以考虑进行合理的重试机制,但需设置最大重试次数,避免无限重试。

  4. 安全停止:在捕获到严重异常时,应确保所有轴停止运动,避免发生安全事故。

  5. 用户友好:将技术异常转换为用户友好的错误信息,避免直接向用户展示底层技术细节。

  6. 资源清理:在 finally 块中确保释放所有资源,包括轴管理器、硬件连接等。

6. 使用示例

6.1 基本用法

// 创建并初始化轴管理器
IAxisManager axisManager = new AxisManager();
if (axisManager.Initialize())
{
    try
    {
        // 获取轴1的信息
        AxisBean axis1 = axisManager.GetAxisById(1);
        Console.WriteLine($"Axis 1 current position: {axis1.CurrentPosition}");

        // 检查轴是否已回零
        if (!axis1.IsHomed)
        {
            Console.WriteLine("Axis 1 is not homed. Homing now...");
            axisManager.HomeAxis(1);
            Console.WriteLine("Homing completed.");
        }

        // 控制轴1以10mm/s的速度移动到100mm位置
        Console.WriteLine("Moving axis 1 to position 100mm...");
        if (axisManager.MoveAxisAbsolute(1, 100.0, 10.0))
        {
            Console.WriteLine("Move command sent successfully.");
        }
    }
    catch (AxisException ex)
    {
        Console.WriteLine($"Axis error: {ex.Message}");
    }
    finally
    {
        // 关闭轴管理器
        axisManager.Close();
    }
}
else
{
    Console.WriteLine("Failed to initialize axis manager.");
}

6.2 事件处理

// 创建并初始化轴管理器
IAxisManager axisManager = new AxisManager();
if (axisManager.Initialize())
{
    // 注册轴状态变化事件处理函数
    axisManager.RegisterAxisStatusChangeHandler((axisId, status) => {
        Console.WriteLine($"Axis {axisId} status changed to: {status}");
    });

    // 注册轴位置到达事件处理函数
    axisManager.RegisterAxisPositionReachedHandler(axisId => {
        Console.WriteLine($"Axis {axisId} has reached target position.");
    });

    // 执行轴运动操作
    // ...
}

6.3 多轴同步运动

// 创建并初始化轴管理器
IAxisManager axisManager = new AxisManager();
if (axisManager.Initialize())
{
    try
    {
        // 假设我们有一个多轴同步运动的扩展方法
        // 控制轴1和轴2同时运动到指定位置
        Dictionary<int, double> targetPositions = new Dictionary<int, double>
        {
            { 1, 100.0 },
            { 2, 200.0 }
        };

        double speed = 10.0;

        // 执行多轴同步运动(这是一个扩展的高级功能)
        // axisManager.MoveMultipleAxesSynchronously(targetPositions, speed);

        Console.WriteLine("Multi-axis synchronous movement completed.");
    }
    catch (AxisException ex)
    {
        Console.WriteLine($"Multi-axis movement error: {ex.Message}");
    }
    finally
    {
        // 关闭轴管理器
        axisManager.Close();
    }
}

7. 最佳实践

  1. 初始化和资源释放:始终确保在使用轴管理器后正确关闭它,以释放资源。

  2. 错误处理:捕获并处理所有可能的轴操作异常,确保系统稳定运行。

  3. 状态检查:在执行关键操作前,始终检查轴的当前状态,确保操作安全。

  4. 回零操作:在执行精确位置控制前,确保轴已经正确回零。

  5. 事件驱动编程:使用事件机制响应轴状态变化,而不是轮询。

  6. 参数验证:在调用API前,验证所有输入参数的有效性。

8. 注意事项

  1. 轴控制操作是实时性要求较高的任务,应避免在主线程中执行耗时操作。

  2. 在多线程环境中使用轴管理器时,需要注意线程安全问题。

  3. 不同的物理轴可能有不同的特性和限制,使用时应参考具体的硬件说明书。

  4. 轴的运动参数(速度、加速度、减速度等)应根据实际设备情况和应用需求合理设置。

  5. 轴操作异常时,应及时停止相关操作,并采取适当的安全措施。