Browse Source

添加存取车task,以及界面按钮

gf 2 năm trước cách đây
mục cha
commit
f8844d2f0e
7 tập tin đã thay đổi với 697 bổ sung938 xóa
  1. 61 41
      ControllWidget.py
  2. 66 73
      PyGLWidget.py
  3. 258 89
      RobotData.py
  4. 207 82
      dijkstra/Map.py
  5. 1 1
      message.proto
  6. 28 590
      message_pb2.py
  7. 76 62
      test.py

+ 61 - 41
ControllWidget.py

@@ -1,48 +1,49 @@
 import math
 
-from PyQt5.QtWidgets import QWidget,QFrame,QLabel,QLineEdit,QPushButton,QComboBox,QCheckBox
-from PyQt5.QtGui import QPixmap,QPainter,QResizeEvent,QCloseEvent,QPaintEvent,QFont
-from PyQt5.QtCore import QSize,QTimer,Qt
+from PyQt5.QtWidgets import QWidget, QFrame, QLabel, QLineEdit, QPushButton, QComboBox, QCheckBox
+from PyQt5.QtGui import QPixmap, QPainter, QResizeEvent, QCloseEvent, QPaintEvent, QFont
+from PyQt5.QtCore import QSize, QTimer, Qt
 from RobotData import Robot
 import dijkstra.Map as mp
+
+
 class ControlFrame(QFrame):
 
-    def __init__(self,UI_data):
+    def __init__(self, UI_data):
         QFrame.__init__(self)
-        [self.name_,self.nodes_]=UI_data
-        self.robot_=Robot(self.name_)
-        self.setGeometry(0,0,500,500)
+        [self.name_, self.nodes_] = UI_data
+        self.robot_ = Robot(self.name_)
+        self.setGeometry(0, 0, 500, 500)
         self.InitUI()
         self.setFrameShape(self.StyledPanel)
-        self.timer_=QTimer()
+        self.timer_ = QTimer()
         self.timer_.timeout.connect(self.Update)
         self.timer_.start(100)
 
-
     def InitUI(self):
 
-        self.basestatic=QLabel(self)
+        self.basestatic = QLabel(self)
         self.basestatic.setText(self.name_)
         self.basestatic.setGeometry(20, 20, 80, 30)
 
-        self.begstatic=QLabel(self)
+        self.begstatic = QLabel(self)
         self.begstatic.setText("  起点")
         self.begstatic.setGeometry(100, 5, 50, 30)
-        self.begQc=QComboBox(self)
+        self.begQc = QComboBox(self)
         self.begQc.setGeometry(160, 5, 80, 30)
 
-        self.endstatic=QLabel(self)
+        self.endstatic = QLabel(self)
         self.endstatic.setText("  终点")
         self.endstatic.setGeometry(100, 50, 50, 30)
-        self.endQc=QComboBox(self)
+        self.endQc = QComboBox(self)
         self.endQc.setGeometry(160, 50, 80, 30)
 
-        self.btnSend=QPushButton(self)
+        self.btnSend = QPushButton(self)
         self.btnSend.setGeometry(150, 100, 100, 40)
         self.btnSend.setText("  启动导航")
         self.btnSend.clicked.connect(self.btnSendClick)
 
-        self.btnCancel=QPushButton(self)
+        self.btnCancel = QPushButton(self)
         self.btnCancel.setGeometry(150, 150, 100, 40)
         self.btnCancel.setText("  取消导航")
         self.btnCancel.clicked.connect(self.btnCancelClick)
@@ -51,45 +52,55 @@ class ControlFrame(QFrame):
         self.endQc.addItems(self.nodes_)
         self.endQc.activated.connect(self.endQCChanged)
 
-        self.posestatic=QLabel(self)
+        self.posestatic = QLabel(self)
         self.posestatic.setGeometry(260, 5, 100, 90)
 
-        self.LedLabel=QLabel(self)
+        self.LedLabel = QLabel(self)
         self.LedLabel.setGeometry(80, 120, 50, 50)
 
-        #发送轴距
-        self.wheelbasestatic=QLabel(self)
+        # 发送轴距
+        self.wheelbasestatic = QLabel(self)
         self.wheelbasestatic.setText("轴距:")
         self.wheelbasestatic.setGeometry(260, 100, 40, 30)
-        self.WheelBaseEdit=QLineEdit(self)
+        self.WheelBaseEdit = QLineEdit(self)
         self.WheelBaseEdit.setText("3.0")
         self.WheelBaseEdit.setGeometry(300, 100, 50, 30)
 
-        self.btnModelCheck=QCheckBox("双车模式",self)
+        self.btnModelCheck = QCheckBox("双车模式", self)
         self.btnModelCheck.setGeometry(260, 150, 100, 40)
         self.btnModelCheck.stateChanged.connect(self.MainAgvchangecb)
 
+        self.btnPark = QPushButton(self)
+        self.btnPark.setGeometry(150, 200, 100, 40)
+        self.btnPark.setText("  存车")
+        self.btnPark.clicked.connect(self.btnParkClick)
+
+        self.btnPick = QPushButton(self)
+        self.btnPick.setGeometry(150, 250, 100, 40)
+        self.btnPick.setText("  取车")
+        self.btnPick.clicked.connect(self.btnPickClick)
+
 
     def Update(self):
-        if self.robot_.timedPose_.timeout()==False:
-            x=self.robot_.timedPose_.statu.x
-            y=self.robot_.timedPose_.statu.y
-            yaw=self.robot_.timedPose_.statu.theta
-            self.posestatic.setText("x : %.3f\ny : %.3f\nΘ : %.2f"%(x,y,yaw*180/math.pi))
+        if self.robot_.timedPose_.timeout() == False:
+            x = self.robot_.timedPose_.statu.x
+            y = self.robot_.timedPose_.statu.y
+            yaw = self.robot_.timedPose_.statu.theta
+            self.posestatic.setText("x : %.3f\ny : %.3f\nΘ : %.2f" % (x, y, yaw * 180 / math.pi))
 
             '''djks_map=mp.DijikstraMap()
             [label,pt]=djks_map.findNeastNode([x,y])
             if self.nodes_.index(label)>=0:
                 self.begQc.setCurrentText(label)'''
 
-        statu="min-width: 32px; min-height: 32px;max-width:32px;\
+        statu = "min-width: 32px; min-height: 32px;max-width:32px;\
                 max-height: 32px;border-radius: 16px;  border:1px solid black;background:green"
-        if self.robot_.Connected()==False:
-            statu="min-width: 32px; min-height: 32px;max-width:32px;\
+        if self.robot_.Connected() == False:
+            statu = "min-width: 32px; min-height: 32px;max-width:32px;\
                 max-height: 32px;border-radius: 16px; border:1px solid black;background:gray"
-            #self.endQc.setEnabled(False)
-        elif self.robot_.IsNavigating()==True:
-            statu="min-width: 32px; min-height: 32px;max-width:32px;\
+            # self.endQc.setEnabled(False)
+        elif self.robot_.IsNavigating() == True:
+            statu = "min-width: 32px; min-height: 32px;max-width:32px;\
                 max-height: 32px;border-radius: 16px; border:1px solid black;background:yellow"
             self.endQc.setEnabled(False)
             self.btnModelCheck.setEnabled(False)
@@ -98,26 +109,35 @@ class ControlFrame(QFrame):
             self.btnModelCheck.setEnabled(True)
         self.LedLabel.setStyleSheet(statu)
 
