English interface selected · this article is currently written in Chinese.
从随机长度出发,能重新演化出 Jansen 的腿吗?
English overview →配合仿真与实验探针的假设探索,等待更多证据或边界检验。
数字花园
🌿 什么是数字花园与思想演进?
遵循 Maggie Appleton 与 Andy Matuschak 的常青笔记理念:这里不是按时间沉底的流水账,而是持续修剪打磨的知识生态。文章按成熟度经历:
- 🌱 萌芽 (Seedling): 发散灵感、读书摘录、开放猜想
- 🌿 演进 (Budding): 结构渐明、初步代码推导、积极修正
- 🌳 常青 (Evergreen): 逻辑闭环、持久经得起检验的基石
- 🔬 实验待证 (Speculative): 结合沙盒与仿真探针的理论探索
这是 Strandbeest 系列的第三篇。前两篇讲了演化史和腿的几何。这一篇做一个朴素的问题:如果只给 GA 一个”什么算好腿”的标准,从乱七八糟的长度开始,它能自己找回 Jansen 的腿吗?
先说明:Jansen 在自己的网站上写过,杆件长度的比例是他在 Atari 电脑上用遗传算法算出来的,但适应度函数和算法细节没有公开记录。这里的 GA 是我对这个思路的重构,不是他方法的复原。
设置
- 基因:13 个连杆长度,拓扑固定为 Jansen 的。
- 算法:带种子的遗传算法(锦标赛选择、混合交叉、高斯变异、精英保留),随机数全部来自种子,同一种子结果完全可复现。
- 起点:“盲搜”——每个长度在 5 到 80 之间均匀随机,只用到 Jansen 数字的数量级。
- 无法装配的腿不直接淘汰,而是给分级惩罚:能装上的曲柄角度越多,分越高。否则随机长度几乎都装不起来,GA 没有东西可爬。
适应度函数先被 GA 骗了三次
我写适应度时想的是”平的着地段 + 足够的抬腿”。GA 立刻找到了漏洞:
- 脚穿过机身:抬腿高度没有上限,GA 让脚荡到髋关节上方,抬腿”很高”。加了一条规则:脚必须始终在髋关节下方。
- 脚只滑不抬:着地占比 100%,轨迹是一条直线,根本不是走路。加了规则:抬腿至少是宽度的 15%,着地占比最多只算 0.6。
- “平”的标准随抬腿变松:我最初把”平”定义为在抬腿高度的 5% 之内,腿抬得越高,标准越松。改成相对轨迹宽度。
这些阈值是我定的设计选择,不是 Jansen 的。教训很老套但很真:你写下的标准就是 GA 会优化的东西,不是你心里想的那个东西。
实验一:把 Jansen 的脚轨迹当目标
20 个种子,种群 150,500 代,默认 GA 参数。适应度是和 Jansen 脚轨迹的形状距离(归一化到宽度 1,0 表示形状一致)。
| 结果 | |
|---|---|
| 形状距离中位数 | 0.0148 |
| 形状距离 < 0.02 的种子 | 19 / 20 |
| 找回连杆长度的种子 | 0 / 20 |
形状能找回,数字找不回。不同的长度组合可以画出几乎一样的轨迹:从形状反推长度是多对一的。我没有验证这些解到底是不同的机构,还是同一个机构在某种我没归一化的对称下的样子。
实验二:用我的”平地行走”目标盲搜
同样的设置,适应度换成我写的”平地行走”(着地段长而平、抬腿足够)。
| 结果 | |
|---|---|
| Jansen 自己的得分 | 0.481 |
| 各种子最优得分的中位数 | 0.390 |
| 超过 Jansen 的种子 | 0 / 20 |
| 与 Jansen 轨迹形状距离的中位数 | 0.087 |
| 形状距离 < 0.05 的种子 | 0 / 20 |
默认参数下,盲搜通常到不了 Jansen 的得分,也没有一次落在他的轨迹形状上。从 Jansen 的长度出发,同一个目标能到 0.72,说明他的腿不是这个目标的最优。
我怀疑是 GA 陷在局部最优,于是用更高的变异率(0.5,尺度 0.15,3 个精英)又跑了一轮同样的 20 个种子。结果没有变好:得分中位数 0.384(默认参数是 0.390),只有 1 个种子超过 Jansen;形状距离 0.02 以内的种子从 19 个降到 10 个。我最初在 6 个种子的小测试里看到”高变异率更好”,那只是噪声。所以这里不能简单归咎于变异率:搜索空间的结构、我的目标函数,都可能是原因,这一轮本身没有把它们拆开。
后来换成熟优化器,这两件事就分开了一部分。 同样的目标、同样的 20 个种子,CMA-ES 每次只用 12000 次评估(GA 的 16 %),最优得分的中位数是 0.529,20 个种子里有 13 个超过了 Jansen;但仍然没有一次落在他的轨迹形状上(0.05 以内 0 / 20)。所以”优化器陷在局部最优”确实是很大一部分原因,而”我的目标函数恰好以 Jansen 的腿为最优”仍然是错的。
能得出什么结论
能说的:在固定拓扑下,D 形、着地段平的脚轨迹,盲搜是找得到的。
不能说的:不能说 GA 找回了 Jansen 的数字,也不能说我的目标函数复现了他的方法。
风能带得动吗
仓库里还有一个动力学模型:身体质量、坡度、阻力,加上一个带传动比的帆驱动曲柄。曲柄所需的扭矩由能量守恒直接算出。腿被当成没有质量,脚不打滑;帆面积、传动比、阻力、转子惯量都是示意假设,所以绝对数值没有意义,只能比较设计,或者比较模型自己的两种算法。
只看脚轨迹的目标,不会带来更省力的腿。 在这些假设下,Jansen 的腿和我演化出的”平地”腿、“高抬腿”腿,扭矩和速度差别不大:步幅短的腿需要的扭矩小,但每转一圈走得也少。
把风速直接放进目标,演化会找到不同的东西。 我把”6 m/s 风里的稳态速度”当适应度,从 Jansen 的长度出发,5 个种子,平地和 10° 坡各一轮。最好的腿比 Jansen 快约 15 %–27 %,但大半是因为腿变大了(步幅更长)。把每条腿缩放到和 Jansen 一样大再比,平地只快约 7 %–16 %,坡上约 4 %–14 %;五个种子全都找到了比 Jansen 更好的腿。更大的腿在多数种子上代价是峰值扭矩更高(平地 Jansen 14.7,五个种子落在 14.1–18.6 N·m)。这是模型内的结果,没有拿真机验证。
飞轮帮不了起步。 我原以为加一个飞轮能帮曲柄越过扭矩峰值,于是写了带惯性的时域模型。测试失败了,原因很清楚:阻力帆的扭矩在转速接近风速时降到零,所以曲柄在峰值扭矩到来之前根本转不快,存不下有用的能量。时域模型给出的起步风速(0.733 m/s)和准静态估算(0.727 m/s)只差约 1%,和转子惯量无关(0.05 到 300 kg·m² 都一样)。惯性能做的只是让速度波动稍微小一点,并让它在风停时多滑行一点:即使很重的转子(300 kg·m²),也只能多走约三分之二圈。
这个模型不含足底打滑、碰撞损失和松软地面,腿也没有质量。
换成更高保真的仿真,上面的扭矩数字就站不住了
上面的风能结论来自一个简化模型(准静态加能量守恒)。我后来用 MuJoCo 搭了一个多体动力学仿真器,把同一个 12 腿行走场景拿去对照。先交代一次更正: 我最初的对照用的仿真器有个 bug,每只脚上有两个重叠的碰撞球,互相碰撞,给所有结果掺进了虚假接触;我是在做回放时发现”脚始终都在着地”才查出来的。下面是修正之后的数字。
- 步幅一致,仿真比简化模型高约 5%–6%。
- 扭矩的形状和幅度大体对上了:默认设置下扭矩曲线的相关系数约 0.59,峰峰值 7.7 对 8.1 N·m。但接触太软(接触刚度低一个数量级)或摩擦低时,相关系数掉到 −0.47 和 0.10。
- 平均扭矩仍高出约 8 N·m:平地上它几乎全是足底打滑耗散的能量,简化模型看不见这一块。所以前面的起步风速和峰值扭矩没有得到验证。
- 仿真器自己的扭矩水平依赖摩擦的数值处理:换摩擦锥类型、摩擦阻抗比、无滑移迭代,平均扭矩最多相差 2.4 倍。数值设置(时间步长 0.5 ms 以内、求解器迭代、环约束刚度)在默认设计上收敛——但这只对默认设计成立:后来发现把时间步长从 0.2 ms 减到 0.1 ms,才让 16 个随机改过杆长的走兽全部通过不变量审计;而 64 个走兽的审计里仍有 19 % 不通过(最坏张开 13.19 mm)。所以”收敛”这句话得带着审计一起看。
- 真正的物理参数得靠实测:接触刚度、摩擦系数,还有一个我至今没弄明白的现象(腿越重,平均扭矩越大,尽管总质量固定)。我还纠正了一个单位:我之前把接触刚度标成 N/m,其实它是按有效质量归一化的刚度(1/s²),不能直接和测得的足垫刚度比。
所以现在我给扭矩报告的是范围:同一个场景用四种摩擦建模各跑一次,取有效运行的最小到最大。这是模型的不确定性,不是测量误差。
一个有意思的发现:起步风速。 我给仿真器加了”帆驱动”(没有电机,帆在风里转曲柄)。小模型在约 0.49 m/s 的风里就能起步(严格判据:静止起步后 40 秒内转满一圈;搜索区间 (0.479, 0.500] m/s),比用电机驱动时的峰值扭矩预测的 0.99 m/s 低一半:电机驱动的峰值包含了 2 rad/s 下的动态载荷,高估了静止时要克服的负载。简化模型的起步判据用的也是峰值扭矩,同样偏保守。(早先记的”约 0.45 m/s”是更宽松判据下的观察,在 40 秒判据下略微不够。)
第二个独立求解器给出的交叉检查。 仓库里现在还有一个独立求解器 K2:平面刚体、真正的库仑静摩擦与动摩擦,不共享 MuJoCo 的接触代码。两者在慢速平地行走上每圈步幅差 0.58 %,起步风速差 4.4 %(MuJoCo 0.692 m/s 对 K2 0.7226 m/s;判据是 15 秒内转满一圈,比上面 40 秒的判据更严,所以数值更大)。这是 E1:两个独立求解器一致——说明这些数字不是某一个引擎的产物。它仍然不是实测:没有任何东西是测出来的。接下来要做的是做一个小的实体,测真实的扭矩和步幅,把接触刚度和摩擦拟合出来。
自己试
代码、实验脚本和结果都在 strandbeest-evolution:
pnpm installpnpm reproduce 20 500 150 default欢迎指出问题,比如更好的适应度函数、动力学模型,或者对 Jansen 方法的一手资料。
文章概念网络
从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。
45 / 45 个节点 · 正文标记术语与关键词概念
从随机长度出发,能重新演化出 Jansen 的腿吗?
回到原文 ↗最后更新于 2026-10-04
引用本文
@article{2026-10-04-re-evolving-the-strandbeest-leg,
author = {枫语},
title = {从随机长度出发,能重新演化出 Jansen 的腿吗?},
journal = {枫语},
year = {2026},
month = {oct},
url = {https://meiluosi.github.io/posts/2026-10-04-re-evolving-the-strandbeest-leg/}
}