ROS实操入门系列(二)操控小乌龟时,监控行走的路线
上一章讲解了,小乌龟操控原理及代码控制小乌龟走圆形路线,这一章通过订阅/turtlesim发出的Topic,获得小乌龟的一些位置信息
获取小乌龟的位姿
-
运行小乌龟节点后,获取该节点的信息,/turtle1/pose就是小乌龟发布的坐标和角度
rosnode info /turtlesim
-
通过命令,获取该topic传输数据类型
rostopic type /turtle1/pose
-
创建subscriber订阅上面的/turtle1/pose
-
运行效果
使用QTimer接管渲染
- 与C++不同,调试结果为可以正常接收到订阅的消息。但是关于窗体关闭事件方面只能通过关闭QT界面来关闭进程,不能通过ctrl+c 命令行来关闭。
Python可以正常接收到订阅消息的原因,在于Python采用的SIP方式进行操作QT的界面UI的中间是一套异步策略。
但是为了更好的优化体验,我们也是可以和C++实现的代码逻辑相通的。 - 接管渲染:
创建自己的渲染定时器 updatetimer = QTimer(self) # 设置定时器的频率 updatetimer.setInterval(20) updatetimer.start() # 监听timer事件 updatetimer.timeout.connect(self.on_update) 渲染逻辑: def on_update(self): self.update() if rospy.is_shutdown(): self.close()
完整代码
#!/usr/bin/env python
# coding: utf-8
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import rospy
from geometry_msgs.msg import Twist
from math import radians, degrees
# turtlesim/Pose
from turtlesim.msg import Pose
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
# 创建自己的渲染定时器
updatetimer = QTimer(self)
# 设置定时器的频率
updatetimer.setInterval(20)
updatetimer.start()
# 监听timer事件
updatetimer.timeout.connect(self.on_update)
# 设置title
self.setWindowTitle("小乌龟控制")
self.resize(400, 0)
# 设置布局
layout = QFormLayout()
self.setLayout(layout)
# 添加控件
self.editLinear = QLineEdit("0")
layout.addRow("线速度", self.editLinear)
self.editAngular = QLineEdit("0")
layout.addRow("角速度", self.editAngular)
self.btnSend = QPushButton("发送")
layout.addRow(self.btnSend)
self.labelX = QLabel()
layout.addRow("当前X坐标", self.labelX)
self.labelY = QLabel()
layout.addRow("当前Y坐标", self.labelY)
self.labelLinear = QLabel()
layout.addRow("当前线速度", self.labelLinear)
self.labelAngular = QLabel()
layout.addRow("当前角速度", self.labelAngular)
self.labelDegrees = QLabel()
layout.addRow("当前角度", self.labelDegrees)
# 添加事件
self.btnSend.clicked.connect(self.clickSend)
# 创建publisher
topicName = "/turtle1/cmd_vel"
self.publisher = rospy.Publisher(topicName, Twist, queue_size=1000)
# 接受小乌龟信息
pose_name = '/turtle1/pose'
rospy.Subscriber(pose_name,Pose,self.pose_call)
def pose_call(self,msg):
if not isinstance(msg,Pose): return
print msg
self.labelX.setText(str(msg.x))
self.labelY.setText(str(msg.y))
self.labelLinear.setText(str(msg.linear_velocity))
self.labelAngular.setText(str(msg.angular_velocity))
# 弧度转角度
self.labelDegrees.setText(str(degrees(msg.theta)))
# self.labelDegrees.setText(str(msg.theta))
def clickSend(self):
linearX = float(self.editLinear.text())
# 角度转弧度
angularZ = radians(float(self.editAngular.text()))
# 构建消息
twist = Twist()
twist.linear.x = linearX
twist.angular.z = angularZ
# 发布
self.publisher.publish(twist)
def on_update(self):
self.update()
if rospy.is_shutdown():
self.close()