-
         self.wheelbasestatic.setVisible(self.robot_.IsMainAgv())
         self.WheelBaseEdit.setVisible(self.robot_.IsMainAgv())
         self.btnModelCheck.setVisible(self.robot_.IsMainAgv())
 
     def MainAgvchangecb(self):
         if self.btnModelCheck.checkState() == Qt.Checked:
-            leng=float(self.WheelBaseEdit.text())
-            self.robot_.SwitchMoveMode(2,leng)
+            leng = float(self.WheelBaseEdit.text())
+            self.robot_.SwitchMoveMode(2, leng)
         if self.btnModelCheck.checkState() == Qt.Unchecked:
-            self.robot_.SwitchMoveMode(1,0)
+            self.robot_.SwitchMoveMode(1, 0)
+
     def endQCChanged(self):
-        id1=self.begQc.currentText()
-        id2=self.endQc.currentText()
-        self.robot_.GeneratePath(id1,id2)
+        id1 = self.begQc.currentText()
+        id2 = self.endQc.currentText()
+        self.robot_.GeneratePath(id1, id2)
 
     def btnSendClick(self):
-        self.robot_.wheelbase_=3
+        self.robot_.wheelbase_ = 3
         self.robot_.ExecNavtask()
+
     def btnCancelClick(self):
         self.robot_.CancelNavTask()
 
+    def btnParkClick(self):
+        id1 = self.begQc.currentText()
+        id2 = self.endQc.currentText()
+        self.robot_.ParkTask(begID=id1, targetID=id2)
 
+    def btnPickClick(self):
+        id1 = self.begQc.currentText()
+        id2 = self.endQc.currentText()
+        self.robot_.PickTask(begID=id1, targetID=id2)

+ 66 - 73
PyGLWidget.py

@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-#===============================================================================
+# ===============================================================================
 #
 # PyGLWidget.py
 #
@@ -30,69 +30,66 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
-#===============================================================================
+# ===============================================================================
 
 from PyQt5 import QtCore, QtGui, QtOpenGL
 import math
 import numpy
 import numpy.linalg as linalg
 import OpenGL
+
 OpenGL.ERROR_CHECKING = True
 from OpenGL.GL import *
 from OpenGL.GLU import *
 
-class PyGLWidget(QtOpenGL.QGLWidget):
 
+class PyGLWidget(QtOpenGL.QGLWidget):
     # Qt signals
     signalGLMatrixChanged = QtCore.pyqtSignal()
     rotationBeginEvent = QtCore.pyqtSignal()
     rotationEndEvent = QtCore.pyqtSignal()
 
-    def __init__(self, parent = None):
+    def __init__(self, parent=None):
         format = QtOpenGL.QGLFormat()
         format.setSampleBuffers(True)
         QtOpenGL.QGLWidget.__init__(self, format, parent)
         self.setCursor(QtCore.Qt.OpenHandCursor)
         self.setMouseTracking(True)
 
-        self.modelview_matrix_  = [
-            [1,0,0,0],
-            [0,1,0,0],
-            [0,0,1,0],
-            [-10.53889084,-2.01535511,-25.95999146,1. ]]
-        self.translate_vector_  = [0, 0, 0.0]
-        self.viewport_matrix_   = []
+        self.modelview_matrix_ = [
+            [1, 0, 0, 0],
+            [0, 1, 0, 0],
+            [0, 0, 1, 0],
+            [-10.53889084, -2.01535511, -25.95999146, 1.]]
+        self.translate_vector_ = [0, 0, 0.0]
+        self.viewport_matrix_ = []
         self.projection_matrix_ = []
-        self.near_   = 0.1
-        self.far_    = 100.0
-        self.fovy_   = 45.0
+        self.near_ = 0.1
+        self.far_ = 100.0
+        self.fovy_ = 45.0
         self.radius_ = 2.0
         self.last_point_2D_ = QtCore.QPoint()
         self.last_point_ok_ = False
         self.last_point_3D_ = [1.0, 0.0, 0.0]
-        self.isInRotation_  = False
-
-
+        self.isInRotation_ = False
 
         # connections
-        #self.signalGLMatrixChanged.connect(self.printModelViewMatrix)
+        # self.signalGLMatrixChanged.connect(self.printModelViewMatrix)
 
     @QtCore.pyqtSlot()
     def printModelViewMatrix(self):
-        print (self.modelview_matrix_)
+        print(self.modelview_matrix_)
 
     def initializeGL(self):
         # OpenGL state
         glClearColor(0.6, 0.6, 0.6, 0.5)
         glEnable(GL_DEPTH_TEST)
         self.reset_view()
-        self.translate([-10,-10,-25.])
-
-
+        self.translate([-10, -10, -25.])
 
     def resizeGL(self, width, height):
-        glViewport(0, 0, width, height );
-        self.set_projection( self.near_, self.far_, self.fovy_ );
+        glViewport(0, 0, width, height)
+        self.set_projection(self.near_, self.far_, self.fovy_)
         self.updateGL()
 
     def paintGL(self):
@@ -100,17 +97,17 @@ class PyGLWidget(QtOpenGL.QGLWidget):
 
         glMatrixMode(GL_MODELVIEW)
         glLoadMatrixd(self.modelview_matrix_)
-        #self.printModelViewMatrix()
+        # self.printModelViewMatrix()
 
     def set_projection(self, _near, _far, _fovy):
         self.near_ = _near
         self.far_ = _far
         self.fovy_ = _fovy
         self.makeCurrent()
-        glMatrixMode( GL_PROJECTION )
+        glMatrixMode(GL_PROJECTION)
         glLoadIdentity()
-        gluPerspective( self.fovy_, float(self.width()) / float(self.height()),
-                        self.near_, self.far_ )
+        gluPerspective(self.fovy_, float(self.width()) / float(self.height()),
+                       self.near_, self.far_)
         self.updateGL()
 
     def set_center(self, _cog):
@@ -127,12 +124,11 @@ class PyGLWidget(QtOpenGL.QGLWidget):
 
     def reset_view(self):
         # scene pos and size
-        glMatrixMode( GL_MODELVIEW )
+        glMatrixMode(GL_MODELVIEW)
         glLoadIdentity();
-        self.modelview_matrix_ = glGetDoublev( GL_MODELVIEW_MATRIX )
+        self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
         self.set_center([0.0, 0.0, 0.0])
 
-
     def reset_rotation(self):
         self.modelview_matrix_[0] = [1.0, 0.0, 0.0, 0.0]
         self.modelview_matrix_[1] = [0.0, 1.0, 0.0, 0.0]
@@ -140,7 +136,7 @@ class PyGLWidget(QtOpenGL.QGLWidget):
         glMatrixMode(GL_MODELVIEW)
         glLoadMatrixd(self.modelview_matrix_)
         self.updateGL()
-   
+
     def translate(self, _trans):
         # Translate the object by _trans
         # Update modelview_matrix_
@@ -179,35 +175,35 @@ class PyGLWidget(QtOpenGL.QGLWidget):
         self.signalGLMatrixChanged.emit()
 
     def view_all(self):
