ROS学习笔记5:常用API和模块导入

前言

本人ROS小白,利用寒假时间学习ROS,在此以笔记的方式记录自己每天的学习过程。争取写满15篇(5/15)。
环境:Ubuntu20.04、ROS1:noetic
环境配置:严格按照下方学习链接的教程配置,基本一次成功。
学习链接【Autolabor初级教程】ROS机器人入门
对应链接文档ROS机器人入门课程《ROS理论与实践》
笔记绝大部分代码使用Python语言编写。
本期关键词:初始化,话题服务,时间,Python模块导入

常用API

初始化API

  1. 初始化API我们在编写节点时都会用到:
rospy.init_node("turtle_cir")

大多情况下只使用了“name"这个参数,接下来介绍另外两个常用的参数,先看看init_node的定义:

def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0):

具体的定义内容很长,这里就不列举了。
2. 常用的大概就是前三个:name, argv=None, anonymous=False
3. name就是节点名称,节点名称中不能包含’/'字符。
4. argv使用时不用在代码里单独列写,只需要在执行rosrun指令时添加参数即可:(注意添加参数的格式,_:=,执行指令后可通过rosparam listrosparam get 参数名来查看)

rosrun helloworld demo_pub.py _A:=100
  1. anonymous使用时需要令anonymous=True,此时程序会为节点名称后缀随机编号,能保证节点名称的唯一性,在多个终端同时执行同一指令时不会报错。
rospy.init_node("talker_pub",anonymous=True)

# 在两个终端同时运行该py文件,再通过rosnode list查看,结果如下:
/rosout
/talker_pub_219549_1706194705863
/talker_pub_219598_1706194710878

话题服务API

  1. rospy.Publisherlatch参数:默认是False,设置成True后,发布方发送的最后一条消息会被保存,当新的订阅方订阅该话题时,将最后一条消息发送给订阅方。可以用在发送雷达地图数据上。建好图后,地图数据都是一样的,循环发送没有意义。可以令latch=True,如果有新的订阅者则发送。
  2. latch是我目前遇到比较常见的参数,其他函数可以在VScode中“转到定义”查看。

回旋函数API

Python中只有rospy.spin(),作用是循环处理回调函数

时间API

1.获取时刻
  • rospy.Time.now()是获取当前时间
  • rospy.Time(时间)是设置时间,基准是1970年1月1日 00:00:00
#! usr/bin/env python

import rospy

if __name__=="__main__":
    rospy.init_node("time_test")
    right_now=rospy.Time.now()
    rospy.loginfo("Righe now time: %.2f",right_now.to_sec())# s
    rospy.loginfo("Righe now time: %.2f",right_now.to_nsec())# ns
    some_time1 = rospy.Time(1234.567891011)
    some_time2 = rospy.Time(1234,567)# the former is s, the latter is ns
    rospy.loginfo("设置时刻1:%.2f",some_time1.to_sec())
    rospy.loginfo("设置时刻2:%.2f",some_time2.to_sec())
2.持续时间
  • rospy.Duration()
  • rospy.sleep()
#! usr/bin/env python

import rospy

if __name__=="__main__":
    rospy.init_node("time_test")   
    # duration
    # 持续时间相关API
    rospy.loginfo("持续时间测试开始.....")
    du = rospy.Duration(2)
    rospy.sleep(du) #休眠函数
    rospy.loginfo("持续时间测试结束.....")
3.时间运算

持续时间可以相加减,时刻不可以相加减

#! usr/bin/env python

import rospy

if __name__=="__main__":
    rospy.init_node("time_test")

    # duration add
    rospy.loginfo("持续时间测试开始.....")
    du1 = rospy.Duration(1)
    du2 = rospy.Duration(2)
    du3=du1+du2
    rospy.sleep(du3)
    rospy.loginfo("持续时间测试结束.....")

如果想尝试一下时刻相加的话,错误代码奉上:

#! usr/bin/env python

import rospy

if __name__=="__main__":
    rospy.init_node("time_test")
    right_now=rospy.Time.now()

    right_now=right_now+right_now
    rospy.loginfo("double right now:%.2f",right_now.to_nsec())

报错如下:

TypeError: unsupported operand type(s) for +: 'Time' and 'Time'
4.定时器

