|
01 ZMC432-V2运动控制器介绍
ZMC432-V2高性能多轴运动控制器是一款兼容EtherCAT总线和脉冲型的独立式运动控制器,自带6轴本地差分脉冲轴,最多可扩展至32轴,能实现总线轴+脉冲轴混合插补的多轴运动控制场合。同时支持正运动远程显示功能,能提供网络组态显示,可实时监控和调整参数配置。

ZMC432-V2硬件功能特性:
(1)支持32轴运动控制(脉冲+EtherCAT总线),EtherCAT最小通讯周期可达125us。
(2)24路通用输入、12路通用输出,2路模拟量输出(DA),其中包括2路高速输入和2路高速输出。
(3)6路差分脉冲轴输出,总线轴、脉冲轴可混合插补。
(4)内置多项实时性运动控制功能,例如视觉飞拍、多维PSO、高速位置锁存,多轴同步运行等。
(5)可通过EtherCAT扩展模块进行IO硬件资源扩展,可扩展至4096个隔离输入口和4096个隔离输出口。
(6)具备丰富的运动控制功能,如点位运动、电子凸轮、直线插补、圆弧插补、连续轨迹加工。
(7)支持掉电检测、掉电存储,多种程序加密方式,能够有效防止系统故障,保护项目工程文件数据,并提高系统的可靠性。
(8)通过纯国产IDE开发环境RTSys进行项目开发,可实时仿真、在线跟踪以及诊断与调试,简便易用,支持多种高级上位机语言联合编程进行二次开发。

02 内容回顾
回顾上两期推文,我们对CAD导图和小线段速度前瞻的C#DEMO中的主要两个功能:CAD导图和运动前瞻设置做了详细的介绍。这次我们回归推文本身,对DEMO软件框架进行介绍。
往期内容详情点击下方链接:
C#运动控制开源(一):CAD导图和小线段速度前瞻的优化之CAD导图
C#运动控制开源(二): CAD导图和小线段速度前瞻优化
03 开发环境
?适用场景:需要CAD导图给XY机台做轨迹运动的场合都可以使用本DEMO测试。
?软件平台:使用Visual Studio C#(即Visual C#)开发。
04 DEMO界面和操作步骤介绍
一、软件框架流程图

二、主界面
打开软件后首先显示的是主界面,主要分为3个部分:
①工具栏提供控制器连接复位,CAD图纸导入及编辑,参数界面跳转等按钮。
②中间部分用于显示导入CAD文件后轨迹的显示。
③右侧操作界面则是用来操作各轴移动以及启动加工,切换到BASIC或者G代码标签则会显示轨迹对应的相关代码。


三、工具栏
①连接控制器:点击控制器→连接控制器弹出控制器连接界面,手动输入控制器IP或者下拉框搜索,点击连接即可连接对应IP控制器,连接成功软件标题会显示连接成功。


②导入CAD图纸:点击文件→打开弹出文件选择界面,选择对应格式的CAD文件,成功导入后会将轨迹显示出来。



③轨迹操作和优化:CAD图纸轨迹显示后,可以进行一些编辑操作。通过左键选取操作对应的轨迹,右键进行画面移动。对应编辑视图中进行轨迹优化以及排序。对应视图中进行显示元素的选择。



四、参数设置
①打开参数界面:点击视图→参数设置可以打开参数设置界面。


②设置轴参数和测试:可以在此页面设置XYZU轴各轴参数,以及进行简单的手动运动测试,确保轴运动没有问题。
③前瞻参数设置:点击前瞻参数标签页,可以进行前瞻参数的设置。

④加工参数设置:点击加工参数标签页,可以进行加工参数的设置。

⑤保存参数设置:点击参数保存按钮,会将所有的设置保存到对应exe所在目录的para文件夹下,下次打开软件会自动读取参数并设置上去。

五、加工操作面板
①开启加工:设置完参数后,可以在操作面板点击启动开始加工,同时记录加工时间和目前状态。对应各轴坐标和速度也会显示出来,轨迹显示视图中也会把当前末端加工位置显示出来,方便观察目前位置。如果加工中需要暂停和停止,点击对应按钮即可。

②显示生成代码:点击BASIC或者G代码标签可以显示当前轨迹对应的运行代码,可以用来排查问题,或者复制到其它软件中直接运行。


