教程 Re:Zero ROS (四)—— 略讲:Service/msg/srv/tf/urdf/launch/param

 **前情提要:上一篇,已经成功建立了工程,并编写了一个节点发布和订阅话题的功能 **

《教程 Re:Zero ROS (三) —— 新建工程、订阅发布话题》
https://blog.csdn.net/Lovely_him/article/details/107751902

教程 Re:Zero ROS (四)

—— Service/msg/srv/tf/urdf/launch/param

1. 编写与测试Service服务

《编写简单的Service和Client (Python)》
http://wiki.ros.org/cn/ROS/Tutorials/WritingServiceClient%28python%29
《测试简单的Service和Client》
http://wiki.ros.org/cn/ROS/Tutorials/ExaminingServiceClient

  • 1)“Service服务”和“Topic话题”的编写差不多,使用区别就在于topic是一直发布与订阅,而service是请求后响应。具体编写可参考wikiros或是中科院的例程
  • 2)“Service服务”一般是用于反馈中。比如,如果我想得知当前小车运动情况,发送一个请求得到小车的响应,返回srv消息。ros一般一个节点一个功能,然后通过话题服务等通讯方式连接起来实现目的。
  • 3)我完成小车仿真的过程中并没有编写过“Service服务”,因为用不到。我的工程体量太小,内容简单,涉及的信息量不大。如果我想反馈信息,只需使用rostopic echo指令或rqt_plotrqt_graph工具查看便可。调用的软件包虽然有提供了“Service服务”,但是我也没怎么用到。

2.了解msg与srv消息

msg
http://wiki.ros.org/msg
srv
http://wiki.ros.org/srv

  • 1)msgsrv属于ros的一种数据类型,可以类比c语言的结构体。srv与msg不同的则是分有响应与请求两部分。
  • 2)ros允许自定义msgsrv,定义完后修改工程的CMakeLists.txt文件便可使用。但是一般没必要自定义,因为ros库本身自带的msgsrv就已经完全够用且有多了。
  • 3)需要关注的是std_msgs/Headermsg消息类型,是关联TF树的重要知识点,在下一点说明。
  • 4)在调试/编写ros工程时,时常需要查看msg或是srv数据类型的定义内容。在终端输入rosmsgrossrv相关指令便可快速查看,这两个指令不需要开启roscre便可以使用。其中用得最多的便是rosmsg/srv show。如果你使用的是”RoboWare“IDE的话,是可以直接查看系统内已安装的msgsrv
  • 在这里插入图片描述

3.编写TF树

tf/Tutorials
http://wiki.ros.org/tf/Tutorials

  • 1)tf的功能就是接收许多坐标的相对消息,然后将其连接起来形成树状图,所以叫tf树。节点可以一直发布消息到tf,也可以一直订阅tf的消息。感觉上tf像是一个节点,因为它能处理接受到的数据并进行转换再发布给订阅的节点。但是在rqt_graph中可知tf属于类似话题类的方框标识大家用多后自然有概念了,这个概念取决你涉及的深度,够自己用,不妨碍理解就好。
  • 2)在小车仿真实验中,有一步要自己编写小车相对于原始起点的坐标,将此坐标发送至tf中,供其他节点调用。以下举个简单的例子,更多例子可参考wikiros或是中科院的例程
#!/usr/bin/env python
#-*-coding:utf-8-*-

# 加载ros的Python基础包
import rospy
# 加载ros的tf2基础包
import tf2_ros
# 加载tf树 的 msg消息
from geometry_msgs.msg import TransformStamped

