本篇的内容结合了博主之前的两篇文章,将传感器数据通过libmodbus读取完成后,利用matplotlib调用窗口,将数据实现可视化。
前期准备:python3 libmodbus matplotlib Opencv CMake
这些内容共同支撑起了本篇文章描述的内容实现,如果其中某个环节您没有配置,可以参照下面的两篇文章,根据实际需求进行配置。
Ubuntu下libmodbus的应用_Witty_Hou的博客-CSDN博客
在读学生自学Ubuntu20.04用C++调用matplotlib历程_Witty_Hou的博客-CSDN博客
1.项目搭建 :
仿照CMake,经典流程搭建工程:创建文件夹(源文件 CMakeLists.txt 头文件 build文件夹)
2.项目内容
本次内容和之前的差别不大,因为要实现实时数据显示,所以需要调用一下matplotlib,通过设置向量vector,用连续的向量首尾相连绘制出图像。通过不断刷新的向量连接,当刷新率超过30帧的时候,就已经看不出折线的痕迹了。
类比一下,此图是用matplotlib模拟的三种不同刷新率的正弦函数,matplotlib执行参数自加操作的时候大概是10个数为1s的时间,如图,x每次加0.1,一秒就刷新100次。那么绿色为100fps,蓝色为25fps,黄色为12.5fps,25帧的在转角处可以看到些许折痕。同理,我们延续这种想法,对传感器进行数据采集和显示,只要我们的帧率大于30,就可以达到没有肉眼可见的延时显示。
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(mini CXX)
find_package(OpenCV REQUIRED)
set(CMAKE_CXX_STANDARD 11)
#指定库路径
file(GLOB_RECURSE Opencv3_LIB "/usr/lib/python3.8/config-x86_64-linux-gnu/*.so")
#指定头文件路径
set(Opencv4_INLCUDE_DIRS "/usr/include/python3.8")
#添加头文件到工程
include_directories(include ${Opencv4_INLCUDE_DIRS})
include_directories(${OpenCV_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(/usr/include/modbus)
# 通常这样设置就可以,如果你的项目包含qrc文件,那么需要将它们单独添加进来
aux_source_directory(. DIRS_SRCS)
add_executable(mini ${DIRS_SRCS})
#添加库文件到工程
target_link_libraries(mini ${Opencv_LIB})
target_link_libraries(mini libpython3.8.so)
TARGET_LINK_LIBRARIES(mini libmodbus.so)
main.cpp
#define _USE_MATH_DEFINES
#include
#include "matplotlibcpp.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "modbus.h"
#pragma comment(lib,"modbus.lib")
namespace plt = matplotlibcpp;
int main()
{
double i = 0.1;
int num;
std::vector x;//定义向量x,用于plot显示
//modbus需要的指针和内容寄存数组
modbus_t* mb;
uint16_t tab_reg[10] = { 0 };
//配置端口信息,并判断端口是否开启成功
mb = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 2);
if (mb == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
//设置从站地址,并判断是否成功
int rc = modbus_set_slave(mb, 254);
if (rc == -1) {
fprintf(stderr, "Invalid slave ID\n");
modbus_free(mb);
return -1;
}
//判断modbus连接是否成功
if (modbus_connect(mb) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(mb);
return -1;
}
//设置响应超时时间为1s
struct timeval t;
t.tv_sec=0;
t.tv_usec=1000000;
modbus_set_response_timeout(mb,&t);
while(i>0) {
int regs = modbus_read_input_registers(mb, 0, 1, tab_reg); //读取传感器数值
std::cout << tab_reg[0] << " g" << std::endl;//在终端输出传感器数值
usleep(10); //延迟10us
num = tab_reg[0];//传感器数值存放到num中
x.push_back(num);//在x向量最后加上传感器数值
if(num > 5000)
break;//自行增加的程序停止,当传感器压力值大于5000时,停止
//横轴每次循环向前移动0.8,当i>1000时,程序停止
i = i + 0.8;
if(i > 1000)
{i = 0;}//设置的循环次数限制,作为项目的一部分,只需要有一种方式能停止就可以,后续可以通过中断来代替
plt::clf();// 清理先前的plot数据
plt::named_plot("pressure", x);//显示数据x的数值,并在右上角注明线条的指代含义以及颜色
plt::xlim(i - 50, i + 150);//横轴展示的范围
plt::title("Pressure"); // 图像标题
plt::legend();// 使能legend
plt::pause(0.01);// 延迟0.01s
}
plt::save("num.pdf");//将数据保存为一份pdf放在build文件夹内
}
由于需要实现动态显示,博主自己去查资料,大多数都通过ion实现,但是由于技术水平不足,目前还没能完美实现,待到后续研究明白,会单独再发一篇文章来记录。本次动态实现的想法是通过横轴不断刷新来实现的,plt::xlim在while循环中随着i的不断变化可以不断刷新,从而达到动态可视化的目的。
3.运行结果
4.可能遇到的问题总结:
(1)更改文件夹名称导致CMakeLists.txt错误
如图:博主将原文件夹的名字mini修改为MINI,其他未作部分未修改,导致CMakeLists.txt错误。
解决方法:将文件夹的名称改回原来的mini。
或者将build文件夹删除,新建一个build重新执行cmake .. make ./mini(可执行文件名)
如果删除build再建的方法行不通,就新建一个工程,把所有文件都通过touch指令重新构建一次,把内容复制过来,不要直接把文件复制过来,否则还是会显示冲突。
再不行,那就只能重启大法好,然后再新构建一次工程。有时候,可能是因为程序没有完全停止,重启电脑可以关闭看不到的启动项。
(2)直接复制一个备份,再次编译的时候显示CMakeLists.txt冲突
解决方法:将复制文件的build文件夹删除,重新建一个build,编译一次。
(3)while循环中没有加终结条件
博主自己在学习过程中,起初都是while(1)直接运行,但是出于不知名的原因,当博主关闭中端之后,传感器还在不断闪烁,代表程序并没有停止。此时再次运行可知性文件,文件并不会报错,但是传感器会速度很慢,并且只输出0,导致没办法调试,因此就不放置错误代码了。写在文章最后,作为一个可能遇到的问题列写出来。如果真的遇到,matplotlib关闭不了,任务管理器也不显示,叉了也会自己启动,像极了电脑中病毒疯狂弹窗的样子。如果遇到,请重启电脑。
如果还有其他问题请留言,或者添加QQ:3122899873,看到都会回复❤