ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

让 T1 Pro 报个电量:Python 读取电池状态与 ROS2 语音播报

让 T1 Pro 报个电量:Python 读取电池状态与 ROS2 语音播报

@TOC


🌌你好!这里是 晓雨的笔记本
在所有感兴趣的领域扩展知识,感谢你的陪伴与支持~
👋 欢迎添加好友 is_yu_ei,不定期掉落福利资讯

写在最前面

版权声明:本文为原创技术实践稿,遵循 CC 4.0 BY-SA 协议。转载请注明出处。涉及官方 SDK 的接口描述及开源项目代码,请以所链接的官方资料和仓库许可证为准。

“现在还剩多少电?”这句话很适合作为 T1 Pro 开发的第一个小目标:终端能显示电量,应用能把数值组织成一句话,再交给语音服务。看起来只是报个数字,背后却连着状态订阅、字段换算和服务调用。哪一步没对上,也容易顺着这条短链路找到原因。

本文围绕这个目标,使用启元公开 T1 ROS 2 SDK 的 Bms 话题和 PlayTts 服务,写一个 Python 入门程序。先通过配套 mock 分支检查数据与请求,再按文末步骤接入设备。环境、代码入口和日志字段都围绕同一个例子展开。[1][2]

图 1|“读状态、说一句”的应用通路:BMS 持续发布状态,Python 组织文本,TTS 接收播报请求。

一个小目标,练到两种接口

Topic 适合持续更新:机器人有新状态,订阅程序就收到新样本。Service 适合按需请求:应用准备好一句话,再发起一次调用。把二者接起来,读者可以同时练到消息类型导入、状态读取、请求构造和回执检查,而不必一开始就处理复杂任务。

1 先把消息类型装进 Python 环境

这篇采用外部开发 PC:PC 运行 Python 应用,T1 运行原厂服务,两者通过局域网通信。官方快速入门推荐 Ubuntu 22.04 与 ROS 2 Humble;本例沿用 Humble 的系统 Python,把环境范围收在状态订阅和语音调用上。[1]

组件本篇用途
Ubuntu 22.04 / ROS 2 Humble运行 rclpy 和 ROS 2 命令行工具
aimdk_msgs生成并导入官方 msg / srv 类型
Python 3.10(Humble 系统环境)运行设备侧接口客户端
已发布 AtomGit 仓库 t1-pro-sdk-demos离线回放、请求构造与响应检查

完成 ROS 2 官方安装步骤后,先构建 aimdk_msgs 消息包。它负责生成 Python 能导入的 msg / srv 类型。下面只选择本例需要的包;官方全量例程的依赖安装方法见快速入门指南。下载中心的 T1 SDK 标记为 v1.0.0.0,复现时再记录源码提交,便于对齐具体文件。[1][2]

source/opt/ros/humble/setup.bashgitclone https://github.com/PrimebotTech/primebot-t1-sdk.gitcdprimebot-t1-sdksudoaptinstallpython3-colcon-common-extensions\ros-humble-rosidl-default-generators\ros-humble-rosidl-default-runtime python3-devgitrev-parse HEAD# 记录本次 SDK 源码版本colcon build --packages-select aimdk_msgs --symlink-installsourceinstall/setup.bash python3-c"from aimdk_msgs.msg import Bms; print('Bms import OK')"

每开一个新终端,依次加载 ROS 基础环境和 SDK 的 install/setup.bash。前者提供 rclpy,后者提供自定义消息与通信配置。看到“Bms import OK”后,再进入程序逻辑,这样导入错误就不会和网络问题混在一起。

本例依赖 ROS 2、官方消息包与少量 Python 代码,普通开发 PC 即可完成接口练习。

2 读到电量后,先把单位换对

电量入口是话题 /aima/hal/bms/state,消息类型是 aimdk_msgs/msg/Bms。官方 Python 例程采用 SensorData QoS,本例保持一致。订阅时同时对齐“话题名、类型、QoS”,收到的消息才能进入回调。[3]

字段含义与处理
remaining_capacity_percentage电量百分比,直接按 0–100 显示
voltage毫伏,除以 1000 得到伏特
current毫安,除以 1000 得到安培;正值充电、负值放电
temperature摄氏度;原值保留
status位掩码,需要逐位解释,不能把非零全部当作故障
fromrclpy.qosimportqos_profile_sensor_datafromaimdk_msgs.msgimportBms## 在 Node 的 __init__ 中订阅:self.sub=self.create_subscription(Bms,'/aima/hal/bms/state',self.on_battery,qos_profile_sensor_data)defon_battery(self,msg):pct=msg.remaining_capacity_percentage voltage_v=msg.voltage/1000.0current_a=msg.current/1000.0self.get_logger().info(f'电量={pct}% 电压={voltage_v:.2f}V 'f'电流={current_a:.2f}A')

例如,消息里 voltage=24200、current=-1200 时,终端应显示 24.2 V 和 -1.2 A。负电流对应放电。status 则是一组状态位:bit 2 表示放电,bit 23 表示电池包异常。它们都可能让数值非零,所以展示时要逐位解释。[3]

有一个很实用的排查顺序:先用 ros2 interface show 检查本地消息定义,再用 ros2 topic info -v 查看发布端和 QoS,最后看回调日志。话题列表解决“通道在哪”,消息类型解决“数据怎么读”;两步分开检查,定位会快很多。

3 发出一句话,再读懂服务回执

公开文档中的 TTS 服务名是 /aimdk_5Fmsgs/srv/PlayTts,服务类型是 aimdk_msgs/srv/PlayTts。前者是运行时地址,后者定义请求对象。保留服务名里的 5F 写法,并在现场用 ros2 service list -t 对照一次即可。[4]

