【10天速通ROS2-PX4无人机】(一) 从零搭建仿真环境,妈妈再也不用担心我炸机了!

前言


### 文章目录

  • [前言](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [@TOC](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [1 编译 PX4 SITL 固件](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [1-1 介绍 PX4](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [1-2 依赖安装](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [1-3 编译](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [2 安装 Micro XRCE-DDS Agent](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [2-1 介绍](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [2-2 安装](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [3 工作空间创建](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [3-1 介绍 px4_msgs](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [3-2 启动飞机脚本](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [4 首次起飞与话题说明](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [4-1 话题含义](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [4-2 机型](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [5 键盘控制节点](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [5-1 PX4 飞行模式](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [5-2 键盘控制脚本](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [5-3 当前项目结构](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6 配置 Gazebo 无人机模型](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6-1 Velodyne VLP-16 3D LiDAR](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6-2 传感器嵌套与 PX4 模型注册](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6-3 IMU](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6-4 双路 RGB 相机](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [6-5 启动全新的飞机](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [7 RViz2 可视化](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [8 网笼测试场地](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [8-1 当前完整项目结构](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [9 完整演示流程](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)
  • [总结](#文章目录 前言 @[TOC] 1 编译 PX4 SITL 固件 1-1 介绍 PX4 1-2 依赖安装 1-3 编译 2 安装 Micro XRCE-DDS Agent 2-1 介绍 2-2 安装 3 工作空间创建 3-1 介绍 px4_msgs 3-2 启动飞机脚本 4 首次起飞与话题说明 4-1 话题含义 4-2 机型 5 键盘控制节点 5-1 PX4 飞行模式 5-2 键盘控制脚本 5-3 当前项目结构 6 配置 Gazebo 无人机模型 6-1 Velodyne VLP-16 3D LiDAR 6-2 传感器嵌套与 PX4 模型注册 6-3 IMU 6-4 双路 RGB 相机 6-5 启动全新的飞机 7 RViz2 可视化 8 网笼测试场地 8-1 当前完整项目结构 9 完整演示流程 总结)

1 编译 PX4 SITL 固件

1-1 介绍 PX4
  • PX4 是一套开源的无人机飞行控制软件,支持从多旋翼到固定翼的各类机型
  • SITL(Software In The Loop,软件在环) 模式允许飞控固件直接在电脑上编译成可执行程序,和 Gazebo 仿真器联动------行为几乎和真飞控一模一样,但不用担心炸机
  • PX4 与 ROS2 之间的通信通过 Micro XRCE-DDS(uORB → DDS 桥梁)实现,从 PX4 v1.14 起这是官方标准方案
  • 说人话就是:你在 Gazebo 里飞仿真飞机,PX4 负责飞控运算,ROS2 负责算法处理,三者之间通过 UDP 端口互相通信
1-2 依赖安装
  • 克隆 PX4 v1.14.3 稳定版:
bash 复制代码
cd ~
git clone https://github.com/PX4/PX4-Autopilot.git --branch v1.14.3 --depth 1 --recurse-submodules
  • 运行官方依赖安装脚本(约 5-10 分钟,需要 sudo):
bash 复制代码
cd ~/PX4-Autopilot
bash ./Tools/setup/ubuntu.sh
  • 如果系统已有 libgazebo11-dev 等基础包,脚本会跳过大部分依赖。但实测可能缺少 libgstreamer 导致 CMake 报 GSTREAMER_APP_LIBRARIES NOTFOUND,补充安装:
bash 复制代码
sudo apt install -y libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev \
  libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev
1-3 编译
  • 首次编译 SITL 固件(约 5-10 分钟):
bash 复制代码
cd ~/PX4-Autopilot
make px4_sitl gazebo-classic
  • 编译成功后会自动弹出 Gazebo 窗口,可以看到一架四旋翼无人机,终端出现 Ready for takeoff! 说明安装成功


2 安装 Micro XRCE-DDS Agent

2-1 介绍
  • Micro XRCE-DDS Agent 是 PX4(uORB 消息总线)与 ROS2(DDS 中间件)之间的通信桥梁
  • PX4 v1.14 起用这个替代了旧版的 MAVROS------它直接通过 UDP 将 PX4 的 uORB 话题映射为 ROS2 的 DDS 话题,延时更低、配置更简单
  • 说人话就是:PX4 内部的传感器数据(IMU、GPS、里程计等)通过 Agent "翻译"成 ROS2 标准话题,ROS2 的控制指令也通过 Agent 发回 PX4
2-2 安装
bash 复制代码
cd ~
git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git --depth 1
cd Micro-XRCE-DDS-Agent
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=~/microros_agent ..
make -j$(nproc)
sudo make install
sudo ldconfig
  • 添加到环境变量:
bash 复制代码
echo 'export PATH="$HOME/microros_agent/bin:$PATH"' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH="$HOME/microros_agent/lib:$LD_LIBRARY_PATH"' >> ~/.bashrc
source ~/.bashrc
  • 验证安装(看到 running... port: 8888 即可 Ctrl+C):
bash 复制代码
MicroXRCEAgent udp4 -p 8888

3 工作空间创建

3-1 介绍 px4_msgs
  • px4_msgs 是 PX4 官方定义的 ROS2 消息包,将 PX4 内部的 uORB 消息一对一映射为 ROS2 的 msg 定义

  • 所有消息都带有 uint64 timestamp(微秒级时间戳,从系统启动开始计数),这是 PX4 内部同步机制的基础

  • 包中共有 20+ 个消息类型,但无人机 Offboard 控制只需关注三个核心消息

  • 这是 ROS2 ↔ PX4 通信的"语言词典"------你的 ROS2 节点要控制飞机,必须依赖这个包

  • 说人话就是:你要给 PX4 发"飞到 (x,y,z)"的指令,得用 PX4 认识的格式,px4_msgs 定义了这个格式

  • 核心消息一:TrajectorySetpoint --- 轨迹设定点

bash 复制代码
# NED 局部世界坐标系
uint64 timestamp                  # 系统启动以来的微秒时间

float32[3] position               # [m] 目标位置 (x=前, y=右, z=下)
float32[3] velocity               # [m/s] 目标速度
float32[3] acceleration           # [m/s²] 目标加速度
float32[3] jerk                   # [m/s³] 仅用于日志

float32 yaw                       # [rad] 目标偏航角 -PI..+PI
float32 yawspeed                  # [rad/s] 目标偏航角速度
  • 这就是你告诉飞机"去(x,y,z)这个位置、面朝 yaw 方向"的指令

  • 关键细节 :任何分量设为 NaN 表示该维度不受控。比如只设 position 不设 velocity,飞控自己会用 PID 位置控制器去跟踪

  • 坐标系是 NED(North-East-Down):x=前、y=右、z=下------所以上升时 z 是负值

  • 核心消息二:OffboardControlMode --- 外部控制模式声明

bash 复制代码
uint64 timestamp

bool position          # 位置控制
bool velocity          # 速度控制
bool acceleration      # 加速度控制
bool attitude          # 姿态控制
bool body_rate         # 角速度控制
bool thrust_and_torque # 推力/扭矩控制
bool direct_actuator   # 直接执行器控制
  • 这是一张"控制权限表",告诉 PX4"我要控制哪些自由度"

  • 致命要求 :必须以 2Hz 以上的频率持续发布,否则 PX4 会触发 Offboard 失效保护(failsafe),自动切回上一模式

  • 我们脚本用 20Hz(timer = 0.05s)发送,与 TrajectorySetpoint 在同一回调中发布,保证同步

  • 核心消息三:VehicleCommand --- 车辆命令

bash 复制代码
uint64 timestamp
uint32 command          # MAVLink 标准命令 ID
float32 param1 ~ param7 # 命令参数(含义取决于具体命令)
uint8 target_system     # 目标系统 ID(通常为 1)
uint8 target_component  # 目标组件 ID(通常为 1)
uint8 source_system     # 源系统 ID
uint16 source_component # 源组件 ID
bool from_external      # 是否来自外部(必须为 True)
  • 这个消息遵循 MAVLink COMMAND_INT 协议,所有命令通过 command 字段区分,param1 ~ param7 的含义完全不同
命令 ID 枚举名 用途 关键参数
400 COMPONENT_ARM_DISARM 解锁/上锁 param11=解锁,0=上锁
176 DO_SET_MODE 切换飞行模式 param1=1(自定义模式), param2=6(OFFBOARD)
22 NAV_TAKEOFF 起飞 param7:目标高度(m),NED 坐标下为负值
21 NAV_LAND 降落 无需参数
180 DO_SET_PARAMETER 设置飞控参数 param1:参数 ID,param2:参数值
  • 踩坑警示param2=6 才是 OFFBOARD,写成 4 是 AUTO 模式------飞机悬停不动、所有 setpoint 被忽略,这是最容易踩的坑

  • 三个消息的关系

    • OffboardControlMode = 声明要"接管"什么
    • TrajectorySetpoint = 具体设的"目标值"
    • VehicleCommand = 一次性指令(解锁、切换模式等)
    • 三者缺一不可:有 Setpoint 但没有 ControlMode → PX4 忽略。有 ControlMode 但没有持续发送 → 2 秒后 Failsafe 触发
bash 复制代码
mkdir -p ~/postgraduate0/px4_ws/src
cd ~/postgraduate0/px4_ws
git clone https://github.com/PX4/px4_msgs.git src/px4_msgs --depth 1
source /opt/ros/humble/setup.bash
colcon build
echo "source ~/postgraduate0/px4_ws/install/setup.bash" >> ~/.bashrc
3-2 启动飞机脚本
  • 仿真需要三个组件同时运行:MicroXRCEAgent(UDP 8888 端口)、PX4 SITL + Gazebo、以及后续的 ROS2 控制节点
  • 把前两个写进 1_bringup.sh,一键启动:
bash 复制代码
#!/bin/bash
# ============================================================
# PX4 + Gazebo + ROS2 联合启动脚本
# 启动顺序: MicroXRCEAgent → PX4 SITL → ROS2 就绪
# Ctrl+C 退出全部
# ============================================================

set -e

cleanup() {
    echo ""
    echo ">>> 正在关闭所有进程..."
    kill $AGENT_PID 2>/dev/null
    pkill -f "gzserver" 2>/dev/null
    pkill -f "gzclient" 2>/dev/null
    pkill -f "px4" 2>/dev/null
    echo ">>> 已全部关闭"
    exit 0
}
trap cleanup SIGINT SIGTERM

# ==================== 配置 ====================
WORKSPACE_DIR="/home/lzh/postgraduate0/px4_ws"
PX4_DIR="$HOME/PX4-Autopilot"
AGENT_BIN="$HOME/microros_agent/bin/MicroXRCEAgent"
AGENT_LIB="$HOME/microros_agent/lib"

# ==================== 1. 启动 Micro XRCE-DDS Agent ====================
echo ">>> [1/3] 启动 Micro XRCE-DDS Agent (UDP port 8888)..."
export LD_LIBRARY_PATH="$AGENT_LIB:$LD_LIBRARY_PATH"
$AGENT_BIN udp4 -p 8888 &
AGENT_PID=$!
sleep 2

if kill -0 $AGENT_PID 2>/dev/null; then
    echo ">>> [1/3] Agent 启动成功 (PID: $AGENT_PID)"
else
    echo "!!! Agent 启动失败,请检查"
    exit 1
fi

# ==================== 2. 启动 PX4 SITL + Gazebo ====================
echo ">>> [2/3] 启动 PX4 SITL + Gazebo Classic..."
cd $PX4_DIR
make px4_sitl gazebo-classic &
PX4_PID=$!
sleep 5

echo ""
echo "============================================"
echo "  仿真环境已启动!"
echo "============================================"
echo "  ROS2 话题测试:"
echo "    ros2 topic list | grep fmu"
echo "  按 Ctrl+C 退出全部"
echo "============================================"

wait
  • 运行 ./1_bringup.sh

4 首次起飞与话题说明

4-1 话题含义
  • 仿真启动后,另开终端验证:
bash 复制代码
source /opt/ros/humble/setup.bash
source ~/postgraduate0/px4_ws/install/setup.bash
ros2 topic list
  • 完整话题分类说明

  • /fmu/in/* --- ROS2 发给 PX4 的控制指令

话题 含义
/fmu/in/trajectory_setpoint 最核心:位置/速度/加速度设定点,Offboard 模式下持续发送目标轨迹
/fmu/in/offboard_control_mode 声明控制模式(位置/速度/姿态等),必须 2Hz 以上持续发送
/fmu/in/vehicle_command 一次性命令:解锁/上锁、模式切换、起飞/降落
/fmu/in/vehicle_attitude_setpoint 姿态设定点(四元数 + 推力)
/fmu/in/vehicle_rates_setpoint 角速度设定点
/fmu/in/vehicle_mocap_odometry 外部动捕里程计输入
/fmu/in/vehicle_visual_odometry 外部视觉/激光里程计输入,可替代 GPS
/fmu/in/vehicle_trajectory_bezier 贝塞尔曲线轨迹(平滑飞行)
/fmu/in/vehicle_trajectory_waypoint 航点轨迹
/fmu/in/obstacle_distance 障碍物距离数据(避障用)
/fmu/in/onboard_computer_status 机载计算机心跳信号
/fmu/in/telemetry_status 数传链路状态
/fmu/in/sensor_optical_flow 光流传感器数据
  • /fmu/out/* --- PX4 发给 ROS2 的飞控状态
话题 含义
/fmu/out/vehicle_odometry 飞控 EKF 里程计(位置 + 速度 + 姿态)
/fmu/out/vehicle_local_position 本地 NED 坐标系下的位置和速度
/fmu/out/vehicle_global_position WGS-84 全球坐标(经纬度 + 高度)
/fmu/out/vehicle_gps_position 原始 GPS 数据
/fmu/out/vehicle_attitude 当前姿态(四元数)
/fmu/out/vehicle_status 飞控状态:解锁状态、飞行模式、电池等
/fmu/out/vehicle_control_mode 当前控制模式标志位
/fmu/out/sensor_combined 融合后的 IMU 数据(加速度 + 角速度)
/fmu/out/position_setpoint_triplet 当前位置设定点三元组(当前/前一个/下一个)
/fmu/out/failsafe_flags 失效保护标志位
/fmu/out/timesync_status 时间同步状态
  • 说人话:/fmu/in/* 是"你想让飞机干什么",/fmu/out/* 是"飞机现在什么状态"
4-2 机型
  • PX4 Gazebo Classic 支持多种无人机和载具模型:
模型 类型 说明
iris 四旋翼 默认机型,通用测试平台
iris_foggy_lidar 四旋翼 + 2D 激光 带雾环境模拟的 2D 激光雷达
iris_rplidar 四旋翼 + RPLidar 带 2D 激光扫描仪
iris_vision 四旋翼 + 视觉 带视觉传感器
standard_vtol 垂直起降固定翼 VTOL 机型
plane 固定翼 常规固定翼
rover 地面小车 差分驱动地面机器人
typhoon_h480 六旋翼 大疆台风 H480 六旋翼
  • 通过 make px4_sitl gazebo-classic_<模型名> 即可切换到对应机型

5 键盘控制节点

5-1 PX4 飞行模式
  • PX4 有多种飞行模式,理解模式切换是 Offboard 控制的前提:
模式 custom_main_mode 说明
MANUAL 1 手动/RC 遥控器模式,直接控制电机
ALTCTL 2 高度保持模式,自动维持高度
POSCTL 3 位置保持模式,自动维持位置和高度
AUTO 4 自动模式(任务/降落/返航等)
OFFBOARD 6 外部控制模式,完全由 ROS2 控制
STABILIZED 7 自稳模式,姿态保持
  • 注意OFFBOARD 的 custom_main_mode 是 6 ,不是 44 是 AUTO)。踩坑重灾区------写成 4 飞机会进入 AUTO_LOITER 悬停不动,所有 setpoint 被忽略

  • 进入 Offboard 模式前必须:

    • 持续以 2Hz 以上频率发布 OffboardControlMode
    • 设置 COM_RCL_EXCEPT = 4(bit 2),允许无 RC 遥控器进入 Offboard(SITL 没有物理遥控器)
5-2 键盘控制脚本
  • 注意务必看到 Ready for takeoff! 再运行控制脚本:
  • 启动脚本 2_keyboard.sh
bash 复制代码
#!/bin/bash
source /opt/ros/humble/setup.bash
source /home/lzh/postgraduate0/px4_ws/install/setup.bash
exec python3 /home/lzh/postgraduate0/px4_ws/2_keyboard_control.py
  • 核心设计:速度模式 + 松手超时悬停
    • 按住 Wvx = 2.0 m/s,timer 20Hz 持续积分到位置设定点,飞机持续前进
    • 松手 → 0.2 秒内没有新按键触发超时,速度归零,飞机悬停
    • 因为终端 cbreak 模式无法检测"松键"事件,用 last_key_time 时间戳模拟
python 复制代码
#!/usr/bin/env python3
"""
PX4 键盘控制 (Offboard 速度模式)
按住飞、松开悬停: WASD=水平  R/F=升降  Q/E=偏航
空格=解锁/上锁  O=Offboard  L=降落  ESC=退出
"""

import rclpy, sys, tty, select, termios, time
from rclpy.node import Node
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy
from px4_msgs.msg import OffboardControlMode, TrajectorySetpoint, VehicleCommand

VEL_XY = 2.0; VEL_Z = 1.5; VEL_YAW = 1.0; TIMEOUT = 0.2

class KeyboardControl(Node):
    def __init__(self):
        super().__init__("keyboard_control")
        qos = QoSProfile(reliability=ReliabilityPolicy.BEST_EFFORT,
                         history=HistoryPolicy.KEEP_LAST, depth=10)
        self.offboard_pub = self.create_publisher(
            OffboardControlMode, "/fmu/in/offboard_control_mode", qos)
        self.traj_pub = self.create_publisher(
            TrajectorySetpoint, "/fmu/in/trajectory_setpoint", qos)
        self.cmd_pub = self.create_publisher(
            VehicleCommand, "/fmu/in/vehicle_command", qos)

        self.x = 0.0; self.y = 0.0; self.z = -1.0; self.yaw = 0.0
        self.vx = self.vy = self.vz = self.vyaw = 0.0
        self.last_key_time = 0.0; self.last_hud_time = 0.0
        self.armed = False
        self.timer = self.create_timer(0.05, self.timer_cb)
        sys.stdout.write("""
╔══════════════════════════════════════════╗
║   PX4 键盘控制 (速度模式)                ║
║   W/S 前后   A/D 左右   R/F 升降        ║
║   Q/E 偏航   空格解锁   O=Offboard       ║
║   L 降落     ESC 退出                    ║
║   按住飞, 松开悬停                       ║
╚══════════════════════════════════════════╝
就绪 --- 按 空格 解锁\r\n""")
        sys.stdout.flush()

    def send_cmd(self, cmd, p1=0., p2=0., p3=0., p4=0., p5=0., p6=0., p7=0.):
        msg = VehicleCommand()
        msg.timestamp = int(self.get_clock().now().nanoseconds / 1000)
        msg.command = cmd
        msg.param1 = float(p1); msg.param2 = float(p2); msg.param3 = float(p3)
        msg.param4 = float(p4); msg.param5 = float(p5); msg.param6 = float(p6)
        msg.param7 = float(p7)
        msg.target_system = 1; msg.target_component = 1
        msg.source_system = 1; msg.source_component = 1
        msg.from_external = True
        self.cmd_pub.publish(msg)

    def timer_cb(self):
        ts = int(self.get_clock().now().nanoseconds / 1000)
        now = time.time()
        if now - self.last_key_time > TIMEOUT:
            self.vx = self.vy = self.vz = self.vyaw = 0.0
        else:
            dt = 1.0 / 20.0
            self.x += self.vx * dt; self.y += self.vy * dt
            self.z += self.vz * dt; self.yaw += self.vyaw * dt

        off = OffboardControlMode(); off.timestamp = ts; off.position = True
        self.offboard_pub.publish(off)

        traj = TrajectorySetpoint(); traj.timestamp = ts
        traj.position = [float(self.x), float(self.y), float(self.z)]
        traj.yaw = float(self.yaw)
        self.traj_pub.publish(traj)

        if now - self.last_hud_time > 0.5:
            self.last_hud_time = now
            spd = (self.vx**2 + self.vy**2 + self.vz**2)**0.5
            sys.stdout.write(
                f"\r  {'ARMED' if self.armed else 'DISARMED'}  "
                f"X={self.x:+.1f} Y={self.y:+.1f} H={-self.z:.1f}m  V={spd:.1f}m/s    ")
            sys.stdout.flush()

    def handle_key(self, ch):
        if ch == " ":
            if self.armed:
                self.send_cmd(400, 0.0); self.armed = False
            else:
                self.send_cmd(180, 8.0, 4.0)   # COM_RCL_EXCEPT=4
                self.send_cmd(400, 1.0)        # ARM
                self.armed = True
        elif ch.lower() == "o":
            self.send_cmd(176, 1.0, 6.0)      # OFFBOARD (main_mode=6, 不是4!)
        elif ch.lower() == "l":
            self.vx=self.vy=self.vz=self.vyaw = 0.0
            self.send_cmd(176, 1.0, 4.0, 6.0) # AUTO.LAND
            self.armed = False
        elif ch.lower() == "w": self.vx = VEL_XY; self.last_key_time = time.time()
        elif ch.lower() == "s": self.vx = -VEL_XY; self.last_key_time = time.time()
        elif ch.lower() == "d": self.vy = VEL_XY; self.last_key_time = time.time()
        elif ch.lower() == "a": self.vy = -VEL_XY; self.last_key_time = time.time()
        elif ch.lower() == "r": self.vz = -VEL_Z; self.last_key_time = time.time()
        elif ch.lower() == "f": self.vz = VEL_Z; self.last_key_time = time.time()
        elif ch.lower() == "q": self.vyaw = VEL_YAW; self.last_key_time = time.time()
        elif ch.lower() == "e": self.vyaw = -VEL_YAW; self.last_key_time = time.time()
        elif ch == "x": self.vx=self.vy=self.vz=self.vyaw = 0.0

    def run(self):
        fd = sys.stdin.fileno(); old = termios.tcgetattr(fd)
        tty.setcbreak(fd)
        try:
            while rclpy.ok():
                dr, _, _ = select.select([sys.stdin], [], [], 0.01)
                if dr:
                    ch = sys.stdin.read(1)
                    if ch == "\x1b": sys.stdout.write("\r\n退出\r\n"); break
                    self.handle_key(ch)
                rclpy.spin_once(self, timeout_sec=0.005)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old)

def main():
    rclpy.init(); node = KeyboardControl()
    try: node.run()
    except KeyboardInterrupt: pass
    finally: node.destroy_node(); rclpy.shutdown()

if __name__ == "__main__": main()
  • 操作流程:
步骤 按键 说明
1 空格 解锁飞控(ARM),自动设置 COM_RCL_EXCEPT=4
2 O 切换到 Offboard 模式,飞控控制权交给 ROS2
3 R(按住) 上升,松手悬停
4 WASD(按住) 水平移动,松手悬停
5 Q/E 偏航旋转
6 L 降落(切回 AUTO.LAND 模式)
7 X 紧急悬停(速度瞬间归零)
5-3 当前项目结构
  • 经过前五节的搭建,px4_ws 目录下的文件结构如下:
bash 复制代码
~/postgraduate0/px4_ws/
├── src/px4_msgs/          # PX4 ROS2 消息定义包
├── install/               # colcon build 编译产物
├── 1_bringup.sh           # 一键启动仿真 (Agent + PX4 + Gazebo)
├── 2_keyboard.sh          # 键盘控制启动脚本
└── 2_keyboard_control.py  # 键盘控制 Python 节点
  • 两个脚本的启动顺序
脚本 终端 职责
./1_bringup.sh 终端 1 启动 Micro XRCE-DDS Agent + PX4 SITL + Gazebo 仿真
./2_keyboard.sh 终端 2 启动键盘控制节点,接管飞机(等 Ready for takeoff! 出现后)
  • 典型工作流
    • 终端 1:./1_bringup.sh → 等待 Gazebo 窗口弹出、终端显示 Ready for takeoff!
    • 终端 2:./2_keyboard.sh → 空格解锁 → O 进 Offboard → WASD 飞
  • 注意1_bringup.sh 的前台进程会阻塞终端,Ctrl+C 一键关闭所有后台进程(Agent + Gazebo + PX4)

6 配置 Gazebo 无人机模型

6-1 Velodyne VLP-16 3D LiDAR
  • PX4 内置模型只支持 2D 激光扫描(foggy_lidarrplidar)和单点测距(lidar),没有一个能输出 sensor_msgs/PointCloud2------这是 FastLIO2 唯一需要的输入格式

  • Velodyne VLP-16 是经典的 16 线旋转式 3D 激光雷达,Gazebo 有现成的 ROS2 插件 libgazebo_ros_velodyne_laser.so,直接输出 PointCloud2

  • 安装插件:

bash 复制代码
sudo apt install -y ros-humble-velodyne-gazebo-plugins ros-humble-velodyne-description
  • ~/.gazebo/models/velodyne_vlp16/model.sdf 创建雷达模型:
xml 复制代码
<sensor name="vlp16" type="gpu_ray">   <!-- GPU 加速,不用 CPU -->
  <update_rate>10</update_rate>
  <ray>
    <scan>
      <horizontal>
        <samples>720</samples>          <!-- 每圈 720 采样点 -->
        <min_angle>-3.14159</min_angle>
        <max_angle>3.14159</max_angle>
      </horizontal>
      <vertical>
        <samples>16</samples>           <!-- 16 条垂直线 -->
        <min_angle>-0.785</min_angle>   <!-- -45° -->
        <max_angle>0.785</max_angle>    <!-- +45° -->
      </vertical>
    </scan>
  </ray>
  <plugin name="vlp16" filename="libgazebo_ros_velodyne_laser.so">
    <ros><namespace>/velodyne</namespace></ros>
    <frame_name>velodyne_link</frame_name>
    <min_range>0.5</min_range>
    <max_range>30.0</max_range>
    <gaussian_noise>0.01</gaussian_noise>
  </plugin>
</sensor>
  • 关键参数演变
参数 初始值 最终值 为什么改
type ray (CPU) gpu_ray CPU 模式 30 万射线/秒直接卡死 Gazebo,飞机桨叶都不转
samples 1875 720 降低 CPU 负担,GPU 下够用
lasers 16→8 16 先降后恢复,确认 GPU 不卡
update_rate 10→5 10 同上
mass 0.83 kg 0.05 kg Iris 自重 ~1.5kg,真机 VLP-16 830g 压在上面飞不起来
  • 降低传感器重量:
xml 复制代码
<mass>0.05</mass>  <!-- 真机 830g,仿真压到 50g -->
  • GPU 加速下的最终设置:gpu_ray + 720 水平采样 + 16 线 + 10Hz = 115,200 pts/s,Gazebo 流畅

  • 垂直视场从 ±15° 扩大到 ±45°,在网笼中能打到更多结构:

xml 复制代码
<min_angle>-0.785</min_angle>   <!-- -45° -->
<max_angle>0.785</max_angle>    <!-- +45° -->
6-2 传感器嵌套与 PX4 模型注册
  • 创建 iris_vlp16 模型,在 iris 无人机上嵌套 Velodyne + IMU + 双路 RGB 相机:
bash 复制代码
iris_vlp16
├── iris (PX4 飞控)
├── [fixed joint] velodyne_vlp16 → velodyne_link (顶置 12cm)
├── [fixed joint] gazebo_ros_imu → imu_link (中部 5cm)
├── [fixed joint] camera_front → camera_front_link (机头前 15cm)
└── [fixed joint] camera_down → camera_down_link (底部,pitch 90° 朝下)
  • 为什么嵌套? PX4 已有的 iris_foggy_lidariris_rplidar 等模型都采用 <include> 嵌套结构------SDF 的 <include> 机制 + <joint> 固定关节是 Gazebo Classic 的标准做法,PX4 源码中已经验证了这条路

  • 注册三步走

  • 第一步:注册 cmake 模型白名单

  • PX4 通过 sitl_targets_gazebo-classic.cmake 维护一个模型白名单,不在名单里的模型无法通过 make 启动

  • 编辑 ~/PX4-Autopilot/src/modules/simulation/simulator_mavlink/sitl_targets_gazebo-classic.cmake,找到 set(models ...)(约第 73 行),在列表中插入 iris_vlp16

cmake 复制代码
set(models
    advanced_plane
    believer
    ...
    iris_vision
    iris_vlp16          # ← 新增这一行
    omnicopter
    ...
)
  • 这个列表决定了哪些模型能通过 make px4_sitl gazebo-classic_<模型名> 启动。当运行 make px4_sitl gazebo-classic_iris_vlp16 时,cmake 会调用 sitl_run.shiris_vlp16 作为模型名传入,Gazebo 从模型路径中查找同名 SDF 文件

  • 第二步:模型文件 + airframe 启动脚本

  • 把写好的模型复制到 PX4 模型目录,并创建同名 SDF(PX4 cmake 第 140 行显式检查 ${model_only}/${model_only}.sdf,只认 iris_vlp16.sdf,不认 model.sdf):

bash 复制代码
cp -r ~/.gazebo/models/iris_vlp16 \
     ~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/
ln -sf model.sdf \
     ~/PX4-Autopilot/Tools/.../models/iris_vlp16/iris_vlp16.sdf
  • 子模型(velodyne_vlp16、gazebo_ros_imu、rgb_camera)同样需要链接到 PX4 的模型目录,否则 <include><uri>model://velodyne_vlp16</uri></include> 会找不到:
bash 复制代码
for m in velodyne_vlp16 gazebo_ros_imu rgb_camera; do
    ln -sf ~/.gazebo/models/$m \
           ~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/$m
done
  • 创建 airframe 启动文件 11015_gazebo-classic_iris_vlp16,文件名格式为 {SYS_AUTOSTART}_gazebo-classic_{模型名}。PX4 启动时 rcS 脚本通过 PX4_SIM_MODEL 环境变量自动匹配 airframe 文件,提取 SYS_AUTOSTART 来初始化飞控参数:
bash 复制代码
cp ~/PX4-Autopilot/ROMFS/.../airframes/10015_gazebo-classic_iris \
   ~/PX4-Autopilot/ROMFS/.../airframes/11015_gazebo-classic_iris_vlp16
  • 在文件末尾追加仿真专用参数(见下方 Airframe 参数),然后拷贝到 build rootfs 使改动立即生效:
bash 复制代码
cp ~/PX4-Autopilot/ROMFS/.../airframes/11015_gazebo-classic_iris_vlp16 \
   ~/PX4-Autopilot/build/px4_sitl_default/rootfs/etc/init.d-posix/airframes/
  • 每次 make 会重新生成 rootfs,所以 ROMFS 和 build rootfs 两处都要放

  • 第三步:更新 bringup 脚本

  • 修改 1_bringup.sh 中的 make target,从默认 iris 切换到 iris_vlp16:

bash 复制代码
# 旧: 默认 iris, 空白世界
make px4_sitl gazebo-classic

# 新: iris_vlp16 + 网笼世界
export PX4_SITL_WORLD="$WORKSPACE_DIR/cage.world"
make px4_sitl gazebo-classic_iris_vlp16
  • PX4_SITL_WORLD 环境变量会被 sitl_run.sh 读取,用绝对路径加载 world 文件,绕过 cmake 的 worlds 白名单

  • Airframe 文件中禁用电池模拟和 RC 遥控器检查(SITL 没有物理电池和遥控器):

bash 复制代码
param set-default PWM_MAIN_FUNC1 101
param set-default PWM_MAIN_FUNC2 102
param set-default PWM_MAIN_FUNC3 103
param set-default PWM_MAIN_FUNC4 104

# 仿真环境: 禁用电池故障保护 + 允许无RC进入Offboard
param set-default COM_BAT_ACT_T 0
param set-default COM_RCL_EXCEPT 4
6-3 IMU
  • 飞机(iris)自带的 IMU 通过 PX4 EKF 处理,经 uXRCE-DDS 发布到 /fmu/out/sensor_combined
  • 但 FastLIO2 需要 原始 IMU 数据 (未经 EKF 滤波的 sensor_msgs/Imu),因此在 gazebo_ros_imu 模型中额外挂载了一个 libgazebo_ros_imu_sensor.so,200Hz,直接发布 /imu/data 到 ROS2
6-4 双路 RGB 相机
  • 挂载两个 libgazebo_ros_camera.so 实例:
    • 前视相机 camera_front:机头前 15cm,高 8cm,640×480 30Hz,话题 /camera_front/cam/image_raw
    • 下视相机 camera_down:机身底部 2cm,pitch 90° 朝下,话题 /camera_down/cam/image_raw
6-5 启动全新的飞机
  • 新的 bringup 脚本加入网笼世界指定:
bash 复制代码
#!/bin/bash
# ============================================================
# PX4 + Gazebo + ROS2 联合启动脚本
# 启动顺序: MicroXRCEAgent → PX4 SITL → ROS2 就绪
# Ctrl+C 退出全部
# ============================================================

set -e

cleanup() {
    echo ""
    echo ">>> 正在关闭所有进程..."
    kill $AGENT_PID 2>/dev/null
    pkill -f "gzserver" 2>/dev/null
    pkill -f "gzclient" 2>/dev/null
    pkill -f "px4" 2>/dev/null
    echo ">>> 已全部关闭"
    exit 0
}
trap cleanup SIGINT SIGTERM

# ==================== 配置 ====================
WORKSPACE_DIR="/home/lzh/postgraduate0/px4_ws"
PX4_DIR="$HOME/PX4-Autopilot"
AGENT_BIN="$HOME/microros_agent/bin/MicroXRCEAgent"
AGENT_LIB="$HOME/microros_agent/lib"

# ==================== 1. 启动 Micro XRCE-DDS Agent ====================
echo ">>> [1/3] 启动 Micro XRCE-DDS Agent (UDP port 8888)..."
export LD_LIBRARY_PATH="$AGENT_LIB:$LD_LIBRARY_PATH"
$AGENT_BIN udp4 -p 8888 &
AGENT_PID=$!
sleep 2

# 检查 Agent 是否成功启动
if kill -0 $AGENT_PID 2>/dev/null; then
    echo ">>> [1/3] Agent 启动成功 (PID: $AGENT_PID)"
else
    echo "!!! Agent 启动失败,请检查"
    exit 1
fi

# ==================== 2. 启动 PX4 SITL + Gazebo ====================
echo ">>> [2/3] 启动 PX4 SITL + Gazebo Classic (iris_vlp16 + 网笼)..."
export PX4_SITL_WORLD="$WORKSPACE_DIR/cage.world"
cd $PX4_DIR
make px4_sitl gazebo-classic_iris_vlp16 &
PX4_PID=$!
sleep 8

# ==================== 3. 最终提示 ====================
echo ""
echo "============================================"
echo "  仿真环境已启动!"
echo "  Agent PID: $AGENT_PID"
echo "  PX4  PID:  $PX4_PID"
echo "============================================"
echo ""
echo "  ROS2 话题测试:"
echo "    source /opt/ros/humble/setup.bash"
echo "    source $WORKSPACE_DIR/install/setup.bash"
echo "    ros2 topic list | grep fmu"
echo ""
echo "  按 Ctrl+C 退出全部"
echo "============================================"
echo ""

# 等待子进程
wait

7 RViz2 可视化

  • PX4 不发布传统 TF 变换,需要手动补充传感器 frame 的静态变换,然后把 world 改成 base_link 作为固定参考帧
  • 3_rviz.sh 启动脚本:先拉起 4 个静态 TF 发布器(传感器外参),再启动 RViz2 加载配置文件:
bash 复制代码
#!/bin/bash
# RViz2 可视化: Velodyne点云 + PX4里程计 + TF
source /opt/ros/humble/setup.bash
source /home/lzh/postgraduate0/px4_ws/install/setup.bash

# 传感器静态 TF: base_link → velodyne_link / imu_link / camera
ros2 run tf2_ros static_transform_publisher \
    0 0 0.12 0 0 0 base_link velodyne_link &
TF1=$!

ros2 run tf2_ros static_transform_publisher \
    0 0 0.05 0 0 0 base_link imu_link &
TF2=$!

ros2 run tf2_ros static_transform_publisher \
    0.15 0 0.08 0 0 0 base_link camera_front_link &
TF3=$!

ros2 run tf2_ros static_transform_publisher \
    0 0 -0.02 0 1.5708 0 base_link camera_down_link &
TF4=$!

# 启动 RViz2
rviz2 -d /home/lzh/postgraduate0/px4_ws/px4_sim.rviz

# 清理
kill $TF1 $TF2 $TF3 $TF4 2>/dev/null
  • RViz 配置文件核心显示项:
显示 话题 类型
Grid --- 参考网格
TF --- 坐标系树
PointCloud2 /velodyne/points 彩虹着色
Odometry /fmu/out/vehicle_odometry 绿色轨迹箭头
AccelStamped /imu/data IMU 加速度矢量
Image ×2 /camera_front/cam/image_raw/camera_down/cam/image_raw 双路 RGB
  • 注意 Humble 没有 rviz_default_plugins/Imu,改用 AccelStamped

  • 完整 px4_sim.rviz 配置文件:

yaml 复制代码
Panels:
  - Class: rviz_common/Displays
    Name: Displays
  - Class: rviz_common/Views
    Name: Views
Visualization Manager:
  Class: ""
  Displays:
    - Class: rviz_default_plugins/Grid
      Name: Grid
      Plane Cell Count: 20
      Cell Size: 1
      Color: 160; 160; 164
      Enabled: true
      Plane: XY
      Reference Frame: base_link
    - Class: rviz_default_plugins/TF
      Name: TF
      Enabled: true
      Frame Timeout: 15
      Marker Scale: 0.3
      Show Arrows: true
      Show Axes: true
      Show Names: true
    - Class: rviz_default_plugins/PointCloud2
      Name: Velodyne
      Enabled: true
      Topic:
        Depth: 5
        Reliability Policy: Best Effort
        Value: /velodyne/points
      Style: Points
      Size (m): 0.03
      Size (Pixels): 2
      Color Transformer: Intensity
      Decay Time: 0.1
      Use Rainbow: true
    - Class: rviz_default_plugins/Odometry
      Name: PX4 Odometry
      Enabled: true
      Topic:
        Depth: 5
        Reliability Policy: Best Effort
        Value: /fmu/out/vehicle_odometry
      Keep: 100
      Shape: Arrow
      Color: 0; 200; 100
      Alpha: 0.7
      Shaft Length: 0.2
      Head Length: 0.1
      Head Radius: 0.05
    - Class: rviz_default_plugins/AccelStamped
      Name: IMU Accel
      Enabled: true
      Topic:
        Depth: 5
        Reliability Policy: Best Effort
        Value: /imu/data
      Scale: 0.5
      Color: 255; 100; 100
      Alpha: 0.7
    - Class: rviz_default_plugins/Image
      Name: Camera Front
      Enabled: true
      Topic:
        Depth: 5
        Reliability Policy: Best Effort
        Value: /camera_front/cam/image_raw
      Transport Hint: raw
    - Class: rviz_default_plugins/Image
      Name: Camera Down
      Enabled: true
      Topic:
        Depth: 5
        Reliability Policy: Best Effort
        Value: /camera_down/cam/image_raw
      Transport Hint: raw
    - Class: rviz_default_plugins/Axes
      Name: Axes
      Enabled: true
      Length: 0.3
      Radius: 0.02
      Reference Frame: base_link
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Fixed Frame: base_link
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz_default_plugins/MoveCamera
    - Class: rviz_default_plugins/Select
    - Class: rviz_default_plugins/Measure
  Value: true
  Views:
    Current:
      Class: rviz_default_plugins/Orbit
      Distance: 10
      Focal Point: {X: 0, Y: 0, Z: 3}
      Name: Current View
      Pitch: 0.5
      Target Frame: base_link
      Yaw: 0.8
Window Geometry:
  Height: 800
  Width: 1200

8 网笼测试场地

  • 需要一个封闭空间验证 SLAM 和避障:9m × 4.6m × 4m,四面 + 天花板共五面网栏
  • 没有现成模型,使用 Python 生成 SDF World 文件------竖杆 + 横杆间距 0.4m,细杆直径 2cm,共 139 根杆
python 复制代码
W,H = 9, 4.6; Hgt, S = 4, 0.4; T = 0.02; parts = []; cnt = 0

def bar(x,y,z,sx,sy,sz):
    global cnt; parts.append(f'<model name="b{cnt}"><static>true</static>'
        f'<pose>{x} {y} {z} 0 0 0</pose><link name="l">'
        f'<collision name="c"><geometry><box><size>{sx} {sy} {sz}</size></box></geometry></collision>'
        f'<visual name="v"><geometry><box><size>{sx} {sy} {sz}</size></box></geometry>'
        f'<material><ambient>0.4 0.4 0.4 1</ambient></material></visual></link></model>')
    cnt += 1

# 四面墙: 竖杆 + 横杆
for y in [-H/2, H/2]:
    for i in range(int(W/S)+1): bar(-W/2+i*S, y, Hgt/2, T, T, Hgt)
    for j in range(1, int(Hgt/S)): bar(0, y, j*S, W, T, T)
for x in [-W/2, W/2]:
    for i in range(1, int(H/S)): bar(x, -H/2+i*S, Hgt/2, T, T, Hgt)
    for j in range(1, int(Hgt/S)): bar(x, 0, j*S, T, H, T)
# 四角柱 + 天花板
for x in [-W/2, W/2]:
    for y in [-H/2, H/2]: bar(x, y, Hgt/2, T, T, Hgt)
for i in range(int(W/S)+1): bar(-W/2+i*S, 0, Hgt, T, H, T)
for j in range(1, int(H/S)): bar(0, -H/2+j*S, Hgt, W, T, T)

with open('cage.world','w') as f:
    f.write(f'<?xml version="1.0"?><sdf version="1.6"><world name="cage">'
            f'<include><uri>model://sun</uri></include>'
            f'<include><uri>model://ground_plane</uri></include>'
            f'{"".join(parts)}</world></sdf>')
  • 通过 PX4_SITL_WORLD 环境变量指定 world 文件,飞机自动生成在场地中央 (0, 0, 0)
8-1 当前完整项目结构
  • 经过六、七、八三章的传感器配置和场地搭建,px4_ws 目录结构更新为:
bash 复制代码
~/postgraduate0/px4_ws/
├── src/px4_msgs/              # PX4 ROS2 消息定义包
├── install/                   # colcon build 编译产物
├── 1_bringup.sh               # 一键启动仿真 (+网笼 +iris_vlp16)
├── 2_keyboard.sh              # 键盘控制启动脚本
├── 2_keyboard_control.py      # 键盘控制 Python 节点
├── 3_rviz.sh                  # RViz2 可视化启动脚本
├── px4_sim.rviz               # RViz2 配置文件
└── cage.world                 # 网笼测试场地 SDF

~/.gazebo/models/
├── iris_vlp16/                # 嵌套 iris + 全部传感器
├── velodyne_vlp16/            # VLP-16 3D LiDAR 模型
├── gazebo_ros_imu/            # ROS2 IMU 传感器模型
└── rgb_camera/                # RGB 相机模型

~/PX4-Autopilot/
├── src/modules/.../sitl_targets_gazebo-classic.cmake  # 已注册 iris_vlp16
├── ROMFS/.../airframes/11015_gazebo-classic_iris_vlp16 # airframe 启动脚本
└── Tools/simulation/gazebo-classic/.../models/iris_vlp16/ # 模型+传感器 SDF
  • 三个脚本的启动顺序与职责
脚本 终端 职责
./1_bringup.sh 终端 1 启动 Agent + PX4 + Gazebo(带 iris_vlp16 + 网笼)
./2_keyboard.sh 终端 2 启动键盘控制节点,接管飞机(等 Ready for takeoff! 出现后)
./3_rviz.sh 终端 3 启动 RViz2 可视化(点云 + 里程计 + IMU + 双路相机)

9 完整演示流程


总结

  • 本文从零搭建了一套完整的 ROS2 无人机仿真闭环:
    • PX4 SITL + Gazebo Classic + Micro XRCE-DDS 基础通信链路
    • 键盘 Offboard 速度模式控制(松手悬停,点按微调)
    • 四传感器集成(3D LiDAR + IMU + 双路 RGB),全部输出标准 ROS2 话题
    • 9m×4.6m 网笼封闭测试场地
    • RViz2 全数据可视化
  • 核心踩坑回顾:
    • PX4 cmake 模型白名单------不注册就没法用 make 启动
    • 雷达 CPU 模式直接卡死 Gazebo------必须用 gpu_ray + 降参数
    • 传感器重量仿真------真机 830g 的 VLP-16 在仿真里压得飞机飞不起来,必须减到 50g
    • COM_RCL_EXCEPT=4 + COM_BAT_ACT_T=0------SITL 没有 RC 遥控器和真实电池,不设这两个参数 Offboard 进不去
    • Offboard 模式 custom_main_mode=6 不是 44AUTO6 才是 OFFBOARD
  • 后续计划:接上 FAST-LIO2(LiDAR+IMU 融合里程计)→ OctoMap(3D 占据地图)→ EGO-Planner(轨迹规划)
  • 如有错误,欢迎指出!
  • 感谢观看!
相关推荐
云上码厂18 小时前
热转导仿真与分析
仿真
沈阳昊天环宇无人机小编辑1 天前
沈阳学无人机怎么选?沈阳昊天环宇:从合规取证到行业应用,构建低空经济时代的核心竞争力
无人机
JulyLi20192 天前
基于光电球机低空无人机智能追踪系统
无人机
某林2122 天前
ROS2 + WebRTC + MQTT 异构系统架构
架构·系统架构·机器人·硬件架构·webrtc·ros2
小许同学记录成长2 天前
QGIS二次开发技术文档
图像处理·qt·信息可视化·无人机
GrepowTattu3 天前
新品发布|Tattu TA-BC无人机电池检测器上线,多通道充电状态尽在掌握
无人机
xuanshang_yutou3 天前
无人机调试起飞遇到的问题及注意事项
无人机
延凡科技4 天前
多场景落地复盘:端边云架构无人机智能巡检系统设计与实践
大数据·数据结构·人工智能·科技·架构·无人机·能源
科技大视界4 天前
无人机智能巡检服务商技术哪家强?
无人机