-        self.translate( [ -( self.modelview_matrix_[0][0] * self.center_[0] +
-                             self.modelview_matrix_[0][1] * self.center_[1] +
-                             self.modelview_matrix_[0][2] * self.center_[2] +
-                             self.modelview_matrix_[0][3]),
-                           -( self.modelview_matrix_[1][0] * self.center_[0] +
-                              self.modelview_matrix_[1][1] * self.center_[1] +
-                              self.modelview_matrix_[1][2] * self.center_[2] +
-                              self.modelview_matrix_[1][3]),
-                           -( self.modelview_matrix_[2][0] * self.center_[0] +
-                              self.modelview_matrix_[2][1] * self.center_[1] +
-                              self.modelview_matrix_[2][2] * self.center_[2] +
-                              self.modelview_matrix_[2][3] +
-                              self.radius_ / 2.0 )])
+        self.translate([-(self.modelview_matrix_[0][0] * self.center_[0] +
+                          self.modelview_matrix_[0][1] * self.center_[1] +
+                          self.modelview_matrix_[0][2] * self.center_[2] +
+                          self.modelview_matrix_[0][3]),
+                        -(self.modelview_matrix_[1][0] * self.center_[0] +
+                          self.modelview_matrix_[1][1] * self.center_[1] +
+                          self.modelview_matrix_[1][2] * self.center_[2] +
+                          self.modelview_matrix_[1][3]),
+                        -(self.modelview_matrix_[2][0] * self.center_[0] +
+                          self.modelview_matrix_[2][1] * self.center_[1] +
+                          self.modelview_matrix_[2][2] * self.center_[2] +
+                          self.modelview_matrix_[2][3] +
+                          self.radius_ / 2.0)])
 
     def map_to_sphere(self, _v2D):
         _v3D = [0.0, 0.0, 0.0]
         # inside Widget?
-        if (( _v2D.x() >= 0 ) and ( _v2D.x() <= self.width() ) and
-            ( _v2D.y() >= 0 ) and ( _v2D.y() <= self.height() ) ):
+        if ((_v2D.x() >= 0) and (_v2D.x() <= self.width()) and
+                (_v2D.y() >= 0) and (_v2D.y() <= self.height())):
             # map Qt Coordinates to the centered unit square [-0.5..0.5]x[-0.5..0.5]
-            x  = float( _v2D.x() - 0.5 * self.width())  / self.width()
-            y  = float( 0.5 * self.height() - _v2D.y()) / self.height()
+            x = float(_v2D.x() - 0.5 * self.width()) / self.width()
+            y = float(0.5 * self.height() - _v2D.y()) / self.height()
 
             _v3D[0] = x;
             _v3D[1] = y;
             # use Pythagoras to comp z-coord (the sphere has radius sqrt(2.0*0.5*0.5))
-            z2 = 2.0*0.5*0.5-x*x-y*y;
+            z2 = 2.0 * 0.5 * 0.5 - x * x - y * y;
             # numerical robust sqrt
-            _v3D[2] = math.sqrt(max( z2, 0.0 ))
+            _v3D[2] = math.sqrt(max(z2, 0.0))
 
             # normalize direction to unit sphere
             n = linalg.norm(_v3D)
@@ -219,8 +215,8 @@ class PyGLWidget(QtOpenGL.QGLWidget):
 
     def wheelEvent(self, _event):
         # Use the mouse wheel to zoom in/out
-        
-        d =  (_event.angleDelta().y()) / 250.0 * self.radius_
+
+        d = (_event.angleDelta().y()) / 250.0 * self.radius_
         self.translate([0.0, 0.0, d])
         self.updateGL()
         _event.accept()
@@ -233,9 +229,9 @@ class PyGLWidget(QtOpenGL.QGLWidget):
         newPoint2D = _event.pos()
 
         if ((newPoint2D.x() < 0) or (newPoint2D.x() > self.width()) or
-            (newPoint2D.y() < 0) or (newPoint2D.y() > self.height())):
+                (newPoint2D.y() < 0) or (newPoint2D.y() > self.height())):
             return
-        
+
         # Left button: rotate around center_
         # Middle button: translate object
         # Left & middle button: zoom in/out
@@ -246,22 +242,22 @@ class PyGLWidget(QtOpenGL.QGLWidget):
         dx = float(newPoint2D.x() - self.last_point_2D_.x())
         dy = float(newPoint2D.y() - self.last_point_2D_.y())
 
-        w  = float(self.width())
-        h  = float(self.height())
+        w = float(self.width())
+        h = float(self.height())
 
         # enable GL context
         self.makeCurrent()
 
         # move in z direction
         if (((_event.buttons() & QtCore.Qt.LeftButton) and (_event.buttons() & QtCore.Qt.MidButton))
-            or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ControlModifier)):
+                or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ControlModifier)):
             value_y = self.radius_ * dy * 2.0 / h;
             self.translate([0.0, 0.0, value_y])
 
-        #rotate
+        # rotate
         elif (_event.buttons() & QtCore.Qt.MidButton
               or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ShiftModifier)):
