
第一次拿到 Yanshee 的时候我以为它和那些只能摆几个固定动作的玩具机器人差不多。直到我打开浏览器进入它自带的 Jupyter 服务敲下一行代码看到机器人的手臂真的抬起来我才意识到这是一台藏在人形外壳里的微型开发工作站。这篇文章是我在这台机器上从 Jupyter 一路折腾到 YanAPI 的完整记录包括硬件认知、环境搭建、接口实战和问题排查给正在做 Yanshee 开发的朋友一点参考。如果你刚入手 Yanshee或者正在纠结到底该用 notebook 还是 API 来做项目这篇文章应该能帮你省掉不少弯路。我不会只讲成功路径也会把踩过的坑和完整排查思路一起讲清楚。文中的代码以我自己实际环境为基础具体函数名和参数在不同固件版本里可能不完全一样使用时请务必以你手上这台机器自带的官方示例为准。1. Yanshee 到底是一台什么样的开发平台先摸清硬件底子再谈开发1.1 硬件底子17 自由度的人形骨架、ARM 主控与整套传感器矩阵拿到 Yanshee 的第一感觉是这并不只是一个会走路的玩具。它高约 40 厘米重量在 2 千克左右外壳以塑料为主在关键受力部位有金属骨架加固。全身一共 17 个自由度分布在头部、双臂、腰部、双腿和足底每个自由度背后都是一路舵机驱动。这样一个自由度配置决定了它能完成挥手、鞠躬、行走、摆臂这些动作但也意味着每个关节的负载能力有限你不可能指望它端着一杯水稳稳不洒。真正把它和普通玩具区分开的地方是它并非一块“焊死的控制板”加“固定程序”而是一台跑 Linux 的 ARM 小电脑。主控使用的平台和树莓派同级别系统里预装了 ROS 核心、Jupyter Notebook 服务和一整套驱动库。也就是说你通过 SSH 能登进去看到完整的文件系统通过 HDMI 外接显示器能直接看到桌面通过 Jupyter 能在浏览器里写 Python 代码控制它动起来。能做到这一点的教育机器人在同等价位下并不多见。传感器方面Yanshee 给我印象最深的是比较完整的感知矩阵头部有摄像头正面有麦克风和扬声器胸口或腹部位置有超声波传感器内部集成了陀螺仪和加速度计足底还有压力传感器。这套东西覆盖了视觉、听觉、距离感知、姿态感知四类能力正好对应教育场景里最常见的交互需求。我后来做项目时发现这种“全而无短板”的配置比单纯追求某一个传感器的精度更实用因为你不需要为了加一块超声波模块去动硬件结构。1.2 三条开发路径的定位Jupyter、YanAPI 与 ROS 怎么选绝大多数 Yanshee 用户会先接触 Jupyter因为它开箱即用不需要任何额外环境。用电脑浏览器连上机器人打开一个 notebook就能逐格执行 Python 代码看到电机转动、语音发声、画面显示。这个阶段的核心价值是“快速验证”你想确认某个函数是不是这样调用的写一行跑一下就知道结果比翻文档快得多。但如果要做完整应用Jupyter 就会有些力不从心。这时 YanAPI 是更合适的选择。它是优必选提供的 Python SDK本质上把机器人机身的能力封装成了可供外部程序调用的库你可以把它放进普通 Python 工程里写 main 函数、定义类、组织模块甚至接到 Flask Web 服务或者定时任务里。它解决的问题不是功能变多了而是开发方式变了——从交互式脚本走向真正的软件工程。ROS 则是另一条路更适合做科研、多机协作和复杂算法验证。ROS 的节点、话题、服务这些概念需要额外学习门槛明显高于前两者。我的建议比较直接刚上手不要碰 ROS先在 Jupyter 和 YanAPI 之间建立对机器人行为的直觉等项目需要多传感器融合、多机器人协同或者做系统级仿真再考虑切 ROS。这个顺序也是大多数教学项目推荐的做法因为先建立行为直觉再学习系统抽象理解成本会低很多。开发路径核心定位适合场景学习成本Jupyter交互式验证快速原型、教学演示、单步调试低YanAPI工程化开发完整应用、自动化流程、Web 集成中ROS系统级集成科研、多机协作、复杂算法验证高1.3 拿到机器后的第一件事网络、系统初始化与连接准备拆箱之后我建议不要急着开机摆动作先做两件事确认系统版本和确认网络连接方式。Yanshee 出厂时可能是自建热点模式也可能需要连接指定局域网不同批次机器的默认行为不完全一样。最稳妥的办法是看包装里的快速入手指南上面通常会写初始情况下怎么连电脑。把电脑和 Yanshee 连到同一个网络后在浏览器里输入机器人的 IP 地址就能看到 Jupyter 的登录页面。这个 IP 地址可以通过路由器后台查看设备列表找到也可以用 HDMI 接显示器直接在桌面里看网络设置。我当时图省事直接看路由器后台两分钟就找到了。这里多说一句如果准备长期开发建议在路由器里给 Yanshee 绑定固定 IP否则重启后地址一变脚本里的连接地址全要改非常浪费生命。初次登录 Jupyter 一般会要求密码在说明书上会有出厂默认值。登录后第一件事建议先去浏览出厂自带的 notebook 示例目录而不是急着新建空白 notebook。这些出厂示例是和你手上固件版本严格配套的涵盖运动、语音、视觉、传感器等分类它们里面的函数名、参数格式比网上任何一份教程都更可信。2. 用 Jupyter 跑通第一条开发链路从浏览器到电机响应2.1 进入 Jupyter 环境的那几个细节进入 Jupyter 操作界面后你会看到文件列表。首次使用建议先新建一个实验 notebook命名可以随手写但最好包含日期和用途比如test_motion_20250110。随着实验增多命名乱掉的成本会越来越高后面整理起来很痛苦。新建之后页面会默认有一个代码单元格。我的经验是第一步不要急着写任何控制代码先写一行测试代码验证内核连通性print(hello yanshee)这个小步骤看似多余实际上能省很多排查时间。如果连 Python 内核都没起来后面写再多代码也只是报错反而干扰判断。看到输出了内容再开始写控制代码这样出错时你至少能确定问题出在控制逻辑而不是环境本身。2.2 第一个有实际意义的动作让机器人对你挥手跑通 hello 之后我建议做的第二个动作不是让机器人走两步而是做一个比较温和的单臂动作比如挥手。原因很简单走路涉及双腿和平衡一旦控制不当容易摔挥手风险低而且反馈明显非常适合第一次体验。我的写法是直接调用运动模块的预设动作接口把动作名称传给机器人from yanshee.api import motion motion.play(wave_hello)注意不同版本的固件和 SDK包名、函数名、动作名称都可能不同。如果你在 notebook 里 import 报错先看一下出厂示例里的 import 写法以它为准。我见过不少人在网上复制代码结果因为版本不同怎么都跑不通最后发现只是导入路径改了一个单词。如果想指定某个关节转到特定角度可以用关节控制接口motion.set_joint(right_shoulder_pitch, 30, 0.5)这里的三个参数大致是关节名称、目标角度、执行时间。关节名称在不同版本里也有差异前面说的原则同样适用以官方示例为准不要凭记忆猜。执行时我先给一个较小的安全角度确认方向正确后再调大避免一不留神让机器人做出幅度过大的动作。2.3 交互式编程的真正边界在 Jupyter 里玩了两三天后我明显感觉到它的两面性。好的一面是即时反馈修改参数、重新执行几秒就能看到结果这种“代码—运动”的闭环反馈是学习机器人控制最好的方式坏的一面是它本质上是一个“人盯着执行”的环境很难承载一个需要持续运行、按条件触发的完整程序。我在后续实验中遇到了几个很具体的问题。第一浏览器和机器人之间的连接偶尔会断开摄像头取流这种长时间循环跑着跑着就报错需要手动重连内核第二notebook 里的状态分散在各个单元格里项目一复杂我经常忘了某个变量是在哪个单元初始化的执行顺序一乱整个逻辑就错乱了第三它没有一个标准的入口函数也没有退出清理机制动作做到一半想停下来只能手动发停止指令比较狼狈。这些问题不是 bug而是交互式编程本身的设计边界遇到它们的时候就该考虑换一种开发方式了。3. Jupyter 很好但项目一复杂就绷不住了迁移到 YanAPI 的真实理由3.1 我在 Jupyter 阶段遇到的四个实际问题第一个问题是断线。我在做视觉识别实验时循环读取摄像头图像去做颜色识别大概跑了三四分钟notebook 的 Kernel 状态变成 disconnected代码还在本地继续但机器人端的服务已经不再响应。虽然重启内核后恢复了但这种中断对流程型实验来说很致命因为你不能确定中断点前后的状态是否一致。第二个问题是状态不共享。我想让机器人一边播放语音一边检测超声波距离一旦有人进入范围就执行下一个动作。这种多任务在 Jupyter 的线性执行模型里非常别扭我需要切到不同单元格手动触发、手动轮询一旦有一个环节忘记执行整个状态机就乱了。第三个问题是工程结构缺失。不到两周我积累了四十多个 notebook 文件有的对应运动实验有的对应语音实验还有的是失败尝试的残留。文件多了之后代码复用基本靠复制粘贴改一个参数要改好几个文件很快我就受不了了。第四个问题是没法做事件驱动。Jupyter 是“人去执行”的模式而我的项目需要“机器人主动判断并执行”比如检测到人靠近才问候。在 notebook 里实现这个逻辑不是不行但要开着浏览器页面挂着循环既不稳定也不优雅。3.2 YanAPI 补上了什么YanAPI 解决的不是某个具体函数的问题而是把“控制机器人”这件事从 notebook 里的临时脚本变成了一个标准 Python 程序。它提供了连接管理、状态查询、动作执行、语音交互、视觉处理等能力的统一封装并且支持在普通 Python 进程里运行。迁移之后我的开发流程发生了三个明显变化。第一我可以把机器人控制代码放进真正的工程目录里用 main.py 作为入口按模块拆分比如 motion_controller.py、voice_system.py代码复用从复制粘贴变成正常的 import。第二我可以把控制程序注册成系统服务或者定时任务只要机器人开机且主控程序存活它就能持续工作不再依赖有人开着浏览器。第三我可以在外部程序里通过基于 YanAPI 的服务层去控制机器人比如做一个 Web 管理页面之后远程下发指令。有一类人可能会怀疑YanAPI 能做的不就是 Jupyter 里那些命令的集合吗迁移的意义在哪里我的回答是命令集合不是重点关键是运行模型发生了改变。Jupyter 是“几个工程师围着一个设备按顺序调”YanAPI 是“一个程序负责一套完整逻辑”。程序化这三个字对机器人开发来说是质的差别因为它意味着可重复、可维护、可集成。4. YanAPI 实战拆解动作、语音、视觉、感知四大核心模块4.1 初始化与连接管理所有功能的前提无论你想做哪个方向的开发连接这一步都跑不掉。我一般会在项目里单独建一个连接管理模块负责初始化机器人实例、建立连接、检查状态from yanshee_sdk import YansheeRobot robot YansheeRobot() robot.connect() print(robot.is_connected())连接成功后建议先查一下固件版本和 API 版本然后打印出来。这个信息在排查问题的时候非常有用很多“接口怎么和文档对不上”的问题本质上都是版本不一致引起的。连接失败时不要急着改代码先看返回的错误码不同错误码对应服务未启动、网络不通、认证失败等不同原因定位路径完全不一样。4.2 动作控制预设动作、关节角度与动画序列三层调用动作控制是 Yanshee 开发里最直观的模块。它有三种常见调用层级预设动作直接调用一个动作名比如鞠躬、挥手、行走最简单适合快速验证和简单交互关节角度控制指定关节和目标角度适合做定制动作但你需要了解每个关节的名称和活动范围动画序列把多个关节动作按时间轴组合适合编排复杂动作。我在实际开发中的建议是能走预设动作就走预设动作不要一上来就调关节角度。预设动作是厂商调好的角度、速度、时间都是安全的而自己调关节角度很容易控制不好范围轻则动作难看重则损坏舵机或造成机械干涉。定制动作尽量限制在几个关键关节的小范围内做完动作后记得回到舒适位不要让机器人长时间保持一个别扭的姿势。动作控制执行时需要特别注意“忙碌状态”。如果机器人正在播放一个动作你又立刻发一个新指令不同版本的固件行为会不一样有的会排队等待有的会直接打断或丢弃。我在项目里会先查询运动状态while robot.is_motion_busy(): time.sleep(0.1) robot.motion.play(bow)这个轮询虽然简单但能避免大量莫名其妙的动作冲突。4.3 语音交互TTS、语音识别与唤醒词Yanshee 的语音能力一般分为两个方向一个是 TTS把文字变成语音说出来另一个是 ASR把用户说的话识别成文字。TTS 通常是同步执行调用后机器人直接开口说话ASR 往往是异步的需要设置回调或者轮询识别结果。我对语音模块的使用心得是TTS 非常适合做状态反馈比如“动作执行完成”“电量偏低”“检测到人脸”这些场景比用屏幕反馈更自然ASR 适合做交互入口但不要假设它对所有环境都有效背景噪音大时识别率会明显下降。如果你要做语音唤起最好先测试一下唤醒词在目标环境下的识别效果而不是直接按照文档的默认参数上生产环境。语音和动作组合时有个小坑如果语音播放和动作执行同时进行可能出现动作做完话还没说完、或者话已经说完动作还在继续的情况。我会在项目里把语音和动作的时序统一在同一个状态机里先用 TTS 预估一个执行时间再安排动作的触发时机这样两个模块不会打架。虽然不是每个项目都需要但一旦需要提前设计好时序远比事后补救省事。4.4 视觉与感知摄像头取流与传感器状态读取视觉部分是 Yanshee 开发里上限最高的模块因为摄像头能做的事情非常多。最简单的场景是从摄像头取一帧图像保存下来或者在界面上显示进阶一点是做人脸检测、颜色识别、二维码识别。这些能力在 SDK 里通常都有封装关键还是先确认你手上固件支持哪些接口。传感器读取方面最常用的是超声波、陀螺仪和足底压力。超声波适合做近距离感知比如判断是否有人靠近陀螺仪适合做姿态判断比如机器人是否摔倒、是否正在倾斜足底压力适合判断行走时是否踩实。这些数据大多是只读的调用方式也比较简单难点在于如何组合起来做决策。我在视觉实验里踩过的一个坑是摄像头取流默认分辨率可能比较高导致处理速度很慢。后来发现可以通过参数调低分辨率检测速度提升了好几倍。如果你做的是实时性要求高的项目建议优先考虑降低分辨率而不是优化算法往往效果立竿见影。5. 从“能跑”到“稳跑”开发过程中踩过的坑与完整排查链路5.1 连接超时从日志、网络、服务三层排查有段时间我的脚本经常在 connect 阶段超时每次重启机器人又能恢复一段时间非常影响开发节奏。我当时的排查过程是这样的先看机器人是否在线ping IP 通了接着用 SSH 登进机器人检查 Jupyter 和 SDK 对应的服务进程发现进程还在再去翻应用日志看到大量 WebSocket 握手超时。问题最终锁定在机器人主控端的底层服务因为长时间运行出现了僵死导致对外连接不稳定。处理方式是重启对应服务并在脚本里加了连接失败重试机制。这个经历给我最大的教训是遇到连接问题不要直接归咎于代码或网络要按“网络层—进程层—日志层”的顺序排查每一步都能过滤掉一批可能性最后问题范围会缩得很小。排查层检查手段常见结论网络层ping IP、查看路由IP 变化、网线松动进程层SSH 查看服务状态服务僵死、内存不足日志层翻应用日志握手超时、认证失败5.2 API 名称与固件版本不匹配查文档的正确姿势Yanshee 的固件迭代过程中API 包名、函数名、参数格式都有过变化。网上搜到的很多代码示例来自不同版本直接复制很容易报 ImportError 或者参数错误。我遇到过最典型的例子是官方文档里写的导入方式和我这台机器上的实际包结构不一样怎么改都报错。后来我总结出一套“文档确认顺序”优先级最高的是出厂自带的 notebook 样例它保证和当前固件配套其次是设备上安装的 SDK 自带的说明文件最后才是在线文档。这个顺序的核心逻辑是和你手上这台机器越贴近的资料越可信。网上教程和社区问答只能作为思路参考不能作为参数依据。每次换机器、刷固件之后我会重新确认一遍关键 API 的名字宁可多花十分钟也不要调试两小时。5.3 关节角度回读漂移别把回读值直接当控制值我在做“按照设定角度摆臂并能回到指定位置”的项目时发现了一个很典型的问题下发了 90 度的关节指令机器人实际到达后回读的角度在 87 到 93 度之间波动偶尔还会差更多。对于展示型项目来说这个误差可以接受但如果你要做精确重复定位这个波动就会积累误差最后动作完全走样。我当时处理这个问题的思路是首先不要用回读值直接作为下一次控制的反馈闭环除非你能确认系统有足够的精度其次在动作序列里加入“相对当前实际角度”的补偿判断比如先读取当前角度再计算目标差量最后在一些对位置精度要求高的场景里使用摄像头图像作为视觉反馈而不是单纯依赖关节编码器。这些方案不一定对所有型号都有效但在类似的教育机器人上思路是通用的。5.4 动作冲突与任务队列设计当程序要同时处理多个触发事件时动作冲突几乎是必然出现的。典型场景是用户连续按了两下交互按钮第一次触发问候动作还没执行完第二次触发直接覆盖了前一个动作机器人的表现就变成“动作做一半突然跳到另一个动作”最后停在哪个姿态都不确定。解决这个问题的方式不是让程序“更聪明”而是设计一个串行化的动作执行队列。所有要执行的动作先进入队列后台只运行一个执行器每次从队列取出一个动作执行完毕后再取下一个。这样虽然会增加动作之间的排队时间但行为是可预测的对于教育机器人来说可预测性比并发性重要得多。我把这个队列封装成了一个很简单的控制器class ActionQueue: def __init__(self, robot): self.robot robot self.queue [] def push(self, action): self.queue.append(action) def run(self): while self.queue: action self.queue.pop(0) self.robot.motion.play(action) while self.robot.is_motion_busy(): time.sleep(0.05)这个控制器不到二十行却解决了我大部分动作混乱问题。如果你做的项目里有交互触发逻辑强烈建议一开始就引入类似的队列不要等到动作冲突发生后再补。6. 再进一步用 YanAPI 搭一个“主动问候”演示项目的设计思路6.1 项目框架感知、决策、执行三段式把 YanAPI 用熟之后我拿它做了一个“主动问候”的小项目当有人走近 Yanshee它会主动转身、看向来人、说一句“你好”并挥手示意如果来人继续说“介绍一下你自己”它会播放一段自我介绍并配合动作。整个项目的核心其实就是三段式感知、决策、执行。感知部分用超声波检测距离变化并在距离小于阈值时触发人脸检测确认确实有人面向机器人决策部分是一个简单的有限状态机只有三个状态待机、问候、应答状态迁移由感知结果驱动执行部分就是语音和动作的组合按照前面说的时序设计来安排。从实现角度来说这个项目并不复杂但它很好地展示了为什么需要从 Jupyter 走向 YanAPI感知循环需要持续运行决策逻辑需要集中管理执行步骤需要稳定编排这些都不是 notebook 交互式执行擅长的事而用 Python 工程加队列调度后整个流程逻辑清晰得多。6.2 项目做完后我对机器人开发的三点体会第一个体会是机器人的开发瓶颈往往不是算法而是稳定性和容错。我在演示时最紧张的一次不是算法出问题而是机器人在一个动作结束后没能正确回到初始姿态导致后面所有动作都偏了一个角度。稳定优先、功能次之这个顺序在嵌入式机器人上永远成立。第二个体会是先跑通再优化。我第一次做这个项目时一上来就想把感知、决策、执行写成漂亮的模块化架构结果花了大量时间在抽象接口上机器人反而不太能动。后来换成“先让挥手和说话跑通再加入距离感知最后加人脸”每一步都有可运行的结果项目推进反而顺利了很多。第三个体会是Jupyter 和 YanAPI 不是二选一的关系。我现在的习惯是遇到不确定的 API 行为先在 Jupyter 里快速验证验证通过后再把它挪进 YanAPI 工程里固化成正式逻辑。一个负责探索一个负责生产这样的组合比单独使用任何一种模式都顺手。如果你也在做 Yanshee 或者类似教育机器人的项目不妨按这个思路试试先用 Jupyter 建立信心再用 YanAPI 搭建正经应用你会发现这套流程比想象中顺畅。