A Method of Obtaining the Actual Position of Multi-Line Radar

Since it is troublesome to pass the manual tape measure test in rviz, I thought of another solution. (I am a newcomer, if there is something wrong, everyone, just take it for fun)

It can also be regarded as recording the growth process, the code is as follows:

# -*- coding:utf8 -*-

import json
import pickle
from PyQt5 import QtGui
from threading import Thread  # 导入线程模块
from multiprocessing import Process
from PyQt5.QtCore import pyqtSignal, QStringListModel, Qt
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QMessageBox, QDialog, QTabWidget, \
    QTabBar  # PYQT5

from window import Ui_MainWindow  # 导入自己的ui窗体
from Get_coordinate_data import Ros_Get_Data  # 导入Ros.py
from new_child import Ui_Dialog

import math
import socket
import os
import sys

class Ui_Window(QMainWindow):
    """
        UI窗口类
    """
    Get_data = pyqtSignal(list)  # 自定义信号,用作接收和发送坐标信息

    def __init__(self):
        QMainWindow.__init__(self)

        self.main_ui = Ui_MainWindow()  # 给主窗口定义一个对象
        self.main_ui.setupUi(self)

        self.main_next = Setps_Next_Ui()

        self.deal_with = 0

        self.send_data_list = []  # 信号发送的列表容器
        self.need_data = 0  # 将需要的数据条数初始化
        self.item_distance_list = []  # 为存放距离的列表




        self.nearly_item_distance_deal_with = []  # 为存放近距离计算结果的列表

        self.perimeter_item_distance_deal_with = []  # 为存放中距离计算结果的列表

        self.far_item_distance_deal_with = []  # 为存放远距离计算结果的列表






        self.index_a = 0  # 索引值变量 对应数据坐标中的x
        self.index_b = 1  # 索引值变量 对应数据坐标中的y
        self.index_c = 2  # 索引值变量 对应数据坐标中的角度
        self.col = 0  # 写入ui窗体表格的列

        self.Get_Text_data()  # 获取需求文件中的数据
        self.ProcDataSocketServer()  # 调用函数

        self.register()  # 定义按钮

        os.system("gnome-terminal -e 'roscore'")  # 通过新终端打开roscore

        self.op_thread = Thread(target=self.open_rviz)  # 开启进程,打开rviz
        self.op_thread.start()
    def register(self):
        """
            使按钮连接各自的对象
        """
        self.main_ui.start.clicked.connect(self.main_next.show)
        self.main_ui.close.clicked.connect(self.close_Laser)
        self.main_ui.start.clicked.connect(self.main_ui.tableWidget.clearContents)
        self.main_ui.start.clicked.connect(self.start_thread)  # 将开始按钮连接到start_thread方法函数


        self.Get_data.connect(self.collect_data)  # 将自定义信号Get_data连接到collect_data函数

    def close_Laser(self):
        pass

    def Get_Text_data(self):
        filename = "configuration_file.json"  # 获取../fc_file文件里的数据
        with open(filename, "r") as f:  # 获取../fc_file文件里的数据
            self.target_text_all = json.load(f)
            self.target_distance = self.target_text_all["Laser_radar"][0]["distance"]  # 使target_distance得到json文件中距离要求的值
            self.differential = self.target_text_all["Laser_radar"][1]["differential"]

    def start_thread(self):
        """
            开启线程
        """

        text = ["程序已启动,请前往rviz中确认点云中的边角距离。"]  # 将提示信息写入到文本框里
        output_message = QStringListModel()
        output_message.setStringList(text)
        self.main_ui.listView.setModel(output_message)

        self.deal_with = 0

        self.flag = True

        self.index_a = 0
        self.index_b = 1  # 每当点击一次线程时 初始化索引值
        self.index_c = 2  # 每当点击一次线程时 初始化索引值
        self.need_data = 0  # 初始化ros里的循环值
        self.col = 0  # 列
        self.send_data_list = []  # 信号发送的列表容器
        self.item_distance_list = []  # 初始化距离写入列表

        self.nearly_item_distance_deal_with = []  # 初始化近距离计算数据列表
        self.perimeter_item_distance_deal_with = []  # 初始化距离计算数据列表
        self.far_item_distance_deal_with = []  # 初始化距离计算数据列表

        self.main_ui.start.setEnabled(False)  # 将开始按钮设定为不可点击
        self.thread_server = Thread(target=self.run)  # 为ui_ros.Get_data_work开启线程
        self.thread_server.daemon = True  # 线程保护
        self.thread_server.start()  # 开始
        p = Process(target=Process_clienct)  # 开启进程
        p.start()

    def open_rviz(self):
        import os
        os.system('rviz -d rviz_configuration_file.rviz')

    def collect_data(self, data):
        """
            由 start_thread 开启的函数方法,为了写入ui窗体表格
        """
        self.send_data_list.append(data[self.index_a])  # 将坐标数据里的对应值放入到send_data_list里
        self.send_data_list.append(data[self.index_b])
        self.send_data_list.append(data[self.index_c])

        self.deal_with += 1
        if self.deal_with % 2 == 0:
            self.item_distance_list = math.sqrt(
                (self.send_data_list[-6] - self.send_data_list[-3]) ** 2 +
                (self.send_data_list[-5] - self.send_data_list[-2]) ** 2)  # 将边长参数计算出来
            if self.need_data <= 12:
                self.nearly_item_distance_deal_with.append(self.item_distance_list)  # 为计算边长列表添加计算的数据
            elif self.need_data <= 24:
                self.perimeter_item_distance_deal_with.append(self.item_distance_list)
            elif self.need_data <= 36:
                self.far_item_distance_deal_with.append(self.item_distance_list)
        self.input_table()

        self.need_data += 1
        if self.need_data == 12:
            nearly_item = "近距离测试结束,请将目标板放置于中距离,放置完成后继续点击。"
            QMessageBox.information(self, '测试结束', nearly_item, QMessageBox.Ok)
        if self.need_data == 24:
            perimeter_item = "中距离测试结束,请将目标板放置于远距离,放置完成后继续点击。"
            QMessageBox.information(self, '测试结束', perimeter_item, QMessageBox.Ok)
        if self.need_data == 36:
            self.main_ui.start.setEnabled(True)  # 将开始按钮设定为可点击

            text = ["数据采集完成"]  # 数据采集结束后 会将数据采集完成输出到文本提示框上
            output_message = QStringListModel()
            output_message.setStringList(text)
            self.main_ui.listView.setModel(output_message)

            self.result_ui()  # 调用计算数据的函数

    def input_table(self):

        newItem_x = str(self.send_data_list[self.index_a])
        x = QTableWidgetItem(newItem_x)  # 转换成窗体格式
        self.main_ui.tableWidget.setItem(0, self.col, x)  # 将数据写入ui窗体表格里
        self.col += 1

        newItem_y = str(self.send_data_list[self.index_b])  # 把列表强制转换成字符串
        y = QTableWidgetItem(newItem_y)  # 转换成窗体格式
        self.main_ui.tableWidget.setItem(0, self.col, y)  # 将数据写入ui窗体表格里
        self.col += 1

        newItem_z = str(self.send_data_list[self.index_c])
        z = QTableWidgetItem(newItem_z)
        self.main_ui.tableWidget.setItem(0, self.col, z)  # 将数据写入ui窗体表格里
        self.col += 1

        if self.deal_with % 2 == 0:
            self.item_distance_list = '%.4f' % self.item_distance_list  # 将位置数据保留4位小数
            newItem_distance = str(self.item_distance_list)  # 将距离数据转换成字符串格式
            item_distance = QTableWidgetItem(newItem_distance)  # 转换成窗体格式
            self.main_ui.tableWidget.setItem(0, self.col, item_distance)  # 将数据写入ui窗体表格里
            self.col += 1

        self.index_a += 3
        self.index_b += 3
        self.index_c += 3

    def result_ui(self):
        """
            计算数据的函数
        """
        nearly_item_distance_deal_with_ok = sum(self.nearly_item_distance_deal_with) / len(self.nearly_item_distance_deal_with)  #
        perimeter_item_distance_deal_with_ok = sum(self.perimeter_item_distance_deal_with) / len(self.perimeter_item_distance_deal_with)  #
        far_item_distance_deal_with_ok = sum(self.far_item_distance_deal_with) / len(self.far_item_distance_deal_with)  #

        nearly_item_distance_deal_with_ok = float('%.4f' % nearly_item_distance_deal_with_ok)
        perimeter_item_distance_deal_with_ok = float('%.4f' % perimeter_item_distance_deal_with_ok)
        far_item_distance_deal_with_ok = float('%.4f' % far_item_distance_deal_with_ok)

        self.input_data(nearly_item_distance_deal_with_ok,
                        perimeter_item_distance_deal_with_ok,far_item_distance_deal_with_ok)  # 将计算完成的数据放到input_data函数里

    def input_data(self, nearly_item_distance_deal_with_ok,
                        perimeter_item_distance_deal_with_ok,far_item_distance_deal_with_ok):
        """
            将result_ui的数据写入到文本框里
        :param text:result_ui的数据
        """
        nearly_differential = abs(nearly_item_distance_deal_with_ok-self.target_distance)
        perimeter_differential = abs(perimeter_item_distance_deal_with_ok-self.target_distance)
        far_differential = abs(far_item_distance_deal_with_ok-self.target_distance)

        unqualified_output_data = "近距离边长的平均值:{}m\n中距离边长的平均值:{}m\n远距离边长的平均值:{}m\n实际的边长是:{}m\n" \
                                  "近距离误差:{}m\n中距离误差:{}m\n远距离误差:{}m\n要求是:{}m\n标定的结果为:不合格".format(
            nearly_item_distance_deal_with_ok, perimeter_item_distance_deal_with_ok,far_item_distance_deal_with_ok,
            self.target_distance,nearly_differential,perimeter_differential,far_differential,self.differential
        )
        qualified_output_data = "近距离边长的平均值:{}m\n中距离边长的平均值:{}m\n远距离边长的平均值:{}m\n实际的边长是:{}m\n" \
                                "近距离误差:{}m\n中距离误差:{}m\n远距离误差:{}m\n要求是:{}m\n标定的结果为:合格".format(
            nearly_item_distance_deal_with_ok,perimeter_item_distance_deal_with_ok,far_item_distance_deal_with_ok,
            self.target_distance,nearly_differential,perimeter_differential,far_differential,self.differential
        )

        if nearly_differential < self.differential and \
                perimeter_differential < self.differential and \
                far_differential < self.differential:  # 将数据和要求作比较
            QMessageBox.information(self, '测试结束', qualified_output_data, QMessageBox.Ok)  # 全部符合条件

        else:
            QMessageBox.information(self, '测试结束', unqualified_output_data, QMessageBox.Ok)  # 如果距离不合格

    def closeEvent(self, QCloseEvent):
        self.sock.close()
        self.flag = False
        print "程序运行结束"

    def ProcDataSocketServer(self):
        self.sock = socket.socket(socket.AF_UNIX)
        SOCK_PATH = "/tmp/testss"  # 统一本地文件地址为"/tmp/testss"

        try:
            os.unlink(SOCK_PATH)
        except:
            pass
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(SOCK_PATH)  # 连接到本地文件
        self.sock.listen(5)  # 最大监听数量为5
        os.chmod(SOCK_PATH, 0777)

    def run(self):
        conn, addr = self.sock.accept()
        while self.flag:
            data = conn.recv(1024)  # 数据接收一次最大为1024
            try:
                order = pickle.loads(data)  # 进行解包
                if order is None:  # 如果数据为空
                    conn.close()  # 断开连接
                    continue
                else:
                    if "type" in order:
                        if order["type"] == "data":
                            order = order["data"]
                            print order
                            self.Get_data.emit(order)
                            ret = 1
                            conn.send(str.encode(str(ret)))
                        elif order["type"] == "wait":
                            ret = 0
                            conn.send(str.encode(str(ret)))
                        else:
                            print "server is close"
            except:
                break
        conn.close()

