从无到有接收串口数据并在pycharm中实现可视化(TI mmwave)



一、Pycharm

如果用到Pycharm我们首先最关键的就是要知道Pycharm的Python环境

1.环境配置

Pycharm的环境配置在这里: 左上角->文件->setting(设置)
在这里插入图片描述
许多我们需要的函数及类都是在这里导入的,非常好用便捷。

2.镜像源配置

在左下角按照如图点击:我这里使用的是清华源 ↓
在这里插入图片描述
在这里插入图片描述

3.工具配置(QtDesigner、PyUIC)

左上角->文件->setting(设置)
在这里插入图片描述

接下来就是对应你下载的python里面的工具的路径:
在这里插入图片描述

在这里插入图片描述

二、代码重要节点

我们要清楚上位机的关键节点,下面就以我个人的节点及个人目的实际操作为例

1.接收串口

这里我想的一些功能包括:
①、可以打开一个或多个串口
②、能够自动识别当前存在的串口号
所以我们首先引入两个库

import serial
import serial.tools.list_ports

我们来简单理解一下

my_ports = list(serial.tools.list_ports.comports())
if not my_ports:
    print("当前无串口")
else:
    for port in my_port:
        print(list(port))

结果就会显示你当前存在的串口
在这里插入图片描述

接下来直奔主题现在我们尝试打开串口并接收串口传输的数据:
这里的串口数据最终会存到final_package。
数据协议要按照自己的协议去划分(我这里的是ti毫米波雷达demo的解析格式)。

class Process_data(QThread):
    fin = pyqtSignal('PyQt_PyObject')

    def __init__(self, com):
        super().__init__()
        self.ser = com

    def run(self):  # 重写QThread run函数
        data = self.processing()
        print(data)
        self.fin.emit(data)  # 信号槽 emit传递函数

    def processing(self):
        flag_Byte = bytearray(b'\x02\x01\x04\x03\x06\x05\x08\x07')  # 当找到附合我们前8个字节的数据 我们才开始按照我们自己的逻辑去读与配置
        this_Byte = self.ser.read(1)
        final_package = bytearray(b'')
        index = 0
        while not this_Byte:
            this_Byte = self.ser.read(1)
        while 1:  # 不断获取数据找符合我们的前八个字节逻辑的那一串数据
            if this_Byte[0] == flag_Byte[index]:   # 这里的[0]是不可以省的 因为flag_Byte[0]为 2 对应this_Byte为b'\x02' 不是2 不能划等号
                index += 1
                final_package.append(this_Byte[0])
                if index == 8:
                    break
                this_Byte = self.ser.read(1)
            else:
                if index == 0:
                    this_Byte = self.ser.read(1)
                index = 0
                final_package = bytearray(b'')
 		versionBytes = self.ser.read(4)

        final_package += bytearray(versionBytes)

        lengthBytes = self.ser.read(4)
        final_package += bytearray(lengthBytes)
        frameLength = int.from_bytes(lengthBytes, byteorder='little')

        frameLength -= 16
        final_package += bytearray(self.ser.read(frameLength))

        return final_package


def recive_start():
    recive.start(priority=QThread.HighestPriority)


def update_data(data):
    print(data)  #这里就是我们要显示在图上的数据了


thread_0 = QTimer()
thread_0.setSingleShot(False)
thread_0.timeout.connect(recive_start)
my_ports = []  # 在查找所有COM之前先初始化列表
ports = list(serial.tools.list_ports.comports())  # 获取串口list的长度
for com in ports:
    my_ports.append(com[0])  # 添加刷新后得到的串口
    if com[0] == 'COM16':
        print('found')
        index = my_ports.index(com[0])
# 这里我们可以加个checkbox 然后将my_ports 加到内部供选择,但这里为调试所以直接进入下一步
try:
    ser = serial.Serial(my_ports[index], 921600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=0.08)
    print('串口打开成功' + my_ports[index])
except:
    print(my_ports[index])
    print('串口打开失败')

if ser.is_open:
    # 在这里我们要思考一个问题,  读取串口数据的同时 我们还要做的是去更新我们的前端显示,所以这里我们直接加个线程来为数据接收增加通道
    recive = Process_data(ser)
    print(recive.fin)
    recive.fin.connect(update_data)
    thread_0.start()

这段代码在执行时 会出现
1、 thread_0.start() 不执行
2、 Process_data中的run函数不执行
是因为代码要在PyQt应用程序上下文中执行。QTimer类是PyQt库的一部分,需要一个QApplication实例才能正常工作。确保在运行代码之前初始化了一个QApplication对象
我这里的执行结果为
found
串口打开成功COM16
bytearray(b’\x02\x01\x04\x03\x06\x05\x08\x07\x03\x01\x04\x07@\x00\x00\x00Ch\n\x00\xc86\x00\x00\x11Mv\xea\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x01\x04\x03\x06\x05\x08\x07\x03\x01\x04\x07@\x00\x00\x00Ch\n\x00\xc86\x00\x00’)
<bound PYQT_SIGNAL fin of Process_data object at 0x0000025E08C10790>
需要注意的是 里面没有\x的值是ASCII 需要手动转 Hex (\n是换行)

