加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
main.py 64.04 KB
一键复制 编辑 原始数据 按行查看 历史
redfalsh 提交于 2022-05-10 21:03 . old version
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
#!/usr/bin/env python
# encoding: utf-8
from common.libs.Log import logger
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QPrintPreviewDialog
from PyQt5.QtMultimedia import QSound
from PIL import Image
import xlwt
import xlrd
import xlsxwriter
from threading import Thread
from threading import Timer
from queue import Queue
import PyQt5_stylesheets
# from images import images_rc
import os
import glob
import re
import win32api
import sys
import random
from decimal import Decimal
import time
import serial
import serial.tools.list_ports
import binascii
import qtawesome as qta
from six import unichr
import numpy as np
import pyqtgraph as pg
pg.setConfigOption('background', '#E3E6E3')
pg.setConfigOption('foreground', 'k')
import pyqtgraph.opengl as gl
from pyqtgraph.opengl import GLViewWidget
from pyqtgraph import GraphicsLayoutWidget
import threading
import numpy as np
import json
BOOT_DIR = os.getcwd()
import configparser
# 打开调试
config = configparser.ConfigParser()
config.read(os.getcwd()+'/conf/base.ini')
DEBUG = True
# DEBUG = False
# auto = config['base']['task_auto']
# CYCLE_TEST = False
# if auto == 'True':
# CYCLE_TEST = True
# if auto == 'False':
# CYCLE_TEST = False
task_stop_err = int(config['base']['task_stop_err'])
task_show = config['base']['task_show']
# task_stop_err = 5000
# 1mm走位需要的脉冲数
# AXIS_MULTIPLE = int(config['base']['pulse'])
AXIS_MULTIPLE = 100
from Help import Help
from Help import WATER_CMD
# 监督通道突变差阈值
data_start = 0
# 界面导入
from pwdInput import PwdInput
from ComSetWidget import ComSetWidget
from BaseSetWidget import BaseSetWidget
from envMeasureWidget import EnvMeasureWidget
from AddPddDialog import PddDialog
from AddOarDialog import OarDialog
from AddScanDialog import ScanDialog, ScanResultWidget
# from DeviceSelectDialog import DeviceInputDlg
from RayGraphWidget import RayCanvasWidget
from RepeatMeasure import RepeatMeasureDialog
# from MotorControl import MotorControlDock
from MotorControl import MotorControlWidget
from MotorControl import MoveShowDock
# from ChartDeal import ChartDealWidget
# 界面导入
from ProjectManager import ProjectDock
from ProjectManager import ProjectCreateDialog
from ProjectManager import TaskRunManager
from fileChangeWidget import FileChangeForm
class GraphWidget(GraphicsLayoutWidget):
def __init__(self):
super(GraphWidget, self).__init__()
# 右上角显示
self.label = pg.LabelItem(justify='right')
self.addItem(self.label, 0, 1, 1, 1)
self.pg = pg
# 曲线添加
self.plot = self.pg.PlotItem()
self.plot = self.addPlot(1, 1, colspan=2)
self.plot.setYRange(0, 100)
self.data = np.random.normal(size=10)
self.curve_master_data = [100, 100]
self.curve_slave_data = [0, 0]
self.curve_data_x = [0, 300]
# 曲线设置
self.plot.setAutoVisible(y=True)
self.plot.setTitle('通道数据实时曲线图')
self.plot.setLabel('left', "相对剂量(%)", units='')
self.plot.setLabel('bottom', "距离(mm)", units='')
self.plot.addLegend()
# self.plot.setRange(xRange=[0,300],yRange=[0,110],padding=0)
# self.plot.setLimits(xMin=0,xMax=300,yMin=0,yMax=110)
# 主测通道和监测通道
self.curve_master = self.plot.plot(self.curve_data_x, self.curve_master_data, name='主测通道',
pen=self.pg.mkPen('r', width=2))
self.curve_slave = self.plot.plot(self.curve_data_x, self.curve_slave_data, name='监测通道',
pen=self.pg.mkPen('g', width=2))
# 网格显示
self.plot.showGrid(x=True, y=True, alpha=0.7)
# 鼠标坐标显示文本
self.text_pos = self.pg.TextItem("(0,0)", anchor=(0.5, -1.0), color='k')
self.plot.addItem(self.text_pos)
self.text_pos.setPos(0, 0)
# 鼠标十字移动
self.vLine = self.pg.InfiniteLine(pen=self.pg.mkPen('b', width=1), angle=90, movable=False)
self.hLine = self.pg.InfiniteLine(pen=self.pg.mkPen('b', width=1), angle=0, movable=False)
self.plot.addItem(self.vLine, ignoreBounds=True)
self.plot.addItem(self.hLine, ignoreBounds=True)
# 鼠标移动绑定
self.vb = self.plot.vb
self.proxy = self.pg.SignalProxy(self.plot.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
self.plot.autoRange()
def find_nearest(self, array, value):
idx = (np.abs(array - value)).argmin()
return array[idx]
def mouseMoved(self, evt):
tx = np.array(self.curve_data_x)
pos = evt[0]
if self.plot.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
self.setCursor(Qt.BlankCursor)
self.text_pos.setText("(%0.1f,%0.1f)" % (mousePoint.x(), mousePoint.y()))
self.text_pos.setPos(mousePoint.x(), mousePoint.y())
# self.label.setText("<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y=%0.1f</span>" % (mousePoint.x(), mousePoint.y()))
# index = int(mousePoint.x())
# try:
# n = self.find_nearest(tx,index)
# index = np.where(tx==n)[0][0]
# self.label.setText("<span style='font-size: 12pt;color: blue'>通道实时数据: </span>\
# <span style='font-size: 12pt'>x=\t{:20}, \
# <span style='color: red'>y1=\t{:28}</span> ,\
# <span style='color: green'>y2=\t{:32}</span>"\
# .format('%0.1f'%mousePoint.x(), '%0.1f'%self.curve_master_data[index],'%0.1f'%self.curve_slave_data[index]))
# self.vLine.setPos(mousePoint.x())
# self.hLine.setPos(mousePoint.y())
# except:
# pass
def drawLine(self, x, y):
self.curve_master.setData(x=self.curve_data_x, y=self.curve_master_data)
self.curve_slave.setData(x=self.curve_data_x, y=self.curve_slave_data)
def draw_two(self, x, master, slave):
if master and slave:
if max(master) == 0 or max(slave) == 0:
master = [m * 100 / (max(master) + 0.000001) for m in master]
slave = [m * 100 / (max(slave) + 0.000001) for m in slave]
else:
master = [m * 100 / max(master) for m in master]
slave = [m * 100 / max(slave) for m in slave]
self.curve_master.setData(x=x, y=master)
self.curve_slave.setData(x=x, y=slave)
else:
self.curve_master.setData(x=[], y=[])
self.curve_slave.setData(x=[], y=[])
# self.plot.setXRange(0,300)
# self.plot.setYRange(0,120)
def clear_data(self):
self.curve_data_x = []
self.curve_master_data = []
self.curve_slave_data = []
self.curve_master.setData(x=self.curve_data_x, y=self.curve_master_data)
self.curve_slave.setData(x=self.curve_data_x, y=self.curve_slave_data)
def drawLineAppend(self):
self.curve_master.setData(self.curve_master_data)
self.curve_slave.setData(self.curve_slave_data)
def tunnelZero(self):
self.curve_data_x = []
self.curve_slave_data = []
self.curve_master_data = []
self.drawLine()
class DataTabView(QTableView):
def __init__(self, parent=None):
'''表格初始化'''
super(DataTabView, self).__init__(parent)
self.model = QStandardItemModel(0, 0)
# self.HeaderList = ['x(mm)', 'y(mm)', 'z(mm)', '主测通道(mGy)', '监测通道(mGy)', '修正', '归一化']
self.HeaderList = ['x(mm)', 'y(mm)', 'z(mm)', '主测通道(cGy/min)', '监测通道(cGy/min)']
self.model.setHorizontalHeaderLabels(self.HeaderList) #
self.setModel(self.model)
# 下面代码让表格100填满窗口
self.horizontalHeader().setStretchLastSection(True)
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.isClearChooseLine_Flag = False
# self.setMaximumHeight(250)
self.clear_data()
# 右键菜单设置
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.right_menu)
def right_menu(self):
self.menu = QMenu()
exportAction = QAction("&导出excel", triggered=self.exportToExcel)
self.menu.addAction(exportAction)
self.menu.exec(QCursor.pos())
def exportToExcel(self):
f = QFileDialog.getSaveFileName(self, "导出Excel", '%s/data' % os.getcwd(), 'Excel Files(*.xls)')
if f[0]:
try:
filename = f[0]
wb = xlwt.Workbook()
ws = wb.add_sheet('sheet1') # sheetname
data = []
data.append(self.HeaderList)
row = self.model.rowCount()
for r in range(0, row):
x = self.model.data(self.model.index(r, 0))
y = self.model.data(self.model.index(r, 1))
z = self.model.data(self.model.index(r, 2))
t1 = self.model.data(self.model.index(r, 3))
t2 = self.model.data(self.model.index(r, 4))
if x and y and z and t1 and t2:
data = []
for r in range(0,row):
data.append([float(x), float(y), float(z), float(t1), float(t2)])
if data:
for i in range(0, len(data)):
for j in range(0, len(data[i])):
ws.write(i, j, data[i][j])
wb.save(filename)
QMessageBox.warning(self, '提示', '导出成功!\r\n%s' % filename, QMessageBox.Yes)
return
QMessageBox.warning(self, '警告', '导出失败!', QMessageBox.Yes)
except:
QMessageBox.warning(self, '警告', '无法导出!', QMessageBox.Yes)
def clear_data(self):
self.model.clear()
self.model = QStandardItemModel(0, 0)
self.model.setHorizontalHeaderLabels(self.HeaderList) #
self.setModel(self.model)
def add_data(self, x='', y='', z='', t1='', t2=''):
rowNum = self.model.rowCount() # 总行数
self.model.setItem(rowNum, 0, QStandardItem(str(x)))
self.model.setItem(rowNum, 1, QStandardItem(str(y)))
self.model.setItem(rowNum, 2, QStandardItem(str(z)))
self.model.setItem(rowNum, 3, QStandardItem(str('%.2f'%t1)))
self.model.setItem(rowNum, 4, QStandardItem(str('%.2f'%t2)))
def insert_data(self, rowNum, x='', y='', z='', t1='', t2=''):
# rowNum = self.model.rowCount() # 总行数
self.model.setItem(rowNum, 0, QStandardItem(str(x)))
self.model.setItem(rowNum, 1, QStandardItem(str(y)))
self.model.setItem(rowNum, 2, QStandardItem(str(z)))
self.model.setItem(rowNum, 3, QStandardItem(str('%.2f'%t1)))
self.model.setItem(rowNum, 4, QStandardItem(str('%.2f'%t2)))
def get_standard(self, x, ave):
import math
n = len(x)
s = 0
for i in range(0, n):
s = s + pow((int(x[i]) - ave), 2)
s = math.sqrt(1 / (n - 1) * s)
return s
def get_data(self):
rowNum = self.model.rowCount() # 总行数
x = [self.model.data(self.model.index(i, 1)) for i in range(0, rowNum)]
line1 = [self.model.data(self.model.index(i, 4)) for i in range(0, rowNum)]
line2 = [self.model.data(self.model.index(i, 5)) for i in range(0, rowNum)]
return (x, line1, line2)
def get_all_data(self):
rowNum = self.model.rowCount() # 总行数
colNum = self.model.columnCount() # 总行数
data = []
for j in range(0, colNum):
col = [self.model.data(self.model.index(i, j)) for i in range(0, rowNum)]
data.append(col)
return data
from ui.main import Ui_MainWindow
# from chartAnalyse import chartAnalyseForm
from ui import images
import winsound
class MainWindow(QMainWindow, Ui_MainWindow):
'''三维水箱主程序'''
signalOpengl = pyqtSignal(float, float, float)
signalOpenglLoadConfig = pyqtSignal(dict)
signalTunnel = pyqtSignal(list, list, list)
signalBeep = pyqtSignal(int, int)
signalMsg = pyqtSignal(str, str)
signalTimer = pyqtSignal()
progress_value = 0
# 移动距离
err_x = 0
err_y = 0
err_z = 0
# 真实坐标
real_x = 0
real_y = 0
real_z = 0
# 前一刻坐标
pre_x = 0
pre_y = 0
pre_z = 0
pulse_x = 0
pulse_y = 0
pulse_z = 0
# 重复性测量标志
repeat_measure_flag = False
# 本底测量标志
env_measure_flag = False
# 移动标志
move_flag = False
task_flag = False
taskmove_flag = False
task_cnt = 0
task_current = None
task = None
# 意外停止标志
stop_flag = False
# 任务第一个点移动显示标志
task_move_first_flag = True
pddoarList = []
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
# 界面尺寸最大化
self.setWindowState(Qt.WindowMaximized)
self.setWindowIcon(QIcon(':icons/images_rc/app.png'))
self.setWindowTitle("三维射束分析仪软件-RG202")
# 串口监测定时器
self.serial = serial.Serial()
self.signalMsg.connect(self.MessageBox)
self.signalTimer.connect(self.Timer)
# 密码输入界面
self.pwdInputDlg = PwdInput()
self.pwdInputDlg.setWindowIcon(QIcon(':icons/images_rc/com.png'))
# 串口通信设置
self.comSetWidget = ComSetWidget()
self.comSetWidget.setWindowIcon(QIcon(':icons/images_rc/com.png'))
# flash基本设置
self.baseSetWidget = BaseSetWidget(None, self.serial)
self.baseSetWidget.setWindowIcon(QIcon(':icons/images_rc/move.png'))
self.baseSetWidget.signal_send.connect(self.cmd_send)
# 本底测量
self.envMeasureWidget= EnvMeasureWidget(None, self.serial)
self.envMeasureWidget.setWindowIcon(QIcon(':icons/images_rc/box.png'))
# 重复性测量
self.repeatMeasureDlg = RepeatMeasureDialog(None, self.serial)
self.repeatMeasureDlg.setWindowIcon(QIcon(':icons/images_rc/repeat.png'))
# 曲线处理
# self.chartDealWidget = ChartDealWidget()
# self.horizontalLayout_chartDeal.addWidget(self.chartDealWidget)
# 电机移动示意
self.move_dock = MoveShowDock(self)
self.move_dock.signal_movePos.connect(self.motorMoveAxis_position)
# 电机控制窗口
self.motorControlWidget = MotorControlWidget(None, self.serial)
self.motorControlWidget.signal_movePos.connect(self.motorMoveAxis_position)
self.motorControlWidget.signal_setLimit.connect(self.setLimit)
self.motorControlWidget.pushButton_backZero.clicked.connect(self.cmd_backZero)
self.motorControlWidget.pushButton_setZero.clicked.connect(self.cmd_ResetAxis)
# 项目窗口
self.proj_create_dlg = ProjectCreateDialog()
self.proj_dock = ProjectDock(self)
self.proj_dock.treeWidget.signalClickTask.connect(self.move_dock.rayGL.load_config)
# 添加dock窗口到主窗口中
self.addDockWidget(Qt.LeftDockWidgetArea, self.proj_dock)
self.addDockWidget(Qt.LeftDockWidgetArea, self.move_dock)
# 曲线显示窗口
self.graph = GraphWidget()
self.dataTab = DataTabView()
self.verticalLayout_chart.addWidget(self.graph)
self.verticalLayout_data_table.addWidget(self.dataTab)
# 曲线分析
# self.chartAnalyse = chartAnalyseForm()
# 坐标3d显示信号
self.signalOpengl.connect(self.updatePos)
# 曲线显示信号绑定
self.signalTunnel.connect(self.graph.draw_two)
self.signalBeep.connect(self.beepSound)
self.serial_init()
# 工具栏和菜单
self.createMenus()
def createMenus(self):
# 文件
self.newProjectAct = QAction(QIcon(':icons/images_rc/file.png'),"&新建项目", self, shortcut="Ctrl+N", triggered=self.proj_dock.treeWidget.newProject)
self.openProjectAct = QAction(QIcon(':icons/images_rc/open.png'), "&打开项目", self, shortcut="Ctrl+O", triggered=self.proj_dock.treeWidget.openProject)
self.closeProjectAct = QAction(QIcon(':icons/images_rc/close.png'), "&关闭项目", self, shortcut="Ctrl+C", triggered=self.proj_dock.treeWidget.closeProject)
self.fileChangeAct = QAction(QIcon(':icons/images_rc/file.png'), "&TPS文件转换", self, triggered=self.TpsFileChange)
self.exitAct = QAction(QIcon(':icons/images_rc/exit.png'), "&退出", self, shortcut="Ctrl+Q", statusTip="关闭程序", triggered=self.close)
# self.printAct = QAction(QIcon(':icons/images_rc/printer.png'), "&打印", self, shortcut="Ctrl+P", triggered=self.chartAnalyse.on_printAction1_triggered)
# self.printPreviewAct = QAction(QIcon(':icons/images_rc/view.png'), "&打印预览", triggered=self.chartAnalyse.on_printAction2_triggered)
self.fileMenu = self.menuBar().addMenu("&文件")
self.fileMenu.addAction(self.newProjectAct)
self.fileMenu.addAction(self.openProjectAct)
self.fileMenu.addAction(self.closeProjectAct)
self.fileMenu.addAction(self.fileChangeAct)
# 最近文件打开
# self.recentProjectMenu = self.fileMenu.addMenu(QIcon(':icons/images_rc/project.png'), "&最近项目")
config_path = os.getcwd() + '/conf/project.ini'
config = configparser.ConfigParser()
config.read(config_path)
recent = dict(config['recent'])
recent_list = [recent[k] for k in recent.keys()]
self.recentProjectActions = []
for s in recent_list:
Action = QAction(QIcon(':icons/images_rc/project.png'), "&%s" % s, self,
triggered=self.proj_dock.treeWidget.openRecentProject)
self.recentProjectActions.append(Action)
# self.recentProjectMenu.addActions(self.recentProjectActions)
self.fileMenu.addSeparator()
self.fileMenu.addAction(self.exitAct)
# 视图
self.addPddTaskAct = QAction(QIcon(':icons/images_rc/pdd.png'),"&添加PDD任务", triggered=self.proj_dock.treeWidget.addPddTask)
self.addOarTaskAct = QAction(QIcon(':icons/images_rc/oar.png'),"&添加OAR任务", triggered=self.proj_dock.treeWidget.addOarTask)
self.projDockShowAct = QAction(QIcon(':icons/images_rc/project.png'), "&项目管理窗口", triggered=self.proj_dock.show)
self.moveDockShowAct = QAction(QIcon(':icons/images_rc/motor.png'), "&移动显示窗口", triggered=self.move_dock.show)
self.viewMenu = self.menuBar().addMenu("&视图")
self.viewMenu.addAction(self.addPddTaskAct)
self.viewMenu.addAction(self.addOarTaskAct)
self.viewMenu.addSeparator()
self.viewMenu.addAction(self.projDockShowAct)
self.viewMenu.addAction(self.moveDockShowAct)
# 设置
# self.comSetAct = QAction(QIcon(':icons/images_rc/com.png'), "&通信串口设置", self, triggered=self.comSetWidget.show)
self.comSetAct = QAction("&通信串口", self, triggered=self.comSetWidget.show)
# self.baseSetAct = QAction(QIcon(':icons/images_rc/move.png'),"&移动和测量设置", self, triggered=self.baseSetWidget.exec)
self.baseSetAct = QAction(QIcon(':icons/images_rc/move.png'),"&移动和测量设置", self, triggered=self.pwdInput)
self.settingMenu = self.menuBar().addMenu("&设置")
self.settingMenu.addAction(self.comSetAct)
self.settingMenu.addAction(self.baseSetAct)
self.skinMenu = self.settingMenu.addMenu("&界面")
self.skinDefaultAct = QAction('&经典(默认)', self, triggered=lambda:self.skinChanged('default'))
self.skinBlackAct = QAction('&黑色', self, triggered=lambda:self.skinChanged('dark'))
self.skinBlueAct = QAction('&天蓝色', self, triggered=lambda:self.skinChanged('blue'))
self.skinMenu.addAction(self.skinDefaultAct)
self.skinMenu.addAction(self.skinBlackAct)
self.skinMenu.addAction(self.skinBlueAct)
# 读取信息
self.readInfoAct = QAction(QIcon(':icons/images_rc/info.png'),'&读取信息', self, triggered=self.cmd_ReadInfo)
# 操作
self.envAct = QAction(QIcon(':icons/images_rc/box.png'),'&本底测量', self, triggered=self.envMeasureWidget.exec)
self.repeatMeasureAct = QAction(QIcon(':icons/images_rc/repeat.png'),'&重复性', self, triggered=self.repeatMeasureDlg.exec)
self.motorControlAct = QAction(QIcon(':icons/images_rc/motor.png'), "&电机操作", triggered=self.motorControlWidget.exec)
self.operateMenu = self.menuBar().addMenu("&操作")
self.operateMenu.addAction(self.envAct)
self.operateMenu.addAction(self.repeatMeasureAct)
self.operateMenu.addAction(self.motorControlAct)
# 其他菜单
self.otherMenu = self.menuBar().addMenu("&其他")
self.openDocMenu = self.otherMenu.addMenu(QIcon(':icons/images_rc/file.png'), "&相关文档")
self.doc_path = os.getcwd() + "/doc"
doc_list=os.listdir(self.doc_path)
self.openDocActions = []
for s in doc_list:
icon = QIcon(':icons/images_rc/file.png')
if s.endswith('.xls') or s.endswith('.xlsx'):
icon = QIcon(':icons/images_rc/excel.png')
if s.endswith('.doc') or s.endswith('.docx'):
icon = QIcon(':icons/images_rc/word.png')
if s.endswith('.pdf'):
icon = QIcon(':icons/images_rc/pdf.png')
Action = QAction(icon, "&%s" % s, self, triggered=self.openDoc)
self.openDocActions.append(Action)
self.openDocMenu.addActions(self.openDocActions)
# 串口状态
self.comboBox_port = QComboBox()
self.qta_com_status = QLabel()
self.qta_com_status.setStyleSheet('color: red;')
self.qta_com_status.setFont(qta.font('fa', 32))
self.qta_com_status.setText(unichr(0xf111))
# 任务执行
self.startTaskAct = QAction(QIcon(':icons/images_rc/start.png'),'&开始执行', self, triggered=self.startMove)
self.stopTaskAct = QAction(QIcon(':icons/images_rc/stop.png'),'&暂停任务', self, triggered=self.pauseMove)
# self.stopMoveAct = QAction('&停止移动', self, triggered=self.motorControlWidget.moveStop)
# 曲线显示
self.chartAnalyseAct = QAction(QIcon(':icons/images_rc/chart.png'),'&单曲线分析', self, triggered=self.proj_dock.treeWidget.showChart)
self.multiChartAnalyseAct = QAction(QIcon(':icons/images_rc/multi-chart.png'),'&多曲线分析', self, triggered=self.proj_dock.treeWidget.multiChartShow)
self.label_comStatus= QLabel()
self.label_comStatus.setMinimumWidth(32)
self.label_comStatus.setStyleSheet('image: url(:icons/images_rc/com-offline.png)')
self.toolbar = self.addToolBar('工具栏')
# self.toolbar.addWidget(self.qta_com_status)
self.toolbar.addWidget(self.label_comStatus)
self.toolbar.addAction(self.comSetAct)
# self.toolbar.addWidget(QLabel('串口通信'))
self.toolbar.addAction(self.readInfoAct)
self.toolbar.addSeparator()
self.toolbar.addAction(self.envAct)
self.toolbar.addAction(self.repeatMeasureAct)
self.toolbar.addSeparator()
self.toolbar.addAction(self.newProjectAct)
self.toolbar.addAction(self.openProjectAct)
self.toolbar.addAction(self.closeProjectAct)
self.toolbar.addSeparator()
self.toolbar.addAction(self.addPddTaskAct)
self.toolbar.addAction(self.addOarTaskAct)
self.toolbar.addSeparator()
self.toolbar.addAction(self.startTaskAct)
self.toolbar.addAction(self.stopTaskAct)
self.toolbar.addSeparator()
self.toolbar.addAction(self.chartAnalyseAct)
self.toolbar.addAction(self.multiChartAnalyseAct)
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.actionDisable(['env','repeat','start','stop'])
def pwdInput(self):
dlg = PwdInput()
if dlg.exec():
pwd = dlg.pwd
if dlg.pwd == 'fushe01020304':
self.baseSetWidget.exec()
else:
QMessageBox.information(self, '提示','密码错误', QMessageBox.Yes)
def TpsFileChange(self):
# 文件转换
self.fileChangeForm= None
self.fileChangeForm= FileChangeForm()
self.fileChangeForm.show()
def actionEnabled(self,action):
if 'env' in action:
self.envAct.setEnabled(True)
if 'com' in action:
self.comSetAct.setEnabled(True)
if 'repeat' in action:
self.repeatMeasureAct.setEnabled(True)
if 'start' in action:
self.startTaskAct.setEnabled(True)
if 'stop' in action:
self.stopTaskAct.setEnabled(True)
def actionDisable(self, action):
if 'env' in action:
self.envAct.setEnabled(False)
if 'com' in action:
self.comSetAct.setEnabled(False)
if 'repeat' in action:
self.repeatMeasureAct.setEnabled(False)
if 'start' in action:
self.startTaskAct.setEnabled(False)
if 'stop' in action:
self.stopTaskAct.setEnabled(False)
def skinChanged(self, name='default'):
if name == "default":
self.setStyleSheet('None')
if name == "dark":
self.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.proj_dock.treeWidget.pddDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.proj_dock.treeWidget.oarDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.proj_dock.treeWidget.createProjectDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.repeatMeasureDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.motorControlWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.comSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.baseSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
self.envMeasureWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_Dark"))
if name == "blue":
self.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.proj_dock.treeWidget.pddDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.proj_dock.treeWidget.oarDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.proj_dock.treeWidget.createProjectDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.repeatMeasureDlg.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.motorControlWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.comSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.baseSetWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
self.envMeasureWidget.setStyleSheet(PyQt5_stylesheets.load_stylesheet_pyqt5(style="style_blue"))
def openDoc(self):
name = self.sender().text().replace('&','')
import win32api
import win32con
from win32comext.shell.shell import ShellExecuteEx
from win32comext.shell import shellcon
helplFile = r'"C:\\Program Files (x86)\\WPS Office\\wps.exe"'
try:
# 文件路径加双引号,防止路径中存在空格
FileName=r'"%s\doc\%s"'%(os.getcwd(), name)
procInfo = ShellExecuteEx(nShow=win32con.SW_SHOWNORMAL,
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
lpVerb='open',
lpFile=helplFile,
lpParameters=FileName)
except:
QMessageBox.warning(self, '错误' , '请安装WPS,并确保其安装路径在: %s'%helplFile , QMessageBox.Yes)
def updatePos(self, x, y, z):
self.motorControlWidget.updatePos(x, y, z)
self.move_dock.updatePos(x, y, z)
def beepSound(self, fps, _time):
t = Timer(0.001, winsound.Beep, args=(fps, _time))
t.start()
def serial_init(self):
'''初始化串口'''
self.serial.timeout = 0.5 # make sure that the alive event can be checked from time to time
self.thread = None
self.serial_find_flag = False
self.serial_alive = False
self.serial.port = None
self.serial.baudrate = '115200'
self.serial.bytesize = 8
self.serial.parity = 'N'
self.serial.stopbits = 1
self.serial.dtr = True
self.serial.rts = True
self.recv = ''
self.portList = []
# 串口查询定时器
self.thread_find_open = threading.Thread(target=self.FindOpenCom)
self.thread_find_open.setDaemon(True)
self.thread_find_open.start()
def Timer(self):
self.timer_recv = QTimer()
self.timer_recv.timeout.connect(self.RecvCom)
self.timer_recv.start(50)
# 状态变化
self.qta_com_status.setStyleSheet('color: green;')
self.label_comStatus.setStyleSheet('image: url(:icons/images_rc/com.png)')
# 读取信息
self.cmd_ReadInfo()
# self.actionEnabled(['start','env','repeat'])
# 任务执行初始化
self.taskRunInit()
def FindOpenCom(self):
'''搜索串口并打开串口'''
while not self.serial_alive:
config = configparser.ConfigParser()
config.read(os.getcwd() + '/conf/com.ini')
port_list = serial.tools.list_ports.comports()
port = ''
baudrate = ''
for p in port_list:
if p.serial_number == config['com']['serial_number']:
port = p.device
baudrate = config['com']['baudrate']
break
if port and baudrate:
self.serial_find_flag = False
self.serial.port = port
self.serial.baudrate = baudrate
try:
self.serial.open()
except serial.SerialException as e:
print(e)
# self.signalMsg.emit('串口打开错误', '错误原因:\n %s' % e)
# QMessageBox.information(self, '串口打开错误', '错误原因:\n %s' % e, QMessageBox.Yes)
else:
self.serial_alive = True
self.signalTimer.emit()
def RecvCom(self):
""" 串口接收 """
if self.serial_alive:
try:
n = self.serial.inWaiting()
if n:
b = self.serial.read(n)
# b = self.serial.read(255)
# if b:
# 将byte转换为十六进制字符串
data = str(binascii.b2a_hex(b).decode('utf-8'))
self.recv += data.upper()
logger.info('接收命令:')
logger.info(' '.join([self.recv[i * 2:i * 2 + 2] for i in range(0, int(len(self.recv) / 2))]))
# if DEBUG:
# print('接收命令:', ' '.join([self.recv[i * 2:i * 2 + 2] for i in range(0, int(len(self.recv) / 2))]))
try:
self.cmd_deal()
except Exception as e:
print(e)
except:
# 串口异常, 关闭串口
if self.serial.isOpen():
self.serial_alive = False
self.serial.close()
# self.qta_com_status.setStyleSheet('color: red;')
self.label_comStatus.setStyleSheet('image: url(:icons/images_rc/com-offline.png)')
self.startTaskAct.setEnabled(False)
self.stopTaskAct.setEnabled(False)
self.repeatMeasureAct.setEnabled(False)
self.envAct.setEnabled(False)
# self.timer_recv.stop()
# 打开串口查询线程
self.thread_find_open = threading.Thread(target=self.FindOpenCom)
self.thread_find_open.setDaemon(True)
self.thread_find_open.start()
def WriteCom(self, cmd):
'''串口写入,十六进制格式字符串'''
if self.serial_alive:
if self.serial.isOpen():
data = binascii.unhexlify(cmd)
logger.info('发送命令:')
logger.info(' '.join([cmd[i * 2:i * 2 + 2] for i in range(0, int(len(cmd) / 2))]))
# if DEBUG:
# print('发送命令:', ' '.join([cmd[i * 2:i * 2 + 2] for i in range(0, int(len(cmd) / 2))]))
self.serial.write(data)
else:
QMessageBox.information(self, '通信提示', '通信异常,请检查通信接口', QMessageBox.Yes)
def cmd_send(self, cmd_list):
'''发送命令'''
if DEBUG:
print((cmd_list))
cmd = ''.join(cmd_list)
cmd.upper()
cmd_start = cmd_list[0]
cmd_len = hex(int(len(cmd) / 2)).replace('0x', '').zfill(4).upper()
cmd_list[1] = cmd_len
if len(cmd_len) == 4:
hex_len = int(cmd_len[:2], 16) + int(cmd_len[-2:], 16)
cmd_sum = (hex(int(cmd_start, 16) + int(cmd_len[:2], 16) + int(cmd_len[-2:], 16))).upper()[-2:]
if len(cmd_len) == 2:
hex_len = int(cmd_len, 16)
cmd_sum = (hex(int(cmd_start, 16) + int(cmd_len, 16))).upper()[-2:]
# print(cmd_sum)
cmd_list[2] = cmd_sum
s = 0
s = int(cmd_list[0], 16) + hex_len + int(cmd_list[2], 16) + int(cmd_list[3], 16)
for i in range(0, len(cmd_list[4])):
if i % 2 == 0:
s = s + int(cmd_list[4][i:i + 2], 16)
s = hex(s).upper()[-2:]
cmd_list[-1] = s
send = ''.join(cmd_list)
self.WriteCom(send)
def cmd_deal(self):
'''串口处理命令,监测校验和是否正确'''
self.recv = self.recv
start = self.recv.find("AA")
startwith = self.recv.startswith('AA')
def find_last(string, s):
last_position = -1
while True:
position = string.find(s, last_position + 1)
if position == -1:
return last_position
last_position = position
start_num = len(re.compile('.*?(AA).*?').findall(self.recv))
if self.recv.startswith('AA'):
for i in re.compile('.*?(AA).*?').findall(self.recv):
if len(self.recv) < 6:
return
theory_len = int(self.recv[2:4], 16)
real_len = len(self.recv) / 2
if theory_len <= real_len:
cmd = self.recv[start:theory_len * 2]
self.recv = self.recv[theory_len * 2:]
# print('截取后',self.recv)
cmd_start = cmd[0:2]
cmd_len = cmd[2:4]
cmd_sum = cmd[4:6]
if cmd_sum == (hex(int(cmd_start, 16) + int(cmd_len, 16))).upper()[-2:]:
cmd_cmd = cmd[6:8]
cmd_data = cmd[8:-2]
cmd_endsum = cmd[-2:]
s = 0
for i in range(0, len(cmd) - 2):
if i % 2 == 0:
s = s + int(cmd[i:i + 2], 16)
s = hex(s).upper()[-2:]
if s == cmd_endsum:
try:
self.cmd_type(cmd_cmd, cmd_data)
except Exception as e:
print(e)
else:
if DEBUG:
self.recv = ''
print('校验错误!!!!!!!!')
print('正确:', s, '错误:', cmd_endsum)
else:
return
else:
self.recv = self.recv[self.recv.find('AA'):]
def cmd_type(self, cmd_cmd, cmd_data):
pos = (self.real_x,self.real_y,self.real_z)
# flash读写基本配置
self.baseSetWidget.serial_deal(cmd_cmd, cmd_data)
# 重复性测量
# self.repeatMeasureDlg.serial_deal(cmd_cmd, cmd_data, pos)
# 漏射线测量
self.envMeasureWidget.serial_deal(cmd_cmd, cmd_data)
if cmd_cmd == '51':
self.doneMoveToTarget(cmd_data)
if cmd_cmd == '50':
self.doneOnceMeasure(cmd_data) # 连续走位
if cmd_cmd == '5A':
self.doneCurrentTask()
if cmd_cmd == '44': # 复位坐标
self.real_x = 0
self.real_y = 0
self.real_z = 0
self.pre_x = 0
self.pre_y = 0
self.pre_z = 0
self.signalOpengl.emit(0, 0, 0)
self.signalMsg.emit('提示', '坐标复位成功')
if cmd_cmd == '53': # 读取坐标
data = cmd_data[2:]
self.real_x, self.real_y, self.real_z = self.get_xyz(data)
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
if cmd_cmd == '54': # 紧急停止
self.doneStop(cmd_data)
if cmd_cmd == '55': # 紧急停止
# 清除命令任务执行标志
self.taskRunThread.clearFlag()
data = cmd_data[2:]
x = data[2:10]
y = data[12:20]
z = data[22:30]
self.updateAxis(x,y,z)
if cmd_cmd == '80':
edge = cmd_data[0:2]
data = cmd_data[2:]
x = data[2:10]
y = data[12:20]
z = data[22:30]
self.updateAxis(x,y,z)
inf = '达到限位'
if edge == '31':
inf = 'x+向达到限位'
if edge == '32':
inf = 'x-向达到限位'
if edge == '33':
inf = 'y+向达到限位'
if edge == '34':
inf = 'y-向达到限位'
if edge == '35':
inf = 'z+向达到限位'
if edge == '36':
inf = 'z-向达到限位'
box = QMessageBox(QMessageBox.Information, "提示", "%s!\r\n\r\n是否回到原点?"%inf)
qyes = box.addButton(self.tr("回原点"), QMessageBox.YesRole)
qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
box.exec_()
if box.clickedButton() == qyes:
self.taskRunThread.clearFlag()
self.cmd_backZero()
elif box.clickedButton() == qcancel:
self.taskRunThread.clearFlag()
else:
return
if cmd_cmd == '6B':
data = cmd_data[2:]
limit_x1 = slice(2,10)
limit_x2 = slice(12,20)
limit_y1 = slice(22,30)
limit_y2 = slice(32,40)
limit_z1 = slice(42,50)
limit_z2 = slice(52,60)
self.motorControlWidget.updateLimit(
self.HexToNeg(data[limit_x1])/AXIS_MULTIPLE ,
self.HexToNeg(data[limit_x2])/AXIS_MULTIPLE ,
self.HexToNeg(data[limit_y1])/AXIS_MULTIPLE ,
self.HexToNeg(data[limit_y2])/AXIS_MULTIPLE ,
self.HexToNeg(data[limit_z1])/AXIS_MULTIPLE ,
self.HexToNeg(data[limit_z2])/AXIS_MULTIPLE
)
if cmd_cmd == '6A':
QMessageBox.information(self, '提示', '设置限位成功!', QMessageBox.Yes)
if cmd_cmd == '71': # 重复性测量
data = cmd_data
if self.repeatMeasureDlg.measure_flag:
'''调试测量数据'''
t1 = 0
t2 = 0
if data[:2] == 'FF':
t1 = int(data[:8], 16) - int('FFFFFFFF', 16) - 1
else:
t1 = int(data[:8], 16)
if data[-8:-6] == 'FF':
t2 = int(data[-8:], 16) - int('FFFFFFFF', 16) - 1
else:
t2 = int(data[-8:], 16)
t1 = self.baseSetWidget.scale_k*t1+self.baseSetWidget.scale_b
t2 = self.baseSetWidget.scale_k_2*t2+self.baseSetWidget.scale_b_2
x = pos[0]
y = pos[1]
z = pos[2]
self.repeatMeasureDlg.table_add_data(x=x,y=y,z=z, t1=t1, t2=t2)
if cmd_cmd == '73': # 停止测量
pass
if cmd_cmd == '41': # 停止测量
self.repeatMeasureDlg.MessageBox('提示', '设置传输速度成功!')
# QMessageBox.information(self, '提示', '设置传输速度成功!', QMessageBox.Yes)
if cmd_cmd == '82':
# 读取信息
_len = int(cmd_data[0:2], 16)
# flash信息处理
flash_start = 2
flash_end = 2+_len*2
flash_info = cmd_data[flash_start:flash_end]
self.baseSetWidget.updateRead(flash_info)
# 坐标信息处理
axis_start = flash_end
axis_end = flash_end + 3*4*2
axis_info = cmd_data[axis_start:axis_end]
self.real_x = self.HexToNeg(axis_info[0:8])/AXIS_MULTIPLE
self.real_y = self.HexToNeg(axis_info[8:16])/AXIS_MULTIPLE
self.real_z = self.HexToNeg(axis_info[16:24])/AXIS_MULTIPLE
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
# 摆放位置
angle_start = axis_end
angle_end = axis_end + 2
angle_info = cmd_data[angle_start:angle_end]
self.proj_dock.treeWidget.pddDlg.styleSet(angle_info)
self.proj_dock.treeWidget.oarDlg.styleSet(angle_info)
QMessageBox.information(self, '提示', '下位机信息读取成功!', QMessageBox.Yes)
self.actionEnabled(['start','env','repeat'])
def updateAxis(self,x,y,z):
"""更新坐标"""
def HexToNeg(hex_str):
if hex_str[0] == 'F' or hex_str[0] == 'f':
return int(hex_str, 16) - (1 << 32)
else:
return int(hex_str, 16)
x = HexToNeg(x)
y = HexToNeg(y)
z = HexToNeg(z)
self.real_x = float('%.3f' % (x / 100))
self.real_y = float('%.3f' % (y / 100))
self.real_z = float('%.3f' % (z / 100))
# self.real_x = float('%.3f' % (x / AXIS_MULTIPLE))
# self.real_y = float('%.3f' % (y / AXIS_MULTIPLE))
# self.real_z = float('%.3f' % (z / AXIS_MULTIPLE))
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
def get_xyz(self, data):
'''处理数据包中包含的xyz坐标'''
if data[2:4] == 'FF': # 计算通道x
x = int(data[2:10], 16) - int('FFFFFFFF', 16) - 1
else:
x = int(data[2:10], 16)
if data[12:14] == 'FF': # 计算通道y
y = int(data[12:20], 16) - int('FFFFFFFF', 16) - 1
else:
y = int(data[12:20], 16)
if data[22:24] == 'FF': # 计算通道z
z = int(data[22:30], 16) - int('FFFFFFFF', 16) - 1
else:
z = int(data[22:30], 16)
return x / AXIS_MULTIPLE, y / AXIS_MULTIPLE, z / AXIS_MULTIPLE
def cmd_read_axis(self):
'''读取当前坐标坐标'''
cmd = WATER_CMD['读取坐标']
self.cmd_send(cmd)
def cmd_ResetAxis(self):
'''复位坐标系'''
cmd = WATER_CMD['复位坐标']
cmd[4] = ''
self.cmd_send(cmd)
def cmd_MoveStop(self):
'''紧急停止'''
cmd = WATER_CMD['移动停止']
cmd[4] = ''
self.cmd_send(cmd)
# self.back_zero_flag = False
# 开启移动标志
self.move_flag = False
self.stop_flag = True
# self.road_cnt= 0
self.task_flag = False
def cmd_ReadInfo(self):
cmd = WATER_CMD['读取信息']
cmd[4] = '18'
self.cmd_send(cmd)
def motorMoveAxis_position(self, x, y, z):
self.err_x = float(x) - self.real_x
self.err_y = float(y) - self.real_y
self.err_z = float(z) - self.real_z
# self.move_flag = True
if self.err_x < 0:
cmd_x = ('32')
else:
cmd_x = ('31')
if self.err_y < 0:
cmd_y = ('34')
else:
cmd_y = ('33')
if self.err_z < 0:
cmd_z = ('36')
else:
cmd_z = ('35')
if DEBUG:
print(('电机走步差值 x:%s y:%s z:%s' % (self.err_x, self.err_y, self.err_z)))
print('电机正在移动到坐标:')
print(('(%s,%s,%s)' % (x, y, z)))
cmd = WATER_CMD['电机走步']
data_x = hex(abs(int('%.0f'%(self.err_x * AXIS_MULTIPLE)))).replace('0x', '').zfill(8).upper()
data_y = hex(abs(int('%.0f'%(self.err_y * AXIS_MULTIPLE)))).replace('0x', '').zfill(8).upper()
data_z = hex(abs(int('%.0f'%(self.err_z * AXIS_MULTIPLE)))).replace('0x', '').zfill(8).upper()
# data_y = hex(int(abs(round(self.err_y, 2) * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
# data_z = hex(int(abs(round(self.err_z, 2) * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
cmd[4] = cmd_x + data_x + cmd_y + data_y + cmd_z + data_z
self.cmd_send(cmd)
def motorMoveAxis_continue(self, x, y, z, step_x, step_y, step_z):
self.err_x = float(x) - self.real_x
self.err_y = float(y) - self.real_y
self.err_z = float(z) - self.real_z
# self.move_flag = True
if self.err_x < 0:
cmd_x = ('32')
else:
cmd_x = ('31')
if self.err_y < 0:
cmd_y = ('34')
else:
cmd_y = ('33')
if self.err_z < 0:
cmd_z = ('36')
else:
cmd_z = ('35')
if DEBUG:
print(('电机走步差值 x:%s y:%s z:%s' % (self.err_x, self.err_y, self.err_z)))
print('电机正在移动到坐标:')
print(('(%s,%s,%s)' % (x, y, z)))
cmd = WATER_CMD['连续测量']
data_x = hex(int(abs(self.err_x * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
data_y = hex(int(abs(self.err_y * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
data_z = hex(int(abs(self.err_z * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
step_pulse_x = hex(int(abs(step_x * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
step_pulse_y = hex(int(abs(step_y * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
step_pulse_z = hex(int(abs(step_z * AXIS_MULTIPLE))).replace('0x', '').zfill(8).upper()
cmd[4] = cmd_x + data_x + cmd_y + data_y + cmd_z + data_z + \
'3A' + step_pulse_x + '3B' + step_pulse_y + '3C' + step_pulse_z
self.cmd_send(cmd)
def setLimit(self, x1,x2,y1,y2,z1,z2):
# err_x = self.real_x
# err_y = self.real_y
# err_z = self.real_z
def tohex_8(t):
return hex(0xFFFFFFFF&int(t*AXIS_MULTIPLE)).replace('0x', '').zfill(8).upper()
cmd = WATER_CMD['设置限位']
cmd[4] ='31' + tohex_8(x1) +\
'32' + tohex_8(x2) +\
'33' + tohex_8(y1) +\
'34' + tohex_8(y2) +\
'35' + tohex_8(z1) +\
'36' + tohex_8(z2)
self.cmd_send(cmd)
def get_road_axis(self, road):
'''获取任务路线所有坐标'''
road = []
def graphChange(self):
"图表切换"
if self.task_current['type'] == 'SCAN':
self.graph.setVisible(False)
self.graphScan.setVisible(True)
else:
self.graph.setVisible(True)
self.graphScan.setVisible(False)
self.scanPoint_x = np.array([])
self.scanPoint_y = np.array([])
self.scanPoint_z = np.array([])
def taskRunInit(self):
"开始移动控制线程"
# 创建移动控制线程
self.taskRunThread = TaskRunManager()
self.taskRunThread.signal.connect(self.MoveControl)
self.timeTaskRun = QTimer()
self.timeTaskRun.timeout.connect(self.taskRunThread.running)
self.timeTaskRun.start(100)
self.moveControlThread_done = False
def taskRunFinish(self):
"关闭移动控制线程"
self.taskRunThread.done = True
self.moveControlThread_done = True
def startMove(self):
self.task = self.proj_dock.treeWidget.getSelectTasks()
if self.task:
self.taskRunThread.firstRun()
else:
QMessageBox.warning(self, "提示","请选择要执行的任务!", QMessageBox.Yes)
def pauseMove(self):
if self.task:
self.taskRunThread.pauseRun()
else:
QMessageBox.warning(self, "提示","请选择要执行的任务!", QMessageBox.Yes)
def doneCurrentTask(self):
"""执行完当前任务, 命令:0x5A"""
self.proj_dock.treeWidget.addDataFile(condition=self.task_current, data=self.pddoarList)
self.actionDisable(['stop'])
if self.task_cnt >= len(self.task) - 1:
self.proj_dock.treeWidget.markDoneTaskFile(self.taskRunThread.step)
"所有任务执行完成"
self.task_flag = False
self.move_flag = False
self.measure_flag = False
self.task_cnt = 0
# 设置移动到第一个点标记
self.task_move_first_flag = False
self.progress_value = 0
# 清除线程中的步骤
self.taskRunThread.step = 0
box = QMessageBox(QMessageBox.Information, "提示", "所有任务已经执行完成!\r\n\r\n是否回到原点?")
qyes = box.addButton(self.tr("回原点"), QMessageBox.YesRole)
qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
box.exec_()
if box.clickedButton() == qyes:
self.taskRunThread.clearFlag()
self.cmd_backZero()
elif box.clickedButton() == qcancel:
self.taskRunThread.clearFlag()
self.startTaskAct.setEnabled(True)
else:
return
else:
self.proj_dock.treeWidget.markDoneTaskFile(self.taskRunThread.step)
if self.baseSetWidget.task_auto:
self.taskRunThread.nextRun()
else:
box = QMessageBox(QMessageBox.Information, "提示", "是否执行下一个任务?")
qyes = box.addButton(self.tr("执行"), QMessageBox.YesRole)
qno = box.addButton(self.tr("回原点"), QMessageBox.NoRole)
qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
box.exec_()
if box.clickedButton() == qyes:
self.taskRunThread.nextRun()
elif box.clickedButton() == qno:
self.taskRunThread.clearFlag()
self.cmd_backZero()
elif box.clickedButton() == qcancel:
self.taskRunThread.clearFlag()
self.startTaskAct.setEnabled(True)
else:
return
def doneMoveToTarget(self, data):
"""移动到目标点走位完成, 命令:0x51"""
if data == 'FF': # 走位完成
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
if self.taskRunThread.move_to_first_flag:
self.taskRunThread.continueRun()
self.taskRunThread.move_to_first_flag = False
return
if self.real_x==0 and self.real_y == 0 and self.real_z == 0:
QMessageBox.information(self, '提升','已经回到原点!',QMessageBox.Yes)
self.startTaskAct.setEnabled(True)
return
data = data[2:]
x = self.HexToNeg(data[2:10])
y = self.HexToNeg(data[12:20])
z = self.HexToNeg(data[22:30])
self.real_x = x / AXIS_MULTIPLE
self.real_y = y / AXIS_MULTIPLE
self.real_z = z / AXIS_MULTIPLE
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
def doneOnceMeasure(self, data):
"""完成一次数据测量采集, 命令: 0x50"""
# print("数据包",data)
if data == 'FF': # 走步任务完成
print("连续测量任务完成")
return
else:
data = data[2:]
x = self.HexToNeg(data[2:10])
y = self.HexToNeg(data[12:20])
z = self.HexToNeg(data[22:30])
self.real_x = float('%.3f' % (x / AXIS_MULTIPLE))
self.real_y = float('%.3f' % (y / AXIS_MULTIPLE))
self.real_z = float('%.3f' % (z / AXIS_MULTIPLE))
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
self.progress_value += 1
t1 = self.HexToNeg(data[-16:-8])
t2 = self.HexToNeg(data[-8:])
# ad采集饱和溢出, 紧急停止
if t1 > 60000 or t2 > 60000:
self.pauseMove()
return
# pdd_data = Help.pdd_data
# # 模拟数据
# for i in range(0, len(pdd_data)):
# tmp_z = pdd_data[i][0]
# if z==tmp_z*100:
# t2 = pdd_data[i][1]
# t1 = pdd_data[i][2]
# break
# 刻度系数转换
t1 = self.baseSetWidget.scale_k*t1+self.baseSetWidget.scale_b
t2 = self.baseSetWidget.scale_k_2*t2+self.baseSetWidget.scale_b_2
t1 = float('%.4f'%t1)
t2 = float('%.4f'%t2)
t = self.task_current
# 添加一次数据
timetest = time.strftime("%Y:%m:%d-%H:%M:%S", time.localtime())
if t['ray_type'] == '电子':
power = t['power'].replace('MV','').replace('MeV','')
if int(power) < 10:
self.pddoarList.append([self.real_x, self.real_y, self.real_z, t2, t1])
self.dataTab.add_data(x=self.real_x, y=self.real_y, z=self.real_z, t1=t2, t2=t1)
else:
self.pddoarList.append([self.real_x, self.real_y, self.real_z, t1, t2])
self.dataTab.add_data(x=self.real_x, y=self.real_y, z=self.real_z, t1=t1, t2=t2)
# self.dataTab.insert_data(rowNum=len(self.pddoarList),x=self.real_x, y=self.real_y, z=self.real_z, t1=t2, t2=t1)
else:
self.pddoarList.append([self.real_x, self.real_y, self.real_z, t1, t2])
self.dataTab.add_data(x=self.real_x, y=self.real_y, z=self.real_z, t1=t1, t2=t2)
# self.dataTab.insert_data(rowNum=len(self.pddoarList), x=self.real_x, y=self.real_y, z=self.real_z, t1=t1, t2=t2)
# return
# 加速器异常停止
if len(self.pddoarList) > 1:
# task_stop_err = self.baseSetWidget.scale_k_2*self.baseSetWidget.task_stop_err+self.baseSetWidget.scale_b_2
err = abs(self.pddoarList[-2][-1] - self.pddoarList[-1][-1])
task_stop_err = self.baseSetWidget.task_stop_err
if abs(self.pddoarList[-2][-1] - self.pddoarList[-1][-1]) > task_stop_err:
self.pauseMove()
return
if self.measure_flag:
data = self.pddoarList
# 曲线显示数据是否实时修正
task_show = self.baseSetWidget.task_show
if task_show == "modify":
x = [float(d[0]) for d in data]
y = [float(d[1]) for d in data]
z = [float(d[2]) for d in data]
tm = [float('%.2f'%float(d[3])) for d in data]
ts = [float('%.2f'%float(d[4])) for d in data]
repeat = [float('%.4f'%(m/(s+0.00000001))) for m,s in zip(tm,ts)]
normal = [float('%.4f'%(100*r/(max(repeat)+0.0000001))) for r in repeat]
data = []
for i in range(0, len(normal)):
# data.append([x[i], y[i], z[i], normal[i], ts[i]])
data.append([x[i], y[i], z[i], normal[i], 0])
if t['type'] == 'PDD':
self.signalTunnel.emit([d[2] for d in data], [d[3] for d in data], [d[4] for d in data])
return
if t['type'] == 'OAR':
if t['angle'] == '0' or t['angle'] == '180':
if t['direction'] == 'G->T' or t['direction'] == 'T->G':
self.signalTunnel.emit([d[1] for d in data], [d[3] for d in data], [d[4] for d in data])
else:
self.signalTunnel.emit([d[0] for d in data], [d[3] for d in data], [d[4] for d in data])
if t['angle'] == '90' or t['angle'] == '270':
if t['direction'] == 'G->T' or t['direction'] == 'T->G':
self.signalTunnel.emit([d[0] for d in data], [d[3] for d in data], [d[4] for d in data])
else:
self.signalTunnel.emit([d[1] for d in data], [d[3] for d in data], [d[4] for d in data])
def doneStop(self, data):
""" 完成紧急停止, 命令: 0x54"""
if len(self.pddoarList) > 1:
print("删除多余的数")
del self.pddoarList[-1]
del self.pddoarList[-1]
row = self.dataTab.model.rowCount()
if row >= 2:
self.dataTab.model.removeRow(row-1)
self.dataTab.model.removeRow(row-2)
else:
self.dataTab.model.removeRow(0)
else:
self.dataTab.clear_data()
self.pddoarList = []
data = data[2:]
x = self.HexToNeg(data[2:10])
y = self.HexToNeg(data[12:20])
z = self.HexToNeg(data[22:30])
self.real_x = float('%.3f' % (x / AXIS_MULTIPLE))
self.real_y = float('%.3f' % (y / AXIS_MULTIPLE))
self.real_z = float('%.3f' % (z / AXIS_MULTIPLE))
self.signalOpengl.emit(self.real_x, self.real_y, self.real_z)
box = QMessageBox(QMessageBox.Information, "警告", "任务执行中断: \r\n1、加速器异常停止\r\n2、剂量率过大,数据溢出\r\n是否继续执行任务?")
qyes = box.addButton(self.tr("继续执行"), QMessageBox.YesRole)
qno = box.addButton(self.tr("回原点"), QMessageBox.NoRole)
qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
box.exec_()
if box.clickedButton() == qyes:
self.taskRunThread.continueRun()
elif box.clickedButton() == qno:
self.taskRunThread.clearFlag()
self.cmd_backZero()
elif box.clickedButton() == qcancel:
self.taskRunThread.clearFlag()
self.startTaskAct.setEnabled(True)
else:
return
def MoveControl(self, msg):
# print(">>>接收到处理指令:", msg)
# 处理消息
if msg == "CONTINUE": # 执行当前任务
self.task_cnt = self.taskRunThread.step
self.task_current = self.task[self.taskRunThread.step]
if self.taskRunThread.pause_flag and self.progress_value <= 0:
self.taskRunThread.moveToFirstPos()
# 撤销暂停标记
self.taskRunThread.pause_flag = False
else:
self.cmd_RunTask(self.task_current)
self.proj_dock.treeWidget.markRunTaskFile(self.taskRunThread.step)
self.signalOpenglLoadConfig.emit(self.task_current)
if msg == "FIRST": # 从指定位置开始移动
self.taskRunThread.step = 0
self.taskRunThread.moveToFirstPos()
self.startTaskAct.setEnabled(False)
if msg == "SELECT": # 从指定位置开始移动
# self.taskRunThread.step = self.proj_dock.taskTableView.select_row
self.taskRunThread.moveToFirstPos()
self.dataTab.clear_data()
if msg == "PAUSE": # 暂停
self.proj_dock.treeWidget.markStopTaskFile(self.taskRunThread.step)
if self.progress_value >= 2:
self.progress_value -= 2
else:
self.progress_value = 0
self.cmd_MoveStop()
if msg == "NEXT": # 下一任务
self.taskRunThread.moveToFirstPos()
if msg == "MOVE_FIRST": # 移动到第一个点位置
self.stopTaskAct.setEnabled(True)
self.task_current = self.task[self.taskRunThread.step]
self.task_cnt = self.taskRunThread.step
t = self.task_current
self.motorMoveAxis_position(t['road'][0][0], t['road'][0][1], t['road'][0][2])
self.progress_value = 0
self.measure_flag = True
self.pddoarList = []
self.dataTab.clear_data()
# self.proj_dock.taskTableView.showCurrentTask(self.task_cnt)
# 曲线固定x轴范围
if t['type'] == 'PDD':
x_list = [x[2] for x in t['road']]
self.graph.plot.setLimits(xMin=min(x_list), xMax=max(x_list), yMin=0, yMax=110)
if t['type'] == 'OAR':
x_list = []
if t['angle'] == '0' or t['angle'] == '180':
if t['direction'] == 'G->T' or t['direction'] == 'T->G':
x_list = [x[1] for x in t['road']]
else:
x_list = [x[0] for x in t['road']]
if t['angle'] == '90' or t['angle'] == '270':
if t['direction'] == 'G->T' or t['direction'] == 'T->G':
x_list = [x[0] for x in t['road']]
else:
x_list = [x[1] for x in t['road']]
if x_list:
self.graph.plot.setLimits(xMin=min(x_list) - 10, xMax=max(x_list) + 10, yMin=0, yMax=110)
else:
self.graph.plot.setLimits(xMin=-200, xMax=200, yMin=0, yMax=110)
def HexToNeg(self, hex_str):
if hex_str[0] == 'F' or hex_str[0] == 'f':
return int(hex_str, 16) - (1 << 32)
else:
return int(hex_str, 16)
def cmd_RunTask(self, task):
'''发送执行任务命令'''
road = task['road']
# 将负数转换成十六进制
tohex = lambda val, nbits: hex((val + (1 << nbits)) % (1 << nbits))
cmd_axis = hex(int(abs(len(road)))).replace('0x', '').zfill(4).upper()
for a in road:
data_x = tohex(int('%.0f'%(a[0] * AXIS_MULTIPLE)), 16).replace('0x', '').zfill(4).upper()
data_y = tohex(int('%.0f'%(a[1] * AXIS_MULTIPLE)), 16).replace('0x', '').zfill(4).upper()
data_z = tohex(int('%.0f'%(a[2] * AXIS_MULTIPLE)), 16).replace('0x', '').zfill(4).upper()
cmd_axis += data_x + data_y + data_z
cmd = WATER_CMD['任务坐标']
cmd[4] = cmd_axis
logger.info('任务坐标')
logger.info(road)
# if DEBUG:
# print('发送任务坐标', road)
self.cmd_send(cmd)
self.signalTunnel.emit([], [], [])
self.move_dock.rayGL.load_config(task)
self.startTaskAct.setEnabled(False)
# self.dataTab.clear_data()
def cmd_backZero(self):
'''回到原点'''
# self.task_move_first_flag = False
# self.taskRunThread.clearFlag()
self.motorMoveAxis_position(0, 0, 0)
def MessageBox(self, title='',msg=''):
QMessageBox.information(self, title ,msg ,QMessageBox.Yes)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
# win = DeviceInputDlg()
# win = ScanDialog()
win = MainWindow()
# win = TaskListWidget()
# win = PddDialog()
# win = OarDialog()
win.show()
app.exec_()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化