class main_class:
    # 初始化函数
    def __init__(self):
        # 创建node节点 —— odom坐标计算
        rospy.init_node('odom_calculate', anonymous=True)
        # 创建tf对象,用于发布odom坐标
        self.odom_tf = tf2_ros.TransformBroadcaster()
        # 创建msg数据对象,用于存储数据于发布数据
        self.msg_tf = TransformStamped()
        # 填写当前时间
        self.msg_tf.header.stamp    = rospy.Time.now().to_sec()
        # 填写参考原点
        self.msg_tf.header.frame_id = odom
        # 填写当前坐标
        self.msg_tf.child_frame_id  = base
        # 设置延时频率
        rate = rospy.Rate(1)
        while not rospy.is_shutdown():
            # 发送TF消息
            self.broadcaster()
            # 延时
            rate.sleep()

    # 回调函数
    def broadcaster(self):
        # 填写当前时间
        self.msg_tf.header.stamp = rospy.Time.now().to_sec()
        # 填写位姿(坐标)消息
        self.msg_tf.transform.rotation.x = 0
        self.msg_tf.transform.rotation.y = 1
        self.msg_tf.transform.rotation.z = 2
        self.msg_tf.transform.translation.x = 3
        self.msg_tf.transform.translation.y = 4
        self.msg_tf.transform.translation.z = 5
        # 向tf树发送坐标消息
        self.odom_tf.sendTransform(self.msg_tf)

if __name__ == '__main__':
    try:
        main_class()
    except rospy.ROSInterruptException:
        pass
  • 3)odom代表起始原点base代表小车位置,即小车当前坐标相对于起始原点,处于什么位置。这个坐标关系是需要根据陀螺仪编码器计算得到的,这里碍于篇幅就删掉赋予固定值。
  • 4)在填写msg信息时,经常忘记有哪些项需要填写,可以使用rosmsg show指令查看。
  • 在这里插入图片描述
  • 5)如果忘记某msg信息每个值代表什么意思,可以尝试翻译变量的ID,或是查看wiki手册

geometry_msgs
http://wiki.ros.org/geometry_msgs
geometry_msgs/TransformStamped Message
http://docs.ros.org/api/geometry_msgs/html/msg/TransformStamped.html

4.wiki-ros手册(http://wiki.ros.org)

  • 0)假设你已经查看过很多次wiki了,或许应该差不多发现了wiki的网址命名规律。
  • 1)查看msg包http://wiki.ros.org+/<msg 包名>;进入页面后再找子msg消息数据类型。例如(srv类似):
http://wiki.ros.org/std_msgs
  • 2)查看pack包http://wiki.ros.org+/move_base;进入页面后可查找子插件和节点功能等相关信息。
http://wiki.ros.org/move_base
  • 3)总结,查看ros相关内容http://wiki.ros.org+/<相关内容>;这个内容必须是大类的,索引查找当然应该从大类筛选到小类。
  • 4)有时候在别的ros工程里看到有不懂的内容,不知道属于哪个大类或是有哪些小类,甚至属于什么类型的都不知道。这时就可以百度关键字<不懂的内容>+ros wkik。如果wiki内含有相关的标题内容,就会直接被搜索到。这个功能还是很方便的。(为什么不用wiki内的搜索框?不知道为什么每次搜索都失败,直接跳转加载超时页面)

5.编写URDF

urdf
http://wiki.ros.org/cn/urdf

  • 1)urdf就是将tf的概念再扩展了一步,tf是宏观,urdf是微观(个人目前使用范围内的理解) 。urdf定义了各个部件之间的坐标关系运动限制,如果对象是机械臂,则是不同关节的长度、可摆动角度等消息;如果对象是小车,则是不同轴承的长度,轮胎的转速等消息。
  • 在这里插入图片描述
  • 2)wiki上的图和例程就很经典,简单了解,直白易懂。根据图就能明白,link就是物块本身属性,joint则是定义两个物块之间的属性。

