在一些控制多轴电机运动的场景下,除了需要驱动器驱动该轴的电机外,还需要用到控制卡协调各轴驱动器的运动控制。为了方便用户使用,往往还需要编写满足功能需求的上位机程序。为了方便演示Qt开发固高控制卡上位机程序的过程,这里基于Qt 5.9.0和C++实现的是最一般的上位机功能,包括运动控制卡的初始化、使能、Z轴的点位运动功能(需要用户输入点位运动的参数:行程、速度、加速度和减速度)。控制对象是Z轴方向运动的光学显微平台。使用顺序:初始化→使能→给定Pos,Vel,Acc,Dcc→写入→点击“下”即电机向下运动。
本文演示的上位机程序界面
控制对象:光学显微平台
硬件部分采用GTS-VB系列4轴插卡式固高运动控制卡作为上层规划指令的发送者,与固高运动控制卡搭配使用的还有端子板。控制卡通过PCI总线插槽与上位机进行通讯,同时控制卡通过CN17连接线连接端子板,端子板上有一系列IO口和轴接口,通过轴接口可以连接各轴驱动器。这里使用的是高创驱动器。
控制系统示意图
GTS-VB系列4轴插卡式固高运动控制卡
我们使用固高控制卡的开环控制模式(脉冲控制),设置高创驱动器为位置齿轮模式。伺服系统的三环控制都在驱动器完成,关于高创驱动器控制算法的调试,请参考高创驱动器的用户手册。应用程序指令是上位机发出的运动规划、IO等指令,经过运动控制器转为底层的运动指令,最终以脉冲的形式发给驱动器。如果在使用过程中遇到复杂问题,可以进一步查阅官方手册《编程手册:GTS运动控制器-基本功能_R1.4》(固高的使用手册编写得还是对用户较为友好的,使用方法比较详细,同时有很多使用例程供用户参考)。
固高控制卡的开环控制模式(脉冲控制)
1、配置驱动器
首先,配置高创驱动器,反馈采用增量式数字量光栅尺,分辨率为0.1μm(10000cnt=1mm),
反馈设置
增量式数字量反馈的每转线数=电机节距/光栅尺分辨率/4倍频,然后需要根据实际需求整定高创的控制器参数,使得运动平台的定位精度和响应满足要求。在此就不赘述了。
数字I/O设置
在数字IO中需要设置远端使能(remote enable)。
设置运动模式
因为电机的每转线数是120000LPP,而在位置齿轮模式中的“转外部脉冲”是每转脉冲数,脉冲与线数之间是4倍关系,因此“转外部脉冲”设置为480000。“电子齿轮分子”和“电子齿轮分母”均可设置为1,表示固高每发送10000cnt电机就运动1mm。这里设置为-1是因为期望的方向与实际电机运动方向相反。
2、配置固高控制卡
下一步是通过固高控制卡自带的上位机软件MCT2008配置固高控制卡。在Windows系统下使用运动控制器,首先要安装驱动程序和动态链接库。驱动程序和动态链接库请通过固高科技官网固高科技 (googoltech.com.cn)下载。安装过程和使用方法可以参考固高相应的使用手册。
打开MCT2008软件,开环模式下 axis 配置流程如下(参考《编程手册:GTS运动控制器-基本功能_R1.4》——4.5.1 开环控制模式):
固高控制卡自带的上位机软件MCT2008
在“工具”-“控制器配置”中,设置需要运动的轴(这里为轴3),将“axis”这一项红框中的各个编号都设置为“none”,然后选择控制器配置中的“控制”-“写入控制器状态”,此时在“视图”-“轴状态”-3轴状态可以看到指示灯都为绿色,表明各个状态都无错误。其他设置则选择默认。
点击“伺服使能”按钮可以使能电机,指示灯为红色。在“视图”-“点位运动”可以打开点位运动窗口,点击“启动运动”即可启动电机。
在“控制器配置”窗口中,点击“文件”-“写入到文件”可以将上述配置保存成.cfg文件,以便后续上位机使用。
保存控制卡的配置文件
3、编写上位机程序
最简单的开发可以参考实现与固高上位机功能类似的上位机软件。首先导入固高控制卡的动态链接库,要使用的是dll\VC\64bit\single_card中的3个文件:gts.dll,gts.h和gts.lib,将这3个文件复制到Qt工程目录下面,
复制需要的3个文件
放到Qt工程目录下
然后需要在Qt中指定链接库,右击项目,添加“外部库”,添加当前项目目录下的gts.lib库文件,
在Qt中指定链接库
同时还需要添加gts.h头文件到Qt项目中,
通过调用库文件中相关的API接口函数来实现相应的功能。固高控制卡封装好的API接口函数都是GT_开头的,可以直接在程序中调用,而且官方手册《编程手册:GTS运动控制器-基本功能_R1.4》(还有高级功能版本则主要涉及控制卡的PT运动模式、PVT运动模式等,这里没有涉及到就不作介绍了)也对函数的使用方法有很详细的例程,很多语句甚至可以直接复制到上位机程序中。
接着开始设计用户界面,这里包括了初始化按钮pbn_Init、使能按钮pbn_Enable、写入按钮pbn_Write、向上运动按钮pbn_Up、向下运动按钮pbn_Down和行程、速度、加速度、减速度输入框lineEdit_Pos、lineEdit_Vel、lineEdit_Acc和lineEdit_Dcc。其中使能按钮pbn_Enable需要勾选“checkable”属性,默认状况下checkable是不选中的,Button默认为触发按钮(trigger button),按下去马上弹起来。选中checkable后,Button变成切换按钮(toggle button),可以有两种状态:按下/弹起。因为电机有使能和去使能两种状态,对应的就是开关的开和关。当pbn_Enable处于按下状态的时候checked为true,否则为false。
然后转到pbn_Enable的toggled(bool)信号的槽,编写使能按钮的槽函数(或者使用Lambda表达式):
1 //使能按钮,槽函数
2 void MainWindow::on_pbn_Enable_toggled(bool checked)
3 {
4 if (checked)
5 {
6 GT_AxisOn(this->Z_num);//Z轴打开驱动器使能
7 }
8 else
9 {
10 GT_AxisOff(this->Z_num);//关闭驱动器使能
11 }
12 }
注:在连接信号和槽的时候,槽函数可以使用Lambda表达式的方式进行处理。在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。
1 //使能按钮的Lambda表达式
2 connect(ui->pbn_Enable, &QPushButton::toggled, [=](){
3 if(ui->pbn_Enable->isChecked())
4 GT_AxisOn(this->Z_num);//Z轴打开驱动器使能
5 else
6 GT_AxisOff(this->Z_num);//Z轴打开驱动器使能
7 });
同样的可以编写初始化按钮pbn_Init的槽函数:
1 //初始化按钮,槽函数
2 void MainWindow::on_pbn_Init_clicked()
3 {
4 ui->pbn_Enable->setChecked(false);//关闭驱动器使能按钮
5 GT_Open();//在使用运动控制器之前,首先需要使用 GT_Open 指令打开运动控制器,和运动控制器建立通讯;只要在应用程序初始化阶段调用一次 GT_Open
6 GT_Reset();//调用 GT_Reset 指令将使运动控制器的所有寄存器恢复到默认状态,一般在打开运动控制器之后调用该指令。
7 GT_LoadConfig("GTS800.cfg");//下载配置信息到运动控制器,调用该指令后需再调用 GT_ClrSts 才能使该指令生效
8 GT_EncOff(3);//将轴3设置为“脉冲计数器”计数方式。
9 GT_ClrSts(1,4);//清除驱动器报警标志、跟随误差越限标志、限位触发标志
10 flag = 1;
11 }
在实现点位运动按钮的功能之前,可以先编写点位运动函数:
1 //点位运动函数,可参考固高编程手册基本功能例程 6-1 点位运动
2 void MainWindow::pointMotion(int num,long pos)//参数num是轴号,pos是点位运动的距离
3 {
4 TTrapPrm trap;//点位运动模式的运动参数,该参数为一个结构体,包含四个参数:加速度,减速度,起跳速度和平滑时间
5 GT_ZeroPos(num);//num轴位置清零
6 GT_SetPrfPos(num, 0);//num轴规划位置清零
7 GT_PrfTrap(num);//将num轴设为点位模式
8 GT_GetTrapPrm(num, &trap);//读取点位运动参数(需要读取所有运动参数到上位机变量)
9 // 设置需要修改的运动参数
10 trap.acc = this->Acc;
11 trap.dec = this->Dcc;
12 trap.smoothTime = 0;//这里假设平滑时间为0
13 GT_SetTrapPrm(num, &trap);//设置点位模式运动下的运动参数
14 GT_SetPos(num, pos);//设置num轴的目标位置
15 GT_SetVel(num, this->Vel);//设置num轴的目标速度
16 GT_Update(1<<(num-1));//启动num轴的运动
17 }
然后用户通过输入框指定点位运动的四个参数,再点击写入按钮pbn_Write保存运动参数:
1 //写入按钮,槽函数
2 void MainWindow::on_pbn_Write_clicked()
3 {
4 QString str1;
5 QString str2;
6 QString str3;
7 QString str4;
8 str1 = ui->lineEdit_Pos->text();//Pos位置输入框的内容
9 str2 = ui->lineEdit_Vel->text();
10 str3 = ui->lineEdit_Acc->text();
11 str4 = ui->lineEdit_Dcc->text();
12 if(str2 == NULL)
13 str2 = "20";//若输入框无内容,则程序设置速度、加速度和减速度的默认值
14
15 if(str3 == NULL)
16 str3 = "1";
17
18 if(str4 == NULL)
19 str4 = "1";
20 this->Pos = qAbs(str1.toLong());//将string类型转换为long类型
21 this->Vel = qAbs(str2.toDouble());
22 this->Acc = qAbs(str3.toDouble());
23 this->Dcc = qAbs(str4.toDouble());
24 }
最后,两个运动按钮可直接调用上述函数:
1 //向上运动按钮,槽函数
2 void MainWindow::on_pbn_Up_clicked()
3 {
4 if(flag == 1)
5 {
6 pointMotion(Z_num,this->Pos);//开始点位运动
7 }
8 }
9
10 //向下运动按钮,槽函数
11 void MainWindow::on_pbn_Down_clicked()
12 {
13 if(flag == 1)
14 {
15 pointMotion(Z_num,-this->Pos);//开始点位运动
16 }
17 }
完整的头文件和源代码文件程序如下:
mainwindow.h文件:
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include "gts.h"
6
7 namespace Ui {
8 class MainWindow;
9 }
10
11 class MainWindow : public QMainWindow
12 {
13 Q_OBJECT
14
15 public:
16 explicit MainWindow(QWidget *parent = 0);
17 ~MainWindow();
18
19 int Z_num = 3; //Z轴对应轴号
20 int flag = 0; //初始化标志
21 long Pos = 0; //位置/速度/加速度/减速度 用户输入值
22 double Vel = 1;
23 double Acc = 1;
24 double Dcc = 1;
25 void pointMotion(int num,long pos);
26
27 private slots:
28 void on_pbn_Init_clicked();//按钮“初始化”
29 void on_pbn_Enable_toggled(bool checked);//按钮“使能”
30 void on_pbn_Write_clicked();//按钮“写入”
31 void on_pbn_Up_clicked();//按钮“上”
32 void on_pbn_Down_clicked();
33
34 private:
35 Ui::MainWindow *ui;
36 };
37
38 #endif // MAINWINDOW_H
mainwindow.cpp文件:
1 #include "mainwindow.h"
2 #include "ui_mainwindow.h"
3
4 MainWindow::MainWindow(QWidget *parent) :
5 QMainWindow(parent),
6 ui(new Ui::MainWindow)
7 {
8 ui->setupUi(this);
9
10 this->setWindowTitle(tr("Z轴上位机实验"));
11
12 // //使能按钮的Lambda表达式
13 // connect(ui->pbn_Enable, &QPushButton::toggled, [=](){
14 // if(ui->pbn_Enable->isChecked())
15 // GT_AxisOn(this->Z_num);//Z轴打开驱动器使能
16 // else
17 // GT_AxisOff(this->Z_num);//Z轴打开驱动器使能
18 // });
19 }
20
21 MainWindow::~MainWindow()
22 {
23 GT_AxisOff(this->Z_num);//在析构函数中可以去使能,即关闭窗口的同时,电机去使能
24 delete ui;
25 }
26
27 //点位运动函数,可参考固高编程手册基本功能例程 6-1 点位运动
28 void MainWindow::pointMotion(int num,long pos)//参数num是轴号,pos是点位运动的距离
29 {
30 TTrapPrm trap;//点位运动模式的运动参数,该参数为一个结构体,包含四个参数:加速度,减速度,起跳速度和平滑时间
31 GT_ZeroPos(num);//num轴位置清零
32 GT_SetPrfPos(num, 0);//num轴规划位置清零
33 GT_PrfTrap(num);//将num轴设为点位模式
34 GT_GetTrapPrm(num, &trap);//读取点位运动参数(需要读取所有运动参数到上位机变量)
35 // 设置需要修改的运动参数
36 trap.acc = this->Acc;
37 trap.dec = this->Dcc;
38 trap.smoothTime = 0;//这里假设平滑时间为0
39 GT_SetTrapPrm(num, &trap);//设置点位模式运动下的运动参数
40 GT_SetPos(num, pos);//设置num轴的目标位置
41 GT_SetVel(num, this->Vel);//设置num轴的目标速度
42 GT_Update(1<<(num-1));//启动num轴的运动
43 }
44
45 //初始化按钮,槽函数
46 void MainWindow::on_pbn_Init_clicked()
47 {
48 ui->pbn_Enable->setChecked(false);//关闭驱动器使能按钮
49 GT_Open();//在使用运动控制器之前,首先需要使用 GT_Open 指令打开运动控制器,和运动控制器建立通讯;只要在应用程序初始化阶段调用一次 GT_Open
50 GT_Reset();//调用 GT_Reset 指令将使运动控制器的所有寄存器恢复到默认状态,一般在打开运动控制器之后调用该指令。
51 GT_LoadConfig("GTS800.cfg");//下载配置信息到运动控制器,调用该指令后需再调用 GT_ClrSts 才能使该指令生效
52 GT_EncOff(3);//将轴3设置为“脉冲计数器”计数方式。
53 GT_ClrSts(1,4);//清除驱动器报警标志、跟随误差越限标志、限位触发标志
54 flag = 1;//初始化标志
55 }
56
57 //使能按钮,槽函数
58 void MainWindow::on_pbn_Enable_toggled(bool checked)
59 {
60 if (checked)
61 {
62 GT_AxisOn(this->Z_num);//Z轴打开驱动器使能
63 }
64 else
65 {
66 GT_AxisOff(this->Z_num);//关闭驱动器使能
67 }
68 }
69
70 //写入按钮,槽函数
71 void MainWindow::on_pbn_Write_clicked()
72 {
73 QString str1;
74 QString str2;
75 QString str3;
76 QString str4;
77 str1 = ui->lineEdit_Pos->text();//Pos位置输入框的内容
78 str2 = ui->lineEdit_Vel->text();
79 str3 = ui->lineEdit_Acc->text();
80 str4 = ui->lineEdit_Dcc->text();
81 if(str2 == NULL)
82 str2 = "20";//若输入框无内容,则程序设置速度、加速度和减速度的默认值
83
84 if(str3 == NULL)
85 str3 = "1";
86
87 if(str4 == NULL)
88 str4 = "1";
89 this->Pos = qAbs(str1.toLong());//将string类型转换为long类型
90 this->Vel = qAbs(str2.toDouble());
91 this->Acc = qAbs(str3.toDouble());
92 this->Dcc = qAbs(str4.toDouble());
93 }
94
95 //向上运动按钮,槽函数
96 void MainWindow::on_pbn_Up_clicked()
97 {
98 if(flag == 1)
99 {
100 pointMotion(Z_num,this->Pos);//开始点位运动
101 }
102 }
103
104 //向下运动按钮,槽函数
105 void MainWindow::on_pbn_Down_clicked()
106 {
107 if(flag == 1)
108 {
109 pointMotion(Z_num,-this->Pos);//开始点位运动
110 }
111 }
考虑到后续程序的发布,且debug版本程序依赖的dll文件很大,一般使用release版本。在Qt左下角的目标选择器(Target selector)中将构建目标设置为Release,编译后项目目录文件夹即包含了release目录,再将配置固高卡时生成的配置文件GTS800.cfg放到release目录下。
至此完成了简单的上位机开发。