PX4 ROS 2 导航界面
主页(PX4 v1.15) 实验性实验性
在撰写本文档时,PX4 ROS 2 接口库的部分内容还处于试验阶段,因此可能会发生变化。
PX4 ROS 2 接口库 通过导航接口,开发人员可以直接从 ROS 2 应用程序(如 VIO 系统或地图匹配系统)向 PX4 发送位置测量数据。该接口为 PX4 和 uORB 消息传递框架提供了一个抽象层,并对通过接口发送的状态估计更新请求引入了一些正确性检查。然后,这些测量数据会被融合到 EKF 中,就像 PX4 内部测量数据一样。
图书馆提供两种课程、 本地位置测量接口
和 全球位置测量接口
它们都暴露了类似的 更新
方法,分别向 PX4 提供局部位置或全局位置更新。位置更新 更新
方法预期位置测量 结构
(本地位置测量
或 全球位置测量
),开发人员可以用自己生成的位置测量值填充这些数据。
安装和首次测试
开始操作需要以下步骤:
将版本库克隆到工作区:
吁CD $ros_workspace/src Git 复制 --递归 https://github.com/Auterion/px4-ros2-interface-lib
信息
为确保兼容性,请使用最新的 主要 PX4 的分支、 px4_msgs 和图书馆。参见 这里.
建立工作区:
吁CD .. 胶管 构建
在另一个外壳中,启动 PX4 SITL:
吁CD $px4-自动驾驶仪 生产 px4_sitl 古董
(这里我们使用的是 Gazebo-Classic,但您也可以使用任何模型或模拟器)。
在另一个 shell 中运行 micro XRCE 代理(之后可以继续运行):
吁MicroXRCEAgent udp4 -p 8888
回到 ROS 2 终端,将刚刚创建的工作区作为源文件(在步骤 3 中),然后运行 全球导航 例如,它会定期发送虚假的全球位置更新:
吁消息来源 install/setup.bash 玫瑰2 运行 global_navigation_cpp 示例 全球导航示例
您应该会得到这样的输出结果,显示全局接口已成功发送位置更新:
吁[INFO] [1702030701.836897756] [example_global_navigation_node]: example_global_navigation_node 正在运行! [DEBUG] [1702030702.837279784] [example_global_navigation_node]: 成功 发送 位置 更新 至 导航 接口。 [DEBUG] [1702030703.837223884] [example_global_navigation_node]:成功向导航界面发送位置更新。
在 PX4 外壳中,可以检查 PX4 是否接收全局位置更新:
吁听众 辅助全球位置
输出结果应该是这样的
吁主题: 辅助全球位置 辅助全球位置 时间戳: 46916000 (0.528000 秒钟 前) timestamp_sample: 46916000 (0 我们 之前 时戳) 纬度 12.343210 不 23.454320 备选案文 12.40000 椭圆体 0.00000 delta_alt: 0.00000 以弗所书 0.31623 epv: 0.44721 terrain_alt: 0.00000 lat_lon_reset_counter: 0 alt_reset_counter: 0 terrain_alt_valid: 假的 dead_reckoning: 假的
现在,您可以使用导航界面发送自己的位置更新信息了。
如何使用图书馆
要发送位置测量结果,需要用测量值填充 position 结构。然后以该结构作为参数调用接口的更新函数。
有关如何使用该界面的基本示例,请查看 例子 在 Auterion/px4-ros2-interface-lib
存储库,如 examples/cpp/navigation/local_navigation 或 examples/cpp/navigation/global_navigation.
本地定位(POSITION)更新
首先确保 PX4 参数 EKF2_EV_CTRL
通过将相应的位设置为 真
:
0
:水平位置数据1
:垂直位置数据2
:速度数据3
:偏航数据
向 PX4 发送本地位置测量值:
用于测量的可用姿态和速度参考帧定义如下 枚举
:
枚举 类 PoseFrame
{
未知,
当地 NED,
本地FRD
};
枚举 类 速度框架
{
未知,
当地 NED,
本地FRD,
身体FRD
};
本地位置测量
结构定义如下
结构 本地位置测量
{
rclcpp::Time timestamp_sample {};
标准::optional<;本征::Vector2f>; position_xy {标准::nullopt};
标准::optional<;本征::Vector2f>; 位置偏差 {标准::nullopt};
标准::optional<float>; position_z {标准::nullopt};
标准::optional<float>; 位置 Z 变量 {标准::nullopt};
标准::optional<;本征::Vector2f>; velocity_xy {标准::nullopt};
标准::optional<;本征::Vector2f>; 速度_x_方差 {标准::nullopt};
标准::optional<float>; velocity_z {标准::nullopt};
标准::optional<float>; 速度 Z 方差 {标准::nullopt};
标准::optional<;本征四元数f>; 姿态四元数 {标准::nullopt};
标准::optional<;本征::Vector3f>; 态度变量 {标准::nullopt};
};
更新()
本地接口的方法需要满足以下条件 本地位置测量
:
- 定义了样本时间戳。
- 值没有 "NAN"。
- 如果提供了测量值,其相关的方差值就会得到很好的定义(例如,如果
位置
则位置偏差
必须定义)。 - 如果提供了测量值,其相关参考框架并非未知(例如,如果
位置
定义,则界面初始化时的姿态帧与PoseFrame::Unknown
).
下面的代码片段是一个 ROS 2 节点的示例,该节点使用本地导航接口向 PX4 发送北-东-下(NED)参照系中的 3D 姿态更新:
类 我的本地测量更新节点 : 公 rclcpp::节点
{
公众:
我的本地测量更新节点()
: 节点("my_node_name";)
{
// 将姿势测量参考框架设置为东北-下
缢 px4_ros2::PoseFrame pose_frame = px4_ros2::PoseFrame::LocalNED;
// 本例中我们只发送姿势测量值
// 将速度测量参考帧设置为未知
缢 px4_ros2::VelocityFrame velocity_frame = px4_ros2::速度框架未知;
// 初始化本地接口 [1]
本地位置测量接口 =
标准::共享<;px4_ros2::本地位置测量接口>(*此,pose_frame,velocity_frame);
}
空白 发送更新()
{
虽然 (运行中) { // 有可能使方法作为回调运行或在定时器上运行
// 生成本地位置测量值
rclcpp::Time timestamp_sample = ...
本征::Vector2f position_xy = ...
本征::Vector2f position_xy_variance = ...
浮动 位置_z = ...
浮动 位置 Z 变量 = ...
// 填充本地位置测量结构 [2]
px4_ros2::LocalPositionMeasurement local_position_measurement{};
本地位置测量时间戳样本 = timestamp_sample;
本地位置测量.position_xy = position_xy;
本地位置测量.位置氧方差 = position_xy_variance;
本地位置测量.position_z = position_z;
本地位置测量.位置 Z 方差 = position_z_variance;
// 使用接口 [3] 将测量结果发送到 PX4
尝试 {
_local_position_measurement_interface->;更新(本地位置测量);
} 捕捉 (缢 px4_ros2导航接口无效参数 及样品; e) {
// 处理因本地位置测量定义无效而导致的异常
RCLCPP_ERROR(get_logger(), "异常捕获: %s";, e.什么());
}
}
}
私人
标准::shared_ptr<;px4_ros2::LocalPositionMeasurementInterface 本地位置测量接口>; 本地位置测量接口;
};
全球位置更新
首先确保 PX4 参数 EKF2_AGP_CTRL
通过将相应位设置为 真
:
0
:水平位置数据1
:垂直位置数据
向 PX4 发送全局位置测量值:
全球位置测量
结构定义如下
结构 全球位置测量
{
rclcpp::Time timestamp_sample {};
标准::optional<;本征::Vector2d>; lat_lon {标准::nullopt};
标准::optional<float>; 水平方差 {标准::nullopt};
标准::optional<float>; 海拔高度标准::nullopt};
标准::optional<float>; 垂直方差 {标准::nullopt};
};
更新()
全局接口的方法希望以下条件成立 全球位置测量
:
- 样本
时间戳样本
的定义。 - 数值没有 NAN。
- 如果提供了测量值,其相关的方差值就会得到很好的定义(例如,如果
lat_lon
则水平方差
必须定义)。
下面的代码片段是一个 ROS 2 节点的示例,它使用全局导航接口向 PX4 发送包含经度、纬度和高度的测量数据:
类 我的全球测量更新节点 : 公 rclcpp::节点
{
公众:
我的全球测量更新节点()
: 节点("my_node_name";)
{
// 初始化全局接口 [1]
全球位置测量接口 =
标准::共享<;px4_ros2::全球位置测量接口>(*此);
}
空白 发送更新()
{
虽然 (运行中) { // 有可能使方法作为回调运行或在定时器上运行
// 生成全球位置测量值
rclcpp::Time timestamp_sample = ...
本征::Vector2d lat_lon = ...
浮动 水平方差 = ...
浮动 海拔高度 = ...
浮动 垂直方差 = ...
// 填充全球位置测量结构 [2]
px4_ros2全球位置测量 global_position_measurement{};
全球定位测量时间戳样本 = timestamp_sample;
global_position_measurement.lat_lon = lat_lon;
全局位置测量水平方差 = 水平方差;
global_position_measurement.altitude_msl = 海拔高度
全球位置测量垂直方差 = 垂直方差;
// 使用接口 [3] 将测量结果发送到 PX4
尝试 {
_global_position_measurement_interface->;更新(全球位置测量);
} 捕捉 (缢 px4_ros2导航接口无效参数 及样品; e) {
// 处理因 global_position_measurement 定义无效而导致的异常
RCLCPP_ERROR(get_logger(), "异常捕获: %s";, e.什么());
}
}
}
私人
标准::shared_ptr<;px4_ros2全球位置测量接口>; 全球位置测量接口;
};
接口的多个实例
使用同一接口的多个实例(如本地接口和本地接口)发送估算更新,会将所有更新信息流传到同一主题,从而导致串扰。这应该不会影响 EKF 的测量融合,但不同的测量源将变得难以区分。