1. 创建package

  1. ros2 pkg create --build-type ament_python turtlesim_service

可以修改package.xml文件如下信息

  1. <description>C++ client server tutorial</description>
  2. <maintainer email="you@email.com">Your Name</maintainer>
  3. <license>Apache License 2.0</license>

2. 编写代码

2.1 节点代码

  1. 在package的turtlesim_service文件夹下创建turtlesim_service.py文件,代码如下 ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QCheckBox import rclpy from rclpy.node import Node from std_srvs.srv import Empty from turtlesim.srv import Kill, Spawn, SetPen, TeleportAbsolute, TeleportRelative

class MainWindow(QWidget): def init(self, node): super(MainWindow, self).init()

  1. self.node = node
  2. self.clear_ser = self.node.create_client(Empty, '/clear')
  3. self.reset_ser = self.node.create_client(Empty, '/reset')
  4. self.spawn_ser = self.node.create_client(Spawn, '/spawn')
  5. self.kill_ser = self.node.create_client(Kill, '/kill')
  6. layout = QVBoxLayout()
  7. self.setLayout(layout)
  8. # part1
  9. clear_btn = QPushButton('清理画布')
  10. # part2
  11. reset_btn = QPushButton('重置')
  12. # part3
  13. layout1 = QHBoxLayout()
  14. self.create_x = QLineEdit()
  15. self.create_y = QLineEdit()
  16. self.create_theta = QLineEdit()
  17. self.create_name = QLineEdit()
  18. self.create_x.setPlaceholderText('x坐标')
  19. self.create_y.setPlaceholderText('y坐标')
  20. self.create_theta.setPlaceholderText('角度')
  21. self.create_name.setPlaceholderText('名字')
  22. create_btn = QPushButton('创建小乌龟')
  23. layout1.addWidget(self.create_x)
  24. layout1.addWidget(self.create_y)
  25. layout1.addWidget(self.create_theta)
  26. layout1.addWidget(self.create_name)
  27. layout1.addWidget(create_btn)
  28. # part4
  29. layout2 = QHBoxLayout()
  30. self.kill_name = QLineEdit()
  31. self.kill_name.setPlaceholderText('名字')
  32. kill_btn = QPushButton('杀死小乌龟')
  33. layout2.addWidget(self.kill_name)
  34. layout2.addWidget(kill_btn)
  35. # part5
  36. layout3 = QHBoxLayout()
  37. self.pen_name = QLineEdit()
  38. self.pen_red = QLineEdit()
  39. self.pen_green = QLineEdit()
  40. self.pen_blue = QLineEdit()
  41. self.pen_width = QLineEdit()
  42. self.pen_close = QCheckBox('关闭')
  43. self.pen_name.setPlaceholderText('名字')
  44. self.pen_red.setPlaceholderText('红')
  45. self.pen_green.setPlaceholderText('绿')
  46. self.pen_blue.setPlaceholderText('蓝')
  47. self.pen_width.setPlaceholderText('粗细')
  48. pen_btn = QPushButton('设置画笔')
  49. layout3.addWidget(self.pen_name)
  50. layout3.addWidget(self.pen_red)
  51. layout3.addWidget(self.pen_green)
  52. layout3.addWidget(self.pen_blue)
  53. layout3.addWidget(self.pen_width)
  54. layout3.addWidget(self.pen_close)
  55. layout3.addWidget(pen_btn)
  56. # part6
  57. layout4 = QHBoxLayout()
  58. self.abs_name = QLineEdit()
  59. self.abs_x = QLineEdit()
  60. self.abs_y = QLineEdit()
  61. self.abs_theta = QLineEdit()
  62. self.abs_x.setPlaceholderText('x坐标')
  63. self.abs_y.setPlaceholderText('y坐标')
  64. self.abs_theta.setPlaceholderText('角度')
  65. self.abs_name.setPlaceholderText('名字')
  66. abs_btn = QPushButton('设置绝对位置')
  67. layout4.addWidget(self.abs_name)
  68. layout4.addWidget(self.abs_x)
  69. layout4.addWidget(self.abs_y)
  70. layout4.addWidget(self.abs_theta)
  71. layout4.addWidget(self.abs_theta)
  72. layout4.addWidget(abs_btn)
  73. # part7
  74. layout5 = QHBoxLayout()
  75. self.rel_name = QLineEdit()
  76. self.rel_linear = QLineEdit()
  77. self.rel_angular = QLineEdit()
  78. self.rel_name.setPlaceholderText('名字')
  79. self.rel_linear.setPlaceholderText('线速度')
  80. self.rel_angular.setPlaceholderText('角速度')
  81. rel_btn = QPushButton('设置相对位置')
  82. layout5.addWidget(self.rel_name)
  83. layout5.addWidget(self.rel_linear)
  84. layout5.addWidget(self.rel_angular)
  85. layout5.addWidget(rel_btn)
  86. # all
  87. layout.addWidget(clear_btn)
  88. layout.addWidget(reset_btn)
  89. layout.addLayout(layout1)
  90. layout.addLayout(layout2)
  91. layout.addLayout(layout3)
  92. layout.addLayout(layout4)
  93. layout.addLayout(layout5)
  94. # click event
  95. clear_btn.clicked.connect(self.clear)
  96. reset_btn.clicked.connect(self.reset)
  97. create_btn.clicked.connect(self.create_turtle)
  98. kill_btn.clicked.connect(self.kill_turtle)
  99. pen_btn.clicked.connect(self.set_pen)
  100. abs_btn.clicked.connect(self.set_abs_pos)
  101. rel_btn.clicked.connect(self.set_rel_pos)
  102. def clear(self):
  103. req = Empty.Request()
  104. self.clear_ser.call_async(req)
  105. def reset(self):
  106. req = Empty.Request()
  107. self.reset_ser.call_async(req)
  108. def create_turtle(self):
  109. req = Spawn.Request()
  110. req.name = self.create_name.text()
  111. req.x = float(self.create_x.text())
  112. req.y = float(self.create_y.text())
  113. req.theta = float(self.create_theta.text())
  114. self.spawn_ser.call_async(req)
  115. def kill_turtle(self):
  116. req = Kill.Request()
  117. req.name = self.create_name.text()
  118. self.kill_ser.call_async(req)
  119. def set_pen(self):
  120. self.set_pen_ser = self.node.create_client(SetPen, f'/{self.pen_name.text()}/set_pen')
  121. req = SetPen.Request()
  122. req.r = int(self.pen_red.text())
  123. req.g = int(self.pen_green.text())
  124. req.b = int(self.pen_blue.text())
  125. req.width = int(self.pen_width.text())
  126. req.off = 1 if self.pen_close.isChecked() else 0
  127. self.set_pen_ser.call_async(req)
  128. def set_abs_pos(self):
  129. self.abs_pos_ser = self.node.create_client(TeleportAbsolute, f'/{self.abs_name.text()}/teleport_absolute')
  130. req = TeleportAbsolute.Request()
  131. req.x = float(self.abs_x.text())
  132. req.y = float(self.abs_y.text())
  133. req.theta = float(self.abs_theta.text())
  134. self.abs_pos_ser.call_async(req)
  135. def set_rel_pos(self):
  136. self.rel_pos_ser = self.node.create_client(TeleportRelative, f'/{self.rel_name.text()}/teleport_relative')
  137. req = TeleportRelative.Request()
  138. req.linear = float(self.rel_linear.text())
  139. req.angular = float(self.rel_angular.text())
  140. self.rel_pos_ser.call_async(req)

def main(): rclpy.init() node = Node(‘turtlesimcontrol’) app = QApplication(sys.argv) window = MainWindow(node) window.show() sys.exit(app.exec())

if name == ‘main‘: main()

  1. <a name="FRPUu"></a>
  2. ## 2.2 添加配置
  3. 1. 打开setup.py文件,在console_scripts节点下添加配置
  4. ```python
  5. 'turtlesim_service = turtlesim_service.turtlesim_service:main',

3. 编译工程

  1. colcon build

4. 运行节点

  1. source install/setup.bash
  2. ros2 run turtlesim_service turtlesim_service