-            #中间键  旋转
+            # 中间键  旋转
             '''if (not self.isInRotation_):
                 self.isInRotation_ = True
                 self.rotationBeginEvent.emit()
@@ -279,7 +275,7 @@ class PyGLWidget(QtOpenGL.QGLWidget):
 
         #  move in x,y direction
         elif (_event.buttons() & QtCore.Qt.LeftButton):
-            #左键移动
+            # 左键移动
 
             z = - (self.modelview_matrix_[0][2] * self.center_[0] +
                    self.modelview_matrix_[1][2] * self.center_[1] +
@@ -289,18 +285,15 @@ class PyGLWidget(QtOpenGL.QGLWidget):
                                                     self.modelview_matrix_[2][3] * self.center_[2] +
                                                     self.modelview_matrix_[3][3])
 
-            fovy   = 45.0
+            fovy = 45.0
             aspect = w / h
-            n      = 0.01 * self.radius_
-            up     = math.tan(fovy / 2.0 * math.pi / 180.0) * n
-            right  = aspect * up
-
-            self.translate( [2.0 * dx / w * right / n * z,
-                             -2.0 * dy / h * up / n * z,
-                             0.0] )
-
-
+            n = 0.01 * self.radius_
+            up = math.tan(fovy / 2.0 * math.pi / 180.0) * n
+            right = aspect * up
 
+            self.translate([2.0 * dx / w * right / n * z,
+                            -2.0 * dy / h * up / n * z,
+                            0.0])
 
         # remember this point
         self.last_point_2D_ = newPoint2D
@@ -316,11 +309,11 @@ class PyGLWidget(QtOpenGL.QGLWidget):
             self.rotationEndEvent.emit()
         last_point_ok_ = False
 
-#===============================================================================
+# ===============================================================================
 #
 # Local Variables:
 # mode: Python
 # indent-tabs-mode: nil
 # End:
 #
-#===============================================================================
+# ===============================================================================

+ 258 - 89
RobotData.py

@@ -1,129 +1,181 @@
-
-
 import time
 import message_pb2 as message
 from mqtt_async import MqttAsync
 import google.protobuf.json_format as jtf
 from dijkstra.Map import DijikstraMap
+
+
+class AGVTaskTag:
+    # ----------------------------------------------------------------
+    # DefaultTask
+    Default_Base =0
+    Default_Idle =Default_Base +1 #初始空闲状态
+    # ----------------------------------------------------------------
+    # ParkTask
+    Park_Base = 1000
+    Park_Idle = Park_Base + 1  # 等待
+    Park_Pause = Park_Base + 2  # 暂停
+    Park_Stop = Park_Base + 3  # 停止(非正常)
+    Park_End = Park_Base + 4  # 结束(正常)
+    Park_Ready2Park = Park_Base + 10  # 调整准备好存车
+    Park_Move2Entrance = Park_Base + 20  # 移动至入口
+    Park_LoadCar = Park_Base + 30  # 装车(夹持)
+    Park_Move2Space = Park_Base + 40  # 移动至车位
+    Park_UnloadCar = Park_Base + 50  # 卸车(松开夹持)
+    Park_Move2Safety = Park_Base + 60  # 移动至安全位置
+    # ----------------------------------------------------------------
+    # PickTask
+    Pick_Base = 2000
+    Pick_Idle = Pick_Base + 0  # 等待
+    Pick_Pause = Pick_Base + 1  # 暂停
+    Pick_Stop = Pick_Base + 2  # 停止(非正常)
+    Pick_End = Pick_Base + 3  # 结束(正常)
+    Pick_Ready2Pick = Pick_Base + 10  # 调整准备好取车
+    Pick_Move2Space = Pick_Base + 20  # 移动至车位
+    Pick_LoadCar = Pick_Base + 30  # 装车(夹持)
+    Pick_Move2Exit = Pick_Base + 40  # 移动至出口
+    Pick_UnloadCar = Pick_Base + 50  # 卸车(松开夹持)
+    Pick_Move2Safety = Pick_Base + 60  # 移动至安全位置
+
+
 class TimeStatu:
-    def __init__(self,statu=None,timeout=3):
-        self.statu=statu
-        self.time=time.time()
-        self.timeout_ms=timeout
+    def __init__(self, statu=None, timeout=3.0):
+        self.statu = statu
+        self.time = time.time()
+        self.timeout_ms = timeout
 
     def timeout(self):
-        tm=time.time()
-        return tm-self.time>self.timeout_ms or self.statu==None
+        tm = time.time()
+        return tm - self.time > self.timeout_ms or self.statu == None
+
 
 class Robot(MqttAsync):
-    def __init__(self,name=""):
-        self.timedPose_=TimeStatu(message.AGVStatu,0)
-        self.timedNavStatu_=TimeStatu(message.NavStatu,0)
-        self.dataTopic_={}
-        self.messageArrivedSignal=None
-        self.currentNavData_=None
-        self.navCmdTopic_=None
-        self.currentNavPathNodes_=None
-        self.currentNavPath_=None
-
-        self.pathColor_=[1,1,0]
-        self.robotColor_=[0.7,0.2,0.3]      #agv当前颜色
-        self.name_=name
-
-        self.l_=0.8       #轮长
-        self.L_=1.3       #轴距
-        self.W_=2.5       #宽
+    def __init__(self, name=""):
+        self.timedPose_ = TimeStatu(message.AGVStatu, 0)
+        self.timedNavStatu_ = TimeStatu(message.NavStatu, 0)
+        self.dataTopic_ = {}
+        self.messageArrivedSignal = None
+        self.currentNavData_ = None
+        self.navCmdTopic_ = None
+        self.currentNavPathNodes_ = None
+        self.currentNavPath_ = None
+
+        self.pathColor_ = [1, 1, 0]
+        self.robotColor_ = [0.7, 0.2, 0.3]  # agv当前颜色
+        self.name_ = name
+
+        self.l_ = 0.8  # 轮长
+        self.L_ = 1.3  # 轴距
+        self.W_ = 2.5  # 宽
+
+        # 地图参数设置
+        self.safety_location = "N8"  # 测试用,安全位置
+        self.entrance_location = "N8"  # 测试用,入口位置
+        self.exit_location = "N8"  # 测试用,出口位置
+
+        # 流程控制相关
+        self.agv_task_tag = AGVTaskTag.Default_Idle
 
     def Color(self):
         if self.IsMainModeStatu():
-            return [0,0,0]
+            return [0, 0, 0]
         return self.robotColor_
+
     def IsMainAgv(self):
-        if self.timedNavStatu_.timeout()==False:
-            if self.timedNavStatu_.statu.main_agv==True:
+        if self.timedNavStatu_.timeout() == False:
+            if self.timedNavStatu_.statu.main_agv == True:
                 return True
         return False
+
     def IsMainModeStatu(self):
         if self.IsMainAgv():
             if self.timedNavStatu_.timeout() == False:
-                if self.timedNavStatu_.statu.move_mode==2:
+                if self.timedNavStatu_.statu.move_mode == 2:
                     return True
         return False
-    def SetSubDataTopic(self,match:dict,messageSignal=None):
-        self.dataTopic_=match
-        self.messageArrivedSignal=messageSignal
+
+    def SetSubDataTopic(self, match: dict, messageSignal=None):
+        self.dataTopic_ = match
+        self.messageArrivedSignal = messageSignal
         for item in match.items():
-            [topic,_]=item
-            self.subscribe(topic,self.on_message)
-    def SetCmdTopic(self,topic):
-        self.navCmdTopic_=topic
-    def SetColor(self,pathColor,robotColor):
-        self.pathColor_=pathColor
-        self.robotColor_=robotColor
-    def ResetPose(self,agv : message.AGVStatu):
-        self.timedPose_=TimeStatu(agv,0.5)
-    def ResetNavStatu(self,statu:message.NavStatu):
-        self.timedNavStatu_=TimeStatu(statu,0.5)
-
-    def on_message(self,client, userdata, msg):
-        topic=msg.topic
+            [topic, _] = item
+            self.subscribe(topic, self.on_message)
+
+    def SetCmdTopic(self, topic):
+        self.navCmdTopic_ = topic
+
+    def SetColor(self, pathColor, robotColor):
+        self.pathColor_ = pathColor
+        self.robotColor_ = robotColor
+
+    def ResetPose(self, agv: message.AGVStatu):
+        self.timedPose_ = TimeStatu(agv, 0.5)
+
+    def ResetNavStatu(self, statu: message.NavStatu):
+        self.timedNavStatu_ = TimeStatu(statu, 0.5)
+
+    def on_message(self, client, userdata, msg):
+        topic = msg.topic
         if self.dataTopic_.get(topic) is not None:
-            dtype=self.dataTopic_[topic]
-            if dtype==message.AGVStatu.__name__:
-                proto=message.AGVStatu()
-                jtf.Parse(msg.payload.decode(),proto)
+            dtype = self.dataTopic_[topic]
+            if dtype == message.AGVStatu.__name__:
+                proto = message.AGVStatu()
+                jtf.Parse(msg.payload.decode(), proto)
                 self.ResetPose(proto)
-            if dtype==message.NavStatu.__name__:
-                self.last_running=self.IsNavigating()
-                proto=message.NavStatu()
-                jtf.Parse(msg.payload.decode(),proto)
+            if dtype == message.NavStatu.__name__:
+                self.last_running = self.IsNavigating()
+                proto = message.NavStatu()
+                jtf.Parse(msg.payload.decode(), proto)
                 self.ResetNavStatu(proto)
-                if self.last_running==True and self.IsNavigating()==False:
-                    self.currentNavPathNodes_=None
-                    self.currentNavPath_=None
+                if self.last_running == True and self.IsNavigating() == False:
+                    self.currentNavPathNodes_ = None
+                    self.currentNavPath_ = None
             if self.messageArrivedSignal is not None:
                 self.messageArrivedSignal()
 
     def MpcSelectTraj(self):
-        traj=[]
-        if self.timedNavStatu_.timeout()==False:
-            nav=self.timedNavStatu_.statu
+        traj = []
+        if self.timedNavStatu_.timeout() == False:
+            nav = self.timedNavStatu_.statu
             for pose2d in nav.selected_traj.poses:
-                traj.append([pose2d.x,pose2d.y,pose2d.theta])
+                traj.append([pose2d.x, pose2d.y, pose2d.theta])
         return traj
 
     def MpcPredictTraj(self):
-        traj=[]
-        if self.timedNavStatu_.timeout()==False:
-            nav=self.timedNavStatu_.statu
+        traj = []
+        if self.timedNavStatu_.timeout() == False:
+            nav = self.timedNavStatu_.statu
             for pose2d in nav.predict_traj.poses:
-                traj.append([pose2d.x,pose2d.y,pose2d.theta])
+                traj.append([pose2d.x, pose2d.y, pose2d.theta])
         return traj
 
     def Connected(self):
-        return self.timedNavStatu_.timeout()==False and self.timedPose_.timeout()==False
+        return self.timedNavStatu_.timeout() == False and self.timedPose_.timeout() == False
+
     def IsNavigating(self):
-        if self.timedNavStatu_.timeout()==False:
-            key=self.timedNavStatu_.statu.key
-            if key=="" or key==None:
+        if self.timedNavStatu_.timeout() == False:
+            key = self.timedNavStatu_.statu.key
+            if key == "" or key == None:
                 return False
         return True
-    def GeneratePath(self,begID,endID):
-        self.currentNavPathNodes_=DijikstraMap().GetShortestPath(begID,endID)
-        self.currentNavPath_=DijikstraMap().CreatePath(self.currentNavPathNodes_,0.5)
+
+    def GeneratePath(self, begID, endID):
+        self.currentNavPathNodes_ = DijikstraMap().GetShortestPath(begID, endID)
+        self.currentNavPath_ = DijikstraMap().CreatePath(self.currentNavPathNodes_, 0.5)
+
     def ExecNavtask(self):
         if self.navCmdTopic_ == None:
             print("Robot has not set nav cmd topic")
             return
         if self.IsNavigating():
-            print(" robot is navigating ,key:%s"%(self.timedNavStatu_.statu.key))
+            print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
             return
 
-        cmd=None
-        if self.currentNavPathNodes_ is not None and self.timedPose_.timeout()==False:
-            statu=self.timedPose_.statu
+        cmd = None
+        if self.currentNavPathNodes_ is not None and self.timedPose_.timeout() == False:
+            statu = self.timedPose_.statu
             if statu is not None:
-                cmd=DijikstraMap().CreateNavCmd([statu.x,statu.y,statu.theta],self.currentNavPathNodes_)
+                cmd = DijikstraMap().CreateNavCmd([statu.x, statu.y, statu.theta], self.currentNavPathNodes_)
         else:
             print("current path is none")
             return
@@ -132,27 +184,144 @@ class Robot(MqttAsync):
             print("Nav cmd is None")
             return
 
-        self.publish(self.navCmdTopic_,jtf.MessageToJson(cmd))
+        self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
         '''while self.IsNavigating()==False:
             time.sleep(1)
             self.publish(self.navCmdTopic_,jtf.MessageToJson(cmd))'''
-    def SwitchMoveMode(self,mode,wheelbase):
 
-        cmd =message.NavCmd()
-        if mode==2:
-            cmd.wheelbase=wheelbase
-            cmd.action=4
-        if mode==1:
-            cmd.action=5
+    def SwitchMoveMode(self, mode, wheelbase):
+
+        cmd = message.NavCmd()
+        if mode == 2:
+            cmd.wheelbase = wheelbase
+            cmd.action = 4
+        if mode == 1:
+            cmd.action = 5
 
-        self.publish(self.navCmdTopic_,jtf.MessageToJson(cmd))
+        self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
 
     def CancelNavTask(self):
-        cmd=message.NavCmd()
-        cmd.action=3
-        self.publish(self.navCmdTopic_,jtf.MessageToJson(cmd))
+        cmd = message.NavCmd()
+        cmd.action = 3
+        self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
 
+    # 存车
+    def ParkTask(self, targetID=None, begID=None):
+        if targetID is None:
+            return
+        if begID is None:  # 默认AGV当前位置为安全位置,否则需要给定位置
+            begID = self.safety_location
+        if self.navCmdTopic_ == None:
+            print("Robot has not set nav cmd topic")
+            return
+        if self.IsNavigating():
+            print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
+            return
+        # 计算完整最短路径(分三段,最后合并)
+        ParkPathNodes_1 = DijikstraMap().GetShortestPath(begID, self.entrance_location)
+        ParkPathNodes_2 = DijikstraMap().GetShortestPath(self.entrance_location, targetID)
+        ParkPathNodes_3 = DijikstraMap().GetShortestPath(targetID, self.safety_location)
+        self.currentNavPathNodes_ = ParkPathNodes_1[0:len(ParkPathNodes_1) - 1] + ParkPathNodes_2[0:len(
+            ParkPathNodes_2) - 1] + ParkPathNodes_3
+        self.currentNavPath_ = DijikstraMap().CreatePath(self.currentNavPathNodes_, 0.5)
+        # 生成完整指令
+        cmd = None
+        if self.currentNavPathNodes_ is not None and self.timedPose_.timeout() is False:
+        # if self.currentNavPathNodes_ is not None:
+            statu = self.timedPose_.statu
+            if statu is not None:
+                cmd = self.CreateNavCmd(ParkPathNodes_1, ParkPathNodes_2, ParkPathNodes_3, AGVTaskTag.Park_Base)
+        else:
+            print("current path is none")
+            return
+        if cmd is None:
+            print("Park cmd is None")
+            return
+
+        self.setAGVTaskTag(AGVTaskTag.Park_Base)
+        self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
+
+    # 取车
+    def PickTask(self, targetID=None, begID=None):
+            if targetID is None:
+                return
+            if begID is None:  # 默认AGV当前位置为安全位置,否则需要给定位置
+                begID = self.safety_location
+
+            if self.navCmdTopic_ == None:
+                print("Robot has not set nav cmd topic")
+                return
+            if self.IsNavigating():
+                print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
+                return
+
+            # 计算完整最短路径(分三段,最后合并)
+            ParkPathNodes_1 = DijikstraMap().GetShortestPath(begID, targetID)
+            ParkPathNodes_2 = DijikstraMap().GetShortestPath(targetID, self.exit_location)
+            ParkPathNodes_3 = DijikstraMap().GetShortestPath(self.exit_location, self.safety_location)
+            self.currentNavPathNodes_ = ParkPathNodes_1[0:len(ParkPathNodes_1) - 1] + ParkPathNodes_2[0:len(
+                ParkPathNodes_2) - 1] + ParkPathNodes_3
+            self.currentNavPath_ = DijikstraMap().CreatePath(self.currentNavPathNodes_, 0.5)
+
+            # 生成完整指令
+            cmd = None
+            if self.currentNavPathNodes_ is not None and self.timedPose_.timeout() is False:
+                statu = self.timedPose_.statu
+                if statu is not None:
+                    cmd = self.CreateNavCmd(ParkPathNodes_1, ParkPathNodes_2, ParkPathNodes_3, AGVTaskTag.Pick_Base)
+            else:
+                print("current path is none")
+                return
+
+            if cmd is None:
+                print("Park cmd is None")
+                return
+
+            self.setAGVTaskTag(AGVTaskTag.Pick_Base)
+            self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
+
+    # parameter:
+    # task_type: 根据其值,分段生成对应的的cmd
+    def CreateNavCmd(self, path_1, path_2, path_3, task_type):
+        cmd_base = DijikstraMap().CreateNavCmd_part_base()
+        cmd_actions = list()
+
+        if task_type == AGVTaskTag.Park_Base:
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_1))
+            act_clamp_1 = message.Action()
+            act_clamp_1.type = (3)
+            cmd_actions.append([act_clamp_1])  # 夹持
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_2))
+            act_clamp_2 = message.Action()
+            act_clamp_2.type = (4)
+            cmd_actions.append([act_clamp_2])  # 松夹持
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_3))
+
+        elif task_type == AGVTaskTag.Pick_Base:
+            cmd_base = DijikstraMap().CreateNavCmd_part_base()
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_1))
+            act_clamp_1 = message.Action()
+            act_clamp_1.type = (3)
+            cmd_actions.append([act_clamp_1])  # 夹持
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_2))
+            act_clamp_2 = message.Action()
+            act_clamp_2.type = (4)
+            cmd_actions.append([act_clamp_2])  # 松夹持
+            cmd_actions.append(DijikstraMap().CreateNavCmd_part_actions(path_3))
+
+        if len(cmd_actions) < 3:
+            return None
+        else:
+            for i in range(len(cmd_actions)):
+                if cmd_actions[i] is not None:
+                    for action in cmd_actions[i]:
+                        cmd_base.actions.add().CopyFrom(action)
 
+            return cmd_base
 
+    def setAGVTaskTag(self, task_tag):
+        self.agv_task_tag = task_tag
 
+    def getAGVTaskTag(self):
+        return self.agv_task_tag
 

+ 207 - 82
dijkstra/Map.py

@@ -5,6 +5,7 @@ import scipy.spatial as spt
 import message_pb2 as message
 import uuid
 
+
 class Node(object):
     def __init__(self, id, x, y):
         self.id_ = id
@@ -44,6 +45,7 @@ def singleton(cls):
 map 采用单例
 '''
 
