分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多段铰接式柔性底盘 · 台阶攀爬原理动画</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0d1117;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;font-family:-apple-system,'Segoe UI',sans-serif;color:#c9d1d9;overflow:hidden}
.title{font-size:1.2rem;margin-bottom:8px;color:#8b949e;text-align:center;letter-spacing:1.5px}
.container{width:96vw;max-width:1200px;background:linear-gradient(145deg,#111820,#161d27);border-radius:12px;padding:6px;box-shadow:0 6px 28px rgba(0,0,0,.6);border:1px solid rgba(255,255,255,.04)}
svg{width:100%;height:auto;display:block}
#chassis_rear_pivot,#chassis_front_pivot{transform-origin:0 0}
#cargo_platform{transform-origin:0 0}
.wheel-spoke{transform-origin:0 0}
#gyro_spinner{transform-origin:0 0}
.bar{margin-top:8px;display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
.bar .it{background:rgba(255,255,255,.05);padding:5px 12px;border-radius:5px;font-size:.75rem;border:1px solid rgba(255,255,255,.06)}
.bar .it b{color:#FF6B35;font-weight:600}
.rbtn{margin-top:8px;padding:7px 22px;background:#FF6B35;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:.82rem;font-weight:600;transition:background .2s}
.rbtn:hover{background:#e05520}
</style>
</head>
<body>
<p class="title">多段铰接式柔性底盘 · 毛毛虫式蠕动攀爬原理</p>
<div class="container">
<svg id="scene" viewBox="0 0 1200 650">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#0d1117"/><stop offset="100%" stop-color="#161d27"/></linearGradient>
<linearGradient id="bG" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#3A8BC5"/><stop offset="100%" stop-color="#1C5A8A"/></linearGradient>
<linearGradient id="pG" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#56C45E"/><stop offset="100%" stop-color="#348F3A"/></linearGradient>
<filter id="gl"><feGaussianBlur stdDeviation="3.5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<filter id="sh"><feDropShadow dx="1" dy="3" stdDeviation="3" flood-color="#000" flood-opacity=".35"/></filter>
</defs>

<!-- Background -->
<rect width="1200" height="650" fill="url(#bg)"/>
<!-- Subtle grid -->
<g opacity=".03" stroke="#fff" stroke-width=".5">
<line x1="0" y1="100" x2="1200" y2="100"/><line x1="0" y1="200" x2="1200" y2="200"/>
<line x1="0" y1="300" x2="1200" y2="300"/><line x1="0" y1="400" x2="1200" y2="400"/>
<line x1="0" y1="500" x2="1200" y2="500"/><line x1="0" y1="600" x2="1200" y2="600"/>
</g>

<!-- Terrain -->
<g id="terrain">
<rect x="0" y="500" width="1200" height="150" fill="#1e1a14" rx="0"/>
<rect x="0" y="498" width="650" height="3" fill="#3a3228" rx="1"/>
<rect x="650" y="420" width="550" height="80" fill="#1e1a14"/>
<rect x="650" y="418" width="550" height="3" fill="#3a3228" rx="1"/>
<rect x="648" y="420" width="5" height="80" fill="#2a2418"/>
<line x1="650" y1="420" x2="650" y2="500" stroke="#4a3f32" stroke-width="1.5"/>
<line x1="650" y1="420" x2="1200" y2="420" stroke="#4a3f32" stroke-width="1"/>
</g>

<!-- Step height annotation -->
<g opacity=".45">
<line x1="632" y1="420" x2="632" y2="500" stroke="#FF6B35" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="628" y1="420" x2="636" y2="420" stroke="#FF6B35" stroke-width="1"/>
<line x1="628" y1="500" x2="636" y2="500" stroke="#FF6B35" stroke-width="1"/>
<text x="626" y="464" font-size="10" fill="#FF6B35" text-anchor="end">h</text>
</g>

<!-- Phase label -->
<rect x="370" y="18" width="460" height="34" rx="7" fill="rgba(0,0,0,.55)" stroke="rgba(255,255,255,.08)" stroke-width="1"/>
<text id="phaseLabel" x="600" y="41" text-anchor="middle" font-size="15" fill="#e6edf3" font-weight="600">① 平地行驶</text>

<!-- Angle readout -->
<g id="angleReadout" opacity="0">
<rect x="16" y="70" width="130" height="30" rx="5" fill="rgba(255,107,53,.15)" stroke="#FF6B35" stroke-width=".8"/>
<text id="angleVal" x="81" y="90" text-anchor="middle" font-size="13" fill="#FF6B35" font-weight="600">弯折角: 0°</text>
</g>

<!-- Force arrow (appears during climbing) -->
<g id="forceArrow" opacity="0">
<line x1="0" y1="0" x2="0" y2="-40" stroke="#4CAF50" stroke-width="2.5" marker-end="url(#arrowHead)"/>
<text x="14" y="-18" font-size="10" fill="#4CAF50" font-weight="600">摩擦力</text>
</g>
<defs><marker id="arrowHead" markerWidth="7" markerHeight="5" refX="6" refY="2.5" orient="auto"><polygon points="0 0,7 2.5,0 5" fill="#4CAF50"/></marker></defs>

<!-- Platform level indicator -->
<g id="levelIndicator" opacity="0">
<line x1="0" y1="0" x2="40" y2="0" stroke="#FFD700" stroke-width="1.5" stroke-dasharray="4,2"/>
<text x="48" y="4" font-size="9" fill="#FFD700">水平</text>
</g>

<!-- ======================== VEHICLE ======================== -->
<g id="vehicle" filter="url(#sh)">

  <!-- ===== REAR CHASSIS PIVOT ===== -->
  <g id="chassis_rear_pivot">
    <g id="chassis_rear">

      <!-- Rear track band -->
      <path d="M-138 15 L-18 15 A15 15 0 0 0-18-15 L-138-15 A15 15 0 0 0-138 15Z" fill="none" stroke="#222" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
      <path class="tread rt" d="M-138 15 L-18 15 A15 15 0 0 0-18-15 L-138-15 A15 15 0 0 0-138 15Z" fill="none" stroke="#444" stroke-width="1.8" stroke-dasharray="5 3.5"/>

      <!-- Rear body -->
      <rect x="-148" y="-40" width="148" height="40" rx="5" fill="url(#bG)"/>
      <rect x="-148" y="-40" width="148" height="4" rx="2" fill="rgba(255,255,255,.13)"/>
      <!-- Body detail lines -->
      <line x1="-148" y1="-20" x2="0" y2="-20" stroke="rgba(255,255,255,.06)" stroke-width=".8"/>

      <!-- Motor -->
      <rect x="-105" y="-34" width="32" height="12" rx="2" fill="#0f3a5e" stroke="#3A8BC5" stroke-width=".7"/>
      <text x="-89" y="-25" font-size="6" fill="#6ABBE8" text-anchor="middle">电机R</text>

      <!-- Rear wheels -->
      <g class="whl" transform="translate(-128,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
      <g class="whl" transform="translate(-28,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>

      <!-- Platform assembly -->
      <g id="platform_joint" transform="translate(-74,-40)">
        <rect x="-3" y="-14" width="6" height="14" fill="#666" rx="1.5"/>
        <circle r="3.5" cy="-14" fill="#888" stroke="#666" stroke-width=".8"/>
        <g id="cargo_platform">
          <rect x="-52" y="-16" width="104" height="16" rx="3" fill="url(#pG)"/>
          <rect x="-52" y="-16" width="104" height="3" rx="1.5" fill="rgba(255,255,255,.18)"/>
          <!-- Cargo -->
          <rect x="-28" y="-29" width="42" height="13" rx="2" fill="#8D6E63" stroke="#6D4C41" stroke-width=".7"/>
          <text x="-7" y="-20" font-size="5.5" fill="#D7CCC8" text-anchor="middle">货物</text>
          <!-- Gyroscope -->
          <g id="gyroscope" transform="translate(34,-8)">
            <circle r="8.5" fill="none" stroke="#FFD700" stroke-width="1" opacity=".6"/>
            <circle r="5.5" fill="none" stroke="#FFD700" stroke-width=".7" opacity=".4"/>
            <g id="gyro_spinner">
              <line x1="-7.5" y1="0" x2="7.5" y2="0" stroke="#FFD700" stroke-width="1"/>
              <line x1="0" y1="-7.5" x2="0" y2="7.5" stroke="#FFD700" stroke-width="1"/>
              <line x1="-5.3" y1="-5.3" x2="5.3" y2="5.3" stroke="#FFD700" stroke-width=".7"/>
              <line x1="5.3" y1="-5.3" x2="-5.3" y2="5.3" stroke="#FFD700" stroke-width=".7"/>
            </g>
            <circle r="1.8" fill="#FFD700"/>
          </g>
          <text x="34" y="-19" font-size="5" fill="#FFD700" text-anchor="middle" opacity=".65">陀螺仪</text>
        </g>
      </g>

    </g>
  </g>

  <!-- ===== FRONT CHASSIS PIVOT ===== -->
  <g id="chassis_front_pivot">
    <g id="chassis_front">

      <!-- Front track band -->
      <path d="M18 15 L138 15 A15 15 0 0 0 138-15 L18-15 A15 15 0 0 0 18 15Z" fill="none" stroke="#222" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
      <path class="tread ft" d="M18 15 L138 15 A15 15 0 0 0 138-15 L18-15 A15 15 0 0 0 18 15Z" fill="none" stroke="#444" stroke-width="1.8" stroke-dasharray="5 3.5"/>

      <!-- Front body -->
      <rect x="0" y="-40" width="148" height="40" rx="5" fill="url(#bG)"/>
      <rect x="0" y="-40" width="148" height="4" rx="2" fill="rgba(255,255,255,.13)"/>
      <line x1="0" y1="-20" x2="148" y2="-20" stroke="rgba(255,255,255,.06)" stroke-width=".8"/>

      <!-- Motor -->
      <rect x="58" y="-34" width="32" height="12" rx="2" fill="#0f3a5e" stroke="#3A8BC5" stroke-width=".7"/>
      <text x="74" y="-25" font-size="6" fill="#6ABBE8" text-anchor="middle">电机F</text>

      <!-- Front wheels -->
      <g class="whl" transform="translate(28,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
      <g class="whl" transform="translate(128,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>

    </g>
  </g>

  <!-- ===== UNIVERSAL JOINT ===== -->
  <g id="universal_joint">
    <circle cx="0" cy="-20" r="11" fill="#FF6B35" stroke="#CC5522" stroke-width="1.8" filter="url(#gl)"/>
    <circle cx="0" cy="-20" r="4.5" fill="#FFB088"/>
    <line x1="-6" y1="-26" x2="6" y2="-14" stroke="#CC5522" stroke-width="1.5"/>
    <line x1="6" y1="-26" x2="-6" y2="-14" stroke="#CC5522" stroke-width="1.5"/>
  </g>

  <!-- Joint label -->
  <g id="jointLabel" opacity=".7">
    <line x1="0" y1="-34" x2="0" y2="-52" stroke="#FF6B35" stroke-width=".8" stroke-dasharray="2,2"/>
    <text x="0" y="-56" font-size="8" fill="#FF6B35" text-anchor="middle">万向节</text>
  </g>

</g>

<!-- 45° limit arc (appears during bending) -->
<g id="limitArc" opacity="0">
  <path id="limitArcPath" d="" fill="none" stroke="rgba(255,107,53,.25)" stroke-width="12" stroke-linecap="round"/>
  <path id="bendArcPath" d="" fill="none" stroke="#FF6B35" stroke-width="3" stroke-linecap="round"/>
  <text id="limitLabel" x="0" y="0" font-size="9" fill="rgba(255,107,53,.5)" text-anchor="middle">45°限</text>
</g>

</svg>
</div>

<div class="bar">
<div class="it">万向节最大弯折角:<b>45°</b></div>
<div class="it">履带宽度:<b>150mm</b></div>
<div class="it">驱动方式:<b>各舱段独立电机</b></div>
<div class="it">稳定:<b>自平衡陀螺仪补偿</b></div>
</div>
<button class="rbtn" onclick="replay()">↻ 重新播放</button>

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script>
/* ========== 常量 ========== */
const GROUND_Y = 500, STEP_TOP = 420, STEP_FACE_X = 650;
const WHEEL_R = 15;
const JOINT_GROUND_Y = GROUND_Y - WHEEL_R;   // 485
const JOINT_STEP_Y  = STEP_TOP  - WHEEL_R;   // 405
const MAX_BEND = 42; // 动画中使用42°,在45°限制内

/* ========== 元素引用 ========== */
const vehicle     = document.getElementById("vehicle");
const frontPivot  = document.getElementById("chassis_front_pivot");
const rearPivot   = document.getElementById("chassis_rear_pivot");
const cargoPlat   = document.getElementById("cargo_platform");
const gyroSpin    = document.getElementById("gyro_spinner");
const phaseLabel  = document.getElementById("phaseLabel");
const angleReadout= document.getElementById("angleReadout");
const angleVal    = document.getElementById("angleVal");
const forceArrow  = document.getElementById("forceArrow");
const levelInd    = document.getElementById("levelIndicator");
const limitArc    = document.getElementById("limitArc");
const limitArcP   = document.getElementById("limitArcPath");
const bendArcP    = document.getElementById("bendArcPath");
const limitLabel  = document.getElementById("limitLabel");
const uJoint      = document.getElementById("universal_joint");

/* ========== 持续动画(轮子、履带、陀螺仪) ========== */
const wheelAnim = gsap.to(".wheel-spoke", {
  rotation: 360, duration: 0.55, repeat: -1, ease: "none"
});
const gyroAnim = gsap.to("#gyro_spinner", {
  rotation: -360, duration: 0.45, repeat: -1, ease: "none"
});
gsap.to(".rt", { strokeDashoffset: -17, duration: 0.35, repeat: -1, ease: "none" });
gsap.to(".ft", { strokeDashoffset: -17, duration: 0.35, repeat: -1, ease: "none" });

/* ========== 工具:绘制弧线路径 ========== */
function arcPath(cx, cy, r, startDeg, endDeg) {
  const s = startDeg * Math.PI / 180, e = endDeg * Math.PI / 180;
  const x1 = cx + r * Math.cos(s), y1 = cy + r * Math.sin(s);
  const x2 = cx + r * Math.cos(e), y2 = cy + r * Math.sin(e);
  const large = Math.abs(endDeg - startDeg) > 180 ? 1 : 0;
  const sweep = endDeg > startDeg ? 1 : 0;
  return `M${x1} ${y1} A${r} ${r} 0 ${large} ${sweep} ${x2} ${y2}`;
}

/* ========== 主时间轴 ========== */
let mainTL;

function buildTimeline() {
  if (mainTL) { mainTL.kill(); }

  // 重置所有状态
  gsap.set(vehicle,    { x: 120, y: JOINT_GROUND_Y });
  gsap.set(frontPivot, { rotation: 0 });
  gsap.set(rearPivot,  { rotation: 0 });
  gsap.set(cargoPlat,  { rotation: 0 });
  gsap.set(forceArrow, { opacity: 0 });
  gsap.set(levelInd,   { opacity: 0 });
  gsap.set(angleReadout,{ opacity: 0 });
  gsap.set(limitArc,   { opacity: 0 });
  gsap.set(uJoint,     { scale: 1, transformOrigin: "0px -20px" });
  gsap.set(phaseLabel, { textContent: "① 平地行驶" });

  mainTL = gsap.timeline({
    repeat: -1,
    repeatDelay: 1.8,
    defaults: { ease: "power2.inOut" }
  });

  /* ---- 阶段1:平地行驶接近台阶 ---- */
  mainTL.addLabel("s1")
    .to(vehicle, { x: STEP_FACE_X - 145, duration: 2.6, ease: "power1.inOut" }, "s1")
    .to(phaseLabel, { duration: 0, textContent: "① 平地行驶 → 接近台阶" }, "s1");

  /* ---- 阶段2:前端触壁 · 被动折叠抬升 ---- */
  mainTL.addLabel("s2", "+=0.15")
    .to(phaseLabel, { duration: 0, textContent: "② 前舱段被动折叠抬升" }, "s2")
    .to(frontPivot, { rotation: -MAX_BEND, duration: 2.2, ease: "power2.out" }, "s2")
    .to(vehicle,    { x: STEP_FACE_X - 90, duration: 2.2, ease: "power1.out" }, "s2")
    // 万向节高亮
    .to(uJoint, { scale: 1.35, duration: 0.4, ease: "back.out(2)" }, "s2")
    .to(uJoint, { scale: 1.15, duration: 0.6 }, "s2+=0.4")
    // 角度指示
    .to(angleReadout, { opacity: 1, duration: 0.3 }, "s2+=0.2")
    .to(limitArc, { opacity: 1, duration: 0.3 }, "s2+=0.2")
    // 摩擦力箭头
    .to(forceArrow, { opacity: 1, duration: 0.3 }, "s2+=0.5")
    // 弯折角实时更新
    .to({}, {
      duration: 2.2,
      onUpdate: function() {
        const r = gsap.getProperty(frontPivot, "rotation");
        const deg = Math.abs(r).toFixed(1);
        angleVal.textContent = "弯折角: " + deg + "°";
        // 更新弧线
        const vx = gsap.getProperty(vehicle, "x");
        const vy = gsap.getProperty(vehicle, "y");
        const jx = vx, jy = vy - 20;
        const arcR = 35;
        limitArcP.setAttribute("d", arcPath(jx, jy, arcR, 180, 180 - 45));
        bendArcP.setAttribute("d", arcPath(jx, jy, arcR, 180, 180 - Math.abs(r)));
        limitLabel.setAttribute("x", jx - arcR - 14);
        limitLabel.setAttribute("y", jy + 4);
        // 箭头位置
        const contactX = Math.min(vx + 128 * Math.cos(r * Math.PI / 180), STEP_FACE_X);
        const contactY = vy + 128 * Math.sin(r * Math.PI / 180);
        forceArrow.setAttribute("transform", `translate(${STEP_FACE_X - 8}, ${Math.min(contactY, GROUND_Y - 10)})`);
      }
    }, "s2");

  /* ---- 阶段3:趴伏台阶边缘 ---- */
  mainTL.addLabel("s3", "+=0.2")
    .to(phaseLabel, { duration: 0, textContent: "③ 前舱段趴伏台阶边缘 · 后段被动倾斜" }, "s3")
    .to(frontPivot, { rotation: 0, duration: 1.8 }, "s3")
    .to(vehicle,    { x: STEP_FACE_X + 30, y: JOINT_STEP_Y, duration: 1.8, ease: "power2.inOut" }, "s3")
    // 后段随关节抬升而倾斜,保持远端触地
    .to(rearPivot,  { rotation: 30, duration: 1.8, ease: "power2.inOut" }, "s3")
    // 平台陀螺仪补偿
    .to(cargoPlat,  { rotation: -30, duration: 1.8, ease: "power2.inOut" }, "s3")
    // 水平指示器
    .to(levelInd,   { opacity: 1, duration: 0.3 }, "s3+=0.3")
    // 角度淡出
    .to(angleReadout,{ opacity: 0, duration: 0.4 }, "s3+=1.2")
    .to(limitArc,   { opacity: 0, duration: 0.4 }, "s3+=1.2")
    .to(forceArrow, { opacity: 0, duration: 0.3 }, "s3+=0.5")
    // 万向节恢复
    .to(uJoint, { scale: 1, duration: 0.5 }, "s3+=0.5")
    // 更新角度
    .to({}, {
      duration: 1.8,
      onUpdate: function() {
        const fr = gsap.getProperty(frontPivot, "rotation");
        const rr = gsap.getProperty(rearPivot, "rotation");
        const bendDeg = Math.max(Math.abs(fr), Math.abs(rr)).toFixed(1);
        angleVal.textContent = "弯折角: " + bendDeg + "°";
        // 水平指示器跟随平台
        const vx = gsap.getProperty(vehicle, "x");
        const vy = gsap.getProperty(vehicle, "y");
        const platX = vx - 74;
        const platY = vy - 40 - 16;
        levelInd.setAttribute("transform", `translate(${platX - 30}, ${platY})`);
      }
    }, "s3");

  /* ---- 阶段4:重心前移 · 后段攀爬 ---- */
  mainTL.addLabel("s4", "+=0.15")
    .to(phaseLabel, { duration: 0, textContent: "④ 后舱段攀爬 · 陀螺仪补偿保持水平" }, "s4")
    .to(rearPivot,  { rotation: 0, duration: 1.8 }, "s4")
    .to(cargoPlat,  { rotation: 0, duration: 1.8 }, "s4")
    .to(vehicle,    { x: STEP_FACE_X + 120, duration: 1.8, ease: "power1.inOut" }, "s4")
    .to(angleReadout,{ opacity: 0, duration: 0.2 }, "s4")
    .to({}, {
      duration: 1.8,
      onUpdate: function() {
        const rr = gsap.getProperty(rearPivot, "rotation");
        const platX = gsap.getProperty(vehicle, "x") - 74;
        const platY = gsap.getProperty(vehicle, "y") - 40 - 16;
        levelInd.setAttribute("transform", `translate(${platX - 30}, ${platY})`);
      }
    }, "s4");

  /* ---- 阶段5:恢复平直 · 继续行驶 ---- */
  mainTL.addLabel("s5", "+=0.1")
    .to(phaseLabel, { duration: 0, textContent: "⑤ 自重恢复平直 · 跨越完成" }, "s5")
    .to(levelInd,   { opacity: 0, duration: 0.4 }, "s5")
    .to(vehicle,    { x: 1060, duration: 2.2, ease: "power1.inOut" }, "s5");
}

buildTimeline();

/* ========== 重播 ========== */
function replay() {
  buildTimeline();
}
</script>
</body>
</html>

这个动画完整呈现了多段铰接式柔性底盘的台阶攀爬原理,核心设计要点如下:

部件层级与连接关系:

  • 前后舱段分别包裹在 chassis_front_pivot / chassis_rear_pivot 组中,两组的旋转原点均为万向节中心 (0,0),确保弯折动作围绕正确的机械锚点发生
  • 货物平台通过 platform_joint 挂载在后舱段顶部,内部 cargo_platform 独立旋转以实现陀螺仪补偿
  • 履带、轮组作为各舱段的子元素,随舱段弯折自然变形

时间轴编排(6 个阶段):

  1. 平地行驶 — 整车平直推进接近台阶
  2. 被动折叠抬升 — 前舱段绕万向节向上弯折约 42°(在 45° 限制内),万向节高亮闪烁,弯折角弧线实时指示
  3. 趴伏台阶边缘 — 前舱段回落至台阶顶面,关节中心抬升,后舱段被动倾斜保持远端触地,平台陀螺仪反向补偿旋转
  4. 后段攀爬 — 后舱段被拉动绕万向节上移,平台持续补偿保持水平
  5. 恢复平直 — 后舱段搭接台阶,自重恢复直线构型,补偿归零

视觉引导:

  • 万向节在弯折时放大+发光,聚焦核心创新点
  • 弯折角弧线对比 45° 限制区间
  • 摩擦力箭头标示台阶面受力
  • 水平指示器标示平台姿态稳定
  • 陀螺仪持续旋转暗示补偿生效
积分规则:第一轮对话扣减8分,后续每轮扣6分