语音-LLM交互通路实现
本示例测试于RDK S100 & S100P平台,外设接线如下图所示。
※LLM(1.5B)演示效果预览※
从语音指令输入结束开始,LLM语音首字响应达到1.5s
1、设备确认与测试
参考来源:3.2.1 RDK S100 系列音频使用指南 | RDK DOC
- 确认设备编号
### 1、确认设备编号
arecord -l
aplay -l
# 检查硬件支持能力 1,0对应卡号和设备号
arecord --dump-hw-params -Dhw:1,0
aplay --dump-hw-params -Dhw:1,0 /dev/zero
- 本地音频收放测试
### 2、录音
arecord -Dhw:1,0 -c 1 -r 16000 -f S16_LE -t wav -d 5 test.wav
# 音频转换
ffmpeg -i test.wav -ac 2 -ar 48000 test_c2.wav
# 音频播放
aplay -Dhw:1,0 test_c2.wav
2、算法包安装:
sudo apt update
# ROS2编译工具安装
sudo apt install python3-colcon-common-extensions
# 安装算法包
sudo apt install tros-humble-sensevoice-ros2\
tros-humble-hobot-tts \
tros-humble-hobot-xlm
3、单步测试
3.1 文本转语音(TTS)
通过TTS模型实现文本转语音功能。
# 安装tts_model并解压到tros下
wget http://archive.d-robotics.cc/tts-model/tts_model.tar.gz
sudo tar -xf tts_model.tar.gz -C /opt/tros/${TROS_DISTRO}/lib/hobot_tts/
- 启动TTS节点
source /opt/tros/humble/setup.bash
# 屏蔽调式打印信息
export GLOG_minloglevel=1
# 启动,配置对应的设备号
ros2 run hobot_tts hobot_tts --ros-args -p playback_device:="plughw:1,0"
- 测试,手动发布话题进行测试,发布话题后音频设备应有声音输出。
ros2 topic pub --once /tts_text std_msgs/msg/String "{data: "" 你好,我是地瓜机器人小助手""}"
3.2 语音转文本(ASR)
参考来源:Sensevoice | RDK DOC
通过ASR的.gguf模型实现语音转文本功能。
模型路径:/opt/tros/humble/lib/sensevoice_ros2/model/
- 启动ASR节点
source /opt/tros/humble/setup.bash
ros2 run sensevoice_ros2 sensevoice_ros2 --ros-args -p push_wakeup:=0 \
-p asr_pub_topic_name:=/prompt_text \
-p micphone_name:="plughw:1,0"
向音频设备说话后,输出示例如下:
※※※需要注意的是,文本话题的发布需要使用唤醒词“你好”来触发。※※※

