前言
- 已安装ros,.bashrc配置完成
- 已创建catkin工作空间
- 已安装rospy
生成一个新的catkin包
- 链接:
http://wiki.ros.org/ROS/Tutorials/CreatingPackage
- 打开一个terminal:
$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
$ cd ..
$ catkin_make
上述指令完成后,~/catkin_ws/src/beginner_tutorials/
下会自动生成CMakeLists.txt
和package.xml
对于非新打开的terminal,需要:source ~/.bashrc
自定义话题消息
- 定义msg消息
$ cd ~/catkin_ws/src/beginner_tutorials/
$ mkdir msg
$ cd msg
$ touch Num.msg
$ rosed beginner_tutorials Num.msg (也可使用vim编辑:vim Num.msg)
在打开的窗口中,输入数据格式,例如:int64 num
。保存退出
- 在package.xml中添加功能包依赖
$ rosed beginner_tutorials package.xml
- 找到
<build_xxx>
的位置(一般在文档末尾)添加以下两行:
<build_export_depend>std_msgs</build_export_depend>
<build_depend>message_generation</build_depend>
- 查看文件添加结果:
$ tail -n +58 package.xml | head -n 2 (+58是行数,可根据实际情况调整)
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
添加完成后如图:
3. 在CMakeLists.txt中添加编译选项
- 增加对message_generation的依赖
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation # 在此处添加新的依赖
)
- 增加消息文件
找到add_message_files
的位置:首次打开CMakeLists.txt,add_message_files
是注释的状态,解开注释即可。
## Generate messages in the 'msg' folder
add_message_files(
FILES
Num.msg # 在此处添加新定义的消息
# Message1.msg
# Message2.msg
)
- 增加消息生成包
找到catkin_package
的位置:首次打开CMakeLists.txt,catkin_package
是注释的状态,解开注释即可。
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES beginner_tutorials
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
- 添加msgs的软件包依赖
找到generate_messages
的位置:首次打开CMakeLists.txt,generate_messages
是注释的状态,解开注释即可。
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
)
- 编译
$ cd ~/catkin_ws
$ catkin_make
- 检查服务
$ rosmsg show beginner_tutorials/Num
int64 num
rospy话题通信
创建scripts:
$ roscd beginner_tutorials/
$ mkdir scripts
$ cd scripts/
$ touch publisher.py # 创建发布者
$ touch listener.py # 创建订阅者
python文件中代码的编写,可以使用IDE,也可以使用rosed、vim等编辑器
创建发布者:publisher.py
#!/usr/bin/python3 //指定python路径,必需
# coding=utf-8
import rospy
from beginner_tutorials.msg import Num
def talker():
pub = rospy.Publisher('chatter', Num, queue_size = 10)
rate = rospy.Rate(10)
while not rospy.is_shutdown():
mynum = int(rospy.get_time())
msg = Num()
msg.num = mynum
rospy.loginfo(mynum)
pub.publish(msg)
rate.sleep()
if __name__ == '__main__':
rospy.init_node('msg_pub', anonymous=True)
try:
talker()
except rospy.ROSInterruptException:
pass
- init_node注意事项
在主线程/主进程中声明 - anonymous传参:
1)True
:node名称后会跟随时间戳,用以避免node重名
2)False
:node唯一,ros意外中断时,该节点需等待系统释放
创建订阅者:listener.py
#!/usr/bin/python3 //指定python路径,必需
#coding=utf-8
import rospy
from beginner_tutorials.msg import Num
def callback(data):
rospy.loginfo(rospy.get_caller_id() + ' I heard %d', data.num)
def listener():
rospy.Subscriber('chatter', Num, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
# In ROS, nodes are uniquely named. If two nodes with the same
# name are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'listener' node so that multiple listeners can
# run simultaneously.
rospy.init_node('msg_sub', anonymous=True)
listener()
运行
- 打开一个terminal,启动ros master
$ roscore
- 新打开一个terminal,启动发布者
$ rosrun beginner_tutorials publisher.py
[INFO] [1656042406.758045]: 1656042406
[INFO] [1656042406.857847]: 1656042406
[INFO] [1656042406.957995]: 1656042406
[INFO] [1656042407.057947]: 1656042407
- 新打开一个terminal,启动订阅者
$ rosrun beginner_tutorials listener.py
[INFO] [1656042406.762065]: /msg_sub I heard 1656042406
[INFO] [1656042406.858974]: /msg_sub I heard 1656042406
[INFO] [1656042406.962152]: /msg_sub I heard 1656042406
[INFO] [1656042407.060434]: /msg_sub I heard 1656042407
查看已开启的node
$ rosnode list
/msg_pub
/msg_sub
/rosout
创建Launch
在beginner_tutorials目录下,创建launch目录:
$ cd ~/catkin_ws/src/beginner_tutorials
$ mkdir launch
$ cd launch
$ vim msg_pub_sub.launch
输入:
<launch>
<node name="publisher" pkg="beginner_tutorials" type="publisher.py" />
<node name="listener" pkg="beginner_tutorials" type="listener.py" />
</launch>
保存退出
附:<node>
参数简要说明:
参考链接:https://www.jianshu.com/p/e55850b87c7d
<launch>
<node
pkg=""
type=""
name=""
respawn="true"
required="true"
launch-prefix="xterm -e"
output="screen"
ns="some_namespace"
/>
</launch>
pkg
:node所在的 package 名称type
: package 中的可执行文件,如果是 python 或者 Julia 编写的,就可能是.py
或者.jl
文件,如果是 c++ 编写的,就是源文件编译之后的可执行文件的名字。name
:node启动之后的名字, 每一个节点都要有自己独一无二的名字。respawn
:若该node关闭,是否自动重新启动required
:若该node关闭,是否关闭其他所有nodelaunch-prefix
: 是否新开一个窗口执行。例如,需要通过窗口进行机器人移动控制的时候,应该为控制 node 新开一个窗口;或者当 node 有些信息输出,不希望与其他 node 信息混杂在一起的时候。output
:默认情况下,launch 启动 node 的信息会存入下面的 log 文件中
/.ros/log/{$run_id}/node_name-number.log
可以通过此处参数设置,令信息显示在屏幕上
8. ns
:将 node 归入不同的 namespace,即在 node name 前边加 ns
指定的前缀。为了实现这类操作,在 node 源文件中定义 node name 和 topic name 时要采用 relative name, 即不加slash符号 /
.
运行launch
- 打开一个terminal,启动ros master(若已启动roscore,该步骤省略)
$ roscore
- 新打开一个terminal,启动launch
指令为:roslaunch {$pkg_name} {$launchfile_name}.launch
$ roslaunch beginner_tutorials msg_pub_sub.launch
注:roslaunch 不能保证 node 的启动顺序,因此 launch 文件中所有的 node 都应该对启动顺序有鲁棒性。
- 日志查看
- 使用指令:
$ rqt_console
- 查看log文件
查看当前roscore运行的run_id:
$ rosparam get /run_id
e04b3b26-f386-11ec-b422-2cf05d2c73c1
# 注:这个数字是根据本机mac地址、运行时间等信息生成的唯一UUID
查看当前run_id的log:
$ cd ~/.ros/log/e04b3b26-f386-11ec-b422-2cf05d2c73c1
$ tail -f node_name-number.log 或者 vim node_name-number.log
参考链接:https://blog.csdn.net/betterzl/article/details/105835403