第一章 ROS空间创建、helloworld的实现、开启多个节点
第二章 话题通信
第三章 服务通信
第四章 参数服务器
第五章 常用指令
第六章 通信机制实操
第七章 ROS通信机制进阶(常用API、Python模块的导入)
第八章 元功能包、节点运行管理launch文件(teleop_twist安装方法)
第九章 重名问题、分布式通信
现在大二,之前大一有幸参加了2021的国赛,很壮烈的拿了个江苏赛区的二等奖。但发现无人机这个题,真的是往堆钱上走了。不上ROS不行,现在来记录一下一个纯小白学习ROS的过程和遇到的问题。防止学弟、学妹们再走我走过的弯路。板子用的是学长给的Jetson Nano(4GB),版本是Ubuntu18.04(已配置好基础ROS所需配置)。
A:应用程序
P:开发编程
I:接口
API之主要目的是提供应用程序与开发人员以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。提供API所定义的功能的软件称作此API的实现。API是一种接口,故而是一种抽象。
#! /usr/bin/env python3
#encoding:utf-8
#1.导包
import rospy
from std_msgs.msg import String #发布的消息类型
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
"""
作用:ROS初始化
参数:
name:设置节点名称
argv:封装节点调用时传递的函数
anonymous:可以为节点名称生成随机后缀。可以解决重名问题
使用:
1.argv使用
可以按照ROS中指定的语法格式,ROS可以解析并加以使用
2.anonymous使用
可以设置为true,节点名称会后缀随机数。可以开启多个节点。
"""
rospy.init_node("sanDai")
#3.实例化 发布者 对象
pub = rospy.Publisher("che",String,queue_size=10) #话题名称,发布类型,容量是10
#4.组织被发布的数据,并编写逻辑发布数据
msg = String() #创建 msg 对象
rate = rospy.Rate(1)
count = 0
rospy.sleep(3 )#防止丢数据,因为创建需要时间。
while not rospy.is_shutdown(): #判断这个节点是否关闭
count +=1
#拼接字符串
msg.data = "hello"+ str(count)
pub.publish(msg)
rospy.loginfo("写出的数据:%s",msg.data)
rate.sleep() #每隔1s执行一次循环
catkin_install_python(PROGRAMS
scripts/demo01_apis_pub_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
roscore
cd myworld/
source ./devel/setup.bash
rosrun plumbing_apis demo01_apis_pub_p.py
rosrun plumbing_apis demo01_apis_pub_p.py _A:=10
rosparam list
/rosdistro
/roslaunch/uris/host_lzl_desktop__34755
/rosversion
/run_id
/sanDai/A
若想查找A的值:rosparam get /sanDai/A
#! /usr/bin/env python3
#encoding:utf-8
#1.导包
import rospy
from std_msgs.msg import String #发布的消息类型
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
"""
作用:ROS初始化
参数:
name:设置节点名称
argv:封装节点调用时传递的函数
anonymous:可以为节点名称生成随机后缀。可以解决重名问题
使用:
1.argv使用
可以按照ROS中指定的语法格式,ROS可以解析并加以使用
2.anonymous使用
可以设置为true,节点名称会后缀随机数。可以开启多个节点。
"""
rospy.init_node("sanDai",anonymous=True)
#3.创建发布者对象
"""
内容:latch
bool值,默认是false
作用:
如果设置为True,可以将发布的最后一条数据保存,且后续
当新的订阅对象连接时,会将该数据发送给订阅者
使用:
latch = True
"""
pub = rospy.Publisher("che",String,queue_size=10,latch=True) #话题名称,发布类型,队列容量是10
#4.编写发布逻辑并发布数据
msg = String() #创建数据
rate = rospy.Rate(1)#指定发布频率
count = 0#设置计数器
rospy.sleep(3 )#防止丢数据,因为创建需要时间。
while not rospy.is_shutdown(): #判断这个节点是否关闭
count +=1
#发布数据
if count<=10:
msg.data = "hello"+ str(count)
pub.publish(msg)
rospy.loginfo("写出的数据:%s",msg.data)
rate.sleep() #每隔1s执行一次循环
catkin_install_python(PROGRAMS
scripts/demo01_apis_pub_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
roscore
cd myworld/
source ./devel/setup.bash
rosrun plumbing_apis demo01_apis_pub_p.py
用命令行创建一个订阅者:rostopic echo /che
#话题名
处理订阅消息时,需要使用到回调函数
def spin():
"""
进入循环处理回调
"""
ROS中时间相关的API是极其常用,比如:获取当前时刻、持续时间的设置、执行频率、休眠、定时器…都与时间相关。
#! /usr/bin/env python3
#encoding:utf-8
import rospy
#rospy中已经导入了时间相关的包
"""
需求1:演示时间相关操作(获取当前时刻+设置指定时刻)
需求2:程序执行中停顿5s
需求3:获取程序开始执行的时刻,且已知持续运行的时间,计算程序结束的时间
需求4:创建定时器,实现类似于rospy.Rate的功能(隔某个时间间隔执行某种操作)
"""
def doMsg(event):
rospy.loginfo("---------------------------------")
rospy.loginfo("调用回调函数的时刻:%.2f",event.current_real.to_sec())#看参数event被调用时刻的秒数
if __name__ == "__main__":
rospy.init_node("hello_time")#初始化节点
# 需求1:演示时间相关操作(获取当前时刻+设置指定时刻)
#获取时刻
right_now = rospy.Time.now()#获取于当前时刻(1.now函数被调用执行的那一刻,2.初始时间1970年01月01日00:00:00),并封装成对象,函数返回值为一个time对象
rospy.loginfo("当前时刻:%.2f",right_now.to_sec())#距离当前时刻多少秒
rospy.loginfo("当前时刻:%.2f",right_now.to_nsec())#距离当前时刻多少纳秒
#设置指定
time1 = rospy.Time(100)#将时间(距离初始时间过去100s)封装成time对象
time2 = rospy.Time(100,312345678)#(secs=0, nsecs=0) 秒和纳秒会集成
rospy.loginfo("指定时刻1:%.2f",time1.to_sec())
rospy.loginfo("指定时刻2:%.2f",time2.to_sec())
#从某个时间值获取时间对象
time3 = rospy.Time.from_sec(200.12)
rospy.loginfo("指定时刻3:%.2f",time3.to_sec())
# 需求2:程序执行中停顿5s
rospy.loginfo("休眠前----------------------------------------------------")
#1.封装一个持续时间对象(5s)
du = rospy.Duration(5,0) #参数(secs=0, nsecs=0)
#2.再将持续时间休眠
#rospy.sleep(du)
rospy.loginfo("休眠后----------------------------------------------------")
# 需求3:获取程序开始执行的时刻,且已知持续运行的时间,计算程序结束的时间
#1.获取一个时刻t1
t1 = rospy.Time.now()
#2.设置一个持续时间du1
du1 = rospy.Duration(5)
#3.结束时刻 t2=t1+du1
t2 = t1 + du1
rospy.loginfo("开始时刻:%.2f",t1.to_sec())
rospy.loginfo("结束时刻:%.2f",t2.to_sec())
# 设置执行频率 每隔5s
# rate = rospy.Rate(0.5)
# while not rospy.is_shutdown():
# rate.sleep() #休眠
# rospy.loginfo("+++++++++++++++")
# 需求4:创建定时器,实现类似于rospy.Rate的功能(隔某个时间间隔执行某种操作)
timer = rospy.Timer(rospy.Duration(2),doMsg)#创建一个定时器对象(period:不同回调函数之间的时间间隔, callback:回调函数, oneshot=False:定时器是不是一次性的, reset=False)
rospy.spin()#有回调函数必有spin
catkin_install_python(PROGRAMS
scripts/demo01_apis_pub_p.py
scripts/demo02_apis_time_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
roscore
cd myworld/
source ./devel/setup.bash
rosrun plumbing_apis demo02_apis_time_p.py
在发布实现时,一般会循环发布消息,循环的判断条件一般由节点状态来控制,C++中可以通过 ros::ok() 来判断节点状态是否正常,而 python 中则通过 rospy.is_shutdown() 来实现判断,导致节点退出的原因主要有如下几种:
另外,日志相关的函数也是极其常用的,在ROS中日志被划分成如下级别:
#! /usr/bin/env python3
#encoding:utf-8
#1.导包
import rospy
from std_msgs.msg import String #发布的消息类型
def cb():
rospy.loginfo("节点正在被关闭---")
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
"""
作用:ROS初始化
参数:
name:设置节点名称
argv:封装节点调用时传递的函数
anonymous:可以为节点名称生成随机后缀。可以解决重名问题
使用:
1.argv使用
可以按照ROS中指定的语法格式,ROS可以解析并加以使用
2.anonymous使用
可以设置为true,节点名称会后缀随机数。可以开启多个节点。
"""
rospy.init_node("sanDai",anonymous=True)
#3.创建发布者对象
"""
内容:latch
bool值,默认是false
作用:
如果设置为True,可以将发布的最后一条数据保存,且后续
当新的订阅对象连接时,会将该数据发送给订阅者
使用:
latch = True
"""
pub = rospy.Publisher("che",String,queue_size=10,latch=True) #话题名称,发布类型,队列容量是10
#4.编写发布逻辑并发布数据
msg = String() #创建数据
rate = rospy.Rate(1)#指定发布频率
count = 0#设置计数器
rospy.sleep(3 )#防止丢数据,因为创建需要时间。
while not rospy.is_shutdown(): #判断这个节点是否关闭 如果节点沒关闭,返回False,如果关闭,返回True
count +=1
#发布数据
if count<=10:
msg.data = "hello"+ str(count)
pub.publish(msg)
rospy.loginfo("写出的数据:%s",msg.data)
else:
#关闭节点
rospy.on_shutdown(cb)#在节点关闭过程中执行一个回调函数
#rospy.spin()循环读取接收到数据,并调用回调函数处理,但是这边是只执行一次,故不用,否则将进入循环
rospy.signal_shutdown("关闭节点")
rate.sleep() #每隔1s执行一次循环
修改cmakelists(162)
catkin_install_python(PROGRAMS
scripts/demo01_apis_pub_p.py
scripts/demo02_apis_time_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
编译运行
新开一个命令行:roscore
再开一个命令行:
cd myworld/
source ./devel/setup.bash
rosrun plumbing_apis demo01_apis_pub_p.py
#! /usr/bin/env python3
import rospy
if __name__ == "__main__":
#演示日志函数
rospy.init_node("hello_log")
rospy.logdebug("DEBUG")
rospy.loginfo("info")
rospy.logwarn("警告")
rospy.logerr("error")
rospy.logfatal("致命的")
修改cmakelists(162)
catkin_install_python(PROGRAMS
scripts/demo01_apis_pub_p.py
scripts/demo02_apis_time_p.py
scripts/demo03_apis_log_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
编译运行
新开一个命令行:roscore
再开一个命令行:
cd myworld/
source ./devel/setup.bash
rosrun plumbing_apis demo03_apis_log_p.py
需求:首先新建一个Python文件A,再创建Python文件UseA,在UseA中导入A并调用A的实现。
实现:
新建两个Python文件,使用 import 实现导入关系;
添加可执行权限、编辑配置文件并执行UseA。
#! /usr/bin/env python3
num = 100
B代码实例讲解如下:
#! /usr/bin/env python3
#encoding:utf-8
"""
需求: 实现基本的话题通信一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
PS: 二者需要设置相同的话题
消息发布方:
循环发布信息:HelloWorld 后缀数字编号
实现流程:
1.导包
2.初始化 ROS 节点:命名(唯一)
3.实例化 发布者 对象
4.组织被发布的数据,并编写逻辑发布数据
"""
#1.导包
from json import tool
import os
import rospy
import sys
from std_msgs.msg import String #发布的消息类型
#设置临时环境变量
#sys.path.insert(0,"/home/lzl/myworld/src/plumbing_pub_sub/scripts")#路径写死,影响了代码到可移植性
#优化,可以动态获取路径
path = os.path.abspath(".")
sys.path.insert(0,path + "/src/plumbing_pub_sub/scripts")
import tools
if __name__ == "__main__":
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node("talker_p")
rospy.loginfo("num = %d",tools.num)
#3.实例化 发布者 对象
pub = rospy.Publisher("chatter",String,queue_size=10) #话题名称,发布类型,容量是10
#4.组织被发布的数据,并编写逻辑发布数据
msg = String() #创建 msg 对象
msg_front = "hello 你好"
count = 0 #计数器
# 设置循环频率 1是1hz
rate = rospy.Rate(1)
rospy.sleep(3 )#防止丢数据,因为创建需要时间。
while not rospy.is_shutdown(): #判断这个节点是否关闭
#拼接字符串
msg.data = msg_front + str(count)
pub.publish(msg)
rate.sleep() #每隔1s执行一次循环
rospy.loginfo("写出的数据:%s",msg.data)
count += 1
catkin_install_python(PROGRAMS
scripts/demo01_pub_p.py
scripts/demo02_sub_p.py
scripts/demo03_pub_person_p.py
scripts/demo04_sub_person_p.py
scripts/tools.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
roscore
cd myworld/
source ./devel/setup.bash
rosrun plumbing_pub_sub demo01_pub_p.py
以上就是今天要讲的内容,本文仅仅简单记录了ROS通信机制进阶(常用API、Python模块的导入),如果有问题请在博客下留言或者咨询邮箱:[email protected]。