ROS 学习笔记 (六)——ros 基础拾遗

1. Parameter Server

参数服务器是和 ros Master 属于同一进程的另一项功能模块。参数服务器通过维护一个字符串到各类数据的键值表,在一个网络可访问的数据库中储存系统的各项配置参数。各个节点可以对参数服务器进行读写。

ros 中的参数是用来进行配置,而不是进行数据通信的。用 ros 参数在节点中交换高频或大容量数据,你会发现性能完全跟不上,此类需求应该用 ros 消息来实现。

参数服务器的维护方式非常的简单灵活,总的来讲有三种方式:
(1)可以在node源文件代码中用 API 访问:

rospy.get_param()
rospy.set_param()
spy.search_param()
rospy.has_param()
rospy.delete_param() 
rospy.get_param_names()

(2)用命令行工具 rosparam与参数服务器交互。

(3)launch文件内读写。实际项目中我们对参数进行设置,尤其是添加参数,一般都不是在程序中,而是在launch文件中。因为launch文件可以方便的修改参数,而写成代码之后,修改参数必须重新编译。 因此我们会在launch文件中将param都定义好。详见:roslaunch 详解

2. 时钟 Time、Duration、Rate

rospy中的关于时钟的操作和roscpp是一致的,都有Time、Duration和Rate三个类。
Time和Duration前者标识的是某个时刻(例如今天22:00),而Duration表示的是时长(例如一周)。但他们具有相同的结构(秒和纳秒)。Rate的功能是指定一个频率,让某些动作按照这个频率来循环执行。

Time 和 Duration 之间可以进行加减运算(Time+Duration),但要注意没有Time+Time的做法。

duration1 = rospy.Duration(3*60) #创建3min时长
time_now1 = rospy.get_rostime() # or rospy.Time.now() 当前时刻的Time对象 返回Time对象
time_now2 = rospy.Time.now() + duration # Time加减Duration返回都是Time

duration2 = time_now2 - time_now1 #从t1到t2的时长,两个Time相减返回Duration类型
duration3 = duration2 - rospy.Duration(2*60) # 两个Duration相减,还是Duration
time_now3 = rospy.get_time() #得到当前时间,返回float 4单位秒
time_4 = rospy.Time(5) #创建5s的时刻

3. 定时器 Timer

rospy.Timer(Duration, callback)   
def my_callback(event):
print 'Timer called at ' + str(event.current_real)

rospy.Timer(rospy.Duration(2), my_callback)  # 第一个参数是时长,第二个参数是回调函数。
#每2s触发一次callback函数
rospy.spin()  # 只有spin才能触发回调函数

回调函数的传入值是TimerEvent类型。

4. Log

ROS为开发者和用户提供了一套日志记录和输出系统,这套系统的实现方式是基于topic,也 就是每个节点都会把一些日志信息发到一个统一的topic上去,这个topic就是 /rosout 。 rosout 本身也是一个node,它专门负责进行日志的记录。我们在启动master的时候,系统就
会附带启动rosout。
包括了五个级别的
DEBUG INFO WARN ERROR FATAL
用法
rospy.loginfo(“info”,vel)

5. TF

wiki.ros/tf
tf/Tutorials
TF的相关数据类型,向量、点、四元数、矩阵都可以表示成类似数组形式,就是它们都可以 用Tuple,List,Numpy Array来表示:
例如:

t = (1.0,1.5,0) #平移,可以用List表示成 t=[1.0,1.5,0],或 numpy.array(1.0,1.5,0)来表示。
q = [1,0,0,0] #四元数
m = numpy.identity(3) #旋转矩阵

TransformStamped.msg的格式规范如下:

扫描二维码关注公众号,回复: 12470927 查看本文章
std_mags/Header header
	uint32 seq
	time stamp
	string frame_id
string child_frame_id
geometry_msgs/Transform transform
	geometry_msgs/Vector3 translation
		float64 x
		float64 y
		float64 z
	geometry_msgs/Quaternion rotation
		float64 x
		float64 y
		flaot64 z
		float64 w

header定义了序号,时间以及frame的名称。
child_frame_id 定义了子link坐标系的 id。
geometry_msgs/Transform 定义了两个frame之间的坐标变换,Vector3三维向量表示平移,Quaternion四元数表示旋转。

