当前位置: 首页 > news >正文

QT实现固高运动控制卡示波器

目录

一、固高示波器

二、基于QCustomPlot实现示波器

三、完整源码


一、固高示波器

        固高运动控制卡自带的软件有一个示波器功能,可以实时显示速度的波形,可辅助分析电机的运行状态。但是我们基于sdk开发了自己的软件,无法再使用该功能,原因是2个软件不能同时与控制卡通信,故此需要我们自己再开发一个示波器。

固高示波器功能展示,功能包括多条曲线的显示、继续/暂停、左移、右移、设置、轴选择等。

二、基于QCustomPlot实现示波器

GCustomPlot简介与使用看官网就可以了

简介, Qt Plotting Widget QCustomPlot - Introduction

下载, Qt Plotting Widget QCustomPlot - Download

需要注意的是需要在pro文件中加入printsuppot模块,源码中使用该模块做pdf打印功能

QT       += printsupport

 参考固高的功能实现速度示波器效果如下

 QCustomPlot初始化设置

    m_customPlot = new QCustomPlot(this);m_customPlot->setObjectName(QLatin1String("customPlot"));ui->vlyPlot->addWidget(m_customPlot);m_customPlot->setBackground(QBrush(QColor("#474848")));m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom |QCP::iSelectPlottables);  /* 可拖拽+可滚轮缩放 */m_customPlot->legend->setVisible(true);

添加两条曲线图,addGraph

    m_customPlot->addGraph();m_customPlot->graph(0)->setPen(QPen(Qt::green, 3));m_customPlot->graph(0)->setName(QStringLiteral("实际速度"));m_customPlot->addGraph();m_customPlot->graph(1)->setPen(QPen(Qt::yellow, 3));m_customPlot->graph(1)->setName(QStringLiteral("规划速度"));

 左右移动,通过设置X轴的范围来改变,再使用replot函数更新视图

m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().lower - ui->spbStep->value(),m_customPlot->xAxis->range().upper - ui->spbStep->value());m_customPlot->replot();

网格线显示与隐藏

        m_customPlot->xAxis->grid()->setVisible(checked);m_customPlot->yAxis->grid()->setVisible(checked);m_customPlot->replot();

添加数据,示波器有向左自动滚动的效果,也是通过设置范围来实现

void OscilloscopeFrame::addData(double key, double actVel, double prfVel)
{m_customPlot->graph(0)->addData(key, actVel);m_customPlot->graph(1)->addData(key, prfVel);m_customPlot->xAxis->rescale();m_customPlot->graph(0)->rescaleValueAxis(false, true);m_customPlot->graph(1)->rescaleValueAxis(false, true);m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().upper,m_fixedLength, Qt::AlignRight);m_customPlot->replot(QCustomPlot::rpQueuedReplot);  /* 实现重绘 */
}

实时显示数据,通过定时器实现

    m_timer = new QTimer();connect(m_timer, &QTimer::timeout, updateData);m_timer->start(OSCILLOSCOPE_UPDATE_MSEC);

鼠标放在曲线上显示当前值,关联鼠标移动信号,映射坐标pixelToCoord

    connect(m_customPlot, SIGNAL(mouseMove(QMouseEvent *)), this,SLOT(plotMouseMoveEvent(QMouseEvent *)));
void OscilloscopeFrame::plotMouseMoveEvent(QMouseEvent *event)
{if ( Qt::ControlModifier == event->modifiers()){int x_pos = event->pos().x();int x_val = m_customPlot->xAxis->pixelToCoord(x_pos);float y = m_customPlot->graph(0)->data()->at(x_val)->value;QString strToolTip = QString("%1,%2").arg(x_val).arg(y);QToolTip::showText(cursor().pos(), strToolTip, m_customPlot);}
}

三、完整源码

OscilloscopeFrame.h

#ifndef OSCILLOSCOPEFRAME_H
#define OSCILLOSCOPEFRAME_H#include <QFrame>
#include "oscilloscopelib_global.h"namespace Ui
{class OscilloscopeFrame;
}class QCustomPlot;class AbstractRobot;class OSCILLOSCOPELIBSHARED_EXPORT OscilloscopeFrame : public QFrame
{Q_OBJECTpublic:explicit OscilloscopeFrame(QWidget *parent = 0);~OscilloscopeFrame();void setFixedLength(double length);void addData(double key, double actVel, double prfVel);void installController(AbstractRobot *controller);private slots:void plotMouseMoveEvent(QMouseEvent *event);private:Ui::OscilloscopeFrame *ui;QCustomPlot *m_customPlot = nullptr;QTimer *m_timer = nullptr;double m_fixedLength;AbstractRobot *m_controller = nullptr;double m_actPos = 0;double m_count = 0;
};#endif // OSCILLOSCOPEFRAME_H

