前言

 

上一节:北邮智能车仿真培训(三)—— 给车舞台让它驰骋

 

这一节主要介绍下ros常用工具和上一节控制小车的python脚本内容。看会了,你就也可以修改代码啦。

 

ROS通信机制

 

简单说下ros的通信机制,ros是通过节点将整个网络互联的,节点间数据传输是TCP协议。

 

这里用淘宝做比方,淘宝的商家看成节点,每个客户也看成节点,淘宝的商家会在自己的店铺发布物品,那么物品就有对应的类型,每个客户的节点就可以找到我们自己感兴趣的商品类型,然后去找到对应的淘宝商家去沟通交流传递信息。这里ros通信也是如此,每个节点都可以发布和订阅消息就好比淘宝商家要发布产品和去进货一样,那如果别的节点对某种类型的消息感兴趣时,就会在两者之间建立TCP链接,来传递消息,就像你想去买一支笔,要的是橙光的牌子,你就会去找市面上发布的这一类消息,如果找到了,你就可以跟商家私聊传递信息。那么怎么去找的这个过程是ROS底层已经帮你实现了,也不用我们去关心。

 

ROS工具

rostopic

 

显示话题的工具,就像上面说的可以通过这个命令看市面上已经发布的东西。

rosnode

 

显示节点的工具,就像上面说的每个客户和商家是一个个的节点

rqt_graph

 

ros的qt画图工具,可以帮助调试一些数据

rqt_image_view

 

ros的qt图像查看工具,可以可视化查看图片消息

rqt_plot

 

可视化绘制某一数据的波形图

rosmsg

 

ros的消息查看工具,就像上面说的你可以查看商家发布的笔是什么具体的牌子

 

以上的每个命令都可以加 --help来查看具体怎么使用,这里不一一说明了

 

例如:

rostopic --help

 

 

Python代码讲解

#!/usr/bin/env python

 

·   这是告诉编译器我写的是一个python的脚本

import rospy, cv2, cv_bridge, numpy
from sensor_msgs.msg import Image
from geometry_msgs.msg import Twist

 

·   第一行是导入ros的py接口包,opencv包,cv_bridge用于ros和opencv图像转换的包,numpy是开源的数值计算扩展包
·   第二行从传感器消息包中导入Image图片类型,因为我们要处理ROS的摄像头的图片所以需要,
·   第三行ROS用Twist类型的消息控制机器人

 

class Follower:

 

·   定义一个类

def __init__(self):
    self.bridge = cv_bridge.CvBridge()

    self.image_sub = rospy.Subscriber('camera/image_raw', 
                                      Image, self.image_callback)
    self.cmd_vel_pub = rospy.Publisher('/cmd_vel',
                                       Twist, queue_size=1)
    self.twist = Twist()

 

 

·   第一行是类的构造函数,在声明这个类对象的时候会调用
·   第二行是定义类的一个成员,他是cv_bridge类型
·   第三行是定义了一个接收图片消息的类的成员,它订阅了camera/image_raw这个消息,这个消息的类型是Image,如果有人发布了这个消息就会进到self.image_callback这个回调函数中
·   第四行定义了一个速度发布节点的类成员,它发布的话题是/cmd_vel,消息类型是Twist,queue_size=1这个参数是必要的,意义不用管。
·   第五行定义了一个Twist类型的消息的成员用来控制机器人

 

#回调函数,每次有对应的消息发布时就会进来,和单片机的中断差不多
def image_callback(self, msg):
	#将ros的CvBridge()类型的图片消息转换成opencv可以处理的图片类型
    image = self.bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8')
    #这一段用的是HSV色相环来从蓝色和白色混合中过滤出白色,这用单片机是写不来的,调用的是opencv的库函数,这里你们可以用opencv的二值化函数来代替
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    lower_white = numpy.array([ 0,  0, 221])
    upper_white = numpy.array([180, 30, 255])
    mask = cv2.inRange(hsv, lower_white, upper_white)
    #这一段是来计算二值化后图片的重心在哪里,因为二值化后白色是1,所以重心便是白色块的中心
    h, w, d = image.shape
    #这里缩小搜索的范围,因为视角原因一部分图是无效的不用处理
    search_top = 3*h/4
    search_bot = 3*h/4 + 20
    mask[0:search_top, 0:w] = 0
    mask[search_bot:h, 0:w] = 0
    #这里计算出重心在图片上的x,y坐标
    M = cv2.moments(mask)
    if M['m00'] > 0:
      cx = int(M['m10']/M['m00'])
      cy = int(M['m01']/M['m00'])
      #将重心画在图片上
      cv2.circle(image, (cx, cy), 20, (0,0,255), -1)
      #下面是用来PID计算方向偏差的
      err = cx - w/2
      #这是线速度,这里的0.2相当于定速0.2m/s
      self.twist.linear.x = 0.2
      #这是角速度这里的除以50相当于在PID的KP
      self.twist.angular.z = -float(err) / 50
      #这里将速度消息发布出去
      self.cmd_vel_pub.publish(self.twist)
      #下面是调试用的显示处理的图片
    cv2.imshow("window", image)
    cv2.waitKey(3)

 

 

这里太多了就写在代码的注释里

rospy.init_node('follower')
follower = Follower()
rospy.spin()

 

·   第一行定义一个节点
·   第二行调用类的构造函数
·   第三行相当于让这个脚本不退出,可以一直处理回调函数

 

结束

 

下一节:北邮智能车仿真培训(五)—— 数据可视化工具的使用