+
 @singleton
 class DijikstraMap(object):
     def __init__(self):
@@ -75,21 +77,23 @@ class DijikstraMap(object):
 
     def VertexDict(self):
         return self.nodes_
+
     def Edges(self):
         return self.graph_.graph_edges
-    def findNeastNode(self,pt):
-        labels=[]
-        pts=[]
+
+    def findNeastNode(self, pt):
+        labels = []
+        pts = []
         for item in self.nodes_.items():
-            [label,node]=item
+            [label, node] = item
             labels.append(label)
-            pts.append([node.x_,node.y_])
-        points=np.array(pts)
-        ckt=spt.KDTree(data=points,leafsize=10)
-        find_pt=np.array(pt)
-        d,i=ckt.query(find_pt)
-        if i>=0 and i<len(pts):
-            return [labels[i],pts[i]]
+            pts.append([node.x_, node.y_])
+        points = np.array(pts)
+        ckt = spt.KDTree(data=points, leafsize=10)
+        find_pt = np.array(pt)
+        d, i = ckt.query(find_pt)
+        if i >= 0 and i < len(pts):
+            return [labels[i], pts[i]]
 
     def GetShortestPath(self, beg, end):
         [pathId, distance] = self.graph_.shortest_path(beg, end)
@@ -102,90 +106,91 @@ class DijikstraMap(object):
         return path
 
     @staticmethod