TF tree 是由很多的frame之间TF拼接而成。TF树的数据类型为tf2_msgs/TFMessage.msg。ROS Hydro版本以前的 tf 树为 tf/tfMessage.msg ,现已弃用。

tf.transformations 提供了一些基本的数学运算函数。

tf 常用指令:

rosrun tf view_frames  # 生成tf树信息的 frames.pdf 文件,打开pdf可以查看坐标系关系
rosrun rqt_tf_tree rqt_tf_tree  # 直接查看tf 树信息
rosrun tf tf_echo [reference_frame] [target_frame]  # 两坐标系之间的转换关系

在很多api中,存在着target frame,source frame,parent frame,child frame,这些名字的参数。
source、target frame是在进行坐标变换时的概念,source是坐标变换的源坐标系,target是目标坐标系。
parent、child frame是在描述坐标系变换时的概念。也是child坐标系在parent坐标系下的描述。如果把child固结于一个刚体,那么这个变换描述的就是刚体在parent坐标系下的姿态。
从child到parent的坐标变换等于从parent到child的frame transform。

static_transform_publisher

static_transform_publisher工具的功能是发布两个参考系之间的静态坐标变换,两个参考系一般不发生相对位置变化
标定后发布机器人和相机的关系可以用 static_transform_publisher,
角度可以是四元数也可以是 RPY 角。最后一个是周期,周期越小频率越高.

rosrun tf static_transform_publisher x y z qx qy qz qw frame_id child_frame_id  period_in_ms

如果要放到launch中

<launch>
<node pkg="tf" type="static_transform_publisher" name="link1_broadcaster" args="1 0 0 0 0 0 1 link1_parent link1 100" />
</launch>

6. robot_state_publisher

robot_state_publisher uses the URDF specified by the parameter robot_description and the joint positions from the topic joint_states to calculate the forward kinematics of the robot and publish the results via tf.

7. 如何从另一个ROS包中导入python模块

参考:
ROS Import Python Module From Another Package
How to import python modules from different ROS packages
ROS Package中的Python使用规范
仅需两步:

  1. 导出 python module 到 ROS 全局命名空间。
  2. 将可执行文件导出到 ROS 全局命名空间。

例如,现在已经 build 了一个名为 robot_helper 的package:

robot_helper
├── api
│   ├── api.py
│   ├── api2.py
│   ├── my_test_exe
│   └── __init__.py
├── scripts
│   ├── manager.py
├── package.xml
├── CMakeLists.txt
├── setup.py

#And inside the api.py, you have some class
class MY_API():
    def __init__(self):

#And inside the api2.py, you have some class
class MY_API2():
    def __init__(self):

7.1 export the Python module (class)

  1. api文件夹中创建一个空文件 __init__.py.
  2. 创建 setup.py,以帮助ROS系统找到该程序包。代码如下:
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup

setup_args = generate_distutils_setup(
    packages=['my_api'],
	package_dir={
    
    '': 'api'}
)

setup(**setup_args)
  1. 在 CMakeLists.txt 文件的find_package后添加:
find_package(catkin REQUIRED COMPONENTS
  rospy
   ···
)
## Uncomment if the package has a setup.py
catkin_python_setup()

解析:

  1. catkin_python_setup()会使 ros 运行setup.py.
  2. _init__.py将文件夹内容公开给setup.py,如果安全的话,可以将__init__.py放在程序包的根目录中。
  3. packages = ['my_python_stuff'] 告诉ROS查找python包,这与python模块无关,不要搞混。
  4. package_dir = {'':'api'}告诉ROS将(./api)中的所有python文件放入全局 python环境中。

现在就可以在其他 packages 中导入 python 模块了,例如:

from api import MY_API
from api2 import MY_API2

install the executable

你可以在CMakeLists中找到:

## this is used only when you have a script and want to make is an executable
# catkin_install_python(PROGRAMS api/my_test_exe
#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

the my_test_exe is actually the file you created and made +x to it.
This my_test_exe is available inside the CMakeList Project name that is:
rosrun robot_helper my_test_exe

这会将包中所有的script 和 launch文件安装到系统lib文件夹中,以便所有python的脚本都可以访问该模块。