2.处理数据

既然收到数据,那就可以按照我们的协议来将我们需要的信息实例化,这就比较简单了,偏逻辑。我们这部分暂时先不做过多工作,上面说到要在QApplication实例中才能使用QTimer类,所以我们进入下一个步骤设计前端,实例QApplication,请看下一步。

3.设计上位机前端

打开我们前面新添加的外部工具QtDesigner.
随后思考自己所需要的控件,我需要:
①.一个单独布局用于放置可视化画布
②.需要控制选择COM口 填写波特率等配置的功能框
简单的设计了一下,大家可按照自己的需求和审美加以改进。
在这里插入图片描述
随后另存到工程下面,使用external Tools 的 PyUIC功能即可生成python文件。
在这里插入图片描述

4.处理上位机后端

前端已经有了现在开始后端继续编写。

首先:引用我们生成的前端py文件。

import test_window     #这里你的py文件叫什么你就些什么

随后:新增下面代码(如果你没有引入可以通过pycharm的提示来自动引入)

class window(QMainWindow, test_window.Ui_MainWindow):  # 前面是QMainWindow方法 后面是我们生成的前端py文件的类名
    def __init__(self):
        super(window, self).__init__()
        self.setupUi(self)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = window()		#对应上面的方法
    window.show()
    sys.exit(app.exec_())

这里我们只运行上面两串的话就会出现我们刚才设计的前端页面。
在这里插入图片描述
最后:我们开始进行控件与语句的配合,使前端与我们前面设计的逻辑相匹配。

# 现在我们已经实例化pyqt了 所以我们重新将我们解析串口数据的函数主要部分修改为下面
class Process_data(QThread):
    fin = pyqtSignal('PyQt_PyObject')

    def __init__(self, com):
        super().__init__()
        self.ser = com

    def run(self):  # 重写QThread run函数
        data = self.processing()
        self.fin.emit(data)  # 信号槽 emit传递函数
    def processing(self):
        flag_Byte = bytearray(b'\x02\x01\x04\x03\x06\x05\x08\x07')  # 当找到附合我们前8个字节的数据 我们才开始按照我们自己的逻辑去读与配置
        this_Byte = self.ser.read(1)
        final_package = bytearray(b'')
        index = 0
        while not this_Byte:
            this_Byte = self.ser.read(1)
        while 1:  # 不断获取数据找符合我们的前八个字节逻辑的那一串数据
            if this_Byte[0] == flag_Byte[index]:  # 这里的[0]是不可以省的 因为flag_Byte[0]为 2 对应this_Byte为b'\x02' 不是2 不能划等号
                index += 1
                final_package.append(this_Byte[0])
                if index == 8:
                    break
                this_Byte = self.ser.read(1)

            else:
                if index == 0:
                    this_Byte = self.ser.read(1)
                index = 0
                final_package = bytearray(b'')
        versionBytes = self.ser.read(4)

        final_package += bytearray(versionBytes)

        lengthBytes = self.ser.read(4)
        final_package += bytearray(lengthBytes)
        frameLength = int.from_bytes(lengthBytes, byteorder='little')

        frameLength -= 16
        final_package += bytearray(self.ser.read(frameLength))
        return final_package


