#!/usr/bin/env python # -*- coding: utf-8 -*- # =============================================================================== # # test.py # # Test program for the simple GL Viewer. # # Copyright (c) 2011, Arne Schmitz # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # =============================================================================== import math import threading import time import sys from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import * from MapGLWidget import MapGLWidget import json import dijkstra.Map as mp import ControllWidget import JointContrallerWidget import ManualOperationWidget import RobotData as RD import message_pb2 as message import google.protobuf.json_format as jtf import google.protobuf.text_format as tf import uuid from mytool.txt_helper.txt_operation import TXTOperation from custom_define import RobotName from mytool.RabbitMq_helper import async_communication as rabitmq # =============================================================================== class MainWindow(QMainWindow): """docstring for Mainwindow""" djks_map_ = mp.MapManager() ui_nodes = {} ui_nodes["street_nodes"] = [] ui_nodes["space_nodes"] = [] def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.basic() self.count_frame_ = ControllWidget.CountFrame() self.LoadMap() self.isLocalTest = False self.isAutoDispatchOnline = True rpc_1 = "192.168.0.70:9090" mqtt_1 = ["pyui1", "192.168.0.70", 1883, "admin", "zx123456"] rpc_2 = "192.168.0.71:9090" mqtt_2 = ["pyui2", "192.168.0.71", 1883, "admin", "zx123456"] if self.isLocalTest: rpc_1 = "127.0.0.1:9090" mqtt_1 = ["pyui-main", "127.0.0.1", 1883, "admin", "zx123456"] rpc_2 = "127.0.0.1:9091" mqtt_2 = ["pyui-child", "127.0.0.1", 1883, "admin", "zx123456"] config1 = {"label": RobotName.strAGVMain, "rpc": rpc_1, "street_nodes": self.ui_nodes["street_nodes"], "space_nodes": self.ui_nodes["space_nodes"], "mqtt": mqtt_1, "subTopics": {"agv_main/agv_statu": message.RobotStatu.__name__, "agv_main/nav_statu": message.NavStatu.__name__}, "cmdTopic": "agv_main/nav_cmd", "robotColor": [0.7, 0.2, 0.3]} config2 = {"label": RobotName.strAGV2, "rpc": rpc_2, # "rpc": "127.0.0.1:9091", "street_nodes": self.ui_nodes["street_nodes"], "space_nodes": self.ui_nodes["space_nodes"], "mqtt": mqtt_2, "subTopics": {"agv_child/agv_statu": message.RobotStatu.__name__, "agv_child/nav_statu": message.NavStatu.__name__}, "cmdTopic": "agv_child/nav_cmd", "robotColor": [0.4, 0.2, 0.8]} self.Controller1 = ControllWidget.ControlFrame(config1) self.Controller2 = ControllWidget.ControlFrame(config2) robot_dict = {self.Controller1.robot_.name_: self.Controller1.robot_, self.Controller2.robot_.name_: self.Controller2.robot_} self.ManualOperationWidget = ManualOperationWidget.ManualOperationWidget(robot_dict) splitter_main = self.split_() self.setCentralWidget(splitter_main) self.gl.SetRobot1Instance(self.Controller1.robot_) self.gl.SetRobot2Instance(self.Controller2.robot_) self.timer_ = QTimer() self.timer_.timeout.connect(self.Update) self.timer_.start(100) # 启动RabbitMQ self.g_rabbitmq = None if self.isAutoDispatchOnline: self.g_rabbitmq = rabitmq.RabbitAsyncCommunicator("192.168.0.201", 5672, "zx", "123456") calbbacks = [["agv_park_command_request_queue", self.recv_park_request], ["agv_pick_command_request_queue", self.recv_pick_request]] self.g_rabbitmq.Init(calbbacks, None) self.g_rabbitmq.setDaemon(True) # 守护线程随主线程结束 self.g_rabbitmq.start() def recv_park_request(self, msg): print("Recv_park_request------------------\n", msg) park_table = message.park_table() try: tf.Parse(msg, park_table) except Exception as e: print("Parse error\n") # split_msg = msg.split(' ') # result = [float(split_msg[0]), float(split_msg[1]), float(split_msg[2])] if self.isAutoDispatchOnline: self.AutoParkTask(park_table) def recv_pick_request(self, msg): print("Recv_pick_request------------------\n", msg) park_table = message.park_table() return def AutoParkTask(self, park_table: message.park_table = None): print("AutoParkTask:---------------------\n") self.djks_map_.Reset() # 重置地图 entrance_id = "S" + str(park_table.terminal_id) # "S1101" entrance_x, entrance_y, entrance_theta = [park_table.entrance_measure_info.measure_info_to_plc_forward.cx, park_table.entrance_measure_info.measure_info_to_plc_forward.cy, ( 90 + park_table.entrance_measure_info.measure_info_to_plc_forward.theta) / 180 * math.pi] # 变换到地图坐标系 [dx, dy, da] = [-0.223411843181, -0.643030941486, 178.9478 / 180 * math.pi] trans_x = -0.99983137 * entrance_x - 0.01836309 * entrance_y + dx trans_y = 0.01836309 * entrance_x - 0.99983137 * entrance_y + dy trans_a = entrance_theta + da - math.pi while trans_a < 0: trans_a += math.pi print("entrance:", entrance_id, trans_x, trans_y, trans_a / math.pi * 180) target_id = "S" + str(park_table.allocated_space_info.table_id) # "S147" print("target:", target_id) wheel_base = park_table.entrance_measure_info.measure_info_to_plc_forward.wheelbase self.Controller1.WheelBaseEdit.setText(str(wheel_base)) self.Controller2.WheelBaseEdit.setText(str(wheel_base)) trans_x += wheel_base / 2 * math.cos(trans_a) trans_y += wheel_base / 2 * math.sin(trans_a) self.djks_map_.ResetSpaceNode(entrance_id, trans_x, trans_y) # 更新库位点 entrance_street_node = self.ComputeStreetNode(entrance_id, trans_x, trans_y, trans_a) self.djks_map_.ResetStreetNode("Input_R1101", entrance_street_node[0], entrance_street_node[1]) # 更新库位点对应马路点 print("entrance_space pose: ", self.djks_map_.map_t.graph_.points[entrance_id]) print("entrance_street pose ", self.djks_map_.map_t.graph_.points["Input_R1101"]) # 加临时边 self.djks_map_.AddEdge_t(entrance_id, "Input_R1101") # 加临时边 for node_id, value in self.djks_map_.VertexDict().items(): if node_id.find("Input") >= 0: self.djks_map_.AddEdge_t("Input_R1101", node_id) # # 开始系列子流程----------------------------------------------------- # # 主车进入口 # cur_main_pose = self.Controller1.robot_.timedRobotStatu_.statu # [label, pt] = mp.MapManager().findNeastNode([cur_main_pose.x, cur_main_pose.y]) # node = mp.MapManager().GetVertex(label)# StreetNode # self.Controller1.robot_.Navigatting(label, entrance_id, True, wheel_base) # # 副车进入口 # cur_child_pose = self.Controller2.robot_.timedRobotStatu_.statu # [label, pt] = mp.MapManager().findNeastNode([cur_child_pose.x, cur_child_pose.y]) # node = mp.MapManager().GetVertex(label)# StreetNode # self.Controller2.robot_.Navigatting(label, entrance_id, True, wheel_base) # # 切换整车模式 # self.Controller1.robot_.MainAgvchangecb() # # 整车进目标车位 # self.Controller1.robot_.Navigatting(entrance_id, target_id, True, wheel_base) # # # 恢复 # self.djks_map_.Reset() def ComputeStreetNode(self, s_id, s_x, s_y, s_theta): """ """ n_x, n_y = 0, 0 if s_id == "S1101": n_y = self.djks_map_.map_t.graph_.points["Input_R1100"][1] k = math.tan(s_theta) n_x = (n_y - s_y) / k + s_x # 弧度 # print(n_x, n_y) return [n_x, n_y] def LoadMap(self): self.gl = MapGLWidget() # 将opengl例子嵌入GUI map = self.load_map("./map.json") for node in map['street_nodes'].items(): [id, point] = node street_node = mp.StreetNode(id, point[0], point[1]) self.djks_map_.AddVertex(street_node) self.gl.AddNode([id, "street_node", point]) self.ui_nodes["street_nodes"].append(id) for node in map['space_nodes'].items(): [id, point] = node [x, y, yaw] = point space_node = mp.SpaceNode(id, point[0], point[1], yaw) self.djks_map_.AddVertex(space_node) glNode = [id, "space_node", [x, y]] self.gl.AddNode(glNode) self.ui_nodes["space_nodes"].append(id) for road in map['roads'].items(): self.gl.AddRoad(road) [_, points] = road for pt1 in points: for pt2 in points: if not pt1 == pt2: self.djks_map_.AddEdge(pt1, pt2) def load_map(self, file): with open(file, 'r', encoding='utf-8') as fp: map = json.load(fp) return map def Update(self): self.gl.update() if self.isAutoDispatchOnline: # self.Controller1.setEnabled(False) # self.Controller2.setEnabled(False) pass else: self.Controller1.setVisible(True) self.Controller2.setVisible(True) # 窗口基础属性 def basic(self): # 设置标题,大小,图标 self.setWindowTitle("GT") self.resize(1100, 650) self.setWindowIcon(QIcon("./image/Gt.png")) # 居中显示 screen = QDesktopWidget().geometry() self_size = self.geometry() self.move(int((screen.width() - self_size.width()) / 2), int((screen.height() - self_size.height()) / 2)) def closeEvent(self, QCloseEvent): self.gl.close() print("close...") # 分割窗口 def split_(self): splitter_main = QSplitter(Qt.Horizontal) splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.count_frame_) splitter.addWidget(self.Controller1) splitter.addWidget(self.Controller2) splitter.addWidget(self.ManualOperationWidget) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 3) splitter.setStretchFactor(2, 3) splitter.setStretchFactor(3, 1) splitter_main.addWidget(splitter) splitter_main.addWidget(self.gl) splitter_main.setStretchFactor(0, 1) splitter_main.setStretchFactor(2, 4) return splitter_main if __name__ == "__main__": app = QApplication(sys.argv) win = MainWindow() win.show() sys.exit(app.exec_()) # =============================================================================== # Main # =============================================================================== '''app = QApplication(sys.argv) mainWindow = MapGLWidget() mainWindow.show() mainWindow.raise_() # Need this at least on OS X, otherwise the window ends up in background sys.exit(app.exec_())''' # =============================================================================== # # Local Variables: # mode: Python # indent-tabs-mode: nil # End: # # ===============================================================================