05
DEMO程序介绍
DEMO中把主要用到的重要程序分别放在了:
ZCadFn.cs,ZGCode.cs,ZmotionCard.cs
依次对应CAD导图,轨迹解析,运动控制三部分,方便大家使用学习。
ZCadFn.cs(CAD导图解析与绘制)

该部分主要提供CAD导图初始化与导入CAD图纸获取轨迹数据,然后进行图形绘制的函数。
form1.cs中按照:初始化CAD→导入CAD文件→获得轨迹数组→绘制轨迹的顺序进行调用。比如下方程序:
//导入CAD文件
if (!m_GloFn.m_ZCad.ZcadReadFile(strFilePath))
{
MessageBox.Show("导入文件失败");
return;
}
//计算比例
if (!m_GloFn.m_ZCad.ZcadPicBoxMath(CadShow.Width, CadShow.Height))
{
MessageBox.Show("导入文件失败");
return;
}
//获取轨迹数组
if (!m_GloFn.m_ZCad.ZcadArrayGet())
{
MessageBox.Show("获取轨迹失败");
return;
}
//绘制一遍CAD
if (!m_GloFn.m_ZCad.ZcadShowPic(CadShow.Width, CadShow.Height, 坐标系ToolStripMenuItem.Checked, 顺序ToolStripMenuItem.Checked, 空移ToolStripMenuItem.Checked, 起点ToolStripMenuItem.Checked, 方向ToolStripMenuItem.Checked,XCurDpos,YCurDpos, UCurDpos))
{
MessageBox.Show("绘制失败");
return;
}
ZGCode.cs.cs(数据转化为G代码或者BASIC代码)
该部分主要提供将轨迹数据转化成G代码或者BASIC代码格式的函数。

主界面上的代码显示就是通过该部分转话后显示到textbox控件中。
if (m_GloFn.m_ZmotionCard.m_bInited && m_GloFn.m_ZCad.m_bInited)
{
string basicCode = "";
string gcode = "";
ZGCode.CadArraytoCode(m_GloFn.m_ZCad.m_ZCad_ArrayInfo, ref basicCode, ref gcode, 仅处理选中图形toolStripMenuItem.Checked,true, CadShow.Width, CadShow.Height);
txt_Basic.Text = basicCode;
txt_GCode.Text = gcode;
}
ZmotionCard.cs(运动控制测试和前瞻下发)
该部分主要提供一些封装好的轴运动控制函数,以及以三次文件形式或者批量函数形式下发轨迹。

单轴控制界面时就是通过按钮调用对应的轴控制函数来实现JOG,定位,回原等测试功能。

