Qt 开发固高运动控制卡(高创驱动器)上位机程序
在一些控制多轴电机运动的场景下,除了需要驱动器驱动该轴的电机外,还需要用到控制卡协调各轴驱动器的运动控制。为了方便用户使用,往往还需要编写满足功能需求的上位机程序。为了方便演示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目录下。
