QT实现步进电机控制和IMU数据读取显示

实现功能:

1.两步进电机分别使能和循环运动,可以设置循环次数、循环里分别运行的角度、旋转的速度和加减速度等等,在最下方的表格里显示发送和接收的CAN报文

2.读取水平电机当前位置和速度并画图显示,示波器暂停、缩放、滑动等功能

3.MCU监听串口IMU数据并通过TCP客户端发出

4.QT服务端接收TCP数据并进行解析,显示对应波形

监听TCP客户端

QT软件在初始化时,对指定TCP端口进行监听,并在成功连接后执行数据监听

Widget::Widget(QWidget *parent):
     QWidget(parent),
     ui(new Ui::Widget),
     time(QTime::currentTime())
{
    tcpServer = new QTcpServer(this);   //创建一个服务器类
    tcpSocket = new QTcpSocket(this);   //创建一个socket类
    tcpServer->listen(QHostAddress::Any,ui->portEdit->text().toUInt());    //服务器对端口号进行监听
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection_slot())); //有网络用户连接进来,就会执行槽函数
}

//当连接客户端tcp,执行相关函数
void Widget::newConnection_slot()
{
    qDebug() << "connected";
    tcpSocket = tcpServer->nextPendingConnection();     //获取与客户端进行通信的套接字
    ui->TCPButton->setStyleSheet("background:rgb(85,255,127)");
    connect(tcpSocket,&QTcpSocket::disconnected,this,&Widget::disonnection_slot); //有网络用户断开连接
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_slot())); //客户端有数据到达服务器,就会产生readyRead信号
}
//当客户端断开连接执行相关函数
void Widget::disonnection_slot(){
    qDebug() << "disconnected";
    ui->TCPButton->setStyleSheet("background:rgb(255,255,127)");//按钮变绿提示已连接
}
//当有数据来,更新波形图
void Widget::readyRead_slot()
{
    int num = tcpSocket->read((char *)&imu_data_,sizeof(ImuData)*10);
    for(int i=0;i<(num/112);i++){
        PlotViewUpdate(1,imu_data_[i].gyro.z*PI/(180*16.4));
        PlotViewUpdate(3,imu_data_[i].ypr.yaw);
    }
    //ui->receTCPEdit->setText(QString::number(imu_data_[0].cnt));
}

这里imu_data_为结构体类型,这样服务端就能一次性接收完数据,无需按照各个变量分别接收

    struct ImuQuat {
        double w;
        double x;
        double y;
        double z;
    };
    struct ImuAcc {
        int16_t x;
        int16_t y;
        int16_t z;
    };

    struct ImuGyro {
        int16_t x;
        int16_t y;
        int16_t z;
    };

    struct ImuYpr {
        double yaw;
        double pitch;
        double roll;
    };

    struct ImuData {
        uint64_t timestamp;
        ImuQuat quat;
        ImuAcc acc;
        ImuGyro gyro;
        ImuGyro gyro_offset;
        ImuYpr ypr;
        uint16_t update_rate;
        uint64_t cnt;
        uint64_t imu_time;
    };
    ImuData imu_data_[10];

对于客户端,发送方式与之对应,imu_data_的数据格式与服务端一致

send(client_sockfd,(char*)&imu_data_,sizeof(ImuData),0);

CAN通信

使用ControlCAN库,需要对应版本,否则可以成功运行,但是Debug会报程序异常终止的错误

根据文档需要使能电机,激活操作模式为位置模式,同时设置运动参数,包括速度、加速度、减速度等,这样就完成了CAN电机的基本配置。

这里需要电机可以多段一直运行,设置电机的目标位置,启动多段运行。

在第一段运行后,执行CAN命令可以直接运行下一段 

 其中,数据的后四字节为数据,40 0D 03 00代表200000,而对应的十六进制为30D40,即按一字节划分,低位在前,符号位代表旋转的方向。

 CAN PDO通信(过程数据对象)

SDO是发-收的形式,频率无法提升,在读取电机速度时频率只有5Hz,这里考虑用PDO自动发送的方式提升数据更新频率。