-    def CreatePath(pathNodes,delta):
-        last_node=None
-        trajectry=[]
+    def CreatePath(pathNodes, delta):
+        last_node = None
+        trajectry = []
         for node in pathNodes:
-            if last_node==None:
-                last_node=node
+            if last_node == None:
+                last_node = node
                 continue
-            dis=last_node.distance(node)
-            if dis<0.5:
-                last_node=node
-                continue    #同一点
+            dis = last_node.distance(node)
+            if dis < 0.5:
+                last_node = node
+                continue  # 同一点
             else:
-                vector=[node.x_-last_node.x_,node.y_-last_node.y_]
-
-                dx=vector[0]
-                dy=vector[1]
-                yaw=math.asin(dy/math.sqrt(dx*dx+dy*dy))
-                if yaw>=0:
-                    if dx<0:
-                        yaw=math.pi-yaw
-                if yaw<0:
-                    if dx<0:
-                        yaw=-math.pi-yaw
-                len=int(math.sqrt(dx*dx+dy*dy)/delta)
-                ax=math.cos(yaw)*delta
-                ay=math.sin(yaw)*delta
-                poses=[]
-                if isinstance(last_node,(SpaceNode)):
-                    yaw=yaw+math.pi
-                for i in range(len+1):
-                    pose=[last_node.x_+i*ax,last_node.y_+i*ay,yaw]
+                vector = [node.x_ - last_node.x_, node.y_ - last_node.y_]
+
+                dx = vector[0]
+                dy = vector[1]
+                yaw = math.asin(dy / math.sqrt(dx * dx + dy * dy))
+                if yaw >= 0:
+                    if dx < 0:
+                        yaw = math.pi - yaw
+                if yaw < 0:
+                    if dx < 0:
+                        yaw = -math.pi - yaw
+                len = int(math.sqrt(dx * dx + dy * dy) / delta)
+                ax = math.cos(yaw) * delta
+                ay = math.sin(yaw) * delta
+                poses = []
+                if isinstance(last_node, (SpaceNode)):
+                    yaw = yaw + math.pi
+                for i in range(len + 1):
+                    pose = [last_node.x_ + i * ax, last_node.y_ + i * ay, yaw]
                     poses.append(pose)
                 trajectry.append(poses)
-                last_node=node
+                last_node = node
         return trajectry
+
     @staticmethod
     def CreateNavCmd(pose, path):
         if len(path) <= 1:
             return None
 
         cmd = message.NavCmd()
-        cmd.action=0  # 新导航
+        cmd.action = 0  # 新导航
         key = str(uuid.uuid4())
-        cmd.key=(key)
+        cmd.key = (key)
         adjustdiff = message.Pose2d()
         node_mpcdiff = message.Pose2d()
         enddiff = message.Pose2d()
-        lastAdjustDiff=message.Pose2d()
+        lastAdjustDiff = message.Pose2d()
 
         # 目标点精度设置
-        adjustdiff.x=(0.1)
-        adjustdiff.y=(0.05)
-        adjustdiff.theta=(0.5 * math.pi / 180.0)
+        adjustdiff.x = (0.1)
+        adjustdiff.y = (0.05)
+        adjustdiff.theta = (0.5 * math.pi / 180.0)
 
-        node_mpcdiff.x=(0.1)
-        node_mpcdiff.y=(0.1)
-        node_mpcdiff.theta=(10 * math.pi / 180.0)
+        node_mpcdiff.x = (0.1)
+        node_mpcdiff.y = (0.1)
+        node_mpcdiff.theta = (10 * math.pi / 180.0)
 
-        enddiff.x=(0.1)
-        enddiff.y=(0.1)
-        enddiff.theta=(5 * math.pi / 180.0)
+        enddiff.x = (0.1)
+        enddiff.y = (0.1)
+        enddiff.theta = (5 * math.pi / 180.0)
 
-        lastAdjustDiff.x=(0.03)
-        lastAdjustDiff.y=(0.03)
-        lastAdjustDiff.theta=(0.3 * math.pi / 180.0)
+        lastAdjustDiff.x = (0.03)
+        lastAdjustDiff.y = (0.03)
+        lastAdjustDiff.theta = (0.3 * math.pi / 180.0)
 
         # 速度限制
         v_limit = message.SpeedLimit()
         angular_limit = message.SpeedLimit()
         horize_limit = message.SpeedLimit()
-        v_limit.min=(0.1)
-        v_limit.max=(0.2)
-        horize_limit.min=(0.05)
-        horize_limit.max=(0.2)
-        angular_limit.min=(1)
-        angular_limit.max=(25.0)
+        v_limit.min = (0.1)
+        v_limit.max = (0.2)
+        horize_limit.min = (0.05)
+        horize_limit.max = (0.2)
+        angular_limit.min = (1)
+        angular_limit.max = (25.0)
         # mpc速度限制
         mpc_x_limit = message.SpeedLimit()
         mpc_angular_limit = message.SpeedLimit()
-        mpc_x_limit.min=(0.05)
-        mpc_x_limit.max=(1.5)
+        mpc_x_limit.min = (0.05)
+        mpc_x_limit.max = (1.5)
 