class window(QMainWindow, test_window.Ui_MainWindow):  # 前面是QMainWindow方法 后面是我们生成的前端py文件的类名
    def __init__(self):
        self.my_ports = []  # 在查找所有COM之前先初始化列表
        super(window, self).__init__()
        self.setupUi(self)
        ports = list(serial.tools.list_ports.comports())  # 获取串口list的长度
        # 此时我们已经有了复选框了 所以我们获取串口之后直接将其添加到复选框的选项中去
        for com in ports:
            self.my_ports.append(com[0])  # 添加刷新后得到的串口
        # 这里我们可以加个checkbox 然后将my_ports 加到内部供选择,但这里为调试所以直接进入下一步

        self.comboBox.addItems(self.my_ports)

        self.thread_0 = QTimer()
        self.thread_0.setSingleShot(False)
        self.thread_0.timeout.connect(self.recive_start)

        self.pushButton.clicked.connect(self.require_com)
        self.pushButton_2.clicked.connect(self.start_com)

    def require_com(self):
        self.my_ports = []
        self.comboBox.clear()
        ports = list(serial.tools.list_ports.comports())
        for com in ports:
            self.my_ports.append(com[0])
        self.comboBox.addItems(self.my_ports)

    def recive_start(self):
        self.recive.start(priority=QThread.HighestPriority)

    def update_data(self, data):    #这里就可以按照自己的串口数据去解析了
        # hex_data = ' '.join(format(byte, '02x') for byte in data)
        # print(hex_data)  # 这里就是我们要显示在图上的数据了
        if self.ser.is_open:
            framelength = struct.unpack('I', data[12:16])[0]
            frame = struct.unpack('I', data[20:24])[0]
            det_num = struct.unpack('I', data[28:32])[0]
            tlv_numflag = struct.unpack('I', data[32:36])[0]
            index = 40
            print(tlv_numflag)
            for i in range(tlv_numflag):
                tlvnum = struct.unpack('I', data[index:index + 4])[0]
                if tlvnum == 1:
                    total = struct.unpack('I', data[index + 4:index + 8])[0]
                    self.deal_1(det_num, data, index)
                    index = total + 8

                elif tlvnum == 2:
                    total = struct.unpack('I', data[index + 4:index + 8])[0]
                    index = total + 8
                elif tlvnum == 3:
                    total = struct.unpack('I', data[index + 4:index + 8])[0]
                    # self.deal_2(det_num, data, index)
                    index = total + 8

    def deal_1(self, num, data, index):
        if num != 0:
            print(index)
            q = struct.unpack('h', data[index + 10:index + 12])[0]
            print(q)
            for i in range(num):
                add = 12 + i * 10
                x = (struct.unpack('h', data[index + add + 4:index + add + 6])[0]) / (2 ** q)
                y = (struct.unpack('h', data[index + add + 6:index + add + 8])[0]) / (2 ** q)
                z = (struct.unpack('h', data[index + add + 8:index + add + 10])[0]) / (2 ** q)
                print(x)
                print(y)
                print(z)
                print('---------------')

    def deal_2(self, num, data, index):
        print('1')

    def start_com(self):
        if self.pushButton_2.text() == '开始':
            try:
                self.ser = serial.Serial(self.comboBox.currentText(), self.lineEdit_2.text(), parity=serial.PARITY_NONE,
                                    stopbits=serial.STOPBITS_ONE, timeout=0.08)
                print('串口打开成功' + self.comboBox.currentText())
            except:
                QMessageBox.about(self, "出错", '串口打开失败')

            if self.ser.is_open:
                # 在这里我们要思考一个问题,  读取串口数据的同时 我们还要做的是去更新我们的前端显示,所以这里我们直接加个线程来为数据接收增加通道
                self.recive = Process_data(self.ser)
                self.recive.fin.connect(self.update_data)
                self.thread_0.start()
                self.pushButton_2.setText('关闭')   # 点击开始之后 要相应把摁扭改为关闭
        else:
            self.ser.close()
            self.pushButton_2.setText('开始')


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = window()
    window.show()
    sys.exit(app.exec_())

5.测试验证

像我这边就是输出x y z
在这里插入图片描述

总之整体的节点流程已经完成了 其他就是自己设计自己想要的结果了,比如:
在这里插入图片描述
好了到这里就结束了。

PyCharm实现数据可视化通常涉及到使用 Python 数据分析库,比如 Pandas 和 Matplotlib、Seaborn 或者 Plotly 等。以下是一个基本流程: 1. **安装必要的库**: - 安装 `pandas` 用于数据处理和清洗, ```bash pip install pandas ``` - 安装 `matplotlib` 或 `seaborn` 或 `plotly` 用于绘图, ```bash pip install matplotlib seaborn plotly ``` 2. **导入加载数据**: 使用 `pandas` 导入 CSV 文件或其他数据源: ```python import pandas as pd df = pd.read_csv('data.csv') ``` 3. **数据分析**: 对数据进行预处理,计算需要可视化的统计指标等。 4. **创建图表**: - 使用 Matplotlib 创建基础图表,例如折线图、散点图或直方图: ```python import matplotlib.pyplot as plt plt.plot(df['column_name']) plt.show() ``` - Seaborn 提供了更高级的图形,例如 violin plots 或 heatmaps: ```python import seaborn as sns sns.heatmap(df.corr()) ``` - Plotly 可以创建交互式的图表: ```python import plotly.express as px fig = px.scatter(df, x='x_column', y='y_column') fig.show() ``` 5. **调整样式和参数**: 根据需求调整颜色、标签、标题等,以及图表的大小、布局等。 6. **保存图表**: ```python plt.savefig('output.png') ``` 7. **利用 PyCharm 图形界面**: - PyCharm 提供了集成的终端和代码片段功能,可以帮助快速执行上述操作,展示结果。 记得在开始前检查是否已安装所需的库,以及根据你的实际数据和需求调整代码。此外,PyCharm 自带的 Data Inspector 也提供了一些初步的数据探索和可视化功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值