rviz 源码详细分析
工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros2/rviz
版本:11.2.26(Humble),子包 8 个,许可证 BSD 3-Clause(Willow Garage / OSRF)。
rviz 仓库实现 ROS 2 的 3D 可视化工具 rviz2:Qt 图形界面 + Ogre3D 渲染引擎 + pluginlib 插件体系(Display / Tool / Panel / ViewController / FrameTransformer)。用户通过订阅 ROS 话题、查询坐标变换,在 3D 场景中绘制激光、点云、机器人模型、TF 等。
范围说明:本仓库为 rviz2 核心;ROS 1 版 rviz 在
ros-visualization/rviz。Humble 尚未移植 Stereo 等少数 ROS 1 功能(见 README)。
1. 总体认识
1.1 核心职责
| 能力 | 实现位置 | 说明 |
|---|---|---|
| 可执行入口 | rviz2 |
main.cpp → VisualizerApp → Qt 事件循环 |
| 应用框架 | rviz_common |
管理器、Display/Tool/Panel、属性树、配置 |
| 3D 渲染 | rviz_rendering |
Ogre 封装、点云/网格/形状等可视对象 |
| 内置插件 | rviz_default_plugins |
LaserScan、TF、RobotModel、Marker 等 |
| Ogre 依赖 | rviz_ogre_vendor |
打包 Ogre3D + CMake 模块 |
| Assimp 依赖 | rviz_assimp_vendor |
网格/DAE/STL 加载 |
| 渲染测试 | rviz_rendering_tests |
mesh loader 等单元测试 |
| 视觉回归测试 | rviz_visual_testing_framework |
截图对比式 GUI 测试 |
1.2 在 ROS 2 栈中的位置
| 对比项 | ROS 1 rviz | ROS 2 rviz(本仓库) |
|---|---|---|
| 节点 API | roscpp | rclcpp + 独立 RosClientAbstraction |
| TF | 硬编码 tf | 可插拔 FrameTransformer(默认 tf2) |
| QoS | 有限 | QosProfileProperty per Display |
| 时间 | /clock 支持 |
rclcpp::Clock + time jump 处理 |
| 插件基类包 | librviz |
rviz_common |
1.3 主循环(一帧)
VisualizationManager::onUpdate()(定时器驱动,约 30Hz):
1 | 1. executor_->spin_some(10ms) // 处理 ROS 回调 |
2. 仓库结构
1 | rviz/ |
2.1 子包一览
| 包名 | 规模 | 职责 |
|---|---|---|
rviz2 |
极小 | 可执行文件、文档 |
rviz_common |
大 | Qt UI 框架、管理器、插件 API |
rviz_rendering |
中 | Ogre 场景对象、RenderSystem 单例 |
rviz_default_plugins |
最大 | 默认 Display/Tool/Panel/View/Transformer |
rviz_ogre_vendor |
vendor | Ogre3D 源码/预编译 + FindOGRE |
rviz_assimp_vendor |
vendor | Assimp 模型加载 |
rviz_rendering_tests |
测试 | rendering 层测试 |
rviz_visual_testing_framework |
测试 | 端到端视觉测试框架 |
3. rviz2:程序入口
rviz2/src/main.cpp 流程:
rclcpp::remove_ros_arguments()— 剥离 ROS 参数,剩余给QApplicationrviz_common::set_logging_handlers()— Qt/Ogre 日志转发到RCLCPP_*- 构造
VisualizerApp(std::make_unique<RosClientAbstraction>()) vapp.init(argc, argv)→ 创建VisualizationFrame、初始化 ROSqapp.exec()— Qt 主循环
VisualizerApp(visualizer_app.cpp)负责:
- 解析命令行(
-d加载.rviz配置等) - 创建
VisualizationFrame - 协调 ROS shutdown 与 Qt 退出
4. rviz_common:应用框架
4.1 核心类关系
1 | VisualizationFrame (QMainWindow) |
DisplayContext(display_context.hpp)是 Display/Tool 插件看到的 窄接口:提供 getSceneManager()、getFrameManager()、getRosNodeAbstraction()、getTransformationManager() 等,便于单元测试 mock。
4.2 Display 插件体系
基类层次:
1 | properties::BoolProperty |
| 基类 | 适用场景 |
|---|---|
Display |
无 ROS 订阅(Grid、Axes) |
RosTopicDisplay<T> |
普通话题订阅 + processMessage() |
MessageFilterDisplay<T> |
需要 TF 同步 的消息(LaserScan、PointCloud2) |
Display 生命周期:
initialize(context)— 获得DisplayContext、创建Ogre::SceneNodeonInitialize()— 子类设置订阅/属性setEnabled(true)→ 订阅话题、显示场景节点- 每帧
update(wall_dt, ros_dt)— 动画、衰减、状态更新 reset()/onDisable()— 清数据、退订
属性树:Display 继承 BoolProperty,子属性(Topic、Color、Size 等)挂到 Qt Model,由 Displays 面板 编辑;load()/save() 写入 .rviz YAML。
4.3 MessageFilterDisplay 与 TF
MessageFilterDisplay 组合:
message_filters::Subscriber+rclcpp::Subscriptiontf2_ros::MessageFilter— 仅当变换可用时投递消息Fixed Frame来自FrameManager
典型回调链(LaserScan):
1 | sensor_msgs/LaserScan 到达 |
4.4 可插拔坐标变换(ROS 2 新特性)
TransformationManager 通过 PluginlibFactory<FrameTransformer> 加载:
| 插件 | 位置 | 行为 |
|---|---|---|
TFFrameTransformer |
rviz_default_plugins |
标准 tf2(默认) |
IdentityFrameTransformer |
rviz_common |
恒等变换(无 TF 时 fallback) |
GUI Transformation 面板 切换插件。依赖 TF 的 Display 应使用 TransformerGuard(rviz_default_plugins),在错误 transformer 下自动禁用。
FrameManager 封装对当前 FrameTransformer 的查询,供 Display 将数据变换到 Fixed Frame。
4.5 Tool / Panel / ViewController
| 类型 | 基类 | 示例 |
|---|---|---|
| Tool | rviz_common::Tool |
Move Camera、Select、2D Nav Goal、Publish Point |
| Panel | rviz_common::Panel |
Displays、Selection、Time、Tool Properties、Views |
| ViewController | rviz_common::ViewController |
Orbit、XY Orbit、First Person、TopDownOrtho |
Tool 处理 RenderPanel 鼠标/键盘事件;ViewController 控制 Ogre::Camera 位姿。
4.6 插件加载:PluginlibFactory
1 | // pluginlib_factory.hpp |
VisualizationManager::createDisplay(class_lookup_name) → DisplayFactory::make() → pluginlib 实例化。
插件注册(rviz_default_plugins/CMakeLists.txt):
1 | pluginlib_export_plugin_description_file(rviz_common plugins_description.xml) |
4.7 ROS 集成层
RosClientAbstraction / RosNodeAbstraction:
- 封装
rclcpp::init、rclcpp::Node创建 - Display 通过
context_->getRosNodeAbstraction()获取节点,在同一 executor 上spin_some - 支持
--ros-args、匿名节点名等
与纯 rclcpp 节点不同,rviz 在 GUI 线程定时 spin,而非单独 rclcpp::spin 线程(部分 Display 仍可能用异步回调)。
4.8 配置持久化
- 格式:YAML(
.rviz文件) - 读写:
YamlConfigReader/YamlConfigWriter+Config树形结构 - 内容:Display 列表、属性值、ViewController、Transformation 插件、窗口布局等
启动:ros2 run rviz2 rviz2 -d my_config.rviz
5. rviz_rendering:Ogre 渲染层
5.1 RenderSystem 单例
RenderSystem::get() 管理:
Ogre::Root初始化- OpenGL 渲染插件加载(
OgreGLPlugin) Ogre::OverlaySystemmakeRenderWindow(window_id, w, h)— 绑定 Qt 窗口 X11/Win/Cocoa ID
与 Qt 集成:RenderPanel 将原生窗口 handle 交给 Ogre 创建 RenderWindow。
5.2 可视对象(objects/)
| 类 | 用途 |
|---|---|
PointCloud / PointCloudRenderable |
点云(激光、DepthCloud) |
Shape |
立方体、球、箭头等 |
Grid |
地面网格 |
BillboardLine |
路径、多边形线 |
MovableText |
3D 文本 |
WrenchVisual / EffortVisual |
力/力矩可视化 |
CovarianceVisual |
协方差椭圆 |
Mesh 加载:mesh_loader + Assimp(rviz_assimp_vendor)加载 DAE/STL/OGRE mesh。
5.3 与 Display 的分工
- Display(rviz_common/plugins):ROS 消息、TF、属性、何时更新
- rendering 对象:如何在 Ogre 里画(材质、顶点缓冲、LOD)
例:LaserScanDisplay 使用 rviz_default_plugins::PointCloudCommon,内部持有 rviz_rendering::PointCloud。
6. rviz_default_plugins:内置插件
6.1 plugins_description.xml
单文件注册 Display / Tool / Panel / ViewController / FrameTransformer(节选):
1 | <class name="rviz_default_plugins/LaserScan" |
class name 即 GUI 中 Add Display 对话框里的 lookup name。
6.2 Display 分类(README 已移植列表)
| 类别 | 代表 Display | 消息类型 |
|---|---|---|
| 传感器 | LaserScan, PointCloud2, Image, Camera | sensor_msgs |
| 机器人 | RobotModel, TF, Odometry | urdf, tf2, nav_msgs |
| 地图 | Map, GridCells | nav_msgs |
| 标注 | Marker, MarkerArray, InteractiveMarker | visualization_msgs |
| 几何 | Pose, Path, Polygon, Wrench | geometry_msgs |
| 其他 | Grid, Axes, DepthCloud, Effort | — |
6.3 LaserScanDisplay 实现要点
1 | class LaserScanDisplay : public |
TransformerGuard确保 tf2 transformer 生效laser_geometry::LaserProjection将 scan 转为点云PointCloudCommon管理颜色、衰减、Ogre 点云对象update()中处理 transformer 切换 与点云衰减
6.4 RobotModelDisplay
- 订阅
robot_description(参数或 topic) - urdf + kdl / tf2 更新关节角
- Ogre 场景图挂载 link mesh(Assimp 加载)
6.5 工具与面板
Tools:MoveCamera、FocusCamera、Measure、Select、Interact、InitialPose、Goal、PublishPoint
Panels:Displays、Help、Selection、Time、Tool Properties、Views、Transformation
ViewControllers:Orbit、XYOrbit、FirstPerson、FrameAligned、ThirdPersonFollower、TopDownOrtho
7. Vendor 包
7.1 rviz_ogre_vendor
- 提供固定版本 Ogre3D(Humble 为 1.x 分支)
- 导出 CMake:
find_package(rviz_ogre_vendor)→Ogre目标 rviz_rendering/rviz_common链接 Ogre
7.2 rviz_assimp_vendor
- 包装 Assimp 库
rviz_renderingmesh_loader 用于 COLLADA/STL 等
7.3 fastrtps_cmake_module 类比
rviz 不依赖 DDS 消息栈做渲染;vendor 仅图形栈。与 rosidl_typesupport_fastrtps 无直接关系。
8. 插件开发概要
详见 docs/plugin_development.md。
8.1 五步开发 Display
- 继承
Display或RosTopicDisplay<T>/MessageFilterDisplay<T> PLUGINLIB_EXPORT_CLASS(my_plugin::MyDisplay, rviz_common::Display)- 编写
plugins_description.xml pluginlib_export_plugin_description_file(rviz_common ...)target_link_libraries(... rviz_common::rviz_common rviz_rendering::rviz_rendering)
8.2 扩展点汇总
| 插件类型 | 基类 |
|---|---|
| Display | rviz_common::Display |
| Panel | rviz_common::Panel |
| Tool | rviz_common::Tool |
| ViewController | rviz_common::ViewController |
| FrameTransformer | rviz_common::transformation::FrameTransformer |
9. 测试体系
9.1 rviz_rendering_tests
- Ogre 环境 fixture
- mesh_loader、ogre media 导出测试
9.2 rviz_visual_testing_framework
- Page Object 模式驱动 Qt GUI
- 发布测试 TF/消息 → 截图 → 与 golden image 对比
- 用于回归 Display 渲染结果
10. 端到端序列图:LaserScan 显示
11. 与 ROS 2 其他组件关系
| 组件 | 关系 |
|---|---|
| tf2 / tf2_ros | 默认 FrameTransformer;MessageFilter 同步 |
| robot_state_publisher | RobotModel 显示 link 姿态 |
| urdf | 解析 robot_description |
| interactive_markers | InteractiveMarkerDisplay |
| rclcpp QoS | Display 可配置 reliability/durability |
| ros2 bag play | rviz 订阅回放话题 + /clock |
12. 调试与常见问题
| 现象 | 排查 |
|---|---|
| Fixed Frame 红字 | TF 树不完整;检查 ros2 run tf2_tools view_frames |
| 话题无显示 | QoS 不兼容;Display 属性中改 QoS |
| 插件找不到 | pluginlib 描述文件是否 export;AMENT_PREFIX_PATH |
| Ogre 黑屏 | 显卡/OpenGL;LIBGL_* 环境变量 |
| sim time 不动 | Time 面板是否 Pause;是否订阅 /clock |
| RobotModel 空白 | robot_description 参数;mesh 路径 package:// |
常用命令:
1 | ros2 run rviz2 rviz2 |
13. 与 ROS 1 rviz 架构对比
| 维度 | ROS 1 | ROS 2(本仓库) |
|---|---|---|
| GUI | Qt | Qt(相同范式) |
| 渲染 | Ogre | Ogre(rviz_rendering 拆分) |
| 插件库 | librviz | rviz_common + pluginlib |
| TF | tf 内置 | 可插拔 Transformer |
| 配置 | .rviz YAML | 兼容思路,格式演进 |
| 代码组织 | 单包为主 | 8 包分层 |
14. 源码阅读顺序
- 启动链:
rviz2/main.cpp→visualizer_app.cpp→visualization_frame.cpp - 主循环:
visualization_manager.cpp的onUpdate() - 插件 API:
display.hpp→ros_topic_display.hpp→message_filter_display.hpp - 工厂:
pluginlib_factory.hpp→add_display_dialog.cpp - 示例 Display:
laser_scan_display.cpp+point_cloud_common.cpp - 渲染:
render_system.cpp→objects/point_cloud.cpp - TF 插件:
transformation_manager.cpp→tf_frame_transformer.cpp - 插件清单:
plugins_description.xml - 插件开发:
docs/plugin_development.md
15. 小结
rviz 仓库以 rviz_common 为 Qt+ROS 调度核心,rviz_rendering 为 Ogre 绘图引擎,rviz_default_plugins 提供开箱即用的 Display/Tool/Panel,rviz2 仅为薄入口。数据路径是:rclcpp 订阅 →(可选 TF 滤波)→ Display 处理消息 → rendering 对象更新 → VisualizationManager 驱动 Ogre 渲染。
自定义可视化应优先继承 RosTopicDisplay 或 MessageFilterDisplay,并理解 Fixed Frame 与 TransformationManager;性能问题则关注 PointCloud 更新频率与 renderOneFrame 限帧逻辑。
正在加载留言…