Linux+QT+SocketCAN:使用信号槽机制实现数据收发
最近在考虑采用面对对象的方式重新搭建机器人的主控程序框架,虽然之前的框架也是有这种思想在里面,但是总感觉还是有程序化编程的影子,很多地方的处理都不太理想,而且虽然之前也是一直在采用QT Creator作为IDE开发程序,但是实际上并没有怎么用QT的库,只是单纯的作为一个IDE来用,未免也是空守宝山而不入。
因此这次决定充分利用QT的库和信号槽机制来对程序框架进行重新构建。
0.开发环境
- HOST平台: Ubuntu16.04
- ARM平台:at91sam9x35
- QT版本: 5.13.1
1.分析
针对Linux上的CAN通信,Socket CAN提供了一种十分简单方便的解决方案,QT中并没有像QTcpSocket一样的库可以使用,因此仍然使用linux内核中提供的库。
考虑到电机等设备会循环向主控返回电机的状态信息,CAN的接收工作十分耗时,因此选择新建一个继承QObject的类,将其Moveto一个QThread中单独执行循环接收工作。
考虑到CAN和Motor对象均为Robot类的对象成员,而各个Motor对象需要调用CAN的发送接口向其他对象发送数据,为避免各对象成员之间的数据交互造成各种麻烦,因此在各对象成员中建立signal与slot,在Robot中进行connect。
eg:
Robot具有两个对象成员CAN和Motor
class Robot:public QObject
{
Q_OBJECT
public:
Robot();
~Robot();
...
CAN *mCAN;
Motor *Wheel_1;
...
}
CAN中构建数据发送槽
class CAN:public QObject
{
Q_OBJECT
...
public slots:
void Transmit(can_frame pFrame);
...
}
Motor中构建数据发送信号
class Motor:public QObject
{
Q_OBJECT
...
signals:
void sendCanMeg(can_frame pFrame);
...
}
Robot中将其连接
Robot::Robot()
{
...
mCAN = new CAN("can1");
Wheel_1= new Motor(WHEEL_1,SPEED_MODE)
connect(Wheel_1,&Motor::sendCanMeg,mCAN ,&CAN::Transmit);
...
}
2.源码
2.1 can.h
#ifndef CAN_H
#define CAN_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <fcntl.h> /*文件控制定义*/
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <Utilities.h>
#include <QDebug>
#include <unistd.h>
// CAN接收线程
class CAN_RcvThread :public QObject
{
Q_OBJECT
public:
CAN_RcvThread(QObject *parent = 0) ;
public slots:
void RcvMegThread(int s);
void stopRcvThread();
private:
bool isStop=