测试代码如下:

#! usr/bin/env python

import rospy

def doTime(event):
    rospy.loginfo("+++++++++++++++++++++++")
    rospy.loginfo("right now time: %s",str(event.current_real))

if __name__=="__main__":
    rospy.init_node("time_test")
    
    rospy.Timer(rospy.Duration(1),doTime)
    rospy.spin()

其中rospy.Duration(1)表示的是回调函数doTime执行的时间间隔(按周期执行),可以类比一下STM32中定时器的捕获中断。

5.节点状态

测试代码如下:

#! /usr/bin/env python

import rospy
from std_msgs.msg import String

def doShut():
    rospy.loginfo("shutdown......")

if __name__ == "__main__":
    rospy.init_node("talker_pub",anonymous=True)
    pub = rospy.Publisher("chat",String,queue_size=10,latch=True)
    msg=String()
    cont="hello! How are you? "
    count=0
    rate=rospy.Rate(1)
    # rospy.sleep(3.0)
     
    while not rospy.is_shutdown():
        if count<=5:
            msg.data=cont+str(count)
            pub.publish(msg)
            rate.sleep()
            rospy.loginfo("output data is: %s",msg.data)
            count+=1
        else:
            rospy.on_shutdown(doShut)
            rospy.signal_shutdown("shutdown")
  1. rospy.is_shutdown()是我们很常用的,如果节点关闭,则会返回True
  2. rospy.on_shutdown()的输入是一个回调函数,当节点被关闭时会调用这个回调函数。
  3. rospy.signal_shutdown()的作用是关闭节点,输入参数是节点关闭的原因,这个原因不会输出在终端。
  4. 小tips:rospy.on_shutdown()rospy.signal_shutdown()最好搭配使用,如上代码所示,不然只使用rospy.on_shutdown()的话,我们在终端Ctrl+C终止进程时,终端会一直执行(输出)回调函数的内容,无法正常关闭。
日志函数
# 参考赵虚左老师的文档:
rospy.logdebug("hello,debug")  #不会输出
rospy.loginfo("hello,info")  #默认白色字体
rospy.logwarn("hello,warn")  #默认黄色字体
rospy.logerr("hello,error")  #默认红色字体
rospy.logfatal("hello,fatal") #默认红色字体

模块导入

  1. 模块导入时,路径是一个特别需要注意的点,我们先看以下代码:
#! /usr/bin/env python
num = 1000
# 这个是demo_tools.py的内容,是即将被导入的模块
#! /usr/bin/env python

import rospy 
import demo_tools # 导入自定义模块

if __name__ == "__main__":

    rospy.init_node("hello_num")
    rospy.loginfo("ready......")
    rospy.loginfo("output:%d",demo_tools.num) 
  1. 在工作空间下用rosrun运行,输出报错:
AttributeError: module 'demo_tools' has no attribute 'num'

大致意思就是说模块’demo_tools’没有属性’num’(也有可能是ModuleNotFoundError的报错)。这个报错的主要原因是rosrun执行时,不能找到demo_tools模块所在路径,因为rosrun运行时的默认查找路径是不包含工作空间下的scripts的。
3. 在XXXX_ws/src/helloworld(功能包)/scripts目录下执行:

python3 hello.py(文件名)

会发现并没有报错,num的值也能正确输出。据此也可以得出造成rosrun报错的原因是路径。
4. 解决方法:

#! /usr/bin/env python

import rospy 
import os
import sys

# 先动态获取工作空间路径(因为rosrun是在工作空间目录下执行的)
path=os.path.abspath(".")
# 将获取到的路径与固定路径(一般来说是固定的)相加,得到自定义模块所在位置
sys.path.insert(0,path+"/src/helloworld/scripts")

import demo_tools

if __name__ == "__main__":

    rospy.init_node("hello_num")  
    rospy.loginfo("ready......")
    rospy.loginfo("output:%d",demo_tools.num)  

往期内容

  1. ROS学习笔记1:基础知识
  2. ROS学习笔记2:话题通信
  3. ROS学习笔记3:服务通信与参数服务器
  4. ROS常用命令记录
  5. ROS学习笔记4:通信机制实操
  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值