class Process_clienct():
    def __init__(self):
        self.ui_ros = Ros_Get_Data()
        self.ui_ros.connectAndSendData()  # 执行Ros_Get_Uwb里的connectAndSendData

class Setps_Next_Ui(QDialog):
    def __init__(self):
        QDialog.__init__(self)

        self.setWindowFlags(Qt.WindowCloseButtonHint)  # 隐藏关闭按钮
        self.text_ui = Ui_Dialog()  # 给主窗口定义一个对象
        self.text_ui.setupUi(self)

        # 隐藏标签
        self.text_ui.tabWidget.tabBar().hide()
        self.text_ui.tabWidget.findChildren(QTabBar)[0].hide()

        self.register()

    def register(self):  # 按钮连接
        self.text_ui.next_page_one.clicked.connect(self.widget_index_one)
        self.text_ui.next_page_two.clicked.connect(self.widget_index_two)
        self.text_ui.privious_page.clicked.connect(self.widget_index_three)

        self.text_ui.picture_point.clicked.connect(self.rviz_point)

        self.text_ui.index_6_return.clicked.connect(self.widget_return_3)

    def widget_index_one(self):
        self.text_ui.tabWidget.setCurrentIndex(1)

    def widget_index_two(self):
        self.text_ui.tabWidget.setCurrentIndex(2)

    def widget_index_three(self):
        self.text_ui.tabWidget.setCurrentIndex(1)

    def rviz_point(self):
        self.text_ui.tabWidget.setCurrentIndex(3)
        png3 = QtGui.QPixmap('./picture/edges.png')
        self.text_ui.picture_text.setPixmap(png3)
        self.text_ui.picture_text.setScaledContents(True)

    def widget_return_2(self):
        self.text_ui.tabWidget.setCurrentIndex(1)

    def widget_return_3(self):
        self.text_ui.tabWidget.setCurrentIndex(2)

    def closeEvent(self, QCloseEvent):
        pass


if __name__ == '__main__':
    """
        运行入口
    """
    app = QApplication(sys.argv)  # 创建应用
    window = Ui_Window()  # 给主窗口定义对象
    window.show()  # 展示主界面
    sys.exit(app.exec_())

See the following link on the ros side

https://blog.csdn.net/weixin_54062353/article/details/124292981

The UI form is as follows

https://blog.csdn.net/weixin_54062353/article/details/124293590

Guess you like

Origin blog.csdn.net/weixin_54062353/article/details/124292864