上一课练习答案
第 1 题
auto f = []()
{
std::cout << "Hi";
};
这里只是:
定义了 lambda。
还没有执行。
必须:
f();
才执行。
第 2 题
int x = 10;
auto f = [x]()
{
std::cout << x;
};
x = 20;
f();
通常输出:
10
因为:
[x]
是按值捕获,相当于保存了当时 x = 10 的一份副本。
第 3 题
int x = 10;
auto f = [&x]()
{
x = 50;
};
f();
最后:
x = 50
因为:
[&x]
是按引用捕获。
第 4 题
[this]()
{
speed = 100;
}
[this] 表示:
这个 lambda 可以访问当前对象的成员。
所以:
speed = 100;
实际上是在操作当前对象自己的 speed。
第 5 题
msg->data
如果 msg 是智能指针,就是:
通过
msg找到它管理的消息对象,然后访问这个消息对象里的data成员。
第 29 课:回调函数 Callback
这一课是我们真正开始进入 ROS2 思维的关键课。
先记一句:
回调函数 = 现在把函数交出去,将来某件事情发生时,由系统替你调用。
它和普通函数最大的区别不是"函数长得不一样",而是:
谁负责调用它。
1. 普通函数
例如:
void hello()
{
std::cout << "Hello";
}
你必须主动:
hello();
流程:
你的代码
↓
主动调用 hello()
↓
hello 执行
2. 回调不是你主动调用
假设我们有:
void onMessage(int data)
{
std::cout << data;
}
普通情况下你可以:
onMessage(10);
但是在回调模式里,我们希望:
把
onMessage告诉系统。
然后系统说:
"好,以后消息来了我帮你调用。"
流程变成:
你把函数交给系统
↓
程序继续运行
↓
消息到达
↓
系统自动调用这个函数
这就是 callback。
3. 用生活例子理解
你去餐厅排队。
服务员说:
"留下电话号码,有位置了我联系你。"
你不是站在那里不停问:
有位置了吗?
有位置了吗?
有位置了吗?
而是:
把联系方式交出去
↓
等待
↓
条件满足
↓
别人主动找你
回调就是这种思想。
4. 为什么 ROS2 特别需要回调?
因为机器人程序大量事件不是你能预测准确时间的。
例如:
相机图像什么时候到?
JointState什么时候来?
激光雷达什么时候更新?
VLA Action什么时候生成?
Service请求什么时候来?
你不能写:
if (现在消息来了)
然后一直傻等。
ROS2 更喜欢:
消息到达时自动执行你的函数。
5. ROS2 subscriber 的核心逻辑
比如订阅:
/joint_states
可以理解成:
程序启动
↓
创建 subscriber
↓
告诉 ROS2:
"收到 JointState 后执行 callback"
↓
继续等待
↓
JointState 到达
↓
ROS2 自动调用 callback(msg)
这就是 subscriber 的灵魂。
6. 为什么 lambda 很适合 callback?
例如:
auto callback = [](int data)
{
std::cout << data;
};
这个 lambda 本身就是:
一段可以被别人以后调用的功能。
所以可以想象:
registerCallback(callback);
意思:
把 callback 交给系统。
以后系统内部可以:
callback(100);
7. 一个最简单的模拟回调
先不用 ROS2:
#include <iostream>
void runCallback(void (*callback)(int))
{
callback(100);
}
这里出现一个新的东西:
void (*callback)(int)
它是:
函数指针
先不要深入语法。
你只需要理解:
runCallback()接收的不是普通数字,而是"一个函数"。
然后:
void printData(int data)
{
std::cout << data << std::endl;
}
调用:
runCallback(printData);
执行过程:
把 printData 函数交给 runCallback
↓
runCallback 内部决定什么时候调用
↓
callback(100)
↓
实际上执行 printData(100)
输出:
100
8. 重点不是函数指针语法
对你现在最重要的是理解:
函数也可以像"数据"一样交给另一个系统
然后:
由对方在未来合适的时候调用。
ROS2 正是大量使用这种模式。
9. ROS2 风格
以后你会看到类似:
[this](const Msg::SharedPtr msg)
{
current_angle = msg->angle;
}
这个 lambda 就可以作为:
subscriber callback。
意思:
ROS2 收到消息后,执行这段代码。
10. 放到 VLA 里
未来你真正可能搭这样的链路:
VLA模型
↓
产生动作
↓
发布 ROS2 Action Topic
↓
机器人控制节点订阅
↓
Action 消息到达
↓
callback 自动执行
↓
解析 msg
↓
生成关节目标
↓
发送给仿真/真机
所以你现在学习 callback,不是在学一个孤立的 C++ 语法。
它直接对应:
VLA 输出怎样进入 ROS2 机器人控制系统。
本课先记住三个角色
以后看到 ROS2 subscriber 时,先找:
1. 谁在监听?
subscriber
2. 监听什么?
topic / message
3. 消息来了做什么?
callback
这是一个非常重要的 ROS2 阅读框架。
本课小练习
1
普通函数:
hello();
是谁主动调用?
2
回调函数最大的特点是什么?
3
如果一个 ROS2 subscriber 订阅:
/joint_states
那么 callback 一般在什么时候执行?
4
为什么 lambda 很适合用作 callback?
5
VLA 发布了一个新的动作消息后,控制节点的 subscriber callback 最可能负责做什么?