OscilloscopeFrame.cpp

#include "OscilloscopeFrame.h"
#include "qcustomplot.h"
#include "ui_OscilloscopeFrame.h"
#include <QtMath>
#include <QDebug>
#include <device/AbstractRobot.h>#define OSCILLOSCOPE_UPDATE_MSEC  60OscilloscopeFrame::OscilloscopeFrame(QWidget *parent) :QFrame(parent),ui(new Ui::OscilloscopeFrame)
{ui->setupUi(this);ui->spbStep->setValue(1);for(int i = 1; i <= 8; ++i){ui->cmbAxisId->addItem(QString::number(i));}m_customPlot = new QCustomPlot(this);m_customPlot->setObjectName(QLatin1String("customPlot"));ui->vlyPlot->addWidget(m_customPlot);m_customPlot->setBackground(QBrush(QColor("#474848")));m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom |QCP::iSelectPlottables);  /* 可拖拽+可滚轮缩放 */m_customPlot->legend->setVisible(true);m_customPlot->addGraph();m_customPlot->graph(0)->setPen(QPen(Qt::green, 3));m_customPlot->graph(0)->setName(QStringLiteral("实际速度"));m_customPlot->addGraph();m_customPlot->graph(1)->setPen(QPen(Qt::yellow, 3));m_customPlot->graph(1)->setName(QStringLiteral("规划速度"));m_customPlot->axisRect()->setupFullAxesBox();m_customPlot->yAxis->setRange(0, 3.3);ui->btnPause2Continue->setCheckable(true);setFixedLength(100);/* 暂停/继续 */connect(ui->btnPause2Continue, &QPushButton::clicked, this, [ = ](){if(!m_timer){return;}bool isCheckable = ui->btnPause2Continue->isCheckable();if(isCheckable){m_timer->stop();ui->btnPause2Continue->setText(QStringLiteral("继续"));}else{m_timer->start(OSCILLOSCOPE_UPDATE_MSEC);ui->btnPause2Continue->setText(QStringLiteral("暂停"));}ui->btnPause2Continue->setCheckable(!isCheckable);});/* 左移 */connect(ui->btnLeftMove, &QPushButton::clicked, this, [ = ](){m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().lower - ui->spbStep->value(),m_customPlot->xAxis->range().upper - ui->spbStep->value());m_customPlot->replot();});/* 右移 */connect(ui->btnRightMove, &QPushButton::clicked, this, [ = ](){m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().lower  + ui->spbStep->value(),m_customPlot->xAxis->range().upper  + ui->spbStep->value());m_customPlot->replot();});/* 显示表格 */connect(ui->chkGrid, &QCheckBox::toggled, this, [ = ](bool checked){m_customPlot->xAxis->grid()->setVisible(checked);m_customPlot->yAxis->grid()->setVisible(checked);m_customPlot->replot();});auto updateData = [ & ](){if(m_controller){int axis = ui->cmbAxisId->currentText().toInt();T_AxisStatus status;int ec = m_controller->readAxisStatus(axis, &status);if(0 == ec){ui->lblActVel->setText(QString::number(status.dEncVel));ui->lblPrfVel->setText(QString::number(status.dPrfVel));ui->lblActPos->setText(QString::number(status.dEncPos));ui->lblPrfPos->setText(QString::number(status.dPrfPos));if(m_actPos != status.dEncPos){m_actPos = status.dEncPos;addData(m_count, status.dEncVel, status.dPrfVel);m_count ++;}}else{ui->lblActVel->setText("error " + QString::number(ec));ui->lblPrfVel->setText("error " + QString::number(ec));ui->lblActPos->setText("error " + QString::number(ec));ui->lblPrfPos->setText("error " + QString::number(ec));}}};m_timer = new QTimer();connect(m_timer, &QTimer::timeout, updateData);m_timer->start(OSCILLOSCOPE_UPDATE_MSEC);connect(m_customPlot, SIGNAL(mouseMove(QMouseEvent *)), this,SLOT(plotMouseMoveEvent(QMouseEvent *)));for(int i = 0; i < 500; i++){double x = qDegreesToRadians((double)i);addData(i, sin(x), cos(x));}
}OscilloscopeFrame::~OscilloscopeFrame()
{m_timer->stop();delete m_timer;m_timer = nullptr;delete ui;
}void OscilloscopeFrame::setFixedLength(double length)
{/* 显示固定长度 */m_fixedLength = length;
}void OscilloscopeFrame::addData(double key, double actVel, double prfVel)
{m_customPlot->graph(0)->addData(key, actVel);m_customPlot->graph(1)->addData(key, prfVel);m_customPlot->xAxis->rescale();m_customPlot->graph(0)->rescaleValueAxis(false, true);m_customPlot->graph(1)->rescaleValueAxis(false, true);m_customPlot->xAxis->setRange(m_customPlot->xAxis->range().upper,m_fixedLength, Qt::AlignRight);m_customPlot->replot(QCustomPlot::rpQueuedReplot);  /* 实现重绘 */
}void OscilloscopeFrame::installController(AbstractRobot *controller)
{m_controller = controller;
}void OscilloscopeFrame::plotMouseMoveEvent(QMouseEvent *event)
{if ( Qt::ControlModifier == event->modifiers()){int x_pos = event->pos().x();int x_val = m_customPlot->xAxis->pixelToCoord(x_pos);float y = m_customPlot->graph(0)->data()->at(x_val)->value;QString strToolTip = QString("%1,%2").arg(x_val).arg(y);QToolTip::showText(cursor().pos(), strToolTip, m_customPlot);}
}

