# Talk-with-human **Repository Path**: masonzhao/talk-with ## Basic Information - **Project Name**: Talk-with-human - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: feat/go2-person-follow - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-21 - **Last Updated**: 2026-10-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 豆包户外机器人演员(虚拟模式 + Unitree GO2 AIR) 这个目录同时提供虚拟机器人演员和 Unitree GO2 AIR 适配器。没有硬件时可先验证户外互动效果, 机器人到位后用同一套人格/对话状态机驱动真实 GO2: ```text 路人靠近 → 摩仔吸引注意 → 征得同意 → 短对话 → 动作/表演 → 礼貌告别 ``` 当前保留豆包实时语音链路,同时把人格、情绪、互动状态机和硬件适配层拆开;默认仍是虚拟动作, 传入 `--unitree` 后切换到真实 GO2,不需要重写角色逻辑。 手机端在 `android/`:Kotlin / Jetpack Compose,豆包实时语音走手机麦克风和扬声器,GO2 通过 WebRTC LocalSTA 控制,并带视觉跟随。 ```powershell cd android .\gradlew.bat assembleDebug ``` 调试包在 `android/app/build/outputs/apk/debug/app-debug.apk`。豆包和 GO2 参数在应用内「设置」填写,可以导出 JSON,再用微信发到另一台手机导入。密钥只放 `.env` 或应用设置里,不要提交进仓库。 ## 安装和配置 桌面端在 `desktop/`。下面的 Python 命令都在这个目录里执行: ```powershell cd desktop python -m pip install -r requirements.txt Copy-Item .env.example .env ``` 在 `.env` 中填写 `VOLC_APP_ID` 和 `VOLC_ACCESS_KEY`。已有旧版 `.env` 也可以继续使用;建议新增: ```dotenv CHARACTER_NAME=摩仔 PET_MODEL=2.2.0.0 PET_SPEAKER=saturn_zh_male_bujiqingnian_tob ``` `CHARACTER_NAME` 优先于旧的 `PET_NAME`。默认角色是“摩仔”:好奇、有一点自恋、嘴硬但友善,喜欢挑战和短表演,被拒绝会自然收尾,不会纠缠。 当前默认使用豆包端到端 SC2.0 的 `saturn_zh_male_bujiqingnian_tob`(不羁青年)。SC2.0 比 O2.0 更强调角色塑造、拟人化表达和情绪演绎,适合户外机器狗;还可以试听: ```dotenv PET_SPEAKER=saturn_zh_male_fengfashaonian_tob # 风发少年,更活泼 PET_SPEAKER=saturn_zh_male_aojiaogongzi_tob # 傲娇公子,反差更强 PET_SPEAKER=saturn_zh_male_cixingnansang_tob # 磁性男嗓,声音更稳 ``` 这组 `saturn_*` 音色需要在火山引擎控制台开通/购买“豆包声音复刻模型 2.0”。购买后通常几分钟内生效,并且可以直接用于实时端到端会话。普通 TTS 的 `emotion=happy/angry/...` 音色不属于这条纯端到端链路;如果优先保证实时打断和低延迟,建议先用 SC2.0 角色音色加角色卡。 `model` 已按实时接口要求放在 `dialog.extra.model`,SC2.0 的 `character_manifest` 由 `character.py` 自动生成。需要整套替换角色卡时,可在 `.env` 设置 `DOUBAO_CHARACTER_MANIFEST`;留空即可使用内置摩仔人格。 ## 联网与唱歌 联网搜索通过实时会话的 `dialog.extra` 打开,配置如下: ```dotenv DOUBAO_ENABLE_WEBSEARCH=true VOLC_WEBSEARCH_API_KEY=你的融合信息搜索API密钥 VOLC_WEBSEARCH_TYPE=web ``` `web_agent` 还需要填写 `VOLC_WEBSEARCH_BOT_ID`。没有 API key 时程序不会发送联网开关,避免 StartSession 直接失败;开通服务并填入 key 后,路人问“今天有什么新闻/附近有什么好玩的”等问题时,豆包会自行检索并播报。 唱歌开关也已接入: ```dotenv DOUBAO_ENABLE_MUSIC=true ``` 但豆包实时接口规定 `enable_music` 只支持 O2.0(`PET_MODEL=1.2.1.1`)和四个 Jupiter 精品音色;当前默认 SC2.0 + Saturn 为了拟人情绪不会发送这个不兼容字段。需要真正开启曲库唱歌时,切换为: ```dotenv PET_MODEL=1.2.1.1 PET_SPEAKER=zh_female_vv_jupiter_bigtts ``` 这会牺牲 SC2.0 的角色音色表现;建议户外常态保持 SC2.0,唱歌专场再切 O2.0。 ## 接入 Unitree GO2 AIR 项目已经接入 [unitree_webrtc_connect](https://github.com/legion1581/unitree_webrtc_connect) 的 GO2 WebRTC 控制适配器。先安装硬件依赖: ```powershell python -m pip install -r requirements-unitree.txt ``` 如果 Windows/Anaconda 安装时出现 `av/filter/...`、`libavcodec/avcodec.h` 或 `Failed building wheel for av`,说明 pip 没拿到 PyAV 二进制 wheel,正在错误地尝试源码编译。 优先在当前 conda 环境安装预编译包,再重试: ```powershell conda install -c conda-forge av python -m pip install --prefer-binary -r requirements-unitree.txt ``` 也可以先确认 pip 能拿到 wheel(不能拿到时不要继续编译): ```powershell python -m pip install --only-binary=:all: av ``` 如果当前镜像提示没有匹配的 `av` wheel,建议新建 Python 3.11 的 conda 环境后再安装, 不要手动下载 FFmpeg 头文件拼装 PyAV: ```powershell conda create -n talk-with-go2 python=3.11 -y conda activate talk-with-go2 python -m pip install -r requirements.txt conda install -c conda-forge av python -m pip install --prefer-binary -r requirements-unitree.txt ``` 在 `.env` 填写机器人连接方式。和电脑在同一局域网时填写 GO2 的 IP: ```dotenv UNITREE_CONNECTION_METHOD=local_sta UNITREE_ROBOT_IP=192.168.x.x UNITREE_DEVICE_TYPE=Go2 # go2:GO2 麦克风输入 + GO2 音箱输出;both:同时保留电脑扬声器监听 UNITREE_AUDIO_MODE=go2 ``` 如果电脑连接 GO2 自己的热点,改用: ```dotenv UNITREE_CONNECTION_METHOD=local_ap ``` Go2 较新固件(通常 `>=1.1.15`)还需要每台机器独有的 `UNITREE_AES_128_KEY`。参考仓库提供的 CLI 获取: ```powershell python .\fetch_unitree_aes_key.py --email 你的Unitree账号邮箱 --device-type Go2 ``` 脚本会提示输入密码;PowerShell 中文系统不要写 `\@`,邮箱里的 `@` 不需要转义。 也可以直接使用 `unitree-fetch-aes-key`,但项目内包装脚本会自动规避中文 Windows 时区导致的请求头错误。 也可以用序列号查询: ```powershell python .\fetch_unitree_aes_key.py --token 你的accessToken --device-type Go2 --sn 你的GO2序列号 --quiet ``` 把输出的 32 位十六进制字符串填入 `.env` 的 `UNITREE_AES_128_KEY`,不要提交到 Git。 机器人到手后建议先做不动作的连接自检(只发 `StopMove`): ```powershell python -u main.py --unitree-check ``` 启动真实 GO2 户外交互: ```powershell # .env 中设置 UNITREE_AUDIO_MODE=go2 后,声音走 GO2 麦克风和音箱 python -u main.py --demo --unitree ``` 暂时没有麦克风时,可以用键盘驱动豆包对话和 GO2 动作: ```powershell python -u main.py --demo --keyboard --unitree ``` 键盘模式里,`/hello`、`/stretch`、`/heart`、`/scrape`、`/sit`、`/stand` 可以逐项测试 GO2 动作;`/newyear` 是项目编排的“红灯 + Hello”拜年效果,GO2 官方没有独立的拜年 API。 `/led red`、`/volume 6`、`/avoid on` 分别测试灯光、音量和避障开关。 语音对话中可以直接说“打个招呼”“拜个年”“比个心”“伸个懒腰”“刨两下地”“坐下”“站起来”。默认的离线兜底只匹配完整的 祈使口令;如果配置了下面的 Ark 意图分类器,模型会先理解自然说法(例如“你往后退一点,离我远点”“给新来的朋友拜个年”, 包括 ASR 的轻微口语变化),但只会返回固定动作枚举,不会接触速度、时长或 Unitree API。疑问、转述、条件句和否定句会返回 `none`,不会误触发。动作通常在豆包开始说话时启动;短回复先结束时,本轮已验证的明确动作仍会执行,但新一轮路人发言会立即 废弃旧结果。避障遥控移动结束时会连续发送全零摇杆包。开场和明确告别会自动使用高置信的 Hello;Heart、Scrape、Stretch 只在明确要求时尝试。AIR 固件若拒绝某个内置动作,本次连接内不会反复请求;允许低速移动时 会退回小幅身体动作。路人直接说“你好”或“新年快乐”时,也会分别配合 Hello 或组合拜年效果;更长的转述句不会触发。 ### 让大模型识别动作意图 在火山方舟创建一个可调用的文本模型 Endpoint,把下面几项填入 `.env`: ```dotenv VOLC_LLM_API_KEY=你的方舟APIKey VOLC_LLM_ENDPOINT_ID=ep-xxxxxxxx VOLC_LLM_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 VOLC_LLM_TIMEOUT_SECONDS=6 VOLC_LLM_MIN_CONFIDENCE=0.72 ``` `VOLC_LLM_ENDPOINT_ID` 要原样填写方舟示例代码中 `model="..."` 的值;根据接入方式,它可能是 `ep-...`,也可能是 `doubao-...` 模型名。程序会关闭该请求的深度思考并要求 JSON 输出,在 ASR 结束后异步调用 `POST /chat/completions`。 分类失败时自动回到本地安全白名单;分类请求不会阻塞豆包收音, 也不能绕过 `UNITREE_ALLOW_RISKY_ACTIONS`、避障确认、动作时长上限和急停逻辑。没有填写 API Key/Endpoint 时仍可运行, 只是使用本地兜底识别。启动后看到 `[意图] 已启用 Ark 大模型自然语言动作识别。` 才表示已启用远程分类。 填好配置后可以先做纯分类自检,不连接豆包实时语音或 GO2: ```powershell python -u main.py --intent-check "离我远一点" ``` 预期日志类似 `[意图] backward(llm, 置信度=0.95)`。置信度以模型实际返回为准。 `/forward`、`/back`、`/left`、`/right`、`/turnaround` 和语音里的“往前走/后退/左转/右转/转身” 只有在设置 `UNITREE_ALLOW_RISKY_ACTIONS=true` 后才会发送。每次移动都会先开启并查询确认避障状态, 确认失败时不发送任何非零运动包;动作结束按官方避障遥控通道连续发送全零摇杆包。显式急停还会额外尝试 `StopMove`,用于停止 内置姿态动作。`/move 0.1 0 0` 最多持续 3 秒,日常语音动作限速且单次不超过 0.8 秒。 GO2 AIR 对很小的无线摇杆量可能存在启动死区。语音前进、后退和原地转向默认分别使用 `UNITREE_FORWARD_SPEED=0.52`、`UNITREE_BACKWARD_SPEED=0.50` 和 `UNITREE_TURN_SPEED=0.60`。 这些值都是 `-1.0..1.0` 摇杆范围内的正幅值,程序会分别限制在线速度 `0.70`、转向速度 `0.80` 以内。 需要按场地微调时只改 `.env`,不要让大模型生成速度或持续时间。首次验证请在空旷处依次使用 `/move 0.52 0 0 0.6`、`/move -0.50 0 0 0.6` 和 `/move 0 0 0.60 0.55`,分别确认前进、后退和转向; 不要用同时包含线速度和转向的命令判断单个方向是否可用。 自动说话小动作也复用这组可见速度,但使用更短的成对反向脉冲并限制上限,始终经过同一避障确认,避免连续聊天时逐渐走远。 默认不自动切换 GO2 运动模式(`UNITREE_AUTO_NORMAL_MODE=false`)。现代固件通常处于 MCF;本项目使用的 Hello/Stretch/Scrape/Heart ID 在普通模式和 MCF 中一致。日志中的 `api_id=1002, code=7004` 是模式切换 被拒绝,不是 Hello 失败,因此 AIR 上建议继续保持 `false`。 当前已接入的 GO2 能力包括:WebRTC 连接、Hello/Stretch/Scrape/Heart/Sit/Stand/StopMove 动作、LED、 音量、障碍物开关,以及受保护的移动接口。`UNITREE_ALLOW_RISKY_ACTIONS` 默认是 `false`;确认现场平整、 机器狗四周至少留出 1 米并准备好急停后再改成 `true`。 实时音频协议可以走 GO2:设置 `UNITREE_AUDIO_MODE=go2` 后,程序会把 GO2 音频帧转换为豆包需要的 16 kHz 单声道 PCM,也会把豆包 24 kHz PCM 转为 WebRTC 所需的 48 kHz 音频。它使用 WebRTC 音频轨道,不走 AudioHub 文件播放,因此延迟和打断行为与电脑模式一致。`both` 模式会额外保留电脑扬声器作为调试监听;默认 `off` 保持原来的电脑音频链路。 注意:宇树官方 Go2 参数页的“语音功能”在 AIR 型号标为未配备(○),PRO/X/EDU 才标为支持(●)。参考 SDK 虽然支持 Go2 的通用音频协议,但这不等于每台 AIR 都有可用的内置麦克风和音箱;AIR 必须先做实机音频验证。若没有音频端点,请使用随身电脑/外接 USB 或蓝牙麦克风和音箱,并将模式设为 `off`。 GO2 音箱播放时,机身麦克风可能拾取自己的声音。首次联调建议先把 GO2 音量调低、人与机器狗保持一定距离,并确认能在摩仔说话时开口打断;若出现自激,可先用 `UNITREE_AUDIO_MODE=both` 配合耳机排查,或暂时关闭 `ALLOW_BARGE_IN`。 开场、打招呼和冷场接话直接复用同一条豆包实时会话的 `ChatTextQuery(501)`:程序只发送 “有人靠近/对方安静”等现场提示,由豆包模型结合摩仔人格现场写出并播放下一句,不抽取固定的 N 条台词,也不需要额外配置 Ark。只有旧版客户端不支持 `query_text` 时,才会退回本地安全短句。 ## 运行 先验证豆包连接和 TTS(不需要麦克风): ```powershell python main.py --text "人格语音测试" ``` 运行实时麦克风对话: ```powershell python main.py ``` 运行户外语音互动。程序会先让豆包现场生成一句搭话,然后打开麦克风;路人可以直接说话,豆包负责理解、生成回答并播放语音: ```powershell python main.py --demo ``` 按 `Ctrl+C` 结束语音互动。 摩仔说完后如果路人保持安静,默认等待 5 秒主动接一次话;连续两次没有回应就自然收尾,不会无限催促。可在 `.env` 调整: ```dotenv PROACTIVE_SILENCE_SECONDS=5.0 PROACTIVE_MAX_NUDGES=2 ``` 默认开启语音打断:从第一句主动搭话开始,摩仔说话时路人直接开口,当前播放会立即停止并切到路人的新问题。电脑扬声器回声较大时,程序会优先用下方 AEC 消除回灌;如果你在 Windows 中仍能直接听到自己的麦克风,请到“录音设备 → 麦克风 → 属性 → 侦听”关闭“侦听此设备”。耳机或定向麦克风也能进一步降低现场回声。最后才考虑临时关闭打断: ```dotenv ALLOW_BARGE_IN=false ``` 本机模式默认启用 SpeexDSP AEC:扬声器实际播放的 PCM 会作为参考,麦克风上传前先消除回声,同时保留路人打断能力。首次启动应看到 `[音频] 本机 AEC 已启用`;如果没有安装 `pyaec`,程序会打印降级原因并透传原始麦克风。可调参数: ```dotenv AUDIO_AEC_ENABLED=true AUDIO_AEC_DELAY_MS=0 AUDIO_AEC_FILTER_LENGTH_MS=400 ``` `AUDIO_AEC_DELAY_MS` 默认 `0`,交给自适应滤波处理声卡时延;只有实测仍有回声时再按 10ms 步进调整。`UNITREE_AUDIO_MODE=go2` 时电脑 AEC 不参与 GO2 麦克风链路,GO2 音箱回声应优先通过机器狗端/定向麦克风处理。 如果声音偏小,可在 `.env` 调整本地播放增益,默认已设为 `1.5`;建议先在 `1.2` 到 `1.8` 之间试,不要一次调得过大: ```dotenv PLAYBACK_GAIN=1.5 ``` 如果 Windows 系统声音正常但程序没有声音,可以显式指定 PortAudio 输出设备。设备名可从程序启动时的 `[扬声器] ... 设备=...` 日志中查看,也可以填名称片段: ```dotenv AUDIO_OUTPUT_DEVICE=你的蓝牙音箱名称 AUDIO_INPUT_DEVICE=你的麦克风名称 ``` 留空则跟随系统默认设备。豆包语音按 `pcm_s16le` 解码,蓝牙音箱不需要切换成特殊音效模式。 Windows 上如果系统默认输入是蓝牙耳机的 `Hands-Free` 麦克风,程序会在未显式指定输入设备时自动切换到电脑麦克风,避免打开麦克风后蓝牙音箱被切到通话模式而无声。也可以直接指定: ```dotenv AUDIO_OUTPUT_DEVICE=MINISO-A109 AUDIO_INPUT_DEVICE=Realtek ``` 如果麦克风和音箱都在机器人上的同一个 MINISO 蓝牙设备,则两项都填同一个名称片段;显式指定后不会触发自动回退: ```dotenv AUDIO_INPUT_DEVICE=MINISO-A109 AUDIO_OUTPUT_DEVICE=MINISO-A109 ``` 服务端响度均衡和输出响度也已打开(`TTS_ENABLE_LOUDNESS_NORM=true`、`TTS_LOUDNESS_RATE=10`),如果现场功放仍偏小,再逐步提高 `PLAYBACK_GAIN`。 需要继续用键盘模拟路人,同时播放角色台词时: ```powershell python main.py --demo --keyboard ``` 没有豆包凭证、麦克风或扬声器时,先用完全离线的静音模式验证人格和状态机: ```powershell python main.py --demo --mute ``` 键盘或静音 demo 可以输入: ```text /nearby 模拟有人靠近 /yes 同意交流 /no 礼貌拒绝 /praise 夸摩仔 /challenge 考考摩仔 /dance 要求表演 /goodbye 告别 /stop 安全急停(/reset 恢复) /help 查看帮助 /quit 退出 ``` 也可以直接输入普通文本,模拟路人说话。状态机默认先征求交流同意,避免机器人在户外强行打扰陌生人。 ## 目录说明 当前架构写在 [docs/architecture.md](docs/architecture.md)。目录、登录、数据流或数据库有变动时,同步改这份文档。 - `docs/`:项目架构文档。 - `other/`:本机留下的豆包文档摘录,不进仓库。 - `android/`:交付给客户的手机 App,包含对话、GO2 控制和视觉跟随。 - `admin/`:后台管理,用来创建和停用客户账号。 - `server/`:服务端 API 和数据库脚本。账号只从后台创建,App 只负责登录。 - `desktop/`:开发用的 Python 桌面原型,不交付客户。 - `character.py`:角色设定、情绪状态和离线/异常兜底台词;同时生成豆包 `system_role`。 - `interaction.py`:`IDLE / CONSENT / TALKING / PERFORMING / GOODBYE / COOLDOWN / SAFETY_STOP` 状态机。 - `robot_adapter.py`:硬件无关的动作接口、`VirtualRobotAdapter` 和 `UnitreeGo2Adapter`。 - `unitree_audio.py`:GO2 麦克风/音箱 WebRTC 音频桥接与采样率转换。 - `doubao.py`、`protocol.py`:豆包实时 WebSocket 协议和客户端。 - `audio.py`:16 kHz 麦克风、24 kHz PCM 播放及顺序播放队列。 - `main.py`:麦克风模式、TTS 冒烟测试和虚拟户外 demo 入口。 第一版不直接执行电机控制,不让模型生成电机指令;真实硬件接入时应继续沿用动作白名单、急停和超时保护。