背景
当前项目中使用 fast_tf 作为 TF(Transform)树管理库,但在实际使用中发现接口设计存在一些不够友好的地方。我们已经在 rmcs_auto_aim_v2 中实现了一个更友好的 static_tf 接口,希望评估是否可以替换 fast_tf。
接口对比
fast_tf 接口设计
定义方式:
// 需要为每个 Link 特化 Joint 模板
template <>
struct fast_tf::Joint<rmcs_description::OdomImu> : fast_tf::ModificationTrackable {
using Parent = rmcs_description::PitchLink;
Eigen::Quaterniond transform = Eigen::Quaterniond::Identity();
};
// 使用 JointCollection 作为容器
using Tf = fast_tf::JointCollection<
GimbalCenterLink, YawLink, PitchLink, MuzzleLink,
TransmitterLink, CameraLink, OdomImu, ...>;
使用方式:
// 需要实例化对象
InputInterface<rmcs_description::Tf> rmcs_tf;
// 获取变换需要传入类型参数和实例
auto transform = fast_tf::lookup_transform<
rmcs_description::BaseLink,
rmcs_description::OdomImu
>(*rmcs_tf);
// 设置变换需要实例
rmcs_tf->set_transform<From, To>(value);
特点:
- ✅ 类型安全(使用类型作为链接标识)
- ❌ 需要为每个 Link 编写模板特化代码
- ❌ 需要实例化
JointCollection 对象
- ❌ 接口分散(
lookup_transform 是全局函数,set_transform 是成员函数)
- ❌ 错误提示不够友好(模板错误信息冗长)
static_tf 接口设计
定义方式:
// 使用嵌套 Joint 构造树结构,声明式风格
constexpr auto static_tf = Joint {
Link<"0">(),
Joint {
Link<"0.0", Eigen::Isometry3d>(),
Joint { Link<"0.0.0", Eigen::Isometry3d>() },
},
Joint {
Link<"0.1", Eigen::Isometry3d>(),
Joint { Link<"0.1.1", Eigen::Isometry3d>() },
},
};
using SentryTf = decltype(static_tf);
使用方式:
// 静态方法,无需实例化
auto transform = SentryTf::look_up<"0.1.1", "0.0.0.0", Eigen::Isometry3d>();
// 获取/设置状态使用字符串名称
auto state = SentryTf::get_state<"0.0", Eigen::Isometry3d>();
SentryTf::set_state<"0.0">(Eigen::Isometry3d::Identity());
// 支持 YAML 序列化
auto result = serialize_from<SentryTf>(yaml);
特点:
- ✅ 声明式树结构定义,直观易读
- ✅ 使用
StaticString(编译时字符串)作为链接标识
- ✅ 静态接口,无需实例化
- ✅ 统一的接口设计(所有操作都是静态方法)
- ✅ 友好的中文错误提示
- ✅ 支持 YAML 序列化/反序列化
- ✅ 编译时树结构验证
- ⚠️ 使用字符串而非类型(类型安全性稍弱,但编译时检查)
功能对比
| 功能 |
fast_tf |
static_tf |
| 树结构定义 |
模板特化 + JointCollection |
嵌套 Joint 构造 |
| 链接标识 |
类型(Type) |
字符串(StaticString) |
| 实例化 |
需要 |
不需要(静态) |
| 获取变换 |
lookup_transform<From, To>(instance) |
Tree::look_up<"from", "to", Type>() |
| 设置变换 |
instance.set_transform<From, To>(value) |
Tree::set_state<"name">(value) |
| 获取状态 |
instance.get_transform<From, To>() |
Tree::get_state<"name", Type>() |
| YAML 序列化 |
❌ |
✅ |
| 错误提示 |
模板错误(英文) |
友好的中文提示 |
| 编译时验证 |
✅ |
✅ |
| 运行时性能 |
相同(都是编译时计算) |
相同 |
待讨论的问题
- 是否需要保持与
fast_tf 的兼容性?
- 字符串标识 vs 类型标识的权衡
- 迁移成本和风险评估
- 性能对比(虽然理论上应该相同)
相关代码
背景
当前项目中使用
fast_tf作为 TF(Transform)树管理库,但在实际使用中发现接口设计存在一些不够友好的地方。我们已经在rmcs_auto_aim_v2中实现了一个更友好的static_tf接口,希望评估是否可以替换fast_tf。接口对比
fast_tf 接口设计
定义方式:
使用方式:
特点:
JointCollection对象lookup_transform是全局函数,set_transform是成员函数)static_tf 接口设计
定义方式:
使用方式:
特点:
StaticString(编译时字符串)作为链接标识功能对比
lookup_transform<From, To>(instance)Tree::look_up<"from", "to", Type>()instance.set_transform<From, To>(value)Tree::set_state<"name">(value)instance.get_transform<From, To>()Tree::get_state<"name", Type>()待讨论的问题
fast_tf的兼容性?相关代码
static_tf实现:static_tf.hppstatic_tf测试:static_tf.cpp