urdf/Tutorials/Create your own urdf file
http://wiki.ros.org/urdf/Tutorials/Create%20your%20own%20urdf%20file

  • 3)如果你没有给自己的设定物体准备模型,urdf还可以定义简易的物体形状与颜色。编写一个关节链接另一个关节的程序并不难,先定个小目标,尝试拼个钢铁侠出来吧。比赛时小车的模型是不允许修改的,我也并没有多研究,有个概念知道是这么回事就好了,之后要用到再回来查。
  • 4)urdf使用的是一种名为 xacro 的宏语言,优点是简单缺点是简单…… 全是标签,只要缩进没有问题,查wiki手册知标签的意思,就是往里面填属性了。还有一点需要注意点是,urdf文件内不可以有中文,注释也不可以。不然运行就会报错。早期看程序学习时把我坑惨了。
  • Ubuntu 20.04版本的noetic下,又许多指令和旧版的不一样,我在查找学习博客时就发现很多操作在noetic不能直接实现。

《ros初探xacro/xacro模型文件》
https://blog.csdn.net/qq_43786066/article/details/104420700
Using Xacro to Clean Up a URDF File
https://wiki.ros.org/urdf/Tutorials/Using%20Xacro%20to%20Clean%20Up%20a%20URDF%20File

6.配置文件CMake/package & 启动文件launch

roslaunch
http://wiki.ros.org/roslaunch/

  • 1)之前编写的topic和service的python文件都是单个执行的,launch则是将调用各个topic和service的可执行文件,且不限于这两,ros几乎所有需要加载的东西都是由launch启动加载的。所以可以将launch理解为启动文件,其基础简单的作用便是启动roscore然后执行程序。
  • 2)要想launch能顺利正常的启动还需要保证工程文件中CMakeLists.txtpackage.xml文件都配置好。因为launch会自动启动roscore,所以启动前还需要保证工程已经编译通过,环境变量已经刷新等操作。(注意,CMakeLists.txtpackage.xml不能存在中文
  • 3)如果添加了msg或是srv,则需要修改:package.xmlCMakeLists.txt
find_package(catkin REQUIRED COMPONENTS std_msgs message_generation)

解决ROS在编译中出现Unknown Cmake command“generate_messages”的问题
https://blog.csdn.net/csdnpen/article/details/107317421

  • 3)如果添加了自定义的msg和srv,则需要修改:package.xmlCMakeLists.txt
 <build_depend>message_generation</build_depend>
 <exec_depend>message_runtime</exec_depend>
generate_messages(DEPENDENCIES std_msgs <自定义msg的名字> <自定义srv文件的名字>)
add_message_files(FILES <自定义msg文件的名字>)
add_service_files(FILES <自定义srv文件的名字>)

创建ROS消息和ROS服务
http://wiki.ros.org/cn/ROS/Tutorials/CreatingMsgAndSrv
Creating a workspace for catkin
http://wiki.ros.org/catkin/Tutorials/create_a_workspace

  • 4)如果添加了.py文件,则需要修改:CMakeLists.txt
catkin_install_python(
	PROGRAMS 
	<py文件名含路径>
  	DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
  • 4)如果.py导入的其他软件包,则需要修改:package.xmlCMakeLists.txt
 <build_depend><添加的软件包></build_depend>
 <exec_depend><添加的软件包></exec_depend>
find_package(catkin REQUIRED COMPONENTS <添加的软件包>)
  • 5)这里面是重点,配置了CATKIN_DEPENDS,则package.xml内也要添加对应的内容。不然就会报错
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES himpack_name
  CATKIN_DEPENDS roscpp rospy std_msgs <包名1>
#  DEPENDS system_lib
)
 <build_depend><包名1></build_depend>
 <exec_depend><包名1></exec_depend>
  • 5)一切准备无误后,就开始编写launch文件,尝试启动之前写好的topic话题.py文件。启动之前确定package.xmlCMakeLists.txt无误,确定.py文件给予了执行权限,确定launch内pkgtype填写无误。任何一步出错都有导致编译失败。(launch的编写格式、标签请上wiki查,具有绝对准确性与详细性)
<?xml version="1.0"?>
<launch>
    <node pkg="himpack_name" type="output_control.py" name="motor_control"/>