按钮调用代码如下:
?回原:
private void btn_X_SingleHome_Click(object sender, EventArgs e)
{
SetAxisParaByCtr(); //先控件参数设置到实际轴参数
m_GloFn.m_ZmotionCard.AxisParaSet(); //读取参数出来之后设置一遍到轴参数上
int axisnum = m_GloFn.m_ZmotionCard.m_nAxis_X;
int datumtype = m_GloFn.m_ZmotionCard.m_nAxis_X_DatumType;
float homespeed = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_DatumSpeed;
float creep = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_Creep;
bool ifbushome = m_GloFn.m_ZmotionCard.m_bAxis_X_BusDatum;
float homeoffset = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_DatumOffset;
m_GloFn.m_ZmotionCard.AxisHome(axisnum,datumtype,homespeed,creep,ifbushome,homeoffset);
}
?定位:
private void btn_X_Move_Click(object sender, EventArgs e)
{
SetAxisParaByCtr(); //先控件参数设置到实际轴参数
m_GloFn.m_ZmotionCard.AxisParaSet(); //读取参数出来之后设置一遍到轴参数上
int axisnum = m_GloFn.m_ZmotionCard.m_nAxis_X;
float movesp = 0;
if (radio_X_LowSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_LowSpeed;
if (radio_X_NomalSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_NormalSpeed;
if (radio_X_HighSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_HighSpeed;
float movedis = Convert.ToSingle(tb_X_MoveDis.Text);
bool ifabsmove = cb_X_IfAbs.Checked;
if(ifabsmove) m_GloFn.m_ZmotionCard.AxisMoveAbs(axisnum,movesp,movedis);
else m_GloFn.m_ZmotionCard.AxisMove(axisnum, movesp, movedis);
}
?点动:
private void btn_X_RVmove_MouseDown(object sender, MouseEventArgs e)
{
SetAxisParaByCtr(); //先控件参数设置到实际轴参数
m_GloFn.m_ZmotionCard.AxisParaSet(); //读取参数出来之后设置一遍到轴参数上
int axisnum = m_GloFn.m_ZmotionCard.m_nAxis_X; float movesp = 0;
if (radio_X_LowSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_LowSpeed;
if (radio_X_NomalSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_NormalSpeed;
if (radio_X_HighSp.Checked) movesp = (float)m_GloFn.m_ZmotionCard.m_dAxis_X_HighSpeed;
m_GloFn.m_ZmotionCard.AxisVmove(axisnum, false, movesp);
}
private void btn_X_RVmove_MouseUp(object sender, MouseEventArgs e)
{
int axisnum = m_GloFn.m_ZmotionCard.m_nAxis_X;
m_GloFn.m_ZmotionCard.AxisCancel(axisnum);
}
前瞻功能则是调用控制器前瞻初始化函数设置参数到控制器中,或者使用平滑函数前瞻将轨迹数据处理成平滑好的数据。
?控制器前瞻设置:
#region
控制器前瞻参数初始化
public bool RunParaIni()
{
//判断控制卡是否初始化成功
if (!m_bInited)
return false; //-1代表初始化未成功
int iret = 0;
//控制器前瞻参数设置到主轴上
iret += zmcaux.ZAux_Direct_SetCornerMode(g_handle, m_nAxis_X, m_nCornerMode); CommandHandler("ZAux_Direct_SetCornerMode", iret); //Corner_Mode
iret += zmcaux.ZAux_Direct_SetMerge(g_handle, m_nAxis_X, 1); CommandHandler("ZAux_Direct_SetMerge", iret); //打开连续插补
iret += zmcaux.ZAux_Direct_SetFullSpRadius(g_handle, m_nAxis_X, m_fLimitR); CommandHandler("ZAux_Direct_SetFullSpRadius", iret); //设置小圆限速半径
StringBuilder cmdbuffack = new StringBuilder(2048);
iret += zmcaux.ZAux_Execute(g_handle, "SPLIMIT_RADIUS(" + m_nAxis_X.ToString() + ") = " + m_fLimitRMinSp.ToString(), cmdbuffack, 2048); CommandHandler("ZAux_Execute", iret);//小圆限速最小限速
iret += zmcaux.ZAux_Direct_SetZsmooth(g_handle, m_nAxis_X, m_fZsmooth); CommandHandler("ZAux_Direct_SetZsmooth", iret); //倒角半径
iret += zmcaux.ZAux_Direct_SetDecelAngle(g_handle, m_nAxis_X, (float)((m_fDecelAngle / 180) * Math.PI)); CommandHandler("ZAux_Direct_SetDecelAngle", iret); //减速角
iret += zmcaux.ZAux_Direct_SetStopAngle(g_handle, m_nAxis_X, (float)((m_fStopAngle / 180) * Math.PI)); CommandHandler("ZAux_Direct_SetStopAngle", iret); //停止角
iret += zmcaux.ZAux_Direct_SetStartMoveSpeed(g_handle, m_nAxis_X, m_fXYSpeed); CommandHandler("ZAux_Direct_SetStartMoveSpeed", iret); //起始速度设置成加工速度
iret += zmcaux.ZAux_Direct_SetEndMoveSpeed(g_handle, m_nAxis_X, m_fXYSpeed); CommandHandler("ZAux_Direct_SetEndMoveSpeed", iret); //结束速度设置成加工速度
if (iret != 0) return false;
return true;
}
#endregion
?平滑前瞻函数处理:
#region
ZTrackSmooth函数平滑下发
public int SmoothByZTrackDown(double[] originalPos,ref float StartRDpos)
//public int SmoothByZTrackDown(ref float StartRDpos)
{
//判断控制卡是否初始化成功
if (!m_bInited)
return -1; //-1代表初始化未成功
int iret = 0;
UInt32 pSmoothPointsNum = 0;
IntPtr pSmoothPoints = (IntPtr)0;
IntPtr parryLine = (IntPtr)0;
IntPtr parryForceSp = (IntPtr)0;
IntPtr parryLmtSp = (IntPtr)0;
IntPtr parryR = (IntPtr)0;
ZTrackSmooth.ZTS_Delete(pSmoothPoints);
ZTrackSmooth.ZTS_Delete(parryLine);
ZTrackSmooth.ZTS_Delete(parryForceSp);
ZTrackSmooth.ZTS_Delete(parryLmtSp);
ZTrackSmooth.ZTS_Delete(parryR);
//提出平滑后的轨迹
double[] SmoothPos = { };
double[] SmoothSpeed = { };
double[] SmoothLimSp = { };
double[] SmoothR = { };
if (m_dDiserr 0) //有设置非线性小圆限速
iret = ZTrackSmooth.ZTS_ContinueSmoothAndSpeed2(g_handle, originalPos, Convert.ToUInt16(originalPos.Length / 2), 2, m_dDiserr, m_dSplineDis, m_dCornerAccel, m_fXYSpeed, m_dLimitRArray, m_dLimitRSpArray, (uint)m_dLimitRArray.Length, out pSmoothPoints, out parryLine, out parryForceSp, out parryLmtSp, out parryR, ref pSmoothPointsNum);
else
iret = ZTrackSmooth.ZTS_ContinueSmoothAndSpeed2(g_handle, originalPos, Convert.ToUInt16(originalPos.Length / 2), 2, m_dDiserr, m_dSplineDis, m_dCornerAccel, m_fXYSpeed, new double[] { 0.1, m_fLimitR }, new double[] { m_fXYSpeed, m_fXYSpeed }, 2, out pSmoothPoints, out parryLine, out parryForceSp, out parryLmtSp, out parryR, ref pSmoothPointsNum);
//提出平滑后的轨迹
SmoothPos = new double[pSmoothPointsNum * 2];
SmoothSpeed = new double[pSmoothPointsNum];
SmoothLimSp = new double[pSmoothPointsNum];
SmoothR = new double[pSmoothPointsNum];
Marshal.Copy(pSmoothPoints, SmoothPos, 0, (int)(pSmoothPointsNum * 2));
Marshal.Copy(parryForceSp, SmoothSpeed, 0, (int)(pSmoothPointsNum));
Marshal.Copy(parryLmtSp, SmoothLimSp, 0, (int)(pSmoothPointsNum));
Marshal.Copy(parryR, SmoothR, 0, (int)(pSmoothPointsNum));
}
StringBuilder cmdbuffack = new StringBuilder(2048);
double rdpos = StartRDpos;
//下发平滑轨迹
for (uint i = 0; i < pSmoothPointsNum; i++)
{
float[] targetpos = new float[2];
targetpos[0] = (float)SmoothPos[i * 2 + 0];
targetpos[1] = (float)SmoothPos[i * 2 + 1];
float runspeed = m_fXYSpeed;
float limitspeed = m_fXYSpeed;
if (m_dDiserr >= 0)
{
runspeed = (float)SmoothSpeed[i];
limitspeed = (float)SmoothLimSp[i];
}
//计算该点需要转的角度值
if (i < pSmoothPointsNum - 2 && i >= 0)
{
double moveangle = CalculateAngleWithX((float)SmoothPos[(i) * 2 + 0], (float)SmoothPos[(i) * 2 + 1], (float)SmoothPos[(i + 1) * 2 + 0], (float)SmoothPos[(i + 1) * 2 + 1]);
rdpos = MoveR(moveangle, StartRDpos);
}
StartRDpos = (float)rdpos;
if (m_b3FileDown) Z3pFile_LineString(targetpos[0], targetpos[1], rdpos, runspeed, limitspeed, i);
else Command_LineString(targetpos[0], targetpos[1], rdpos, runspeed, limitspeed, i);
}
ZTrackSmooth.ZTS_Delete(pSmoothPoints);
ZTrackSmooth.ZTS_Delete(parryLine);
ZTrackSmooth.ZTS_Delete(parryForceSp);
ZTrackSmooth.ZTS_Delete(parryLmtSp);
ZTrackSmooth.ZTS_Delete(parryR);
return iret;
}
#endregion
前瞻处理好后按照一定格式用三次文件或者批量函数下发到控制器中运行,流程可以直接参考自动线程的程序处理。
#region线程
public void Thread_Run()
{
WorkStart = DateTime.Now;
RunStatus = "自动运行中";
m_GloFn.m_ZmotionCard.AxisParaSet();
//读取参数出来之后设置一遍到轴参数上
if (!m_GloFn.m_ZmotionCard.RunParaIni())
{
MessageBox.Show("前瞻参数设置失败");
return;
}
//获取轨迹数组
if (!m_GloFn.m_ZCad.ZcadArrayGet())
{
MessageBox.Show("获取轨迹失败");
return;
}
//如果皮带跟随
if (m_GloFn.m_ZmotionCard.m_bSync)
//开启皮带跟随
{
if (m_GloFn.m_ZmotionCard.AxisBeltSync() != 0)
{
MessageBox.Show("皮带跟随失败");
return;
}
}
//取消U轴插补速度计算
int iret = 0;
iret = zmcaux.ZAux_Direct_SetInterpFactor(m_GloFn.m_ZmotionCard.g_handle, m_GloFn.m_ZmotionCard.m_nAxis_VU, 0); m_GloFn.m_ZmotionCard.CommandHandler("ZAux_Direct_SetInterpFactor", iret);
//记录U轴坐标 float RDpos = 0;
iret = zmcaux.ZAux_Direct_GetDpos(m_GloFn.m_ZmotionCard.g_handle, m_GloFn.m_ZmotionCard.m_nAxis_U,ref RDpos); m_GloFn.m_ZmotionCard.CommandHandler("ZAux_Direct_GetDpos", iret);
//解析轨迹下发
if (m_GloFn.m_ZmotionCard.m_b3FileDown) m_GloFn.m_ZmotionCard.Z3pFile_Init(); //三次文件初始化
else m_GloFn.m_ZmotionCard.CommandIni();
List OriginalPos = new List(); double Pos_x1, Pos_x2, Pos_z1, Pos_y1, Pos_y2, Pos_z2;
double Pos_x1_2, Pos_x2_2, Pos_z1_2, Pos_y1_2, Pos_y2_2, Pos_z2_2;
bool ifsplit = false;
bool ifdownZ = false;
for (int i = 0; i < m_GloFn.m_ZCad.m_nZCad_ArrayLen; i++) //遍历数组
{
Pos_x1 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].x1;
Pos_x2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].x2;
Pos_z1 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].z1;
Pos_y1 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].y1;
Pos_y2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].y2;
Pos_z2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].z2;
ifsplit = false;
if ((仅处理选中图形toolStripMenuItem.Checked == true) && (m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].m_nChoose == 0)) continue;
switch (m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].m_nItemtype)
{
case ZmotionCad.ZCAD_ITEMTYPE_VECTLine: //线型
if ((m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i].m_nInVectFrist == 1) || (ifdownZ)) //是否轨迹起点起始
{
ifdownZ = false;
double StartAngle = m_GloFn.m_ZmotionCard.CalculateAngleWithX(Pos_x1, Pos_y1, Pos_x2, Pos_y2);
//下发空移落刀指令
if (m_GloFn.m_ZmotionCard.m_b3FileDown) m_GloFn.m_ZmotionCard.Z3pFile_StartString(Pos_x1, Pos_y1, StartAngle, ref RDpos);
else m_GloFn.m_ZmotionCard.Command_StartString(Pos_x1, Pos_y1, StartAngle, ref RDpos);
OriginalPos.Clear();
//把起点存下来
OriginalPos.Add(Pos_x1);
OriginalPos.Add(Pos_y1);
}
OriginalPos.Add(Pos_x2); //记录过程点
OriginalPos.Add(Pos_y2);
if (i + 1 < m_GloFn.m_ZCad.m_nZCad_ArrayLen)
{
Pos_x1_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].x1;
Pos_x2_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].x2;
Pos_z1_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].z1;
Pos_y1_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].y1;
Pos_y2_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].y2;
Pos_z2_2 = m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].z2;
//大于停止角就抬刀
if (Math.Abs(m_GloFn.m_ZmotionCard.CalculateAngle(Pos_x1, Pos_y1, Pos_x2, Pos_y2, Pos_x1_2, Pos_y1_2, Pos_x2_2, Pos_y2_2)) > m_GloFn.m_ZmotionCard.m_fStopAngle) ifsplit = true;
//判断下个点是否空移点
if ((m_GloFn.m_ZCad.m_ZCad_ArrayInfo[i + 1].m_nInVectFrist == 1) || (ifsplit)) //下条运动为空移点,需要抬刀
{
if (ifsplit == false)
{
OriginalPos.Add(Pos_x2); //记录过程点
OriginalPos.Add(Pos_y2);
}
//下发加工轨迹
m_GloFn.m_ZmotionCard.SmoothByZTrackDown(OriginalPos.ToArray(), ref RDpos);
//m_GloFn.m_ZmotionCard.SmoothByZTrackDown( ref RDpos);
//下发抬刀动作
if (m_GloFn.m_ZmotionCard.m_b3FileDown) m_GloFn.m_ZmotionCard.Z3pFile_EndString(Pos_x2, Pos_y2);
else m_GloFn.m_ZmotionCard.Command_EndString(Pos_x2, Pos_y2);
if (ifsplit)
{
ifdownZ = true;
ifsplit = false;
}
}
}
if (i == m_GloFn.m_ZCad.m_nZCad_ArrayLen - 1)
{
//下发加工轨迹
m_GloFn.m_ZmotionCard.SmoothByZTrackDown(OriginalPos.ToArray(), ref RDpos);
//m_GloFn.m_ZmotionCard.SmoothByZTrackDown(ref RDpos);
//下发抬刀动作
if (m_GloFn.m_ZmotionCard.m_b3FileDown) m_GloFn.m_ZmotionCard.Z3pFile_EndString(Pos_x2, Pos_y2);
else m_GloFn.m_ZmotionCard.Command_EndString(Pos_x2, Pos_y2);
if (ifsplit)
{
ifdownZ = true;
ifsplit = false;
}
}
break;
default:
break;
}
}
if (m_GloFn.m_ZmotionCard.m_b3FileDown) m_GloFn.m_ZmotionCard.Z3pFile_End(); //三次文件结束
//等待3次文件结束
while (true)
{
int runstatus = 0;
StringBuilder cmdbuffack = new StringBuilder(2048);
iret = zmcaux.ZAux_DirectCommand(m_GloFn.m_ZmotionCard.g_handle,$"?PROC_STATUS({m_GloFn.m_ZmotionCard.Z3P_FILE_TASK})", cmdbuffack,2048); m_GloFn.m_ZmotionCard.CommandHandler("ZAux_DirectCommand", iret);
runstatus = Convert.ToInt16(cmdbuffack.ToString());
if (runstatus == 0) break;
}
//等待运动结束
while (true)
{
int idle = 0;
iret = zmcaux.ZAux_Direct_GetIfIdle(m_GloFn.m_ZmotionCard.g_handle, m_GloFn.m_ZmotionCard.m_nAxis_X, ref idle); m_GloFn.m_ZmotionCard.CommandHandler("ZAux_Direct_GetIfIdle", iret);
if (idle != 0) break;
}
//如果皮带跟随
if (m_GloFn.m_ZmotionCard.m_bSync) //取消皮带跟随绑定
{
m_GloFn.m_ZmotionCard.beltsyncend();
}
//恢复U轴插补速度计算
iret = zmcaux.ZAux_Direct_SetInterpFactor(m_GloFn.m_ZmotionCard.g_handle, m_GloFn.m_ZmotionCard.m_nAxis_VU, 1); m_GloFn.m_ZmotionCard.CommandHandler("ZAux_Direct_SetInterpFactor", iret);
RunStatus = "待机";
}
教学视频请点击→C#运动控制开源(三): CAD导图和小线段速度前瞻优化的软件框架
完整代码获取地址
▼

本次,正运动技术C#运动控制开源(三): CAD导图和小线段速度前瞻优化的软件框架,就分享到这里。
更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

正运动技术专注于运动控制技术研究和通用运动控制软硬件产品的研发,是国家级高新技术企业。正运动技术汇集了来自华为、中兴等公司的优秀人才,在坚持自主创新的同时,积极联合各大高校协同运动控制基础技术的研究。主要业务有:运动控制卡_运动控制器_EtherCAT运动控制卡_EtherCAT控制器_运动控制系统_视觉控制器__运动控制PLC_运动控制_机器人控制器_视觉定位_XPCIe/XPCI系列运动控制卡等等。
|