req=PlayTts.Request()req.header.header.stamp=node.get_clock().now().to_msg()req.tts_req.text='你好,T1,SDK 连接测试。'req.tts_req.priority_level.value=TtsPriorityLevel.INTERACTION_L6 req.tts_req.priority_weight=0req.tts_req.domain='t1_pgc_demo'req.tts_req.trace_id=str(uuid.uuid4())req.tts_req.is_interrupted=Falsefuture=client.call_async(req)

请求中最容易写错的是时间戳:外层 header 是 CommonRequest,它内部还有一个 header,因此字段路径是 req.header.header.stamp。domain 说明请求来自哪个应用,trace_id 关联这次请求与日志。普通问候使用 INTERACTION_L6,同优先级请求选择排队处理。[4]

图 2|TTS 回执按框架码、业务状态和语音结果逐层检查,预计时长与诊断信息一并保留。

future 完成后,继续读取框架码 code、业务状态 status.value 和语音结果 is_success。成功条件是三项同时满足;预计时长 estimated_duration 以毫秒计。超时日志则保留“结果未知”和 trace_id,先查回执与现场状态,再决定是否重发。[4]

4 先看一轮输出,再切换到设备

从 AtomGit 获取文末指定版本后,在仓库根目录执行下面的命令。mock 分支构造一条电池消息和一份 TTS 回执:76%、24.2 V、-1.2 A 是固定测试输入,用来检查换算和输出,运行时不需要 ROS。

gitclone https://atomgit.com/WTYuong/t1-pro-sdk-demos.gitcdt1-pro-sdk-demosgitcheckout 3a62e33 python3-mpipinstall-rrequirements-core.txt python3 sdk_hello.py--mockpython3-munittest discover-stests-v## 另开终端,加载 ROS 和 SDK 后进入本仓库:python3 sdk_hello.py--livepython3 sdk_hello.py--live--speak
检查项mock / 单元测试结果
字段换算76%、24.2 V、−1.2 A,与合成输入一致
框架失败、业务失败、TTS 失败均被响应检查逻辑拒绝
请求嵌套路径与优先级按官方字段结构完成对象级测试
整套代码单元测试40 项通过;记录在 results/unit_tests.txt

本轮重新运行,40 项单元测试全部通过,四个示例的 mock 入口也正常结束。这里检查的是 Python 数据处理与请求对象逻辑;接入设备后,再沿同一条日志链路检查 DDS 收发和实际播报。

出问题时,从哪一层开始看?

现象优先排查
无法导入 aimdk_msgs构建是否成功;本终端是否加载 install/setup.bash
只有 /rosout,看不到设备节点开发模式、同一网段、ROS_DOMAIN_ID 与网卡绑定
能读电量,TTS 找不到服务核对 service list -t 的名称和类型
返回成功但现场无声音依次查看静音、音量和音频设备,再决定是否重发

5 留下一个以后还能复用的小工具

首次接入时,按照官方 App 中的启用须知选择基础开发模式,并完成模式生效步骤。确认 PC 与 T1 网络连通,加载 SDK 环境后查看 node list、topic list 和 service list -t。多网卡、Domain ID 或缓冲区配置问题,集中对照官方通信章节处理。[1]

程序先用 --live 读取状态;确认电量输出、音量和静音设置后,再加 --speak 发起一次播报。把这两个动作做成独立开关,调试状态显示时就可以保持安静,需要演示完整请求时再开启声音。

现场建议保留六项信息:SDK 提交、设备固件版本、话题与服务名、首条样本时间、请求 trace_id、服务回执。以后遇到“昨天能用,今天怎么没声音”,这几项记录就能帮助区分版本变化、网络问题和请求失败。

结语

从一句“现在还剩多少电”出发,我们得到了一套小而完整的 SDK 使用顺序:导入类型、订阅状态、转换单位、组织请求、检查回执。下一篇做低电量提醒时,电池客户端和语音函数都可以直接复用,新增工作主要落在应用规则上。

源码与复现

公开仓库:WTYuong/t1-pro-sdk-demos | 本文示例版本:3a62e33

复现版本:git checkout 3a62e33(克隆并进入仓库后执行)。

本篇代码:sdk_hello.py · ros_io.py · tests/test_io.py

复现命令(仓库根目录):python3 sdk_hello.py --mock # 电池状态与 TTS 响应离线验证

本篇先运行 --mock;整套测试命令为 python3 -m unittest discover -s tests -v。加载 ROS / SDK 环境后用 --live 读设备状态,再用 --live --speak 验证播报。

资料与代码来源

[1] T1 SDK 快速入门与集成指南 查看原文

[2] 启元开发者社区:T1 SDK 下载入口 查看原文

[3] Bms.msg:电池字段与状态位 查看原文

[4] PlayTts.srv 与请求/响应类型 查看原文

[5] 配套实现与测试:sdk_hello.py、ros_io.py、tests/test_io.py;对应代码提交 3a62e33。

技术资料核对日期:2026-10-20。配图依据公开接口与本文应用流程绘制。

继续开发时,可到启元机器人开发者社区(https://dev.primebot.com/)查阅 SDK、接口文档与开发案例,也欢迎分享自己的复现记录和改进思路。


hello,这里是 晓雨的笔记本。如果你喜欢我的文章,欢迎三连给我鼓励和支持:👍点赞 📁关注 💬评论,我会给大家带来更多有用有趣的文章。

原文链接 👉 【发布后更新】

欢迎大家点开下面名片,添加好友交流。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进