相关文章:

QT实现固高运动控制卡示波器

目录 一、固高示波器 二、基于QCustomPlot实现示波器 三、完整源码 一、固高示波器 固高运动控制卡自带的软件有一个示波器功能&#xff0c;可以实时显示速度的波形&#xff0c;可辅助分析电机的运行状态。但是我们基于sdk开发了自己的软件&#xff0c;无法再使用该功能&…...

洛谷P1157详解(两种解法,一看就会)

一、问题引出 组合的输出 题目描述 排列与组合是常用的数学方法&#xff0c;其中组合就是从 n n n 个元素中抽出 r r r 个元素&#xff08;不分顺序且 r ≤ n r \le n r≤n&#xff09;&#xff0c;我们可以简单地将 n n n 个元素理解为自然数 1 , 2 , … , n 1,2,\dot…...

JavaScript异步编程和回调

目录 1、编程语言中的异步 2、JavaScript 3、回调 &#xff13;.&#xff11;在回调中处理错误 &#xff13;.&#xff12;回调的问题 &#xff13;.&#xff12;回调的替代方案 1、编程语言中的异步 默认情况下&#xff0c;JavaScript是同步的&#xff0c;并且是单线程…...

Qt开发笔记(Qt5.9.9下载安装环境搭建win10)

#1 Qt下载网站&#xff08;国内、国外镜像&#xff09; #2 Qt5.9.9安装选项 #3 配置系统环境变量 #4 创建测试项目 #1 Qt下载网站&#xff08;国内、国外镜像&#xff09; 官方下载地址&#xff08;慢&#xff09;&#xff1a;http://download.qt.io/ 国内镜像网站 这里给大家…...

使用Plist编辑器——简单入门指南

本指南将介绍如何使用Plist编辑器。您将学习如何打开、编辑和保存plist文件&#xff0c;并了解plist文件的基本结构和用途。跟随这个简单的入门指南&#xff0c;您将掌握如何使用Plist编辑器轻松管理您的plist文件。 plist文件是一种常见的配置文件格式&#xff0c;用于存储应…...

Python常用的开发工具合集

​ Python是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等领域。随着Python在各个领域的应用越来越广泛&#xff0c;越来越多的Python开发工具也涌现出来。但是&#xff0c;对于新手来说&#xff0c;选择一款合适的Python开发工具可…...

机器学习之线性回归

往期目录 python在线性规划中的应用 文章目录 一、线性回归算法概述1.1 什么是线性回归&#xff1f;1.2 线性回归算法原理1.3 线性回归的应用场景 二、线性回归算法Python实现2.1 导入必要的库2.2 随机生成数据集2.3 拟合模型2.4 预测结果2.5 结果可视化 三、完整代码 线性回归…...

中国系统正式发声!所有用户永久免费,网友:再见了,CentOS!

