ROS Best Practices

敲代码前,调研现有 ROS 软件包:http://www.ros.org/browse/list.php

代码风格参考 ROS C++ Style Guide 和 Google style-guide

单位和坐标参考 Standard Units of Measure and Coordinate Conventions

坐标系规范

测试参考 http://wiki.ros.org/UnitTesting

ROS软件包组织

  • 一个包不要太大,考虑分解为多个包
  • 避免循环依赖
  • 把具有相同依赖的程序考虑融合为一个包
  • 把私有程序合并为一个包
  • 有一个只包含消息、服务和动作的包,例如 ros/common_msgs
  • 多个包组成 stack

ROS软件包命名参考 Naming ROS ResourcesREP-144: ROS Package Naming

  • 足够明确,例如 planner wavefront_planner

包、节点、话题、服务、TF 等命名规范 参考 ROS Best Practices: Lorenz Mösenlechner, Technische Universität München, July 2012

  • 包名称用小写字母,勿用 - 而用 _
  • 用下划线 _ 分割
  • 消息、服务和动作采用 camelCase 命名方式,例如 geometry_msgs/PoseStamped
  • 动作名称中勿含 action

Messages, services and actions are named in camel case: geometry_msgs/PoseStamped? Names in a message/service/action definition are all lower case with underscores as separator: geometry_msgs/Pose end_effector?

自定义消息和服务

  • 尽可能用 ROS 提供的
  • 不要为每个 topic/service/action 单独定义 msg/srv/action
  • 参考
    • std_msgs
      • Bool
      • Byte
      • ByteMultiArray
      • Char
      • ColorRGBA
      • Duration
      • Empty
      • Float32
      • Float32MultiArray
      • Float64
      • Float64MultiArray
      • Header
      • Int16
      • Int16MultiArray
      • Int32
      • Int32MultiArray
      • Int64
      • Int64MultiArray
      • Int8
      • Int8MultiArray
      • MultiArrayDimension
      • MultiArrayLayout
      • String
      • Time
      • UInt16
      • UInt16MultiArray
      • UInt32
      • UInt32MultiArray
      • UInt64
      • UInt64MultiArray
      • UInt8
      • UInt8MultiArray
    • common_msgs
      • actionlib_msgs
      • diagnostic_msgs
      • geometry_msgs
      • nav_msgs
        • 消息msg
          • GridCells
          • MapMetaData
          • OccupancyGrid
          • Odometry
          • Path
        • 服务srv
          • GetMap
          • GetPlan
          • SetMap
        • 动作action
          • GetMap
      • sensor_msgs
      • shape_msgs
      • stereo_msgs
      • trajectory_msgs
      • visualization_msgs

文档规范

  • 每个包有 README.md/Wiki
    • 说明节点的功能
    • 说明提供和依赖的话题、服务和动作
    • 说明参数及其默认值
  • 提供 launch 文件
  • 提供 rosinstall 文件?
  • 模版 README.md

ROS包文件结构: 针对package_name(不含msg/srv/action)

package_name
|— config
 |— robots
  |— my_robot.yaml
 |— sensors
  |— velodyne.yaml
  |— hokuyo_laser_range.yaml
|— include/package_name
 |— Class1.hpp
 |— Class2.hpp
|— launch
 |— node1_name.launch
 |— node2_name.launch
|— rviz
 |— package_name.rviz
|— scripts
 |— my_script.py
|— src
 |— Class1.cpp
 |— Class2.cpp
 |— node1_name_node.cpp
 |— node2_name_node.cpp
|— test
 |— Class1Test.cpp
 |— Class2Test.cpp
 |— test_package_name.cpp
|— CMakeLists.txt
|— package.xml

针对 package_name_msgs

package_name_msgs
|— action
 |— MyAction.action
|— msg
 |— MyMessage.msg
|— srv
 |— MyService.srv
|— CMakeLists.txt
|— package.xml

参考 Packages: Common_Files_and_Directories

Topics vs Services vs Actionlib vs Parameters vs Dynamic Parameters

  • 参考 ROS Patterns - Communication
  • 话题发布连续的数据流,如传感器数据
  • 服务完成花费时间较短的计算
  • 动作完成花费时间较长的流程,比如抓取、导航……
  • 参数保存运行时不变的数值
  • 动态参数保存运行时可变的数值

发布空间/几何数据(TF),参考 http://wiki.ros.org/ROS/Patterns/Communication

节点具柄 (Node Handles)

  • 公有节点具柄: nh_ = ros::NodeHandle();
  • 私有节点具柄: nh_private_ = ros::NodeHandle(“~”);
  • 命名节点具柄: nh_aslam_ = ros::NodeHandle(“aslam”);
  • 全局节点具柄: nh_global_ = ros::NodeHandle(“/“);
    • !!!不要使用全局命名

话题名称应简单清晰,参考:

参数名称采用层级结构,例如

camera/left/name: left_camera
camera/left/exposure: 1
camera/right/name: right_camera
camera/right/exposure: 1.1

而不是camera_left_name: left_camera。YAML文件内容如下:

camera:
  left:
    name: left_camera
    exposure: 1
  right:
    name: right_camera
    exposure: 1.1

参数组织方法

<launch>
 <node pkg="my_package" type="my_node" name="my_name" output="screen">
  <param name="my_parameter" value="10" />
 </node>
</launch>

导入YAML文件:

<launch>
 <node pkg="my_package" type="my_node" name="my_name" output="screen">
  <rosparam command="load" file="$(find my_package)/config/robots/starleth.yaml" />
  <rosparam command="load" file="$(find my_package)/config/sensors/default.yaml" />
 </node>
</launch>

如何使用第三方库

  • 尽可能使用 Debian 包
  • rosdep 解决依赖关系

launch文件

<include file=“$(find package_name)/launch/another.launch”/>

打印消息和日志

  • 使用ROS_INFO, ROS_DEBUG
  • 使用合适的日志等级: Debug, info, warn, error, fatal.

检查订阅者数量节省计算资源

if (publisher.getNumSubscribers() < 1) return;

Bag数据包

rosbag record <topic> <topic> …
rosbag play foo.bag
rosbag play --clock foo.bag
rosparam set use_sim_time true

时间使用ROS提供的接口

  • ros::Time
  • ros::Duration
  • ros::Rate

消息格式转换 Eigen

Eigen::Vector3d my_super_cool_vector(1.0, 2.0, 3.0);
geometry_msgs::Point point_msg;
tf::pointEigenToMsg(my_super_cool_vector, point_msg);
super_cool_publisher_.publish(point_msg);
Eigen::Vector3d my_super_cool_vector(1.0, 2.0, 3.0);
tf::Vector3 my_super_cool_vector_tf;
tf::vectorEigenToTF(my_super_cool_vector, my_super_cool_vector_tf);
tf::Transform transform;
transform.setOrigin(my_super_cool_vector_tf);
transform_broadcaster_.sendTransform(
 tf::StampedTransform(transform, ros::Time::now(), “map”, “world”));

catkin 编译参数

catkin config [list of your flags]

catkin config -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_ARG1=-std=c++11