C#编写上位机驱动运动控制板卡
- 项目概述
- 控制原理
- 功能实现
- 上位机界面
- 通讯连接模块
- 断开连接模块
- 刷新输入模块
- 控制输出模块
- 单轴控制模块
- 刷新界面
- 轴1+点动(位移伺服模式)
- 轴2-点动(位移伺服模式)
- 缓停
- 急停
- 轴1连续正转(速度伺服模式)
- 轴1连续反转(速度伺服模式)
- 多轴拟合运动模块
- 环形轨迹
- 正方形轨迹
- 三轴螺旋插补
- 尾言
项目概述
笔者曾自费1200软妹币购置了一款运动控制板卡,利用下班时间琢磨出上位机,用以取代传统的PLC控制系统。IO卡及运动卡均可走RJ45水晶头串联,可级联8块,最多4096IO点及256轴联动,延时2ms以内。某些型号具备脉冲控制、编码盘伺服控制、加加速度扭矩控制,性能及性价比都不逊色于PLC。笔者已完成了部分功能的编写。系虎彩全厂首次尝试不含PLC的运动控制系统。
控制原理
安装原厂驱动后,可以使用SDK包进行开发。笔者选用了RJ45直连的方式,较走交换机的TCP/IP模式延时更短,可靠性更好。经万用表测试为NPN型。
使用脉冲控制步进驱动器。伺服控制要复杂一些。
功能实现
上位机界面
使用VS2019,Win Form写出界面。
先用AI绘制个图放右下角。。。希望虎彩自动化水平越来越高。。。
主控界面用于调用其它功能模块。
先连接板卡,之后可以测试各种功能。使用完后断开。
通讯连接模块
此处需加以限定。
#region 下拉框有效性判断
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//MessageBox.Show("xx");
if (this.comboBox1.SelectedIndex == 0)
{
comboBox2.Enabled = true;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
comboBox6.Enabled = false;
comboBox7.Enabled = false;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 1)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
comboBox6.Enabled = false;
comboBox7.Enabled = false;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 2)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = false;
comboBox6.Enabled = false;
comboBox7.Enabled = false;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 3)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
comboBox6.Enabled = false;
comboBox7.Enabled = false;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 4)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
comboBox6.Enabled = true;
comboBox7.Enabled = false;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 5)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
comboBox6.Enabled = true;
comboBox7.Enabled = true;
comboBox8.Enabled = false;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 6)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
comboBox6.Enabled = true;
comboBox7.Enabled = true;
comboBox8.Enabled = true;
comboBox9.Enabled = false;
}
else if (this.comboBox1.SelectedIndex == 7)
{
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
comboBox6.Enabled = true;
comboBox7.Enabled = true;
comboBox8.Enabled = true;
comboBox9.Enabled = true;
}
}
#endregion
连接板卡。
private void button1_Click(object sender, EventArgs e)
{
short rtn = 0;
ushort Conenection_Number = 0;
ushort[] Station_Number = { 0, 1, 2, 3, 4, 5, 6, 7 };
ushort[] Station_Type = { 0, 0, 0, 0, 0, 0, 0, 0 };
Conenection_Number = (ushort)(this.comboBox1.SelectedIndex + 1);
ushort.TryParse(comboBox2.Text, out Station_Type[0]);
ushort.TryParse(comboBox3.Text, out Station_Type[1]);
ushort.TryParse(comboBox4.Text, out Station_Type[2]);
ushort.TryParse(comboBox5.Text, out Station_Type[3]);
ushort.TryParse(comboBox6.Text, out Station_Type[4]);
ushort.TryParse(comboBox7.Text, out Station_Type[5]);
ushort.TryParse(comboBox8.Text, out Station_Type[6]);
ushort.TryParse(comboBox9.Text, out Station_Type[7]);
rtn = CMCDLL_NET.MCF_Open_Net(Conenection_Number, ref Station_Number[0], ref Station_Type[0]);
if (rtn == 0)
{
this.Close();
MessageBox.Show("连接成功");
}
else
{
MessageBox.Show("打开卡失败!!! 检查硬件是否接好。");
}
}
断开连接模块
#region 断开运动控制卡
private void button2_Click(object sender, EventArgs e)
{
short rtn;
rtn = CMCDLL_NET.MCF_Close_Net();
MessageBox.Show("断开成功");
}
#endregion
刷新输入模块
public ChangeInput()
{
InitializeComponent();
Image Image1;
Image Image2;
this.comboBox1.SelectedIndex = 0;
//ushort StationNumber = 0;
timer1.Enabled = true;
#region 初始化图形显示
Image1 = new Bitmap(@"E:\work\技术攻关\C#运动控制卡\练习程序\2020.11.15\运动控制卡~练习\Resources\灯-绿.png");//绿色代表接通
Image2 = new Bitmap(@"E:\work\技术攻关\C#运动控制卡\练习程序\2020.11.15\运动控制卡~练习\Resources\灯-红.png");//红色代表断开
pictureBox1.Image = Image2;
pictureBox2.Image = Image2;
pictureBox3.Image = Image2;
pictureBox4.Image = Image2;
pictureBox5.Image = Image2;
pictureBox6.Image = Image2;
pictureBox7.Image = Image2;
pictureBox8.Image = Image2;
pictureBox9.Image = Image2;
pictureBox10.Image = Image2;
pictureBox11.Image = Image2;
pictureBox12.Image = Image2;
pictureBox13.Image = Image2;
pictureBox14.Image = Image2;
pictureBox15.Image = Image2;
pictureBox16.Image = Image2;
pictureBox17.Image = Image2;
pictureBox18.Image = Image2;
pictureBox19.Image = Image2;
pictureBox20.Image = Image2;
pictureBox21.Image = Image2;
pictureBox22.Image = Image2;
pictureBox23.Image = Image2;
pictureBox24.Image = Image2;
pictureBox25.Image = Image2;
pictureBox26.Image = Image2;
pictureBox27.Image = Image2;
pictureBox28.Image = Image2;
pictureBox29.Image = Image2;
pictureBox30.Image = Image2;
pictureBox31.Image = Image2;
pictureBox32.Image = Image2;
#endregion
}
插入图片。
private void timer1_Tick(object sender, EventArgs e)
{
short rtn;
ushort i = 0;
ushort[] Input = new ushort[16];
Image Image1;
Image Image2;
Image1 = new Bitmap(@"E:\work\技术攻关\C#运动控制卡\练习程序\2020.11.15\运动控制卡~练习\Resources\灯-绿.png");//绿色代表接通
Image2 = new Bitmap(@"E:\work\技术攻关\C#运动控制卡\练习程序\2020.11.15\运动控制卡~练习\Resources\灯-红.png");//红色代表断开
#region 刷新输入00~15共计16个点的状态显示
for (i = 0; i < 16; i++)
{
rtn = CMCDLL_NET.MCF_Get_Input_Bit_Net(i, ref Input[i], 0);
if (i == 0)
{
if (Input[i] == 0)
{
pictureBox1.Image = Image1;
}
else
{
pictureBox1.Image = Image2;
}
}
else if (i == 1)
{
if (Input[i] == 0)
{
pictureBox2.Image = Image1;
}
else
{
pictureBox2.Image = Image2;
}
}
else if (i == 2)
{
if (Input[i] == 0)
{
pictureBox3.Image = (Image)Image1;
}
else
{
pictureBox3.Image = (Image)Image2;
}
}
else if (i == 3)
{
if (Input[i] == 0)
{
pictureBox4.Image = (Image)Image1;
}
else
{
pictureBox4.Image = (Image)Image2;
}
}
else if (i == 4)
{
if (Input[i] == 0)
{
pictureBox8.Image = (Image)Image1;
}
else
{
pictureBox8.Image = (Image)Image2;
}
}
else if (i == 5)
{
if (Input[i] == 0)
{
pictureBox7.Image = (Image)Image1;
}
else
{
pictureBox7.Image = (Image)Image2;
}
}
else if (i == 6)
{
if (Input[i] == 0)
{
pictureBox6.Image = (Image)Image1;
}
else
{
pictureBox6.Image = (Image)Image2;
}
}
else if (i == 7)
{
if (Input[i] == 0)
{
pictureBox5.Image = (Image)Image1;
}
else
{
pictureBox5.Image = (Image)Image2;
}
}
else if (i == 8)
{
if (Input[i] == 0)
{
pictureBox12.Image = (Image)Image1;
}
else
{
pictureBox12.Image = (Image)Image2;
}
}
else if (i == 9)
{
if (Input[i] == 0)
{
pictureBox11.Image = (Image)Image1;
}
else
{
pictureBox11.Image = (Image)Image2;
}
}
else if (i == 10)
{
if (Input[i] == 0)
{
pictureBox10.Image = (Image)Image1;
}
else
{
pictureBox10.Image = (Image)Image2;
}
}
else if (i == 11)
{
if (Input[i] == 0)
{
pictureBox9.Image = (Image)Image1;
}
else
{
pictureBox9.Image = (Image)Image2;
}
}
else if (i == 12)
{
if (Input[i] == 0)
{
pictureBox16.Image = (Image)Image1;
}
else
{
pictureBox16.Image = (Image)Image2;
}
}
else if (i == 13)
{
if (Input[i] == 0)
{
pictureBox15.Image = (Image)Image1;
}
else
{
pictureBox15.Image = (Image)Image2;
}
}
else if (i == 14)
{
if (Input[i] == 0)
{
pictureBox14.Image = (Image)Image1;
}
else
{
pictureBox14.Image = (Image)Image2;
}
}
else if (i == 15)
{
if (Input[i] == 0)
{
pictureBox13.Image = (Image)Image1;
}
else
{
pictureBox13.Image = (Image)Image2;
}
}
}
}
笔者设置为100ms自动刷新,即10Hz,用于图形化展示完全够用。
控制输出模块
初始化。
public ChangeOutput()
{
InitializeComponent();
#region 初始化可选项
comboBox1.SelectedIndex = 0;
radioButton1.Checked = false;
radioButton2.Checked = true;
radioButton3.Checked = true;
radioButton4.Checked = false;
radioButton5.Checked = true;
radioButton6.Checked = false;
radioButton7.Checked = true;
radioButton8.Checked = false;
radioButton9.Checked = true;
radioButton10.Checked = false;
radioButton11.Checked = true;
radioButton12.Checked = false;
radioButton13.Checked = true;
radioButton14.Checked = false;
radioButton15.Checked = true;
radioButton16.Checked = false;
radioButton17.Checked = true;
radioButton18.Checked = false;
radioButton19.Checked = true;
radioButton20.Checked = false;
radioButton21.Checked = true;
radioButton22.Checked = false;
radioButton23.Checked = true;
radioButton24.Checked = false;
radioButton25.Checked = true;
radioButton26.Checked = false;
radioButton27.Checked = true;
radioButton28.Checked = false;
radioButton29.Checked = true;
radioButton30.Checked = false;
radioButton31.Checked = true;
radioButton32.Checked = false;
#endregion
}
全部高电平。
#region 全部高电平
private void button1_Click(object sender, EventArgs e)
{
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_Set_Output_Net(0xffff, StationNumber);
#region 同时改变单点选框
radioButton1.Checked = true;
radioButton4.Checked = true;
radioButton6.Checked = true;
radioButton8.Checked = true;
radioButton10.Checked = true;
radioButton12.Checked = true;
radioButton14.Checked = true;
radioButton16.Checked = true;
radioButton18.Checked = true;
radioButton20.Checked = true;
radioButton22.Checked = true;
radioButton24.Checked = true;
radioButton26.Checked = true;
radioButton28.Checked = true;
radioButton30.Checked = true;
radioButton32.Checked = true;
#endregion
}
#endregion
全部低电平。
#region 全部低电平
private void button2_Click(object sender, EventArgs e)
{
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_Set_Output_Net(0, StationNumber);
#region 同时改变单点选框
radioButton2.Checked = true;
radioButton3.Checked = true;
radioButton5.Checked = true;
radioButton7.Checked = true;
radioButton9.Checked = true;
radioButton11.Checked = true;
radioButton13.Checked = true;
radioButton15.Checked = true;
radioButton17.Checked = true;
radioButton19.Checked = true;
radioButton21.Checked = true;
radioButton23.Checked = true;
radioButton25.Checked = true;
radioButton27.Checked = true;
radioButton29.Checked = true;
radioButton31.Checked = true;
#endregion
}
#endregion
由于原厂函数有多余参数,笔者进行了二次封装。
//重新封装置位函数
public void SetY(int Y)
{
int index = Y;
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
//index = comboBox1.SelectedIndex; //获取comboBox索引
rtn = CMCDLL_NET.MCF_Set_Output_Bit_Net((ushort)index, 1, StationNumber);
//MessageBox.Show("置位成功"+"\n"+"Y="+Y.ToString()+"index="+index.ToString());//???????????
}
//重新封装置0函数
public void RstY(int Y)
{
int index = Y;
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
//index = comboBox1.SelectedIndex; //获取comboBox索引
rtn = CMCDLL_NET.MCF_Set_Output_Bit_Net((ushort)index, 0, StationNumber);
//MessageBox.Show("置0成功" + "\n" + "Y=" + Y.ToString() + "index=" + index.ToString());//???????????
}
对16个点添加判断功能。
#region 输出点12
private void radioButton26_CheckedChanged(object sender, EventArgs e)
{
if (radioButton26.Checked == true)
{
//MessageBox.Show("输出点12为高电平");
SetY(12);
}
else
//MessageBox.Show("输出点12为低电平");
RstY(12);
}
#endregion
单轴控制模块
其实可以手动调用多个电机转动。
由于笔者购置的板卡只有4轴,故只写出四轴点动。
刷新界面
点动时需要实时刷新界面的参数,防止撞机,故笔者使用30ms的计时器刷新界面。
#region 刷新信息
private void timer1_Tick(object sender, EventArgs e)
{
short rtn;
int i = 0;
int POS1 = 0;
int POS2 = 0;
int POS3 = 0;
int POS4 = 0;
double Command_Vel1 = 0;
double Command_Vel2 = 0;
double Command_Vel3 = 0;
double Command_Vel4 = 0;
double Encode_Vel1 = 0;
double Encode_Vel2 = 0;
double Encode_Vel3 = 0;
double Encode_Vel4 = 0;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_Get_Position_Net(0, ref POS1, StationNumber); //获取轴1当前位置
rtn = CMCDLL_NET.MCF_Get_Position_Net(1, ref POS2, StationNumber); //获取轴2当前位置
rtn = CMCDLL_NET.MCF_Get_Position_Net(2, ref POS3, StationNumber); //获取轴3当前位置
rtn = CMCDLL_NET.MCF_Get_Position_Net(3, ref POS4, StationNumber); //获取轴4当前位置
textBox3.Text = POS1.ToString(); //轴1位置信息显示到textBox3中
textBox6.Text = POS2.ToString(); //轴2位置信息显示到textBox6中
textBox8.Text = POS3.ToString(); //轴3位置信息显示到textBox8中
textBox10.Text = POS4.ToString(); //轴4位置信息显示到textBox10中
rtn = CMCDLL_NET.MCF_Get_Vel_Net(0, ref Command_Vel1, ref Encode_Vel1, StationNumber); //获取轴1当前速度
rtn = CMCDLL_NET.MCF_Get_Vel_Net(1, ref Command_Vel2, ref Encode_Vel2, StationNumber); //获取轴2当前速度
rtn = CMCDLL_NET.MCF_Get_Vel_Net(2, ref Command_Vel3, ref Encode_Vel3, StationNumber); //获取轴3当前速度
rtn = CMCDLL_NET.MCF_Get_Vel_Net(3, ref Command_Vel4, ref Encode_Vel4, StationNumber); //获取轴4当前速度
textBox4.Text = Command_Vel1.ToString(); //轴1速度信息显示到textBox4中
textBox5.Text = Command_Vel2.ToString(); //轴2速度信息显示到textBox5中
textBox7.Text = Command_Vel3.ToString(); //轴3速度信息显示到textBox7中
textBox9.Text = Command_Vel4.ToString(); //轴4速度信息显示到textBox9中
}
#endregion
轴1+点动(位移伺服模式)
笔者使用了三元运算符来减少代码量。
S型启动与T型启动读者自行脑补。
笔者手头没有编码器,故只靠带编码盘的闭环步进电机套装实现半闭环。读者可自行加装多摩川等厂家的编码盘实现全闭环,也可购置手轮实现手动控制电机圈数。
#region 轴1+点动
private void button1_Click(object sender, EventArgs e)
{
short rtn;
double Vini = 0;
double Vend = 0;
double VEL = 0;
double Vmax = 0;
double Vjerk = 0;
int POS = 0;
ushort Profile = 0;
ushort Position_Mode = 0;
double.TryParse(textBox11.Text, out Vini);
double.TryParse(textBox15.Text, out Vend);
double.TryParse(textBox12.Text, out VEL);
double.TryParse(textBox13.Text, out Vmax);
double.TryParse(textBox14.Text, out Vjerk);
int.TryParse(textBox1.Text, out POS);
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
//Profile = (ushort)comboBox_Profile.SelectedIndex;
//Position_Mode = (ushort)comboBox_Position.SelectedIndex;
Profile = (ushort)(radioButton1.Checked ? 0 : 1);
Position_Mode = (ushort)(radioButton4.Checked?0:1);
//MessageBox.Show(Profile.ToString()+"\n"+Position_Mode.ToString());
rtn = CMCDLL_NET.MCF_Set_Axis_Profile_Net(0, Vini, VEL, Vmax, Vjerk, Vend, Profile, StationNumber);
rtn = CMCDLL_NET.MCF_Uniaxial_Net(0, POS, Position_Mode, StationNumber);//轴1正向点位运动
}
#endregion
轴2-点动(位移伺服模式)
对POS参数取反即可。
#region 轴1-点动
private void button2_Click(object sender, EventArgs e)
{
short rtn;
double Vini = 0;
double Vend = 0;
double VEL = 0;
double Vmax = 0;
double Vjerk = 0;
int POS = 0;
ushort Profile = 0;
ushort Position_Mode = 0;
double.TryParse(textBox11.Text, out Vini);
double.TryParse(textBox15.Text, out Vend);
double.TryParse(textBox12.Text, out VEL);
double.TryParse(textBox13.Text, out Vmax);
double.TryParse(textBox14.Text, out Vjerk);
int.TryParse(textBox1.Text, out POS);
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
Profile = (ushort)(radioButton1.Checked ? 0 : 1);
Position_Mode = (ushort)(radioButton4.Checked ? 0 : 1);
rtn = CMCDLL_NET.MCF_Set_Axis_Profile_Net(0, Vini, VEL, Vmax, Vjerk, Vend, Profile, StationNumber);
rtn = CMCDLL_NET.MCF_Uniaxial_Net(0, -POS, Position_Mode, StationNumber);//轴1反向点位运动
}
#endregion
其余2轴与之相似,笔者在此不再赘述。
缓停
S型曲线于T型曲线停止读者自行脑补。
#region 缓停
private void button9_Click(object sender, EventArgs e)
{
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(0, 10000, 100000, 1, StationNumber);//设置轴1S型停止曲线参数
rtn = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(1, 10000, 100000, 1, StationNumber);//设置轴2S型停止曲线参数
rtn = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(2, 10000, 100000, 1, StationNumber);//设置轴3S型停止曲线参数
rtn = CMCDLL_NET.MCF_Set_Axis_Stop_Profile_Net(3, 10000, 100000, 1, StationNumber);//设置轴4S型停止曲线参数
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(0, 1, StationNumber);//设置轴1为平滑停止模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(1, 1, StationNumber);//设置轴1为平滑停止模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(2, 1, StationNumber);//设置轴1为平滑停止模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(3, 1, StationNumber);//设置轴1为平滑停止模式
}
#endregion
急停
#region 急停
private void button10_Click(object sender, EventArgs e)
{
short rtn;
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(0, 0, StationNumber);//设置轴1为急停模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(1, 0, StationNumber);//设置轴2为急停模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(2, 0, StationNumber);//设置轴3为急停模式
rtn = CMCDLL_NET.MCF_Axis_Stop_Net(3, 0, StationNumber);//设置轴4为急停模式
}
#endregion
轴1连续正转(速度伺服模式)
#region 轴1+连续
private void button20_Click(object sender, EventArgs e)
{
short rtn;
double VEL = 0;
double Vjerk = 0;
double.TryParse(textBox12.Text, out VEL);
double.TryParse(textBox14.Text, out Vjerk);
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_JOG_Net(0, VEL, Vjerk, StationNumber);//轴1正向连续运动
}
#endregion
轴1连续反转(速度伺服模式)
#region 轴1-连续
private void button19_Click(object sender, EventArgs e)
{
short rtn;
double VEL = 0;
double Vjerk = 0;
double.TryParse(textBox12.Text, out VEL);
double.TryParse(textBox14.Text, out Vjerk);
ushort StationNumber = 0;
StationNumber = (ushort)comboBox1.SelectedIndex;
rtn = CMCDLL_NET.MCF_JOG_Net(0, -VEL, Vjerk, StationNumber);//轴1反向连续运动
}
#endregion
VEL参数取反即可。
多轴拟合运动模块
环形轨迹
#region 环形轨迹
private void button1_Click(object sender, EventArgs e)
{
short rtn = 0;
ushort[] Axis_List = { 0, 1 };//插补轴列表:0轴,1轴
int[] dDist_List = { 0, 0 };
uint Command_Number = 0;
ushort StationNumber = 0;
double dV_ini;
double dV_end;
double dMaxV;
double dMaxA;
double dJerk;
double dMaxA_Time = 0.01; // 10ms加速度时间
double dJerk_Time = 0.01;
StationNumber = (ushort)0;
dV_ini = 1000; //开始速度 1K
dMaxV = 10000; //最大速度 10K
dMaxA = 10000 / dMaxA_Time; //最大加速度 = 速度 / 加速度时间
dJerk = dMaxA / dJerk_Time; //最大加加速度 = 加速度 / 加加速度时间
dV_end = 1000; //结束速度 1K
rtn = CMCDLL_NET.MCF_Buffer_Start_Net(0, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Set_Profile_Net(0, dV_ini, dMaxV, dMaxA, dJerk, dV_end, 1, StationNumber);
dDist_List[0] = 10000;
dDist_List[1] = 0;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
dDist_List[0] = 0;
dDist_List[1] = -10000;
rtn = CMCDLL_NET.MCF_Buffer_Arc_Radius_Net(0, ref Axis_List[0], ref dDist_List[0], 5000, 0, 1, StationNumber);
dDist_List[0] = -10000;
dDist_List[1] = 0;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
dDist_List[0] = 0;
dDist_List[1] = 10000;
rtn = CMCDLL_NET.MCF_Buffer_Arc_Radius_Net(0, ref Axis_List[0], ref dDist_List[0], 5000, 0, 1, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_End_Net(0, ref Command_Number, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Execute_Net(0, 1, StationNumber);
}
#endregion
正方形轨迹
#region 正方形轨迹
private void button3_Click(object sender, EventArgs e)
{
short rtn = 0;
ushort Count = 0;
ushort[] Axis_List = { 0, 1 };
int[] dDist_List = { 0, 0 };
uint Command_Number = 0;
ushort StationNumber = 0;
double dV_ini = 0;
double dV_end = 0;
double dMaxV = 0;
double dMaxA = 0;
double dJerk = 0;
double dMaxA_Time = 0.01; // 10ms加速度时间
double dJerk_Time = 0.01;
StationNumber = (ushort)0;
dV_ini = 1000; //开始速度 1K
dMaxV = 10000; //最大速度 10K
dMaxA = 10000 / dMaxA_Time; //最大加速度 = 速度 / 加速度时间
dJerk = dMaxA / dJerk_Time; //最大加加速度 = 加速度 / 加加速度时间
dV_end = 1000; //结束速度 1K
rtn = CMCDLL_NET.MCF_Buffer_Start_Net(0, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Set_Profile_Net(0, dV_ini, dMaxV, dMaxA, dJerk, dV_end, 1, StationNumber);
dDist_List[0] = 10000;
dDist_List[1] = 0;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
dDist_List[0] = 0;
dDist_List[1] = -10000;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
dDist_List[0] = -10000;
dDist_List[1] = 0;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
dDist_List[0] = 0;
dDist_List[1] = 10000;
rtn = CMCDLL_NET.MCF_Buffer_Line2_Net(0, ref Axis_List[0], ref dDist_List[0], 1, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_End_Net(0, ref Command_Number, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Execute_Net(0, 1, StationNumber);
}
#endregion
三轴螺旋插补
#region 3轴螺旋形插补
private void button4_Click(object sender, EventArgs e)
{
short rtn = 0;
ushort[] Axis_List = { 0, 1 };
int[] dDist_List = { 0, 0 };
uint Command_Number = 0;
ushort StationNumber = 0;
double dV_ini = 0;
double dV_end = 0;
double dMaxV = 0;
double dMaxA = 0;
double dJerk = 0;
double dMaxA_Time = 0.01;
double dJerk_Time = 0.01;
StationNumber = (ushort)0;
dV_ini = 1000; //开始速度 1K
dMaxV = 10000; //最大速度 10K
dMaxA = 10000 / dMaxA_Time; //最大加速度 = 速度 / 加速度时间
dJerk = dMaxA / dJerk_Time; //最大加加速度 = 加速度 / 加加速度时间
dV_end = 1000; //结束速度 1K
rtn = CMCDLL_NET.MCF_Buffer_Start_Net(0, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Set_Profile_Net(0, dV_ini, dMaxV, dMaxA, dJerk, dV_end, 1, StationNumber);
for (int ii = 0; ii < 5; ii++)
{
rtn = CMCDLL_NET.MCF_Buffer_Sync_Follow_Net(0, 2, 1000, StationNumber);
dDist_List[0] = 10000;
dDist_List[1] = 10000;
rtn = CMCDLL_NET.MCF_Buffer_Arc_Radius_Net(0, ref Axis_List[0], ref dDist_List[0], 5000, 0, 1, StationNumber);
}
rtn = CMCDLL_NET.MCF_Buffer_End_Net(0, ref Command_Number, StationNumber);
rtn = CMCDLL_NET.MCF_Buffer_Execute_Net(0, 1, StationNumber);
}
#endregion
笔者只写了3种模式,不代表本款板卡只能拟合这4种曲线。
事实上,只要算法合适,Bézier curve、B-spline curve、Nburs curve甚至读取CAD的dwg图纸都不是问题。笔者也只有做SCARA四轴机械臂的小本事。欢迎有大本事的读者写个6轴算法,做个CNC,笔者也沾沾光。
尾言
常用的板卡还有固高卡、雷赛卡,考虑到笔记本电脑没有PCI及PCI-e插槽,笔者选用了RJ45口的板卡。
领导阶级眼里不如机修和电工、夜班周末班“实在”的脑力劳动成果,应该是属于全体地球人类的。