点关注公众号&#xff0c;回复“1024”获取2TB学习资源&#xff01; 如果说&#xff1a;没有操作系统会怎么样&#xff1f; 对于个PC来说&#xff0c;无论是台式机、笔记本、平板等等&#xff0c;一切都变的一无是处&#xff0c;这些硬件对我们来说&#xff0c;和一堆废铁没什么…...

Oracle数据库坏块类故障

正常的数据块有其特有的固定格式&#xff0c;如果某数据块内部出现了混乱而导致Oracle无法读取&#xff0c;则可称其为坏块。数据库坏块的影响范围可大可小&#xff0c;严重时会导致数据库无法打开。当数据库出现坏块时&#xff0c;一般出现ORA-01578错误、ORA-10632错误或者OR…...

andorid之摄像头驱动流程--MTK平台

camera成像原理&#xff1a; 景物通过镜头生产光学图像投射到sensor表面上&#xff0c;然后转为模拟电信号&#xff0c;经过数模变成数字图像信号&#xff0c;在经过DSP加工出来&#xff0c;然后在通过IO接口传输到CPU处理。 由于摄像头满足总线、驱动、设备模型&#xff0c;…...

Android9.0 iptables用INetd实现屏蔽ip黑名单的实现

1.前言 在9.0的系统rom定制化开发中,在system中netd网络这块的产品需要中,会要求设置屏蔽ip地址之内的功能,liunx中iptables命令也是比较重要的,接下来就来在INetd这块实现屏蔽ip黑名单的的相关功能,就是在app中只能屏蔽某个网址,就是除了这个网址,其他的都能上网,最后…...

介绍一下json

目录 介绍一下json Elasticsearch7.6学习指南 介绍一下json JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它以易于阅读和编写的文本形式表示结构化数据。JSON最初是由Douglas Crockford在2001年提出的&#xff0c;它在we…...

DI依赖注入环境

1.构造器注入 上一章节已经说过了&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLoca…...

《程序员面试金典(第6版)》面试题 16.18. 模式匹配(暴力破解 + 剪枝)

题目描述 你有两个字符串&#xff0c;即pattern和value。 pattern字符串由字母"a"和"b"组成&#xff0c;用于描述字符串中的模式。 例如&#xff0c;字符串"catcatgocatgo"匹配模式"aabab"&#xff08;其中"cat"是"a&q…...

一天吃透SpringCloud面试八股文

1、什么是Spring Cloud &#xff1f; Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序&#xff0c;提供与外部系统的集成。Spring cloud Task&#xff0c;一个生命周期短暂的微服务框架&#xff0c;用于快速构建执行有限数据处理的应用程序。 Sprin…...

java生成图片缩略图

目录 前言一、使用Base64编码方式1、基本方法2、压缩本地图片保存到本地3、压缩网络图片到图片服务器 二、使用thumbnailator工具方式1、导入依赖2、压缩本地图片保存到本地 前言 下面介绍了两种获取图片缩略图的方式&#xff0c;全都不是一次性压缩&#xff0c;如果没有达到设…...

《统计学习方法》——隐马尔可夫模型(下)

学习算法 HMM的学习&#xff0c;在有观测序列的情况下&#xff0c;根据训练数据是否包含状态序列&#xff0c;可以分别由监督学习算法和无监督学习算法实现。 监督学习算法 监督学习算法就比较简单&#xff0c;基于已有的数据利用极大似然估计法来估计隐马尔可夫模型的参数。…...

Liunx top 命令详解

文章目录 top补充说明语法选项top交互命令实例 top 显示或管理执行中的程序 补充说明 top命令 可以实时动态地查看系统的整体运行情况&#xff0c;是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面&#xff0c;用热键可以管理。 语法…...

基于 SpringBoot 的医院固定资产系统

本文将介绍基于 SpringBoot 技术的医院固定资产系统的设计和实现。医院固定资产管理是医疗机构管理工作的重要组成部分&#xff0c;它对医院的正常运营和管理具有重要的意义。本系统的设计和实现将有助于医疗机构更好地管理和维护其固定资产。 1. 系统需求分析 医院固定资产管…...

【企业信息化】第2集 免费开源ERP: Odoo 16 销售管理系统

文章目录 前言一、概览二、使用功能1.通过清晰报价提高销售效率2.创建专业报价单3.管理订单及合同4.简化沟通5.维护产品&价格6.直观的报告7.集成 三、总结 前言 世界排名第一的免费开源ERP: Odoo 16 销售管理系统。通过Odoo Sign应用程序和在线支付&#xff0c;发送报价。…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...