一、Rviz(The Robot Visualization Tool)
机器人可视化工具,可以将如激光雷达,摄像头等传感器信息可视化显示,还能显示机器人运算处理的中间结果和即将执行的目标指示。
在终端中直接输入rviz打开
可以将设定好的观测配置保存为.rviz文件,下次打开时可以直接加载
二、激光雷达消息包格式
可以在终端中输入以下命令来查看激光雷达消息包
rostopic echo /scan --noarr
其中/scan是激光雷达发布采集到数据的话题,--noarr表示将数组折叠,否则消息包看起来会相当混乱
seq 是一个序列号(sequence number),表示该消息是某个话题发布的第几条消息。stamp 是时间戳(timestamp),表示该消息生成的时间。、
frame_id 是一个字符串,表示该消息关联的坐标系(frame of reference)
在 ROS 中,坐标系用于描述空间中的位置和方向。
不同的传感器或数据源通常会使用不同的坐标系,例如 "laser" 表示激光雷达的坐标系。
坐标变换(TF,Transform)系统会利用 frame_id 来管理不同坐标系之间的关系。
三、用python实现订阅者节点获取激光雷达测距信息
1.在catkin_ws工作空间src子目录下使用以下指令新建一个软件包,命名为lidar_pkg,其中依赖项多了一个sensor_msgs,传感器消息类型。
catkin_create_pkg lidar_pkg roscpp rospy sensor_msgs
创建完成后记得回退到上一级目录并用catkin_make编译,目的是将软件包加入ros系统的软件包列表里。
2.在vscode里找到这个软件包,新建scripts文件夹并在文件夹里新建lidar_node.py文件。(这一步与其他订阅者节点一样)
3.编写代码
#!/usr/bin/env python3
#coding=utf-8
import rospy
from sensor_msgs.msg import LaserScan #引入激光雷达的消息格式
def LidarCallback(msg):
dist = msg.ranges[180]
rospy.loginfo("前方测距 range[180] = %f 米", dist)
if __name__ == "__main__":
rospy.init_node("lidar_node")#向rospy申请初始化节点
lidar_sub = rospy.Subscriber("/scan",LaserScan,LidarCallback,queue_size=10)#创建订阅者对象
rospy.spin()#让节点保持运行别退出
4.打开代码文件所在文件夹,从终端打开,给py文件加上可执行权限chmod +x lidar_node.pya
5.通过rosrun lidar_pkg lidar_node.py运行文件,通过wpr_simulation测试效果。
四、激光雷达避障节点(一个节点同时是发布者和订阅者)
#!/usr/bin/env python3
#coding=utf-8
import rospy
from sensor_msgs.msg import LaserScan #引入激光雷达的消息格式
from geometry_msgs.msg import Twist #引入速度消息格式
count = 0
def LidarCallback(msg):#激光雷达每扫过一圈就会调用这个回调函数,可以从激光雷达消息包中查看scan_time数据来获得回调函数的调用频率
global vel_pub #把vel_pub这个发布者对象定义成全局变量
#如果不定义这个全局变量,下面会重新生成一个vel_pub对象,这个对象没有加入速度话题/cmd_vel,无法发布速度消息
global count
dist = msg.ranges[180]
l_dist = msg.ranges[210]
r_dist = msg.ranges[150]
rospy.loginfo("前方测距 range[180] = %f 米", dist)
if count > 0:
count -= 1
rospy.loginfo("转向中,前方测距 range[180] = %f 米", dist)
if l_dist > 1.5 and r_dist > 1.5 and dist > 1.5:#如果前方、左前方、右前方的障碍物都大于1.5米,说明机器人已经转向完成
count = 0
return#如果count大于0,说明机器人正在转向,直接返回,忽略掉后面的速度发送操作
vel_cmd = Twist()#创建速度消息对象
if l_dist < 1.5:
vel_cmd.angular.z = -0.5#如果左前方障碍物小于1.5米,转向
count = 70 #当机器人检测到障碍物时,给变量赋值70
elif r_dist < 1.5:
vel_cmd.angular.z = 0.5
count = 70
elif dist < 1.5:
vel_cmd.angular.z = 1.0
count = 100
else:
vel_cmd.linear.x = 0.3#如果前方障碍物大于1.5米,前进
vel_pub.publish(vel_cmd)#发布速度消息
if __name__ == "__main__":
rospy.init_node("lidar_node")#向rospy申请初始化节点
vel_pub = rospy.Publisher("/cmd_vel",Twist,queue_size=10)#创建发布者对象
lidar_sub = rospy.Subscriber("/scan",LaserScan,LidarCallback,queue_size=10)#创建订阅者对象
rospy.spin()#让节点保持运行别退出
在之前激光雷达测距信息节点基础上修改,加入发布者对象即可
1.让大管家rospy发布速度控制话题/cmd_vel
vel_pub = rospy.Publisher("/cmd_vel",Twist,queue_size=10)#创建发布者对象
注意要把这个发布者对象在回调函数里声明为全局变量,否则每次调用回调函数都会重新生成一个未关联速度话题的发布者节点
2.构建速度控制消息包vel_cmd
vel_cmd = Twist()#创建速度消息对象
3.根据激光雷达的测距数值,实时调整机器人运动速度,避开障碍物
if l_dist < 1.5:
vel_cmd.angular.z = -0.5#如果左前方障碍物小于1.5米,转向
count = 70 #当机器人检测到障碍物时,给变量赋值70
elif r_dist < 1.5:
vel_cmd.angular.z = 0.5
count = 70
elif dist < 1.5:
vel_cmd.angular.z = 1.0
count = 100
else:
vel_cmd.linear.x = 0.3#如果前方障碍物大于1.5米,前进
vel_pub.publish(vel_cmd)#发布速度消息
注意:如果只检测前方距离并转向的话,会忽视机器人宽度,造成侧面碰撞的情况,所以要定义一个全局变量count,一旦检测到前方有障碍物就把count置为50(意义是忽略接下来的50次回调函数调用,专心转向)