-        mpc_angular_limit.min=(0 * math.pi / 180.0)
-        mpc_angular_limit.max=(3 * math.pi / 180.0)
+        mpc_angular_limit.min = (0 * math.pi / 180.0)
+        mpc_angular_limit.max = (3 * math.pi / 180.0)
 
         # 创建动作集----------------------
 
@@ -194,7 +199,7 @@ class DijikstraMap(object):
         for node in path:
             if last_node == None:
                 last_node = node
-                count+=1
+                count += 1
                 continue
 
             # 运动到上一点
@@ -212,13 +217,13 @@ class DijikstraMap(object):
                 yaw = yaw + math.pi
             # 添加调整动作
             act_adjust = message.Action()
-            act_adjust.type=(1)
+            act_adjust.type = (1)
 
-            act_adjust.target.x=(last_node.x_)
-            act_adjust.target.y=(last_node.y_)
-            act_adjust.target.theta=(yaw)
-            #最后一个调整点
-            if count==len(path)-2:
+            act_adjust.target.x = (last_node.x_)
+            act_adjust.target.y = (last_node.y_)
+            act_adjust.target.theta = (yaw)
+            # 最后一个调整点
+            if count == len(path) - 2:
                 act_adjust.target_diff.CopyFrom(lastAdjustDiff)
             else:
                 act_adjust.target_diff.CopyFrom(adjustdiff)
@@ -229,15 +234,15 @@ class DijikstraMap(object):
 
             # 添加mpc动作
             act_along = message.Action()
-            act_along.type=(2)
-
-            act_along.begin.x=(last_node.x_)
-            act_along.begin.y=(last_node.y_)
-            act_along.begin.theta=(yaw)
-            act_along.target.x=(node.x_)
-            act_along.target.y=(node.y_)
-            act_along.target.theta=(yaw)
-            if count==len(path)-1:
+            act_along.type = (2)
+
+            act_along.begin.x = (last_node.x_)
+            act_along.begin.y = (last_node.y_)
+            act_along.begin.theta = (yaw)
+            act_along.target.x = (node.x_)
+            act_along.target.y = (node.y_)
+            act_along.target.theta = (yaw)
+            if count == len(path) - 1:
                 act_along.target_diff.CopyFrom(enddiff)
             else:
                 act_along.target_diff.CopyFrom(node_mpcdiff)
@@ -246,6 +251,126 @@ class DijikstraMap(object):
             cmd.actions.add().CopyFrom(act_along)
 
             last_node = node
-            count+=1
+            count += 1
 
         return cmd
+
+    # 生成指令的基础信息
+    @staticmethod
+    def CreateNavCmd_part_base():
+        cmd = message.NavCmd()
+        cmd.action = 0  # 新导航
+        key = str(uuid.uuid4())
+        cmd.key = (key)
+
+        return cmd
+
+    # 生成指令的动作集
+    @staticmethod
+    def CreateNavCmd_part_actions(path):
+        if len(path) <= 1:
+            return None
+
+        adjustdiff = message.Pose2d()
+        node_mpcdiff = message.Pose2d()
+        enddiff = message.Pose2d()
+        lastAdjustDiff = message.Pose2d()
+
+        # 目标点精度设置
+        adjustdiff.x = (0.1)
+        adjustdiff.y = (0.05)
+        adjustdiff.theta = (0.5 * math.pi / 180.0)
+
+        node_mpcdiff.x = (0.1)
+        node_mpcdiff.y = (0.1)
+        node_mpcdiff.theta = (10 * math.pi / 180.0)
+
+        enddiff.x = (0.1)
+        enddiff.y = (0.1)
+        enddiff.theta = (5 * math.pi / 180.0)
+
+        lastAdjustDiff.x = (0.03)
+        lastAdjustDiff.y = (0.03)
+        lastAdjustDiff.theta = (0.3 * math.pi / 180.0)
+
+        # 速度限制
+        v_limit = message.SpeedLimit()
+        angular_limit = message.SpeedLimit()
+        horize_limit = message.SpeedLimit()
+        v_limit.min = (0.1)
+        v_limit.max = (0.2)
+        horize_limit.min = (0.05)
+        horize_limit.max = (0.2)
+        angular_limit.min = (1)
+        angular_limit.max = (25.0)
+        # mpc速度限制
+        mpc_x_limit = message.SpeedLimit()
+        mpc_angular_limit = message.SpeedLimit()
+        mpc_x_limit.min = (0.05)
+        mpc_x_limit.max = (1.5)
+
+        mpc_angular_limit.min = (0 * math.pi / 180.0)
+        mpc_angular_limit.max = (3 * math.pi / 180.0)
+
+        # 创建动作集----------------------
+        actions = list()
+        last_node = None
+        count = 0
+        for node in path:
+            if last_node == None:
+                last_node = node
+                count += 1
+                continue
+
+            # 运动到上一点
+            vector = [node.x_ - last_node.x_, node.y_ - last_node.y_]
+            dx = vector[0]
+            dy = vector[1]
+            yaw = math.asin(dy / math.sqrt(dx * dx + dy * dy))
+            if yaw >= 0:
+                if dx < 0:
+                    yaw = math.pi - yaw
+            if yaw < 0:
+                if dx < 0:
+                    yaw = -math.pi - yaw
+            if isinstance(last_node, (SpaceNode)):
+                yaw = yaw + math.pi
+            # 添加调整动作
+            act_adjust = message.Action()
+            act_adjust.type = (1)
+
+            act_adjust.target.x = (last_node.x_)
+            act_adjust.target.y = (last_node.y_)
+            act_adjust.target.theta = (yaw)
+            # 最后一个调整点
+            if count == len(path) - 2:
+                act_adjust.target_diff.CopyFrom(lastAdjustDiff)
+            else:
+                act_adjust.target_diff.CopyFrom(adjustdiff)
+            act_adjust.velocity_limit.CopyFrom(v_limit)
+            act_adjust.horize_limit.CopyFrom(horize_limit)
+            act_adjust.angular_limit.CopyFrom(angular_limit)
+            actions.append(act_adjust)
+
+            # 添加mpc动作
+            act_along = message.Action()
+            act_along.type = (2)
+
+            act_along.begin.x = (last_node.x_)
+            act_along.begin.y = (last_node.y_)
+            act_along.begin.theta = (yaw)
+            act_along.target.x = (node.x_)
+            act_along.target.y = (node.y_)
+            act_along.target.theta = (yaw)
+            if count == len(path) - 1:
+                act_along.target_diff.CopyFrom(enddiff)
+            else:
+                act_along.target_diff.CopyFrom(node_mpcdiff)
+            act_along.velocity_limit.CopyFrom(mpc_x_limit)
+            act_along.angular_limit.CopyFrom(mpc_angular_limit)
+            actions.append(act_along)
+
+            last_node = node
+            count += 1
+        return actions
+

+ 1 - 1
message.proto

