由于在rviz中通过手动卷尺测试比较麻烦,所以想了另一种解决思路。(本人新人,如有不对各位大佬就当看个乐呵)
也算是记录下成长的过程,代码如下:
# -*- 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_())
ros端见如下链接
https://blog.csdn.net/weixin_54062353/article/details/124292981
UI窗体见如下
https://blog.csdn.net/weixin_54062353/article/details/124293590