</launch>
  • 6)编写完成后,catkin_mate编译,然后source ~/.bashrc刷新环境变量,最后roslaunch执行launch文件,然后启动rqt_graph工具查看节点。
catkin_mate
source ~/.bashrc
roslaunch output_control.launch
  • 在这里插入图片描述
  • 7)可以看到,启动launch文件时,ros也会被启动,相对于执行力一次roscore。同时节点图内查看的节点名是没有后缀的。不同于单个文件启动。
  • 8)大多数时候launch是分功能块写的,部分节点归为一类,一起启动会相对于启动某种功能。这样便会用launch打包在一起,然后被其他launch文件引用/调用。同时,如果某些launch被打包后不能单独启动,只能被其他launch调用的话,会在.launch后缀名后加上.xml,一起组成.launch.xml。这样便只能用于被调用了,使用起来有点像载入参数。

7.参数param/yaml

rosparam
http://wiki.ros.org/rosparam

  • 1)大多数时候,为了增加程序的适用性移植性,都不会把程序的参数“写死”。比如之前写的topic发送程序,我们已经把"发布的topic话题名"和“订阅的topic话题名”,我们日后调用该程序时,若对应的topic名不一致,我们还需要打开程序的源代码修改。这样就极其不方便了。
  • 2)如果需要把.py的变量转为可变参数,只需要作如下修改。rospy.get_param内的第一个参数即为参数名,第二个参数为默认参数值,可有可无。这个函数就是把该参数的值返回给node_name变量,如果没有默认值也没有设置值的话就会报错。
# 创建node节点 —— 电机控制
node_name = rospy.get_param('~node_name',"motor_control")
rospy.init_node(node_name, anonymous=True)
  • 3).py内修改好后,在launch内就可以设置参数了。name为参数名,value为参数值,type为参数类型,可为实数或是字符。字符为"string",实数为"double"需要注意多就是,如果参数是实数变量,则.py内的默认参数不需要加双引号,但是launch内还是要加
<?xml version="1.0"?>
<launch>
    <node pkg="himpack_name" type="output_control.py" name="motor_control">
        <param name="node_name" type="string" value="motor_control"/>
    </node>
</launch>
# .py内
max_angle = rospy.get_param('~max_angle',0.32)
# .launch内
<param name="max_angle" type="double" value="0.32"/>
  • 4)除了可以在.py.cpp内设置参数,launch内也可以设置参数。注意格式$(arg node_name)。参数default是指默认值,该launch文件被其他launch调用时如果没设置这个参数,这个参数必须有个默认值。同时,<param …… value……>一定value不能为default,切记。
<?xml version="1.0"?>
<launch>
    <arg name="node_name" default="motor_control"/>
    <node pkg="himpack_name" type="output_control.py" name="motor_control">
        <param name="node_name" type="string" value="$(arg node_name)"/>
    </node>
</launch>
  • 5)同时,如果参数实在过多,在launch文件内排布的不美观的话,还可以另外再打包为参数文件.param这种情况是确定好了部分参数的值,不需要再被外层调用修改时使用。 说白了就是,一般在调用ros官方库时才用,因为官方软件包已经是成品,有完善的功能,但是需要配置很多参数。所以就有了,param参数打包文件。编写也很简单,只需要"参数名:参数值"即可。
i: 1.0
d: 1.0
  • 6)如果参数是msg或是srv类型的,需要配置多层参数,则需要按缩进分层

8. 总结

  • 1)现在已经把ros工程的大致结构介绍完了,掌握这些知识,对于搭建仿真小车来说已经绰绰有余了。
  • 2)下一篇教程将开始一步步创建仿真小车的ros工程。同时简单介绍map_server/move_base/amcl/slam等与小车导航、定位有关的软件包。
  • 3)待补。 感谢你能看到这里,这是一个完整的系列,如果还没看前后篇,开去看吧。

《教程 Re:Zero ROS (五)—— 导入模型,关节控制器 》
https://blog.csdn.net/Lovely_him/article/details/107806662

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值