遥测系统(Telemetry)使用指南¶
约 4123 个字 175 行代码 预计阅读时间 16 分钟
Telemetry 类常见方法表格¶
| 方法 | 作用 | 备注注意项 |
|---|---|---|
| addData(String key, Object value) | 添加一个键值对数据项到遥测显示 | 返回 Item 对象,支持链式调用 |
| addData(String key, String format, Object... args) | 使用格式化字符串添加键值对数据 | 支持类似 printf 的格式化字符串 |
| addLine() | 添加一个空行 | 返回 Line 对象,支持链式调用 addData |
| addLine(String lineCaption) | 添加带有标题的行 | 返回 Line 对象,支持链式调用 |
| update() | 将累积的遥测数据发送到驾驶站显示 | 每次添加数据后必须调用才能显示 |
| clear() | 清除非保留的常规遥测数据 | 不会清除日志数据和已设置为保留的数据 |
| clearAll() | 清除所有常规遥测数据,包括保留项 | 不会清除日志数据 |
| removeItem(Item item) | 移除特定的数据项 | 删除由 addData 返回的 Item 对象 |
| removeLine(Line line) | 移除特定的行 | 删除由 addLine 返回的 Line 对象 |
| setAutoClear(boolean autoClear) | 设置更新时是否自动清除数据 | 默认为 true,每次 update 前清除数据 |
| isAutoClear() | 检查是否启用了自动清除 | 返回布尔值 |
| setMsTransmissionInterval(int msInterval) | 设置遥测数据传输的最小时间间隔 | 默认值为 250ms (4Hz) |
| getMsTransmissionInterval() | 获取当前遥测数据传输间隔 | 返回毫秒值 |
| log() | 获取日志管理器对象 | 返回 Log 对象,可访问日志相关方法 |
| log().add(String message) | 添加日志消息 | 日志消息在 update 后不会被清除 |
| log().clear() | 清除所有日志消息 | 只清除日志数据,不影响普通数据 |
| log().setCapacity(int capacity) | 设置日志最大容量(行数) | 超出容量时,最旧的日志会被移除 |
| log().setDisplayOrder(DisplayOrder displayOrder) | 设置日志显示顺序 | 可选 NEWEST_FIRST 或 OLDEST_FIRST |
| addAction(Runnable action) | 添加在遥测间隔到期时要执行的操作 | 用于创建定时执行的操作 |
| speak(String text) | 通过文本到语音功能播放消息 | 立即执行,不需要调用 update 方法 |
| speak(String text, String languageCode, String countryCode) | 使用特定语言和地区播放文本 | 如 zh-CN 表示中文(中国),en-US 表示英文(美国) |
什么是遥测系统 (Telemetry)?¶
遥测系统是 FTC 机器人程序中非常重要的调试和信息显示工具。它允许您的机器人程序向驾驶站应用程序发送文本和数据,这些信息会显示在手机或平板电脑屏幕上,帮助您:
-
调试程序中的问题
-
显示传感器读数和电机状态
-
追踪程序执行流程
-
向驾驶员提供重要信息
简单来说,遥测系统就像是机器人和人类之间的"聊天窗口",让机器人可以告诉您它正在做什么、发现了什么、遇到了什么问题。
基本用法¶
1. 添加和显示数据¶
最基本的遥测操作是添加数据并更新显示:
// 添加简单文本消息
telemetry.addData("状态", "初始化完成");
// 添加带数值的消息
telemetry.addData("电机功率", 0.75);
// 添加带格式化数值的消息
telemetry.addData("电池电压", "%.1f 伏特", 12.5);
// 更新显示(发送数据到驾驶站)
telemetry.update();
要记住的重要一点:必须调用telemetry.update()才能将数据发送到驾驶站显示。
2. 覆盖与累加¶
关于数据添加和清除机制的重要说明:
-
调用addData()时,数据会被添加到遥测缓冲区,不会自动覆盖同名键的数据
-
只有在调用telemetry.update()时,系统才会根据setAutoClear设置决定是否清除数据
-
默认情况下(setAutoClear(true)),调用update()会清除之前的所有控制消息,然后发送新数据
-
当设置setAutoClear(false)时,调用update()不会清除之前的控制消息,新旧数据会一起显示
// 默认行为(setAutoClear为true)
telemetry.addData("状态", "初始化中");
telemetry.update(); // 显示"状态: 初始化中"
telemetry.addData("状态", "初始化完成");
telemetry.update(); // 清除之前数据,只显示"状态: 初始化完成"
// 设置为不自动清除
telemetry.setAutoClear(false);
telemetry.addData("状态", "初始化中");
telemetry.update(); // 显示"状态: 初始化中"
telemetry.addData("状态", "初始化完成");
telemetry.update(); // 同时显示"状态: 初始化中"和"状态: 初始化完成"
需要注意的是,addData()方法会返回 Item 类型对象,这使得您可以进行链式调用:
记住:无论自动清除设置如何,日志消息(通过log().add()添加的)始终会保留,除非明确调用telemetry.log().clear()或达到日志容量上限。
3. 多行数据¶
您可以使用以下方式添加多条相关信息:
// 方法1:使用换行符
telemetry.addData("信息", "第一行\n第二行");
// 方法2:使用链式调用
telemetry.addLine("机器人状态")
.addData("电机", "运行中")
.addData("伺服", "就位");
// 方法3:直接链式调用addData
telemetry.addData("机器人状态", "正常")
.addData("电机", "运行中")
.addData("伺服", "就位");
4. addLine 与 addData 的区别¶
addLine和addData的主要区别:
-
addData是用于添加键值对的方法(如 "速度: 50")
-
addLine是创建一个新行,可以作为多个相关数据的"标题"
-
addLine返回一个可以继续添加数据的对象,支持链式调用
-
addData返回 Item 类型,也支持链式调用,可以连续添加多条数据
示例对比:
// 使用addData链式调用
telemetry.addData("机器人状态", "正常")
.addData("电机", "0.5")
.addData("舵机", "0.7");
// 使用addLine链式调用
telemetry.addLine("驱动系统\n")
.addData("左电机", "0.5")
.addData("右电机", "0.6");
显示效果对比:
注意:默认情况下每次调用telemetry.update()前会清除之前的所有常规遥测数据(如果setAutoClear(true))。
高级功能¶
1. 延迟评估(提高性能)¶
如果某些数据计算成本较高(如传感器读数),可以使用函数延迟计算:
// 仅在实际需要发送数据时才计算电池电压(遥测传输是被限制的,以减少带宽使用)
telemetry.addData("电压", new Func<Double>() {
@Override public Double value() {
return getBatteryVoltage(); // 这个方法只在需要时调用
}
});
延迟评估的原理解释¶
延迟评估的原理是:只在实际需要显示数据时才进行计算,而不是每次调用addData时就计算。
new Func
-
创建一个"任务包",里面包含了计算数据的方法
-
遥测系统会在真正需要显示数据时,才"打开包裹"执行里面的方法
-
@Override public Double value()表示重写原有的value方法
-
return getBatteryVoltage();是实际获取数据的代码
-
整个过程类似于"懒加载",只在必要时才执行耗时操作
这对于获取传感器数据、进行复杂计算或耗时操作特别有用,可以提高程序效率。
遥测系统"打开包裹"(即执行延迟评估函数)的确切时机是由 FTC SDK 内部实现决定的,这个过程对开发者是透明的,但有几个关键时刻会触发这个行为:
-
当调用 telemetry.update()时:这是最主要的触发点。当您调用 update()方法时,遥测系统会遍历所有添加的数据项,对于那些使用 Func 对象(延迟评估)的项目,它会在此时调用其 value()方法获取实际值。
-
传输数据到驾驶站前:系统在实际将数据发送到驾驶站显示之前,会确保所有需要的值都已计算完成。
为什么延迟评估能提高效率 ?
- 如果您在一个循环中多次添加相同的数据项,但只在循环结束时调用一次 update(),那么耗时的计算只会在真正需要展示数据时执行一次,而不是每次添加数据时都计算。
2. 日志功能¶
遥测系统还提供日志功能,可以保存历史消息:
// 添加日志消息
telemetry.log().add("机器人启动");
telemetry.log().add("发现障碍物");
// 设置日志容量(保存多少行)
telemetry.log().setCapacity(10);
// 设置显示顺序(最新的在前还是最老的在前)
telemetry.log().setDisplayOrder(Telemetry.Log.DisplayOrder.NEWEST_FIRST);
普通 addData 与 log().add() 的区别¶
addData和log().add()的主要区别:
- 数据持久性:addData:显示当前状态,每次 update 后会被新数据覆盖log().add():保存历史记录,新消息会追加而不是覆盖旧消息
数据持久性:
-
addData:显示当前状态,每次 update 后会被新数据覆盖
-
log().add():保存历史记录,新消息会追加而不是覆盖旧消息
-
显示方式:addData:显示在主遥测区域,通常显示实时状态log().add():显示在日志区域(通常在主区域下方),记录历史事件
显示方式:
-
addData:显示在主遥测区域,通常显示实时状态
-
log().add():显示在日志区域(通常在主区域下方),记录历史事件
-
适用场景:addData:适合显示实时变化的数据(如电机功率、位置)log().add():适合记录事件发生(如"已完成导航"、"检测到障碍物")
适用场景:
-
addData:适合显示实时变化的数据(如电机功率、位置)
-
log().add():适合记录事件发生(如"已完成导航"、"检测到障碍物")
简单来说,addData就像仪表盘,显示当前状态;而log().add()就像行车记录仪,记录发生过的事件。
3. 清除数据¶
清除之前添加的所有数据:
clear() 与 clearAll() 的区别¶
clear()和clearAll()的区别:
-
clear():只清除通过addData或addLine添加的非保留常规遥测数据(即未设置setRetained(true)的项目)
-
clearAll():清除所有常规遥测数据(包括保留项目)以及所有动作(actions),但不会清除日志数据
重要的是要明白,无论是clear()还是clearAll(),都不会清除通过log().add()添加的日志数据。日志数据只会在以下情况被清除:
-
调用telemetry.log().clear()
-
日志数据达到了通过log().setCapacity()设置的容量上限,此时最旧的日志会被自动移除
如果您想保留日志记录但刷新实时数据,使用clear();如果想完全重置所有常规遥测数据(包括保留项目),使用clearAll()。
4. 消息持久性¶
控制遥测数据在调用update()方法时是否自动清除:
// 设置为不自动清除(新旧消息会一起显示)
telemetry.setAutoClear(false);
// 恢复默认行为(每次update前自动清除)
telemetry.setAutoClear(true);
自动清除机制解释¶
自动清除机制(setAutoClear)只影响通过addData和addLine添加的常规遥测数据,不影响日志(即通过log().add()添加的数据)。
-
当setAutoClear(true)时(默认行为):每次调用update()前会先清除之前添加的所有常规数据
-
当setAutoClear(false)时:调用update()时不会清除之前的数据,新添加的数据会与之前的数据一起显示
重要的是要理解,数据清除是在update()方法调用时发生的,而不是在添加新数据时。只有调用update(),数据才会实际发送到驾驶站显示。
日志数据(通过log().add()添加的)始终是累积的,无论自动清除设置如何,只受log().setCapacity()限制,且只能通过telemetry.log().clear()显式清除。
5. 保持某些数据始终显示¶
// 关闭自动清除
telemetry.setAutoClear(false);
// 仅清除不再需要的数据
telemetry.clear(); // 默认只清除非保留数据
// 或者使用removeItem/removeLine方法精确移除特定数据
Item tempData = telemetry.addData("临时信息", "将被移除");
telemetry.removeItem(tempData); // 只移除这一项数据
6. 格式化数字¶
// 显示两位小数
telemetry.addData("精确值", "%.2f", 3.14159);
// 显示科学计数法
telemetry.addData("大数", "%.2e", 1234567.89);
7. 使用语音功能 (speak 方法)¶
Telemetry 提供了 speak 方法,可以让驾驶站设备通过语音播报重要信息,让驾驶员不必始终盯着屏幕查看状态。
// 基本用法 - 使用默认语言朗读文本
telemetry.speak("Robot initialized");
// 指定语言和地区进行朗读
telemetry.speak("Ready to start", "en", "US"); // 英文(美国)
telemetry.speak("Commencer la mission", "fr", "FR"); // 法语(法国)
speak 方法与 addData 的区别¶
-
执行机制不同:speak()方法会立即发送语音请求到驾驶站,不需要调用update()addData()添加的数据必须通过update()才能发送到驾驶站显示
-
speak()方法会立即发送语音请求到驾驶站,不需要调用update()
-
addData()添加的数据必须通过update()才能发送到驾驶站显示
-
使用场景不同:speak()适合传达需要驾驶员立即注意的重要信息addData()适合显示需要持续监控的状态信息
-
speak()适合传达需要驾驶员立即注意的重要信息
-
addData()适合显示需要持续监控的状态信息
speak 方法使用技巧¶
- 添加延时:在连续调用多个speak()方法时,应添加适当延时javatelemetry.speak("Object detected");sleep(2000);// 等待语音完成telemetry.speak("Starting navigation");123
添加延时:在连续调用多个speak()方法时,应添加适当延时
- 语言和地区代码:语言代码(languageCode):使用 ISO 639 标准的双字母代码"zh" - 中文"en" - 英文"ja" - 日语"ko" - 韩语国家/地区代码(countryCode):使用 ISO 3166 标准的双字母代码"CN" - 中国"US" - 美国"GB" - 英国"JP" - 日本
语言和地区代码:
-
语言代码(languageCode):使用 ISO 639 标准的双字母代码"zh" - 中文"en" - 英文"ja" - 日语"ko" - 韩语
-
"zh" - 中文
-
"en" - 英文
-
"ja" - 日语
-
"ko" - 韩语
-
国家/地区代码(countryCode):使用 ISO 3166 标准的双字母代码"CN" - 中国"US" - 美国"GB" - 英国"JP" - 日本
-
"CN" - 中国
-
"US" - 美国
-
"GB" - 英国
-
"JP" - 日本
-
在 Driver Hub 上启用 TTS 功能:在 Driver Hub 上打开 FTC Driver Station 应用点击右上角的三点菜单(⋮)在菜单中选择 Settings (设置)将 Sound 选项设置为 ON
在 Driver Hub 上启用 TTS 功能:
-
在 Driver Hub 上打开 FTC Driver Station 应用
-
点击右上角的三点菜单(⋮)
-
在菜单中选择 Settings (设置)
-
将 Sound 选项设置为 ON
-
适度使用:避免频繁使用语音功能,以免干扰驾驶员优先用于关键状态变化和警告信息保持语音提示简短明了
适度使用:
-
避免频繁使用语音功能,以免干扰驾驶员
-
优先用于关键状态变化和警告信息
-
保持语音提示简短明了
示例:使用 speak 方法的完整示例
@TeleOp(name="语音提示演示")
public class SpeakDemo extends LinearOpMode {
@Override
public void runOpMode() {
// 初始化提示
telemetry.speak("Robot initialized");
telemetry.addData("Status", "Initialized");
telemetry.update();
waitForStart();
// 开始提示
telemetry.speak("Starting operation", "en", "US");
while (opModeIsActive()) {
// 检测障碍物示例
if (isObstacleDetected()) {
telemetry.speak("Warning, obstacle detected");
sleep(2000); // 给语音足够的播放时间
}
// 正常遥测数据更新
telemetry.addData("Motor Power", motorPower);
telemetry.update();
}
}
private boolean isObstacleDetected() {
// 假设的障碍物检测逻辑
return false;
}
}
8. 移除特定遥测数据 (removeItem 和 removeLine 方法)¶
Telemetry 提供了两个方法来移除已添加但尚未发送的特定遥测数据:
// 保存addData返回的Item引用
Item motorItem = telemetry.addData("Motor Power", 0.5);
Item servoItem = telemetry.addData("Servo Position", 0.3);
// 稍后移除特定数据项
telemetry.removeItem(motorItem); // 只移除电机功率数据
// 保存addLine返回的Line引用
Line statusLine = telemetry.addLine("Status")
.addData("Mode", "AUTO")
.addData("Task", "Navigation");
// 稍后移除整行
telemetry.removeLine(statusLine); // 移除整个状态行及其所有数据
removeItem 和 removeLine 的应用场景¶
- 动态管理显示信息:在不同阶段显示不同信息,移除不再相关的数据在保持setAutoClear(false)的同时,选择性地移除特定数据
动态管理显示信息:
-
在不同阶段显示不同信息,移除不再相关的数据
-
在保持setAutoClear(false)的同时,选择性地移除特定数据
-
条件显示:只在特定条件下显示某些信息例如:只在检测到障碍物时显示障碍物信息,其余时间移除此信息
条件显示:
-
只在特定条件下显示某些信息
-
例如:只在检测到障碍物时显示障碍物信息,其余时间移除此信息
-
优化显示空间:在屏幕空间有限时,移除暂时不重要的信息优先显示当前阶段最关键的数据
优化显示空间:
-
在屏幕空间有限时,移除暂时不重要的信息
-
优先显示当前阶段最关键的数据
removeItem/removeLine 与 clear 的区别¶
-
removeItem/removeLine:精确移除特定的数据项或行,其他数据保持不变
-
clear():移除所有非保留数据
-
clearAll():移除所有数据,包括保留项
注意事项¶
-
引用保存:必须保存addData或addLine返回的引用,才能稍后移除
-
立即生效:移除操作立即生效,但只有调用update()后才会在驾驶站更新显示
-
替代方法:如果不需要保留引用,可以考虑使用条件性的addData来控制显示内容
9. 控制遥测数据刷新频率¶
setMsTransmissionInterval(int msInterval)方法用于设置遥测数据传输的最小时间间隔,影响数据刷新频率。
// 设置更新频率为每秒10次(100毫秒)
telemetry.setMsTransmissionInterval(100);
// 设置更新频率为每秒2次(500毫秒)
telemetry.setMsTransmissionInterval(500);
setMsTransmissionInterval 与 update 的关系¶
setMsTransmissionInterval和update()方法的关系是:
- 最小间隔限制:setMsTransmissionInterval设置的是数据发送的最小时间间隔即使您频繁调用update(),系统也不会超过这个频率发送数据默认值为 250 毫秒(4Hz),即每秒最多发送 4 次数据
最小间隔限制:
-
setMsTransmissionInterval设置的是数据发送的最小时间间隔
-
即使您频繁调用update(),系统也不会超过这个频率发送数据
-
默认值为 250 毫秒(4Hz),即每秒最多发送 4 次数据
-
实际更新机制:当您调用update()时,系统会检查距离上次发送数据是否已超过设定的间隔如果间隔不足,虽然update()会执行(准备数据),但不会实际发送数据只有当时间间隔满足条件时,数据才会发送到驾驶站
实际更新机制:
-
当您调用update()时,系统会检查距离上次发送数据是否已超过设定的间隔
-
如果间隔不足,虽然update()会执行(准备数据),但不会实际发送数据
-
只有当时间间隔满足条件时,数据才会发送到驾驶站
-
实际刷新频率: 实际数据刷新频率 = min(update 调用频率, msInterval)
实际刷新频率: 实际数据刷新频率 = min(update 调用频率, msInterval)
示例:
// 设置最小间隔为100毫秒
telemetry.setMsTransmissionInterval(100);
// 情况1:每50毫秒调用一次update
while (opModeIsActive()) {
updateSensorData();
telemetry.update(); // 实际上每100毫秒才会发送一次
sleep(50);
}
// 情况2:每200毫秒调用一次update
while (opModeIsActive()) {
updateSensorData();
telemetry.update(); // 每次调用都会发送,因为已超过最小间隔
sleep(200);
}
应用场景¶
-
调试场景:设置较短间隔(50-100ms)获取更实时的反馈
-
比赛场景:使用较长间隔(250-500ms)减轻通信负担
-
传感器监控:根据传感器更新频率调整最小间隔
实用场景¶
1. 传感器调试¶
// 显示颜色传感器值
telemetry.addData("颜色", "R:%d G:%d B:%d",
colorSensor.red(), colorSensor.green(), colorSensor.blue());
// 显示距离传感器值
telemetry.addData("距离", "%.1f 厘米", distanceSensor.getDistance(DistanceUnit.CM));
2. 状态机调试¶
telemetry.addData("当前状态", currentState.toString());
telemetry.addData("计时器", "%.1f 秒", stateTimer.seconds());
3. 自动驾驶进度¶
总结¶
遥测系统是连接机器人和人类操作者的桥梁,有效使用它可以:
-
加速调试过程
-
提高驾驶员对机器人状态的了解
-
帮助追踪复杂程序的执行流程
-
诊断传感器和电机问题
从简单的文本消息开始,逐步添加更复杂的数据显示,很快您就能掌握这个强大工具的各种用法!
参考资源¶
-
FTC SDK 官方文档
-
Telemetry 类 JavaDocs
-
ConceptTelemetry.java 示例