完整代码

  1. import typing
  2. from PyQt5 import QtCore
  3. import rclpy
  4. from rclpy.node import Node
  5. from example_interfaces.srv import AddTwoInts
  6. from PyQt5.QtWidgets import QWidget,QApplication,QFormLayout,QLineEdit,QLabel,QPushButton
  7. from PyQt5.QtCore import QTimer
  8. import sys
  9. from turtlesim.msg import Pose
  10. from geometry_msgs.msg import Twist
  11. from std_msgs.msg import Float64
  12. from threading import Thread
  13. import math
  14. import time
  15. class MainWindow(QWidget):
  16. def __init__(self, node) -> None:
  17. super().__init__()
  18. # 节点
  19. self.node = node
  20. # 初始化ui界面
  21. self.init_ui()
  22. # 定时器
  23. timer = QTimer(self)
  24. timer.setInterval(20)
  25. timer.start()
  26. timer.timeout.connect(self.onUpdate)
  27. # 当前的x y theta
  28. self.curX = 0
  29. self.curY = 0
  30. self.curTheta = 0
  31. # 订阅位置
  32. self.sub = self.node.create_subscription(Pose,'/turtle1/pose',self.pose_callback,10)
  33. # 小乌龟控制发布者
  34. self.control_pub = self.node.create_publisher(Twist,'/turtle1/cmd_vel',10)
  35. # 发布小乌龟速度
  36. self.speed_pub = self.node.create_publisher(Float64,'/turtle/speed',10)
  37. def pose_callback(self,pose):
  38. self.curX = pose.x
  39. self.curY = pose.y
  40. self.curTheta = pose.theta
  41. # 设置当前位置
  42. self.xL.setText(str(self.curX))
  43. self.yL.setText(str(self.curY))
  44. self.thetaL.setText(str(self.curTheta))
  45. # 定时更新
  46. def onUpdate(self):
  47. if not rclpy.ok():
  48. self.close()
  49. return
  50. rclpy.spin_once(self.node)
  51. def init_ui(self):
  52. # 布局
  53. layout = QFormLayout()
  54. self.setLayout(layout)
  55. self.targetEditX = QLineEdit()
  56. self.targetEditY = QLineEdit()
  57. self.xL = QLabel()
  58. self.yL = QLabel()
  59. self.thetaL = QLabel()
  60. self.kpE = QLineEdit()
  61. self.kiE = QLineEdit()
  62. self.kdE = QLineEdit()
  63. executeBtn = QPushButton('执行')
  64. vSweepBtn = QPushButton('纵向扫地')
  65. layout.addRow('目标X:',self.targetEditX)
  66. layout.addRow('目标Y:',self.targetEditY)
  67. layout.addRow('当前X:',self.xL)
  68. layout.addRow('当前Y:',self.yL)
  69. layout.addRow('当前theta:',self.thetaL)
  70. layout.addRow('KP:',self.kpE)
  71. layout.addRow('KI:',self.kiE)
  72. layout.addRow('KD:',self.kdE)
  73. self.kpE.setText('0.1')
  74. self.kiE.setText('0.1')
  75. self.kdE.setText('0.1')
  76. self.targetEditX.setText('8.544444561')
  77. self.targetEditY.setText('5.544444561')
  78. layout.addRow('',executeBtn)
  79. layout.addRow('',vSweepBtn)
  80. executeBtn.clicked.connect(self.move)
  81. vSweepBtn.clicked.connect(self.vSweep)
  82. def vSweep(self):
  83. print('zhixing1')
  84. Thread(target=self.vSweepImpl).start()
  85. def vSweepImpl(self):
  86. print('zhixing2')
  87. for i in range(1,11):
  88. self.executeMove(i,1)
  89. self.executeMove(i,10)
  90. def distance(self,curX,curY,targetX,targetY):
  91. return math.sqrt(pow(targetX-curX,2)+pow(targetY-curY,2))
  92. def caclAngle(self,curX,curY,targetX,targetY,theta):
  93. angle = math.atan2(targetY-curY,targetX-curX)-theta
  94. if angle>math.pi:
  95. angle -= 2*math.pi
  96. elif angle<-math.pi:
  97. angle += 2*math.pi
  98. return angle
  99. def executeMove(self,targetX,targetY):
  100. dst = self.distance(self.curX,self.curY,targetX,targetY)
  101. # 定义时间
  102. control_time = 5.0
  103. # 掉头时间
  104. turnTime = control_time/12
  105. # 睡眠
  106. hz = 10
  107. # 频率
  108. rate = self.node.create_rate(hz)
  109. # 当前速度
  110. curSpeed = 0
  111. # 上一次的速度差
  112. lastSpeedDiff = 0
  113. # 累计误差
  114. totalSpeedDiff = 0
  115. # kp ki kd
  116. kp = float(self.kpE.text())
  117. ki = float(self.kiE.text())
  118. kd = float(self.kdE.text())
  119. # 求速度
  120. while self.distance(self.curX,self.curY,targetX,targetY)>0.1:
  121. # 目标速度
  122. speed = self.distance(self.curX,self.curY,targetX,targetY)/control_time
  123. # kp
  124. curSpeedDiff = speed-curSpeed
  125. curSpeed += curSpeedDiff*kp
  126. # kd
  127. curSpeed += (curSpeedDiff-lastSpeedDiff)*kd
  128. lastSpeedDiff = curSpeedDiff
  129. # ki
  130. totalSpeedDiff += curSpeedDiff
  131. curSpeed += totalSpeedDiff*ki
  132. # 发布控制小乌龟
  133. data = Twist()
  134. data.linear.x = curSpeed
  135. data.angular.z = self.caclAngle(self.curX,self.curY,targetX,targetY,self.curTheta)/turnTime
  136. self.control_pub.publish(data)
  137. # 发布速度plot显示
  138. speed_data = Float64()
  139. speed_data.data = curSpeed
  140. self.speed_pub.publish(speed_data)
  141. rate.sleep()
  142. control_time -= 1.0/hz
  143. # time.sleep(0.09)
  144. print('stop')
  145. # 发布控制小乌龟
  146. data = Twist()
  147. data.linear.x = 0.0
  148. self.control_pub.publish(data)
  149. def move(self):
  150. targetX = float(self.targetEditX.text())
  151. targetY = float(self.targetEditY.text())
  152. # 开启线程执行
  153. Thread(target=self.executeMove,args=(targetX,targetY)).start()
  154. def main():
  155. rclpy.init()
  156. node = Node('service_server_node')
  157. app = QApplication(sys.argv)
  158. window = MainWindow(node)
  159. window.show()
  160. print('app start')
  161. result = app.exec_()
  162. node.destroy_node()
  163. rclpy.shutdown()
  164. sys.exit(result)
  165. if __name__ == '__main__':
  166. main()