一、运动控制概述
运动控制技术是自动化技术和电气拖动技术的融合,以工控机、PLC、DSP等为控制器的运动控制技术融合了微电子技术、计算机技术、检测技术、自动化技术以及伺服控制技术等学科的新成果,在工业生产中起着极为重要的作用。
早期的运动控制技术主要是伴随着数控技术、机器人技术和工厂自动化技术的发展而发展的。现已广泛应用于国民经济的各个行业,且应用形式多种多样,主要应用领域如下:
1)冶金行业:电弧炉电机控制、轧机轧辊控制、产品定尺控制等。
2)机械行业:机床定位控制、加工轨迹控制、自动化流水线及机械手的控制等。
3)信息行业:磁盘驱动器磁头的定位控制、打印机的控制等。
4)建筑行业:电梯及电梯群的控制等。
5)其他行业:立体仓库和立体车库的控制等。
二、运动控制系统的组成
- 控制器(PLC、运动控制卡、嵌入式系统)
- 驱动器(步进、伺服驱动器)
- 电机(步进电机、伺服电机、直线电机)
- 反馈装置(编码器、光栅尺)
例如:在一个简单移动平台中,有一个Y轴可以进行送料的工作。主要由正运动的控制卡、汇川的驱动器、汇川的电机构成,当然我们一般会有一个主机,通用做法是一个电脑上编写有程序来控制板卡。
电脑上的软件下发去某个位置的指令,其中包含速度、位置等;
由正运动的控制卡负责将指令转换成驱动器命令,下发给伺服驱动器;
伺服驱动器再将命令转换成电机需要的电压和电流,让电机运转,电机末端一般安装有编码器,伺服驱动器会一直采集编码器的脉冲信号来修改电压和电流直到到达目标位置。
三、运动控制算法
- PID控制原理及优化
- 前馈控制与扰动补偿
- 轨迹规划(S曲线、T型速度规划)
- 多轴同步控制
PID控制(比例-积分-微分控制)
-
原理:通过比例项(P)快速响应误差、积分项(I)消除稳态误差、微分项(D)抑制振荡,实现动态平衡。
-
特点:结构简单、调试方便、稳定性高,但对非线性系统适应性弱。
-
应用:工业电机调速、恒温控制、无人机姿态调整等线性系统
四、运动控制通信协议
- 脉冲方向控制
- 总线协议(EtherCAT、CANopen、Modbus)
以下是运动控制通信协议的全面解析,涵盖脉冲方向控制和总线协议(EtherCAT、CANopen、Modbus) 的核心原理、技术特点及应用场景:
(一)、脉冲方向控制(Pulse-Direction Control)
脉冲方向控制是伺服/步进电机最基础的位置控制方式,通过脉冲频率控制速度、脉冲数量控制位移、方向信号电平控制转向。
技术原理
脉冲信号(PULSE):
每个脉冲对应电机固定角位移(步距角)。例如1.8°步进电机需200个脉冲完成一圈旋转。
公式:位移量 = 脉冲数 × 步距角 / 360°
方向信号(DIR):
高电平(+24V)正转,低电平(0V)反转,需在脉冲输出前设定方向。
差分信号抗干扰:
采用
PULSE+/PULSE-
和DIR+/DIR-
差分对,提升长距离传输稳定性。
工作模式与配置
模式
信号逻辑
适用场景
脉冲+方向
单路脉冲 + 方向电平(正转DIR=High,反转DIR=Low)
低成本小型设备(≤200kHz)
CW/CCW
双路独立脉冲(CW脉冲=正转,CCW脉冲=反转)
高速(>200kHz)或长距离传输
A/B正交脉冲
两路相位差90°的脉冲(A超前B=正转,A滞后B=反转)
高精度编码器反馈系统
驱动器需通过参数(如
H05.15
)匹配控制器输出模式,否则导致方向错误或定位偏差。关键参数设置
电子齿轮比:
调节输入脉冲与实际位移的比例。
公式:实际位移 = 输入脉冲数 ×(电子齿轮分子 / 电子齿轮分母)。
例:设置分子/分母=4/1,则1个脉冲驱动电机转动4个步距角。
方向信号延时:
方向信号需提前脉冲0.5μs以上,避免电机启动瞬间反向抖动。
(二)、总线协议(EtherCAT、CANopen、Modbus)
总线协议适用于多轴协同、高实时性场景,替代传统脉冲控制,解决布线复杂和同步精度问题。
1. EtherCAT(以太网控制自动化技术)
核心机制:
"飞读飞写"帧处理:主站帧依次穿越各从站,每个从站实时读写数据,单帧完成多设备通信。
分布式时钟:主站同步所有从站时钟,同步误差≤±1ns,保障多轴插补精度。
性能优势:
通信周期≤100μs,支持4轴同步控制(如研华控制卡)。
带宽利用率>90%,远高于传统以太网。
2. CANopen(基于CAN总线的应用层协议)
核心机制:
对象字典:标准化参数存储结构(如0x607C“目标位置”、0x6040“控制字”)。
NMT网络管理:主站控制从站状态(启动/停止/复位)。
性能优势:
支持1Mbps速率,最多127个节点,适合分布式控制(如10轴插片机系统)。
抗干扰性强,适用于电磁环境复杂场景。
3. Modbus(主从式串行通信协议)
核心机制:
主站轮询:主站按地址顺序查询从站数据,响应延迟随节点数增加。
寄存器读写:通过功能码(如03读保持寄存器、06写单寄存器)访问参数。
性能局限:
无实时保障,通信周期≥100ms,仅适用非同步控制(如启停命令、温度读取)。
仅支持简单数据类型(16位整数)。
(三)、协议选型对比
维度 |
脉冲方向控制 |
EtherCAT |
CANopen |
Modbus |
---|---|---|---|---|
实时性 |
中(依赖脉冲频率) |
超高(≤100μs) |
高(1Mbps速率) |
低(≥100ms) |
同步精度 |
无多轴同步能力 |
±1ns |
±10μs |
不支持 |
最大轴数 |
≤4轴(受限于PLC脉冲口) |
≥64轴 |
127节点 |
32节点(RTU模式) |
布线复杂度 |
高(每轴需2~4芯线) |
低(菊花链拓扑) |
中(总线型拓扑) |
中(星型/总线拓扑) |
抗干扰能力 |
弱(需差分信号增强) |
强(以太网屏蔽) |
强(CAN差分信号) |
弱(RS485需终端电阻) |
典型成本 |
低(无需专用网卡) |
高(需专用主站) |
中 |
低 |
五、上位机控制
1、板卡连接
2、初始化参数
3、轴参数设置
4、相对移动
5、绝对移动
6、回原
7、Jog移动
板卡类
/// <summary>
/// 板卡抽象基类
/// </summary>
public abstract class CardBase
{
/// <summary>
/// 卡参数
/// </summary>
public CardParam cardParam { get; set; }
public short CardNo => (short)cardParam.CardNo;
/// <summary>
/// 坐标系建立成功标志
/// </summary>
protected bool buildOK = false;
/// <summary>
/// 卡初始化成功标志
/// </summary>
private bool online;
/// <summary>
/// 在线状态
/// </summary>
public bool OnLine
{
get { return online; }
set { online = value; }
}
/// <summary>
/// 写错误信息方法
/// </summary>
public WriteInfo WriteInfo = null;
/// <summary>
/// 卡基类 有参构造方法
/// </summary>
/// <param name="cardParam">卡参数</param>
public CardBase(CardParam cardParam)
{
this.cardParam = cardParam;
WriteInfo = new WriteInfo((str) =>
{
Console.WriteLine(str);
});
}
/// <summary>
/// 设置错误信息输出函数
/// </summary>
/// <param name="writeInfo">回调函数</param>
public void SetWriteInfoCB(WriteInfo writeInfo)
{
this.WriteInfo = writeInfo;
for (int i = 0; i < AxisBaseList.Count; i++)
{
AxisBaseList[i].SetWriteInfoCB(writeInfo);
}
}
#region 板卡初始化
/// <summary>
///板卡初始化
/// </summary>
/// <returns></returns>
public abstract OperationResult Init();
/// <summary>
///关闭板卡
/// </summary>
/// <returns></returns>
public abstract OperationResult DeInit();
/// <summary>
/// 读取板卡固件版本号
/// </summary>
/// <returns></returns>
public abstract string GetCardVersioin();
#endregion 板卡初始化
#region IO 操作
/// <summary>
/// 读取一组连续的输入
/// </summary>
/// <param name="startport"></param>
/// <param name="endport"></param>
/// <param name="data"></param>
/// <returns></returns>
public abstract bool ReadIoIn(int startport, int endport, ref int data);
/// <summary>
/// 读取一个输入点
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public abstract bool ReadIoInBit(int index);
/// <summary>
/// 读取一组连续的输出
/// </summary>
/// <param name="startport"></param>
/// <param name="endport"></param>
/// <param name="data"></param>
/// <returns></returns>
public abstract bool ReadIoOut(int startport, int endport, ref int data);
/// <summary>
/// 读取一个输出点
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public abstract bool ReadIoOutBit(int index);
/// <summary>
/// 写一个IO输出点
/// </summary>
/// <param name="index"></param>
/// <param name="bit"></param>
/// <returns></returns>
public abstract bool WriteIoBit(int index, bool bit);
/// <summary>
/// 写一组IO输出数据
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public abstract bool WriteIo(int startport, int endport, int data);
///// <summary>
///// 读取数字IO输入状态
///// </summary>
///// <param name="type">0:正限位 | 1:负限位 | 2:驱动报警| 3:原点开关| 4:通用输入|</param>
///// <returns></returns>
//public abstract int GetDi(InputIOType type);
///// <summary>
///// 读取数字IO输入状态
///// </summary>
///// <param name="type">0:正限位 | 1:负限位 | 2:驱动报警| 3:原点开关| 4:通用输入|</param>
///// <returns></returns>
//public abstract bool[] GetInput(InputIOType type);
///// <summary>
///// 读取数字IO输出状态
///// </summary>
///// <param name="type">10:驱动器使能 | 11:报警清除 | 12:通用输出|</param>
///// <returns></returns>
//public abstract int GetDo(OutputIOType type);
///// <summary>
///// 读取输出状态 读取多位
///// </summary>
///// <param name="type">10:驱动器使能 | 11:报警清除 | 12:通用输出|</param>
///// <returns></returns>
//public abstract bool[] GetOutput(OutputIOType type);
///// <summary>
///// 读取输入状态 读1位
///// </summary>
///// <param name="index">索引1-16</param>
///// <returns></returns>
//public abstract bool GetInputBit(int index);
///// <summary>
///// 读取输出状态 读1位
///// </summary>
///// <param name="index">索引1-16</param>
///// <returns></returns>
//public abstract bool GetOutputBit(int index);
///// <summary>
///// 设置输出状态 写1位
///// </summary>
///// <param name="index">索引</param>
///// <param name="state">状态</param>
///// <returns></returns>
//public abstract bool SetOutputBit(int index, bool state);
///// <summary>
///// 设置输出状态 写32位
///// </summary>
///// <param name="value">值</param>
///// <returns></returns>
//public abstract bool SetOutput(int value);
#endregion IO 操作
#region 插补运动
/// <summary>
/// 以当前位置为起始点进行多轴直线插补最多4轴
/// </summary>
/// <param name="axisNo">轴号数组最多4轴</param>
/// <param name="pos">位置数组</param>
/// <param name="vel">速度</param>
/// <param name="acc">加速度</param>
/// <returns>操作结果</returns>
public abstract OperationResult MoveLineXYZAAbs(short[] axisNo, double[] pos, double vel, double acc = 0.2);
/// <summary>
/// XYC 2D 整圆插补 以起点(终点)位置和圆心位置为输入参数 画整圆
/// </summary>
/// <param name="axisNo">轴号数组</param>
/// <param name="pos">圆弧的起点(终点)X 圆弧的圆心X </param>
/// <param name="center">圆弧的起点(终点)Y 圆弧的圆心Y</param>
/// <param name="vel">速度</param>
/// <param name="acc">加速度</param>
/// <returns>操作结果</returns>
public abstract OperationResult MoveCircular(short[] axisNo, double[] pos, double[] center, double vel, double acc = 0.2);
/// <summary>
/// XYR 2D圆弧插补 起始点 过度点位置 终点位置为输入参数 画半圆
/// </summary>
/// <param name="axisNo">轴号数组</param>
/// <param name="pos">起始 XY坐标</param>
/// <param name="pos1">过度点 XY坐标</param>
/// <param name="pos2">终点 XY坐标</param>
/// <param name="vel">速度</param>
/// <param name="acc">加速度</param>
/// <returns>操作结果</returns>
public abstract OperationResult MoveArc(short[] axisNo, double[] pos, double[] pos1, double[] pos2, double vel, double acc = 0.2);
/// <summary>
/// 空间圆弧插补
/// </summary>
/// <param name="axisNo">轴号</param>
/// <param name="posX">开始位置</param>
/// <param name="posY">经过位置</param>
/// <param name="posZ">终点位置</param>
/// <param name="vel">速度</param>
/// <param name="acc">加速度</param>
/// <returns></returns>
public abstract OperationResult MoveArcOfSpace(short[] axisNo, double[] posStart, double[] posTransition, double[] posEnd, double vel, double acc = 0.2);
/// <summary>
///等待插补运动完成
/// </summary>
/// <returns></returns>
public abstract OperationResult WaitInterpolatorXYStop();
#endregion 插补运动
#region 轴对象操作
/// <summary>
/// 轴集合
/// </summary>
public List<AxisBase> AxisBaseList = new List<AxisBase>();
/// <summary>
/// 获取板卡所有参数json(卡参数+所有轴参数)
/// </summary>
public abstract string GetCardAxisParamJson();
/// <summary>
/// 添加轴对象
/// </summary>
/// <param name="axisBase"></param>
/// <returns></returns>
public abstract bool AddAxisObj(AxisParam axisParam);
/// <summary>
/// 删除轴对象
/// </summary>
/// <param name="axisBase"></param>
/// <returns></returns>
public abstract bool DelAxisObj(AxisParam axisParam);
/// <summary>
/// 修改轴参数
/// </summary>
/// <param name="axisParam"></param>
/// <returns></returns>
public abstract bool ModifyAxisPara(AxisParam axisParam);
#endregion 轴对象操作
#region 2. 轴控制动作
/// <summary>
/// 停止板卡中全部轴
/// </summary>
/// <returns></returns>
public abstract bool StopAllAxis();
/// <summary>
/// 停止轴(正常停止)
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool StopAxis(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.StopAxis();
}
return false;
}
/// <summary>
///停止轴(急停)
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool StopEmg(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.StopEmg();
}
return false;
}
/// <summary>
///绝对位置移动
/// </summary>
/// <param name="nAxisNo">轴号</param>
/// <param name="nPos">位置</param>
/// <param name="nSpeed">速度</param>
/// <param name="accSpeed">加速度</param>
/// <returns></returns>
public virtual OperationResult AbsMove(int nAxisNo, double nPos, double nSpeed = -1, double accSpeed = -1)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.AbsMove(nPos, nSpeed, accSpeed);
}
return new OperationResult() { IsSuccess = false, ErrorMsg = "对象为null" };
}
/// <summary>
///相对位置移动
/// </summary>
/// <param name="nAxisNo"></param>
/// <param name="nPos"></param>
/// <param name="nSpeed"></param>
/// <returns></returns>
public virtual OperationResult RelativeMove(int nAxisNo, double nPos, double nSpeed = -1, double accSpeed = -1)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.RelativeMove(nPos, nSpeed, accSpeed);
}
return new OperationResult() { IsSuccess = false, ErrorMsg = "对象为null" };
}
/// <summary>
///jog运动
/// </summary>
/// <param name="nAxisNo"></param>
/// <param name="bPositive"></param>
/// <param name="nSpeed"></param>
/// <returns></returns>
public virtual OperationResult JogMove(int nAxisNo, bool bPositive, double nSpeed = -1)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.JogMove(bPositive, nSpeed);
}
return new OperationResult() { IsSuccess = false, ErrorMsg = "对象为null" };
}
/// <summary>
///开启使能
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool ServoOn(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.ServoOn();
}
return false;
}
/// <summary>
///断开使能
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool ServoOff(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.ServoOff();
}
return false;
}
/// <summary>
///获取轴的当前位置
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual double GetAixsPos(int nAxisNo)
{
if (!OnLine)
{
throw new Exception("板卡未连接!");
}
if (AxisBaseList.Count == 0)
{
throw new Exception("没有可用的轴对象");
}
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.GetAixsPos();
}
return -999999.4;
}
/// <summary>
///位置清零
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool SetPosZero(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.SetPosZero();
}
return false;
}
/// <summary>
/// 读取伺服使能状态
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool IsServoOn(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.IsServoOn();
}
return false;
}
/// <summary>
///回原点
/// </summary>
/// <param name="nAxisNo">轴号</param>
/// <param name="nParam">回原方向 1:正方向 -1:负方向</param>
/// <returns></returns>
public virtual OperationResult Home(int nAxisNo, int nParam)
{
if (!OnLine)
{
return new OperationResult() { IsSuccess = false, ErrorMsg = "设备没有连接!" };
}
if (AxisBaseList.Count == 0)
{
return new OperationResult() { IsSuccess = false, ErrorMsg = "没有可用的轴对象" };
}
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.Home(nParam);
}
return new OperationResult() { IsSuccess = false, ErrorMsg = $"没有找对轴号:{nAxisNo} 对应的轴对象" };
}
/// <summary>
/// 回原点是否正常停止
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual OperationResult IsHomeNormalStop(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.IsHomeNormalStop();
}
return new OperationResult() { IsSuccess = false, ErrorMsg = "轴对象为null" };
}
/// <summary>
/// 停止回原动作
/// </summary>
/// <returns></returns>
public virtual bool StopHomeAction(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.StopHomeAction();
}
return false;
}
/// <summary>
/// 清除轴状态
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual bool ClrSts(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.ClrSts();
}
return false;
}
/// <summary>
/// 清除所有轴状态
/// </summary>
/// <returns></returns>
public abstract bool ResetAllAxisStatus();
/// <summary>
///获取轴卡运动状态
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public virtual int GetMotionState(int nAxisNo)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.GetMotionState();
}
return -1;
}
/// <summary>
/// 检测是否有轴报警
/// </summary>
/// <returns></returns>
public abstract bool CheckAllAxisAlarm();
/// <summary>
/// 读取轴报警
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool IsAlarmFlag(int nAxisNo);
/// <summary>
/// 读取轴正限位
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool IsPosLimitFlag(int nAxisNo);
/// <summary>
/// 读取轴负限位
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>h
public abstract bool IsNegLimitFlag(int nAxisNo);
/// <summary>
/// 读取轴原点
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool IsHomeFlag(int nAxisNo);
/// <summary>
/// 获取回零状态
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool IsHomeStatus(int nAxisNo);
/// <summary>
/// 轴停止
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool IsStop(int nAxisNo);
#endregion 2. 轴控制动作
/// <summary>
/// 设置单轴的某一运动参数
/// </summary>
/// <param name="nAxisNo">轴号</param>
/// <param name="nParam">参数:1:加速度 2:减速度 3:起跳速度 4:结束速度(凌华卡) 5:平滑时间(固高卡S曲线) 其它:自定义扩展</param>
/// <param name="nData">参数值</param>
/// <returns></returns>
public virtual bool SetAxisParam(int nAxisNo, AxisMotionParam nParam, int nData)
{
var v = AxisBaseList.Find(c => c.axisParam.AxisNo == nAxisNo);
if (v != null)
{
return v.SetAxisParam(nParam, nData);
}
return false;
}
}
轴控制类
/// <summary>
/// 轴抽象基类
/// </summary>
public abstract class AxisBase
{
/// <summary>
/// 轴无效值
/// </summary>
public const double AxisInvalidPos = -999999.4;
/// <summary>
/// 轴参数
/// </summary>
public AxisParam axisParam { get; set; }
/// <summary>
/// 轴号
/// </summary>
public short AxisNo => (short)axisParam.AxisNo;
/// <summary>
/// 卡号
/// </summary>
public short CardNo => (short)axisParam.CardNo;
/// <summary>
/// 脉冲当量
/// </summary>
public float Units => (float)(axisParam.Subdivide * 1.0 / axisParam.HelicalPitch);
///// <summary>
///// 停止回原动作(标志)
///// 判断此标志true 停止进行中的回原动作
///// </summary>
//protected bool stopHome;
/// <summary>
/// 构造方法
/// </summary>
/// <param name="axisParam">轴参数</param>
public AxisBase(AxisParam axisParam)
{
this.axisParam = axisParam;
WriteInfo = new WriteInfo((str) =>
{
Console.WriteLine(str);
});
}
/// <summary>
/// 写错误信息方法
/// </summary>
public WriteInfo WriteInfo = null;
/// <summary>
/// 设置错误信息输出函数
/// </summary>
/// <param name="writeInfo">回调函数</param>
public void SetWriteInfoCB(WriteInfo writeInfo)
{
this.WriteInfo = writeInfo;
}
// 轴的操作方法 jog move abs 使能
#region 2. 轴控制动作
/// <summary>
/// 停止回原动作
/// </summary>
/// <returns></returns>
public abstract bool StopHomeAction();
/// <summary>
///轴位置清零
/// </summary>
/// <returns></returns>
public abstract bool SetPosZero();
/// <summary>
/// 报警清除
/// </summary>
/// <returns>结果</returns>
public abstract bool ClrSts();
/// <summary>
///开启使能
/// </summary>
/// <returns></returns>
public abstract bool ServoOn();
/// <summary>
///断开使能
/// </summary>
/// <returns></returns>
public abstract bool ServoOff();
/// <summary>
/// 伺服使能状态
/// </summary>
/// <returns> </returns>
public abstract bool IsServoOn();
/// <summary>
/// 绝对位置移动
/// </summary>
/// <param name="nPos">位置</param>
/// <param name="nSpeed">速度 默认为:-1 表示使用轴参数的速度</param>
/// <param name="accSpeed">加速度 默认为:-1 表示使用轴参数的加速度</param>
/// <returns></returns>
public abstract OperationResult AbsMove(double nPos, double nSpeed = -1,double accSpeed=-1);
/// <summary>
///相对位置移动
/// </summary>
/// <param name="nPos"></param>
/// <param name="nSpeed">速度 默认为:-1 表示使用轴参数的速度</param>
/// <returns></returns>
public abstract OperationResult RelativeMove(double nPos, double nSpeed = -1,double accSpeed=-1);
/// <summary>
///jog运动
/// </summary>
/// <param name="bPositive">方向</param>
/// <param name="nSpeed">速度 默认为:-1 表示使用轴参数的速度</param>
/// <returns></returns>
public abstract OperationResult JogMove(bool bPositive, double nSpeed = -1);
/// <summary>
///轴正常停止
/// </summary>
/// <param name="nAxisNo"></param>
/// <returns></returns>
public abstract bool StopAxis();
/// <summary>
/// 单轴急停
/// </summary>
/// <returns></returns>
public abstract bool StopEmg();
/// <summary>
///获取轴的当前位置
/// </summary>
/// <returns></returns>
public abstract double GetAixsPos();
/// <summary>
/// 回原
/// </summary>
/// <param name="nParam">回原方向 1:正方向 -1:负方向</param>
/// <param name="timeout">超时时间(-1表示 不启用超时时间)</param>
/// <returns></returns>
public abstract OperationResult Home(int nParam);
/// <summary>
/// 回原点是否正常停止
/// </summary>
/// <returns></returns>
public abstract OperationResult IsHomeNormalStop();
#endregion 2. 轴控制动作
#region 3. 轴状态
/// <summary>
///获取轴运动状态
/// </summary>
/// <returns></returns>
public abstract int GetMotionState();
///// <summary>
/////获取轴卡运动IO信号
///// </summary>
///// <returns></returns>
//public abstract int GetMotionIoState();
///// <summary>
///// 轴是否正常停止
///// </summary>
///// <returns> -2:指令返回错误 -1:运动中 1:驱动器报警 4:正限位 5:负限位 3:未使能</returns>
//public abstract int IsAxisNormalStop();
/// <summary>
/// 轴是否报警
/// </summary>
/// <returns>返回 true 报警 false 没有报警</returns>
public abstract bool IsAlarmFlag();
/// <summary>
/// 轴是否处于正限位
/// </summary>
/// <returns></returns>
public abstract bool IsPosLimitFlag();
/// <summary>
/// 轴是否处于负限位
/// </summary>
/// <returns></returns>
public abstract bool IsNegLimitFlag();
public abstract bool IsHomeFlag();
///// <summary>
///// 等待轴正常停止
///// </summary>
///// <returns>操作结果</returns>
//public abstract OperationResult WaitStop();
#endregion 3. 轴状态
/// <summary>
/// 设置轴的 单一控制参数
/// </summary>
/// <param name="nParam">参数类型:1:加速度 2:减速度 3:起跳速度 4:结束速度 5:平滑时间 其它:自定义扩展</param>
/// <param name="nData">参数值</param>
/// <returns></returns>
public abstract bool SetAxisParam(AxisMotionParam nParam, int nData);
/// <summary>
/// 设置轴软极限
/// </summary>
/// <returns></returns>
public abstract bool SetSoftLimit();
/// <summary>
/// 轴状态检测
/// </summary>
/// <returns>检测结果 OperationResult</returns>
public abstract OperationResult CommonMotionValidate();
/// <summary>
/// 更新轴信息
/// </summary>
public void UpdataState()
{
axisParam.NegativeSignalState = IsNegLimitFlag();
axisParam.PositiveSignalState = IsPosLimitFlag();
axisParam.HomeSignalState = IsHomeFlag();
axisParam.AxisPos = GetAixsPos();
axisParam.IsErrState = IsAlarmFlag();
}
}