@@ -43,7 +43,7 @@ message Trajectory
 
 message Action
 {
-  int32 type = 1; // 1:原地调整,2:巡线
+  int32 type = 1; // 1:原地调整,2:巡线, 3:夹持, 4:松夹持
   Pose2d begin = 2;
   Pose2d target = 3;
   Pose2d target_diff = 4;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 28 - 590
message_pb2.py


+ 76 - 62
test.py

@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#===============================================================================
+# ===============================================================================
 #
 # test.py
 #
@@ -31,10 +31,12 @@
 # (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 time
 import sys
+
+from PyQt5 import QtWidgets, QtGui
 from PyQt5.QtGui import *
 from PyQt5.QtWidgets import *
 from PyQt5.QtCore import *
@@ -46,128 +48,140 @@ import RobotData as RD
 import message_pb2 as message
 import google.protobuf.json_format as jtf
 import uuid
-#===============================================================================
+
+
+# ===============================================================================
 
 
 class MainWindow(QMainWindow):
     """docstring for Mainwindow"""
-    djks_map_=mp.DijikstraMap()
-    ui_nodes=[]
+    djks_map_ = mp.DijikstraMap()
+    ui_nodes = []
 
-    def __init__(self, parent = None):
-        super(MainWindow,self).__init__(parent)
+    def __init__(self, parent=None):
+        super(MainWindow, self).__init__(parent)
         self.basic()
 
         self.LoadMap()
-        self.Controller1 = ControllWidget.ControlFrame(["AGV1",self.ui_nodes])
-        self.Controller2 = ControllWidget.ControlFrame(["AGV2",self.ui_nodes])
+        self.Controller1 = ControllWidget.ControlFrame(["AGV1", self.ui_nodes])
+        self.Controller2 = ControllWidget.ControlFrame(["AGV2", self.ui_nodes])
 
         splitter_main = self.split_()
         self.setCentralWidget(splitter_main)
 
-
-        self.Controller1.robot_.connect("pyUI_r1","192.168.0.70",1883,"admin","zx123456")
-        dataTopics={"agv1_child/agv_statu":message.AGVStatu.__name__,
-                    "agv1_child/nav_statu":message.NavStatu.__name__}
-        self.Controller1.robot_.SetSubDataTopic(dataTopics,self.messageArrived)
+        self.Controller1.robot_.connect("pyUI_r1", "127.0.0.1", 1883, "admin", "zx123456")
+        dataTopics = {"agv1_child/agv_statu": message.AGVStatu.__name__,
+                      "agv1_child/nav_statu": message.NavStatu.__name__}
+        self.Controller1.robot_.SetSubDataTopic(dataTopics, self.messageArrived)
         self.Controller1.robot_.SetCmdTopic("agv1_child/nav_cmd")
         self.Controller1.robot_.loop_start()
-        self.Controller1.robot_.SetColor([0.7,0.2,0.3],[0.7,0.2,0.3])
+        self.Controller1.robot_.SetColor([0.7, 0.2, 0.3], [0.7, 0.2, 0.3])
         self.gl.SetRobot1Instance(self.Controller1.robot_)
 
-        self.Controller2.robot_.connect("pyUI_r2","192.168.0.70",1883,"admin","zx123456")
-        dataTopics={"agv1/agv_statu":message.AGVStatu.__name__,
-                    "agv1/nav_statu":message.NavStatu.__name__}
-        self.Controller2.robot_.SetSubDataTopic(dataTopics,self.messageArrived)
+        self.Controller2.robot_.connect("pyUI_r2", "127.0.0.1", 1883, "admin", "zx123456")
+        dataTopics = {"agv1/agv_statu": message.AGVStatu.__name__,
+                      "agv1/nav_statu": message.NavStatu.__name__}
+        self.Controller2.robot_.SetSubDataTopic(dataTopics, self.messageArrived)
         self.Controller2.robot_.SetCmdTopic("agv1/nav_cmd")
         self.Controller2.robot_.loop_start()
-        self.Controller2.robot_.SetColor([0.4,0.2,0.8],[0.4,0.2,0.8])
+        self.Controller2.robot_.SetColor([0.4, 0.2, 0.8], [0.4, 0.2, 0.8])
         self.gl.SetRobot2Instance(self.Controller2.robot_)
 
     def LoadMap(self):
-        self.gl = MapGLWidget()   #将opengl例子嵌入GUI
-        map=self.load_map("./map.json")
-
+        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])
+            [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.gl.AddNode([id, "street_node", point])
             self.ui_nodes.append(id)
         for node in map['space_nodes'].items():
-            [id,point]=node
-            [x,y,connectId]=point
-            space_node=mp.SpaceNode(id,point[0],point[1],connectId)
+            [id, point] = node
+            [x, y, connectId] = point
+            space_node = mp.SpaceNode(id, point[0], point[1], connectId)
             self.djks_map_.AddVertex(space_node)
-            self.djks_map_.AddEdge(id,connectId)
-            glNode=[id,"space_node",[x,y]]
+            self.djks_map_.AddEdge(id, connectId)
+            glNode = [id, "space_node", [x, y]]
             self.gl.AddNode(glNode)
-            self.gl.AddRoad(["conn%s-%s"%(id,connectId),[id,connectId]])
+            self.gl.AddRoad(["conn%s-%s" % (id, connectId), [id, connectId]])
             self.ui_nodes.append(id)
 
         for road in map['roads'].items():
             self.gl.AddRoad(road)
 
-            [_,points]=road
+            [_, points] = road
             for pt1 in points:
                 for pt2 in points:
-                    if not pt1==pt2:
-                        self.djks_map_.AddEdge(pt1,pt2)
+                    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)
+    def load_map(self, file):
+        with open(file, 'r', encoding='utf-8') as fp:
+            map = json.load(fp)
             return map
 
     def messageArrived(self):
         self.gl.update()
 
-    #窗口基础属性
+    # 窗口基础属性
     def basic(self):
-        #设置标题,大小,图标
+        # 设置标题,大小,图标
         self.setWindowTitle("GT")
-        self.resize(1100,650)
+        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))
+        self.move(int((screen.width() - self_size.width()) / 2), int((screen.height() - self_size.height()) / 2))
 
     def closeEvent(self, QCloseEvent):
         self.gl.close()
 
-    #分割窗口
+    # 基于布局的显示窗口
     def split_(self):
-        splitter_main = QSplitter(Qt.Horizontal)
-        splitter = QSplitter(Qt.Vertical)
+        total_layout = QtWidgets.QGridLayout()
 
-        splitter.addWidget(self.Controller1)
-        splitter.addWidget(self.Controller2)
+        # 地图显示布局
+        display_layout = QtWidgets.QGridLayout()
+        display_layout.setObjectName("display_layout")
+        display_layout.addWidget(self.gl)
+        total_layout.addLayout(display_layout, 0, 1, 1, 1)
 
-        splitter.setStretchFactor(0,1)
-        splitter.setStretchFactor(1,1)
+        # 操作控制布局
+        control_layout = QtWidgets.QGridLayout()
+        control_layout.setObjectName("control_layout")
+        control_layout.addWidget(self.Controller1)
+        control_layout.addWidget(self.Controller2)
+        total_layout.addLayout(control_layout, 0, 0, 1, 1)
 
-        splitter_main.addWidget(splitter)
-        splitter_main.addWidget(self.gl)
+        # 总布局设置
+        total_layout.setColumnStretch(0, 2)
+        total_layout.setColumnStretch(1, 5)
+        total_layout.setRowStretch(0, 1)
 
-        splitter_main.setStretchFactor(0,1)
-        splitter_main.setStretchFactor(2,4)
+        # 将总布局加载到主窗口
+        centerWidget = QtWidgets.QWidget()
+        # font = QtGui.QFont()
+        # font.setFamily("楷体")
+        # font.setPointSize(15)
+        # centerWidget.setFont(font)
+        centerWidget.setLayout(total_layout)
 
 
+        return centerWidget
 
-        return splitter_main
 
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     win = MainWindow()
-    win.show()
+    win.showMaximized()
     sys.exit(app.exec_())
 
-
-#===============================================================================
+# ===============================================================================
 # Main
-#===============================================================================
+# ===============================================================================
 
 '''app = QApplication(sys.argv)
 mainWindow = MapGLWidget()
@@ -175,11 +189,11 @@ 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:
+# Park_End:
 #
-#===============================================================================
+# ===============================================================================