3.3 LLM(hbm量化格式)
- 下载LLM量化模型(.hbm格式)
在S100(P)系统中创建一个工作目录(如~/Audio_LLM/),下载量化模型到本地,这里以官方支持的DeepSeek_R1_Distill_Qwen_1.5B作为示例。
mkdir Audio_LLM && cd Audio_LLM
wget -c ftp://oeftp@sdk.d-robotics.cc/oe_llm/model/DeepSeek_R1_Distill_Qwen_1.5B_1024.hbm --ftp-password=Oeftp~123$%
- 添加配置文件,从tros中复制
# config中为示例使用的模型配置文件
cp -r /opt/tros/humble/lib/hobot_xlm/config/ .
添加后的工作目录结构如下所示:
- 默认系统配置即可体验该功能。若模型参数量大,可以尝试修改系统配置来满足推理需求。
# 设置 ION 内存空间最大, 满足大模型推理需求
# S100建议体验1.5B模型,设置ION分配策略为balanced
# S100P则推荐体验7B模型,设置ION分配策略为bpu_first
/usr/hobot/bin/hb_switch_ion.sh balanced # 更激进的话,使用bpu_first参数
reboot
# 设置性能模式(仅S100P)
devmem 0x2b047000 32 0x99
devmem 0x2b047004 32 0x99
- 在当前工作目录下(存在模型文件和config配置),启动订阅发布方式节点:
source /opt/tros/humble/setup.bash
lib=/opt/tros/humble/lib/hobot_xlm/lib
export LD_LIBRARY_PATH=${lib}:${LD_LIBRARY_PATH}
# 启动
ros2 run hobot_xlm hobot_xlm --ros-args -p feed_type:=1 \
-p ros_string_sub_topic_name:="/prompt_text" \
-p model_name:="DeepSeek_R1_Distill_Qwen_1.5B"
- 手动发布/prompt_text话题:
ros2 topic pub --once /prompt_text std_msgs/msg/String "{data: ""Please make a self-introduction in Chinese""}"
测试示例如下:
4、语音交互
- 基本的语音交互流程:
用户音频输入 —> ASR语音识别,发布提示词话题(如/prompt_text) —> LLM接收提示词话题,推理后发布语音文本话题(如/tts_text) —> TTS接收语音文本话题,输出音频。
4.1 基于hbm量化模型
以下流程主要用于LLM的hbm量化模型实现语音交互
板端audio_llm功能包仓库: Willian-Marshell/audio_llm
-
从github仓库中获取
audio_llmpython功能包,在工作空间下进行编译,编译后source:source install/setup.bash。 -
编译完成后,即可在LLM的工作目录(包含模型和配置文件)下运行启动文件了。
cd /path/to/your/hbm_llm #该目录下需要有hbm模型文件、config配置目录
# 启动launch
ros2 launch audio_llm audio_xlm.launch.py
语音交互测试效果如下:
4.2 基于gguf量化模型
除了使用hbm量化形式的LLM来进行语音交互外,还可以使用gguf量化形式的LLM,llama-cpp原生支持gguf格式LLM,因此可以使用tros的hobot-llamacpp算法包来进行推理。
- 新建
Llama_LLM工作目录、安装算法包及模型
sudo apt update
# 安装llamacpp及其依赖包
sudo apt install tros-humble-hobot-llamacpp tros-humble-hobot-shm
# 新建工作目录
mkdir Llama_LLM && cd Llama_LLM
# LLM模型、ViT模型下载
wget https://hf-mirror.com/D-Robotics/InternVL2_5-1B-GGUF-BPU/resolve/main/Qwen2.5-0.5B-Instruct-Q4_0.gguf
wget https://hf-mirror.com/D-Robotics/InternVL2_5-1B-GGUF-BPU/resolve/main/rdks100/vit_model_int16.hbm
# 从tros工作空间中复制配置文件
cp -r /opt/tros/humble/lib/hobot_llamacpp/config/ .
- 模型测试
在Llama_LLM工作目录下,使用静态图片对ViT和LLM进行测试:
ros2 run hobot_llamacpp hobot_llamacpp --ros-args -p feed_type:=0 \
-p image:=config/image2.jpg \
-p image_type:=0 -p user_prompt:="描述一下这张图片." \
-p model_file_name:=vit_model_int16.hbm \
-p llm_model_name:=Qwen2.5-0.5B-Instruct-Q4_0.gguf
- 语音交互
通过hobot_llamacpp中的launch文件进行启动,这里将其中的两个launch文件copy到前面创建的功能包audio_llm中,并执行编译。
# 复制启动文件
cd /path/to/rdk_ws/src/audio_llm/launch/
cp /opt/tros/humble/share/hobot_llamacpp/launch/llama_llm.launch.py .
cp /opt/tros/humble/share/hobot_llamacpp/launch/llama_vlm.launch.py .
# 编译
cd /path/to/your/rdk_ws
colcon build
编译完成后在Llama_LLM工作目录(包含模型和配置文件)下运行即可,效果如下。
# 启动llm对话,选择对应的音频设备
ros2 launch audio_llm llama_llm.launch.py audio_device:="plughw:1,0"
# 选择相机类型
export CAM_TYPE=usb #或者mipi
source rdk_ws/install/setup.bash
cd llama_VLM/
# 启动ViT+LLM图文对话,同时指定vit模型名称、选择对应的音频设备
ros2 launch audio_llm llama_vlm.launch.py \
llamacpp_vit_model_file_name:=vit_model_int16.hbm \
audio_device:="plughw:1,0"
附录(创建audio_llm功能包)
创建ros2工作空间、新建python功能包
mkdir -p rdk_ws/src
cd rdk_ws/src
ros2 pkg create --build-type ament_python audio_llm
在功能包目录下创建launch文件夹并添加audo_xlm.launch.py启动文件。
cd audio_llm
mkdir launch && cd launch
nano audio_xlm.launch.py
#打开文件后写入如下代码
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
push_wakeup = LaunchConfiguration('push_wakeup', default='0')
asr_pub_topic_name = LaunchConfiguration('asr_pub_topic_name', default='/prompt_text')
micphone_name = LaunchConfiguration('micphone_name', default='plughw:1,0')
playback_device = LaunchConfiguration('playback_device', default='plughw:1,0')
feed_type = LaunchConfiguration('feed_type', default='1')
ros_string_sub_topic_name = LaunchConfiguration('ros_string_sub_topic_name', default='/prompt_text')
model_name = LaunchConfiguration('model_name', default='DeepSeek_R1_Distill_Qwen_1.5B')
# 为 hobot_xlm 节点设置 LD_LIBRARY_PATH
# 注意:原始命令中的路径是 /opt/tros/humble/lib/hobot_xlm/lib
xlm_lib_path = '/opt/tros/humble/lib/hobot_xlm/lib'
current_ld_path = os.environ.get('LD_LIBRARY_PATH', '')
if current_ld_path:
new_ld_path = f"{xlm_lib_path}:{current_ld_path}"
else:
new_ld_path = xlm_lib_path
# 添加 ROS_LOG_DIR 环境变量
ros_log_dir = '/tmp/ros_logs' # 或者任何现有可写目录,如 '/root/.ros/log'
os.makedirs(ros_log_dir, exist_ok=True)
hobot_xlm_env = {
'LD_LIBRARY_PATH': new_ld_path,
'ROS_LOG_DIR': ros_log_dir
}
return LaunchDescription([
# 声明 launch 参数,允许外部修改
DeclareLaunchArgument('push_wakeup', default_value='0',
description='Whether to push wakeup (0 or 1)'),
DeclareLaunchArgument('asr_pub_topic_name', default_value='/prompt_text',
description='Topic name for ASR output'),
DeclareLaunchArgument('micphone_name', default_value='plughw:1,0',
description='Micphone device name (ALSA)'),
DeclareLaunchArgument('playback_device', default_value='plughw:1,0',
description='Playback device for TTS'),
DeclareLaunchArgument('feed_type', default_value='1',
description='Feed type for hobot_xlm'),
DeclareLaunchArgument('ros_string_sub_topic_name', default_value='/prompt_text',
description='Input topic for hobot_xlm (ASR result)'),
DeclareLaunchArgument('model_name', default_value='DeepSeek_R1_Distill_Qwen_1.5B',
description='Model name for LLM'),
# 1. sensevoice_ros2 节点
Node(
package='sensevoice_ros2',
executable='sensevoice_ros2',
name='sensevoice_ros2',
output='screen',
parameters=[{
'push_wakeup': push_wakeup,
'asr_pub_topic_name': asr_pub_topic_name,
'micphone_name': micphone_name,
}]
),
# 2. hobot_tts 节点
Node(
package='hobot_tts',
executable='hobot_tts',
name='hobot_tts',
output='screen',
parameters=[{
'playback_device': playback_device,
}]
),
# 3. hobot_xlm 节点(需要额外环境变量)
Node(
package='hobot_xlm',
executable='hobot_xlm',
name='hobot_xlm',
output='screen',
parameters=[{
'feed_type': feed_type,
'ros_string_sub_topic_name': ros_string_sub_topic_name,
'model_name': model_name,
}],
env=hobot_xlm_env,
),
])
同时修改setup.py和package.xml。
import os
from glob import glob
from setuptools import find_packages, setup
package_name = 'audio_llm'
setup(
name=package_name,
version='0.0.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='root',
maintainer_email='root@todo.todo',
description='TODO: Package description',
license='TODO: License declaration',
extras_require={
'test': [
'pytest',
],
},
entry_points={
'console_scripts': [
],
},
)
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>audio_llm</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="root@todo.todo">root</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<exec_depend>ros2launch</exec_depend>
<exec_depend>sensevoice_ros2</exec_depend>
<exec_depend>hobot_tts</exec_depend>
<exec_depend>hobot_xlm</exec_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
全部文件修改后,在工作空间下编译即可。










