C#编写上位机驱动运动控制板卡

  • 项目概述
  • 控制原理
  • 功能实现
  • 上位机界面
  • 通讯连接模块
  • 断开连接模块
  • 刷新输入模块
  • 控制输出模块
  • 单轴控制模块
  • 刷新界面
  • 轴1+点动(位移伺服模式)
  • 轴2-点动(位移伺服模式)
  • 缓停
  • 急停
  • 轴1连续正转(速度伺服模式)
  • 轴1连续反转(速度伺服模式)
  • 多轴拟合运动模块
  • 环形轨迹
  • 正方形轨迹
  • 三轴螺旋插补
  • 尾言


项目概述

笔者曾自费1200软妹币购置了一款运动控制板卡,利用下班时间琢磨出上位机,用以取代传统的PLC控制系统。IO卡及运动卡均可走RJ45水晶头串联,可级联8块,最多4096IO点及256轴联动,延时2ms以内。某些型号具备脉冲控制、编码盘伺服控制、加加速度扭矩控制,性能及性价比都不逊色于PLC。笔者已完成了部分功能的编写。系虎彩全厂首次尝试不含PLC的运动控制系统。

控制原理

安装原厂驱动后,可以使用SDK包进行开发。笔者选用了RJ45直连的方式,较走交换机的TCP/IP模式延时更短,可靠性更好。经万用表测试为NPN型。
使用脉冲控制步进驱动器。伺服控制要复杂一些。

功能实现

上位机界面

使用VS2019,Win Form写出界面。

javascript做运动控制上位机编程 上位机运动控制卡_单片机


先用AI绘制个图放右下角。。。希望虎彩自动化水平越来越高。。。

主控界面用于调用其它功能模块。

先连接板卡,之后可以测试各种功能。使用完后断开。

通讯连接模块

javascript做运动控制上位机编程 上位机运动控制卡_运动学_02


此处需加以限定。

#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

刷新输入模块

javascript做运动控制上位机编程 上位机运动控制卡_控制器_03


javascript做运动控制上位机编程 上位机运动控制卡_运动学_04


javascript做运动控制上位机编程 上位机运动控制卡_运动学_05

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,用于图形化展示完全够用。

控制输出模块

javascript做运动控制上位机编程 上位机运动控制卡_运动学_06


初始化。

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

单轴控制模块

其实可以手动调用多个电机转动。

javascript做运动控制上位机编程 上位机运动控制卡_电脑硬件_07


由于笔者购置的板卡只有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参数取反即可。

多轴拟合运动模块

javascript做运动控制上位机编程 上位机运动控制卡_单片机_08

环形轨迹

#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口的板卡。

领导阶级眼里不如机修和电工、夜班周末班“实在”的脑力劳动成果,应该是属于全体地球人类的。