1.PDO映射对应的SDO报文

采用Tx-PDO2

节点地址:280h + 1=281 COB_ID范围1-7F

第一步:关闭PDO分配功能,把对应PDO的COB-ID的最高位置1;

关闭TPDO2,报文:23 01 18 01 80 02 00 80

第二步:清除原有有映射的内容,把0X1600~0X1603和0X1A00~1A03的子索引置0;

设置映射对象的数量为0,报文为:2F 01 1A 00 00 00 00 00

第三步:写入PDO映射内容;

映射对象0X606C到TPDO2的子索引1中,报文为:23 01 1A 01 40 00 6C 60 电机速度

映射对象0X6064到TPDO2的子索引2中,报文为:23 01 1A 02 40 00 64 60 电机位置

此时发送报文的格式为:

第四步:写入该PDO映射对象的总个数;

设置映射对象总数量为2,报文为2F 01 1A 00 02 00 00 00

第五步:重新打开PDO分配功能,把对应PDO的COB-ID的最高位置0;

开启TPDO2,报文:23 01 18 01 80 02 00 00

第六步:保存所有参数,给对象字典(OD)1010的子索引0x01中写入“65766173h”(ASCII码:save)时执行保存;处理完成后,无论是否成功,此对象的值自动恢复为0;

保存所有参数,报文:23 10 10 01 73 61 76 65

2.配置异步模式的报文

同步模式需要同步帧,这里采用异步模式,当无事件发生时,按照Event timer上传数据;当有事件发生时,数据会立即上传。

配置异步模式的步骤:

第一步:将NMT状态切换到运行状态;

将NMT状态切换到运行状态:01 01 将COB_ID设置000

第二步:配置异步TPDO通道;

配置异步模式:23 01 18 02 FF 00 00 00

第三步:如果要读取驱动器相关参数,需要把NMT状态机切换到运行状态;
第四步:改变相关参数,数据会立即上传;
第五步:异步模式下设置Event timer

异步模式下,设置Event timer:2B 01 18 05 D0 07 00 00(设置事件时间为2000ms),当无事件发生时,按照2s上传数据;当有事件发生时,数据会立即上传;

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的MATLAB代码示例,用于IMU数据采集和里程计实现: ```matlab % 初始化IMU和里程计 imu = imuSensor('SampleRate', 100); odo = odometer('TrackWidth', 0.5, 'TicksPerRev', 360); % 开始采集数据 imuData = zeros(1000, 6); odoData = zeros(1000, 3); for i = 1:1000 % 获取IMU数据 [accel, gyro] = readAcceleration(imu); imuData(i, :) = [accel, gyro]; % 获取里程计数据 [v, w] = readVelocity(odo); odoData(i, :) = [v, w]; % 更新里程计 update(odo, v, w, imu.SampleTime); end % 绘制采集到的数据 t = (1:1000)/imu.SampleRate; subplot(2, 1, 1); plot(t, imuData(:, 1:3)); title('IMU Acceleration Data'); legend('X', 'Y', 'Z'); ylabel('Acceleration (m/s^2)'); xlabel('Time (s)'); subplot(2, 1, 2); plot(t, imuData(:, 4:6)); title('IMU Gyro Data'); legend('X', 'Y', 'Z'); ylabel('Angular Velocity (rad/s)'); xlabel('Time (s)'); figure; plot(odoData(:, 1), odoData(:, 2)); title('Odometry Data'); xlabel('Distance (m)'); ylabel('Angle (rad)'); ``` 这个代码示例中,我们首先初始化了一个IMU传感器和一个里程计,并使用一个循环来连续读取它们的数据IMU数据保存在`imuData`数组中,里程计数据保存在`odoData`数组中。我们还使用`update`函数来更新里程计的状态。 最后,我们使用MATLAB的绘图功能来绘制采集到的数据。`subplot`函数用于创建一个包含多个子图的图形窗口。在这个示例中,我们绘制了IMU加速度和陀螺仪数据的子图,以及里程计数据的单独子图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值