分享图
动画工坊
引擎就绪
<!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>
    :root {
      --bg-color: #080c14;
      --panel-bg: rgba(13, 22, 38, 0.75);
      --panel-border: rgba(0, 240, 255, 0.2);
      --accent-cyan: #00f0ff;
      --accent-orange: #ff9f1c;
      --accent-gold: #ffd166;
      --accent-green: #06d6a0;
      --text-dim: #64748b;
      --text-main: #cbd5e1;
      --text-bright: #ffffff;
      --font-mono: 'SF Mono', 'Segoe UI Mono', 'Fira Code', 'Consolas', monospace;
      --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', sans-serif;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      user-select: none;
    }

    body {
      width: 100vw;
      height: 100vh;
      background: radial-gradient(circle at 50% 30%, #101a2e 0%, var(--bg-color) 80%);
      color: var(--text-main);
      font-family: var(--font-ui);
      overflow: hidden;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-between;
    }

    /* 顶部精简微型信息栏(绝对定位边缘,不挡画面) */
    .hud-header {
      position: absolute;
      top: 12px;
      left: 16px;
      right: 16px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      pointer-events: none;
      z-index: 10;
    }

    .hud-title-wrap {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .status-badge {
      width: 7px;
      height: 7px;
      background: var(--accent-green);
      border-radius: 50%;
      box-shadow: 0 0 8px var(--accent-green);
      animation: pulse-green 2s infinite;
    }

    @keyframes pulse-green {
      0%, 100% { opacity: 1; transform: scale(1); }
      50% { opacity: 0.4; transform: scale(0.85); }
    }

    .main-title {
      font-size: 13px;
      font-weight: 600;
      letter-spacing: 0.8px;
      color: var(--text-bright);
      text-transform: uppercase;
    }

    .sub-title {
      font-size: 11px;
      color: var(--text-dim);
      font-family: var(--font-mono);
      margin-left: 6px;
    }

    .tech-specs-mini {
      display: flex;
      gap: 12px;
      font-family: var(--font-mono);
      font-size: 11px;
      color: var(--text-dim);
    }

    .tech-specs-mini span b {
      color: var(--accent-cyan);
      font-weight: 500;
    }

    /* 左右角落微型遥测 HUD */
    .telemetry-tag {
      position: absolute;
      bottom: 68px;
      font-family: var(--font-mono);
      font-size: 10px;
      color: var(--text-dim);
      background: var(--panel-bg);
      border: 1px solid var(--panel-border);
      padding: 6px 10px;
      border-radius: 4px;
      backdrop-filter: blur(8px);
      pointer-events: none;
      z-index: 10;
      line-height: 1.5;
    }

    .telemetry-left { left: 16px; }
    .telemetry-right { right: 16px; text-align: right; }

    .tag-val {
      color: var(--accent-cyan);
      font-weight: bold;
    }
    .tag-warn {
      color: var(--accent-orange);
      font-weight: bold;
    }

    /* 主动画区域:占据 100% 空间,居中 */
    .stage-container {
      position: relative;
      width: 100vw;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    svg#stage {
      width: 100%;
      height: 100%;
      max-width: 1200px;
      max-height: 720px;
      filter: drop-shadow(0 0 20px rgba(0,0,0,0.6));
    }

    /* 底部紧凑浮动控制条 */
    .hud-controller {
      position: absolute;
      bottom: 14px;
      display: flex;
      align-items: center;
      gap: 12px;
      background: var(--panel-bg);
      border: 1px solid var(--panel-border);
      padding: 6px 14px;
      border-radius: 20px;
      backdrop-filter: blur(12px);
      box-shadow: 0 8px 32px rgba(0,0,0,0.4);
      z-index: 20;
    }

    .ctrl-btn {
      background: transparent;
      border: 1px solid rgba(255,255,255,0.15);
      color: var(--text-main);
      padding: 4px 10px;
      border-radius: 12px;
      font-size: 11px;
      font-family: var(--font-ui);
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 4px;
      transition: all 0.2s ease;
    }

    .ctrl-btn:hover {
      border-color: var(--accent-cyan);
      color: var(--accent-cyan);
      background: rgba(0, 240, 255, 0.08);
    }

    .ctrl-btn.active {
      border-color: var(--accent-cyan);
      color: #000;
      background: var(--accent-cyan);
      font-weight: 600;
    }

    .timeline-slider-wrap {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .timeline-slider {
      appearance: none;
      width: 140px;
      height: 4px;
      background: rgba(255,255,255,0.15);
      border-radius: 2px;
      outline: none;
      cursor: pointer;
    }

    .timeline-slider::-webkit-slider-thumb {
      appearance: none;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: var(--accent-cyan);
      box-shadow: 0 0 6px var(--accent-cyan);
      cursor: pointer;
    }

    .phase-badge {
      font-family: var(--font-mono);
      font-size: 11px;
      color: var(--accent-gold);
      padding: 2px 8px;
      background: rgba(255, 209, 102, 0.1);
      border: 1px solid rgba(255, 209, 102, 0.3);
      border-radius: 4px;
      min-width: 90px;
      text-align: center;
    }

    /* SVG 内部样式 */
    .ground-grid { stroke: rgba(255,255,255,0.04); stroke-width: 1; }
    .stair-surface { fill: #111a2c; stroke: #1e2d4a; stroke-width: 2; }
    .stair-edge-highlight { stroke: #00f0ff; stroke-width: 2.5; stroke-linecap: round; opacity: 0.8; }
    .hazard-stripe { stroke: #ff9f1c; stroke-width: 2; opacity: 0.4; }
  </style>
</head>
<body>

  <!-- 顶部精简微型 HUD(严格控制尺寸,不遮挡动画中央) -->
  <header class="hud-header">
    <div class="hud-title-wrap">
      <div class="status-badge"></div>
      <div class="main-title">行星三轮组自适应爬楼原理</div>
      <div class="sub-title">PLANETARY TRI-STAR LOCOMOTION</div>
    </div>
    <div class="tech-specs-mini">
      <span>轮径 Φ: <b>120mm</b></span>
      <span>回转半径 R: <b>165mm</b></span>
      <span>最大摆角: <b>±12°</b></span>
    </div>
  </header>

  <!-- 左下角实时受力与运动学数据 -->
  <div class="telemetry-tag telemetry-left">
    <div>前星轮转矩: <span id="tel-torque" class="tag-val">18.4 N·m</span></div>
    <div>阻尼伸缩量: <span id="tel-damper" class="tag-val">+4.2 mm</span></div>
    <div>质心水平加速度: <span id="tel-acc" class="tag-val">0.03 m/s²</span></div>
  </div>

  <!-- 右下角姿态与稳定度数据 -->
  <div class="telemetry-tag telemetry-right">
    <div>货箱姿态角: <span id="tel-tilt" class="tag-warn">0.2° (超稳)</span></div>
    <div>摆臂补偿角: <span id="tel-swing" class="tag-val">-6.8°</span></div>
    <div>自适应工况: <span id="tel-mode" class="tag-val">台阶翻转</span></div>
  </div>

  <!-- 中央主可视化画布(SVG高保真精密渲染) -->
  <main class="stage-container">
    <svg id="stage" viewBox="0 0 1000 580" preserveAspectRatio="xMidYMid meet">
      <defs>
        <!-- 背景高科技网格定义 -->
        <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
          <path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>
          <circle cx="40" cy="40" r="1" fill="rgba(0,240,255,0.15)"/>
        </pattern>

        <!-- 金属与发光渐变 -->
        <linearGradient id="chassis-grad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#334155"/>
          <stop offset="50%" stop-color="#64748b"/>
          <stop offset="100%" stop-color="#334155"/>
        </linearGradient>

        <linearGradient id="arm-grad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="#0284c7"/>
          <stop offset="50%" stop-color="#00f0ff"/>
          <stop offset="100%" stop-color="#0369a1"/>
        </linearGradient>

        <linearGradient id="cargo-grad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="#1e293b"/>
          <stop offset="100%" stop-color="#0f172a"/>
        </linearGradient>

        <linearGradient id="damper-grad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#e2e8f0"/>
          <stop offset="50%" stop-color="#94a3b8"/>
          <stop offset="100%" stop-color="#475569"/>
        </linearGradient>

        <radialGradient id="wheel-rim" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stop-color="#38bdf8"/>
          <stop offset="40%" stop-color="#0f172a"/>
          <stop offset="90%" stop-color="#1e293b"/>
          <stop offset="100%" stop-color="#00f0ff"/>
        </radialGradient>

        <radialGradient id="center-hub" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stop-color="#ffffff"/>
          <stop offset="50%" stop-color="#ff9f1c"/>
          <stop offset="100%" stop-color="#b45309"/>
        </radialGradient>

        <!-- 滤镜发光 -->
        <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
          <feGaussianBlur stdDeviation="3" result="blur" />
          <feComposite in="SourceGraphic" in2="blur" operator="over"/>
        </filter>

        <filter id="glow-orange" x="-20%" y="-20%" width="140%" height="140%">
          <feGaussianBlur stdDeviation="4" result="blur" />
          <feComposite in="SourceGraphic" in2="blur" operator="over"/>
        </filter>

        <!-- 轮子模板定义 (子轮 r=18, 代表120mm) -->
        <g id="sub-wheel">
          <!-- 橡胶外胎 -->
          <circle cx="0" cy="0" r="18" fill="#1e293b" stroke="#00f0ff" stroke-width="1.8"/>
          <!-- 胎纹 -->
          <circle cx="0" cy="0" r="14" fill="none" stroke="rgba(0,240,255,0.3)" stroke-width="1" stroke-dasharray="3,3"/>
          <circle cx="0" cy="0" r="9" fill="#0f172a" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
          <!-- 轮毂花纹指示旋转 -->
          <line x1="-12" y1="0" x2="12" y2="0" stroke="rgba(0,240,255,0.7)" stroke-width="1.5"/>
          <line x1="0" y1="-12" x2="0" y2="12" stroke="rgba(0,240,255,0.7)" stroke-width="1.5"/>
          <circle cx="0" cy="0" r="3.5" fill="#00f0ff"/>
        </g>

        <!-- 行星三叉臂转子组件模板 (R=48, 代表165mm回转半径) -->
        <g id="tri-star-arm">
          <!-- 回转包络辅助圆圈 -->
          <circle cx="0" cy="0" r="48" fill="none" stroke="rgba(0,240,255,0.18)" stroke-width="1" stroke-dasharray="4,4"/>
          <!-- 三叉刚体骨架 -->
          <path d="M 0 0 L 0 -48 M 0 0 L 41.57 24 M 0 0 L -41.57 24" stroke="url(#arm-grad)" stroke-width="7" stroke-linecap="round"/>
          <path d="M 0 0 L 0 -48 M 0 0 L 41.57 24 M 0 0 L -41.57 24" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" opacity="0.8"/>
          <!-- 臂尖轮轴固定座 -->
          <circle cx="0" cy="-48" r="6" fill="#0369a1" stroke="#00f0ff" stroke-width="1.5"/>
          <circle cx="41.57" cy="24" r="6" fill="#0369a1" stroke="#00f0ff" stroke-width="1.5"/>
          <circle cx="-41.57" cy="24" r="6" fill="#0369a1" stroke="#00f0ff" stroke-width="1.5"/>
          <!-- 中心回转主轴承 -->
          <circle cx="0" cy="0" r="14" fill="#0f172a" stroke="#ff9f1c" stroke-width="2.5" filter="url(#glow-orange)"/>
          <circle cx="0" cy="0" r="6" fill="url(#center-hub)"/>
        </g>
      </defs>

      <!-- 坐标网格背景 -->
      <rect width="1000" height="580" fill="url(#grid)"/>

      <!-- 楼梯与环境几何体 -->
      <g id="environment">
        <!-- 楼梯剖面 -->
        <path d="M 0 490 
                 L 320 490 
                 L 320 410 
                 L 490 410 
                 L 490 330 
                 L 660 330 
                 L 660 250 
                 L 830 250 
                 L 830 170 
                 L 1000 170 
                 L 1000 580 
                 L 0 580 Z" 
              class="stair-surface"/>

        <!-- 楼梯踏面防滑边缘发光带 -->
        <line x1="320" y1="410" x2="490" y2="410" class="stair-edge-highlight"/>
        <line x1="490" y1="330" x2="660" y2="330" class="stair-edge-highlight"/>
        <line x1="660" y1="250" x2="830" y2="250" class="stair-edge-highlight"/>
        <line x1="830" y1="170" x2="1000" y2="170" class="stair-edge-highlight"/>
        <line x1="0" y1="490" x2="320" y2="490" class="stair-edge-highlight"/>

        <!-- 楼梯立面警示斑马纹 -->
        <line x1="320" y1="420" x2="320" y2="480" class="hazard-stripe"/>
        <line x1="490" y1="340" x2="490" y2="400" class="hazard-stripe"/>
        <line x1="660" y1="260" x2="660" y2="320" class="hazard-stripe"/>
        <line x1="830" y1="180" x2="830" y2="240" class="hazard-stripe"/>

        <!-- 楼梯台阶尺寸标注 -->
        <g opacity="0.4" transform="translate(495, 370)">
          <text x="0" y="0" fill="#cbd5e1" font-size="10" font-family="var(--font-mono)">阶高 h=80</text>
        </g>
        <g opacity="0.4" transform="translate(540, 322)">
          <text x="0" y="0" fill="#cbd5e1" font-size="10" font-family="var(--font-mono)">踏宽 w=170</text>
        </g>
      </g>

      <!-- 动态轨迹线与触地点指示层 -->
      <g id="trajectory-layer">
        <!-- 轨迹留痕将在 JS 中动态绘制 -->
        <path id="front-wheel-trail" d="" fill="none" stroke="rgba(0,240,255,0.4)" stroke-width="1.5" stroke-dasharray="2,2"/>
        <path id="cargo-trail" d="" fill="none" stroke="rgba(255,209,102,0.6)" stroke-width="2"/>
      </g>

      <!-- 车辆主体机构动力学装配体 -->
      <g id="robot-assembly">
        
        <!-- 1. 底盘大梁 (连接后轮轴与前轮轴) -->
        <g id="chassis-group">
          <!-- 桁架大梁 -->
          <line id="chassis-beam" x1="0" y1="0" x2="200" y2="0" stroke="url(#chassis-grad)" stroke-width="10" stroke-linecap="round"/>
          <line id="chassis-core" x1="0" y1="0" x2="200" y2="0" stroke="#00f0ff" stroke-width="2" stroke-linecap="round" opacity="0.8"/>
          <!-- 大梁上的铰接点安装座 -->
          <circle id="mount-rear" cx="40" cy="0" r="5" fill="#1e293b" stroke="#00f0ff" stroke-width="1.5"/>
          <circle id="mount-damper" cx="150" cy="0" r="5" fill="#1e293b" stroke="#ff9f1c" stroke-width="1.5"/>
        </g>

        <!-- 2. 后行星三轮组 -->
        <g id="rear-tri-star">
          <!-- 转臂总成 -->
          <use href="#tri-star-arm" />
          <!-- 3个行星子轮 -->
          <g id="rear-w0" transform="translate(0, -48)"><use href="#sub-wheel"/></g>
          <g id="rear-w1" transform="translate(41.57, 24)"><use href="#sub-wheel"/></g>
          <g id="rear-w2" transform="translate(-41.57, 24)"><use href="#sub-wheel"/></g>
        </g>

        <!-- 3. 前行星三轮组 (主动/主要翻越组) -->
        <g id="front-tri-star">
          <!-- 转动扭矩力弧指示 (翻转时高亮) -->
          <path id="front-torque-arc" d="M 0 -58 A 58 58 0 0 1 50 30" fill="none" stroke="#ff9f1c" stroke-width="3" stroke-dasharray="4,4" filter="url(#glow-orange)" opacity="0"/>
          <!-- 转臂总成 -->
          <use href="#tri-star-arm" />
          <!-- 3个行星子轮 -->
          <g id="front-w0" transform="translate(0, -48)"><use href="#sub-wheel"/></g>
          <g id="front-w1" transform="translate(41.57, 24)"><use href="#sub-wheel"/></g>
          <g id="front-w2" transform="translate(-41.57, 24)"><use href="#sub-wheel"/></g>
          <!-- 翻转力矩动态箭头提示 -->
          <g id="front-force-arrow" opacity="0">
            <line x1="0" y1="0" x2="35" y2="-35" stroke="#ff9f1c" stroke-width="2.5" marker-end="url(#arrow)"/>
            <text x="38" y="-38" fill="#ff9f1c" font-size="11" font-family="var(--font-mono)" font-weight="bold">F_flip</text>
          </g>
        </g>

        <!-- 4. 被动阻尼减震与水平保持机构 -->
        <!-- 后主摆臂 (Passive Swing Arm) -->
        <line id="swing-arm" x1="0" y1="0" x2="0" y2="-60" stroke="#64748b" stroke-width="6" stroke-linecap="round"/>
        <circle id="swing-hinge-top" cx="0" cy="-60" r="4.5" fill="#00f0ff"/>

        <!-- 前液压阻尼器 (Hydraulic Damper: 缸体 + 活塞杆) -->
        <g id="damper-group">
          <line id="damper-cylinder" x1="0" y1="0" x2="20" y2="-40" stroke="url(#damper-grad)" stroke-width="8" stroke-linecap="round"/>
          <line id="damper-rod" x1="20" y1="-40" x2="40" y2="-60" stroke="#00f0ff" stroke-width="4" stroke-linecap="round"/>
          <!-- 减震弹簧线圈简绘 -->
          <line id="damper-spring" x1="10" y1="-20" x2="30" y2="-50" stroke="#ffd166" stroke-width="2" stroke-dasharray="3,3"/>
          <circle id="damper-hinge-top" cx="40" cy="-60" r="4.5" fill="#ff9f1c"/>
        </g>

        <!-- 5. 顶层调平载物平台与精密货物 (始终被动保持水平) -->
        <g id="cargo-platform">
          <!-- 调平底座平台 -->
          <rect x="-30" y="-12" width="220" height="12" rx="4" fill="url(#cargo-grad)" stroke="#00f0ff" stroke-width="1.8"/>
          <!-- 平台内部骨架轻量化孔 -->
          <circle cx="20" cy="-6" r="3" fill="#0b0f17"/>
          <circle cx="80" cy="-6" r="3" fill="#0b0f17"/>
          <circle cx="140" cy="-6" r="3" fill="#0b0f17"/>

          <!-- 载运的高价值精密设备箱 -->
          <rect x="-10" y="-72" width="180" height="60" rx="3" fill="#1e293b" stroke="#64748b" stroke-width="1.5"/>
          <rect x="0" y="-62" width="160" height="40" rx="2" fill="#0f172a" stroke="rgba(0,240,255,0.3)" stroke-width="1"/>
          
          <!-- 货物状态仪表:微型虚拟水平仪气泡 -->
          <g transform="translate(80, -42)">
            <rect x="-35" y="-8" width="70" height="16" rx="8" fill="#09131f" stroke="#00f0ff" stroke-width="1.2"/>
            <line x1="-10" y1="-8" x2="-10" y2="8" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
            <line x1="10" y1="-8" x2="10" y2="8" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
            <!-- 气泡 (动态保持中央) -->
            <circle id="spirit-bubble" cx="0" cy="0" r="5" fill="#00f0ff" filter="url(#glow-cyan)"/>
            <text x="0" y="18" fill="#94a3b8" font-size="8" font-family="var(--font-mono)" text-anchor="middle">HORIZON: 0.0°</text>
          </g>

          <!-- 载荷标识 -->
          <text x="15" y="-48" fill="#ffd166" font-size="9" font-family="var(--font-mono)" font-weight="bold">IFR-PAYLOAD</text>
          <text x="15" y="-36" fill="#64748b" font-size="8" font-family="var(--font-mono)">AUTO-STABLE</text>
        </g>

      </g>

      <!-- 尺寸与运动原理解析标注微图元 -->
      <g id="annotations" opacity="0.85">
        <!-- 动态摆角限制指示弧 -->
        <g id="angle-indicator" transform="translate(0, 0)">
          <path id="angle-arc" d="" fill="none" stroke="#ffd166" stroke-width="1.5" stroke-dasharray="2,2"/>
          <text id="angle-text" x="0" y="0" fill="#ffd166" font-size="10" font-family="var(--font-mono)">θ=0°</text>
        </g>
      </g>
    </svg>
  </main>

  <!-- 底部微型浮动控制条 (支持暂停、拖动、阶段一键切换) -->
  <footer class="hud-controller">
    <button id="btn-play" class="ctrl-btn active">
      <span id="play-icon">⏸</span> 暂停
    </button>
    <div class="timeline-slider-wrap">
      <input type="range" id="time-slider" class="timeline-slider" min="0" max="1000" value="0">
    </div>
    <div id="phase-label" class="phase-badge">平地行驶</div>
    <button id="btn-mode-flat" class="ctrl-btn">平地</button>
    <button id="btn-mode-climb" class="ctrl-btn">攀爬跨障</button>
    <button id="btn-mode-damping" class="ctrl-btn">阻尼抑振</button>
  </footer>

  <script>
    /**
     * 行星三轮组爬楼梯自适应机构 - 运动学仿真引擎
     * 遵循 TRIZ 最终理想解 (IFR):利用机械自适应翻转 + 被动阻尼平衡消除碰撞与倾角矛盾
     */
    (function() {
      // 机构核心几何与运动学参数
      const R_ARM = 48;        // 星轮转臂半径 (等效 165mm)
      const R_WHEEL = 18;      // 行星小轮半径 (等效 120mm 轮径)
      const WHEEL_BASE = 190;  // 前后星轮中心轴距
      const STAIR_W = 170;     // 楼梯踏步宽度
      const STAIR_H = 80;      // 楼梯踏步高度
      const STAIR_X0 = 320;    // 第一级台阶立面 X 坐标
      const GROUND_Y = 490;    // 平地 Y 坐标

      // 关键 DOM 节点缓存
      const svgStage = document.getElementById('stage');
      const rearTriStar = document.getElementById('rear-tri-star');
      const frontTriStar = document.getElementById('front-tri-star');
      const chassisBeam = document.getElementById('chassis-beam');
      const chassisCore = document.getElementById('chassis-core');
      const mountRear = document.getElementById('mount-rear');
      const mountDamper = document.getElementById('mount-damper');
      const swingArm = document.getElementById('swing-arm');
      const swingHingeTop = document.getElementById('swing-hinge-top');
      const damperCylinder = document.getElementById('damper-cylinder');
      const damperRod = document.getElementById('damper-rod');
      const damperSpring = document.getElementById('damper-spring');
      const damperHingeTop = document.getElementById('damper-hinge-top');
      const cargoPlatform = document.getElementById('cargo-platform');
      const spiritBubble = document.getElementById('spirit-bubble');
      const frontTorqueArc = document.getElementById('front-torque-arc');
      const frontForceArrow = document.getElementById('front-force-arrow');
      const cargoTrail = document.getElementById('cargo-trail');
      const timeSlider = document.getElementById('time-slider');
      const phaseLabel = document.getElementById('phase-label');
      const btnPlay = document.getElementById('btn-play');
      const playIcon = document.getElementById('play-icon');

      // 遥测数据文本节点
      const telTorque = document.getElementById('tel-torque');
      const telDamper = document.getElementById('tel-damper');
      const telAcc = document.getElementById('tel-acc');
      const telTilt = document.getElementById('tel-tilt');
      const telSwing = document.getElementById('tel-swing');
      const telMode = document.getElementById('tel-mode');

      // 运动轨迹点缓存
      const cargoTrailPoints = [];

      // 动画时序与状态控制
      let isPlaying = true;
      let animProgress = 0; // 0.0 ~ 1.0 循环
      const ANIM_DURATION = 14000; // 单次完整越障周期 14 秒
      let lastTimestamp = performance.now();

      /**
       * 环境几何高度计算函数:根据小轮 X 位置获取当前地面/台阶高度
       */
      function getTerrainHeight(x) {
        if (x < STAIR_X0) return GROUND_Y;
        if (x < STAIR_X0 + STAIR_W) return GROUND_Y - STAIR_H * 1;
        if (x < STAIR_X0 + STAIR_W * 2) return GROUND_Y - STAIR_H * 2;
        if (x < STAIR_X0 + STAIR_W * 3) return GROUND_Y - STAIR_H * 3;
        return GROUND_Y - STAIR_H * 4;
      }

      /**
       * 行星三轮组运动学解算器:
       * 输入中心 X 坐标,计算星轮中心高度 Y、星轮转臂角度 angleArm,以及各子轮自转角 angleWheel
       */
      function solveTriStarKinematics(xCenter) {
        // 单个台阶爬升的触发区间
        // 平地时双轮接地 (标准对称角 30° / 150° 接地,中心高度 = Terrain_Y - R_ARM*sin(30°) - R_WHEEL = Terrain_Y - 42)
        const baseCenterYOffset = 42;
        
        let yCenter = getTerrainHeight(xCenter) - baseCenterYOffset;
        let armAngle = 0; // 0° 表示单轮正上方,两轮在下方平地支撑
        let isFlipping = false;
        let flipProgress = 0;

        // 检测前轮是否撞上台阶立面并触发 120° 翻转
        for (let stepIdx = 0; stepIdx < 4; stepIdx++) {
          const stairStepX = STAIR_X0 + stepIdx * STAIR_W;
          // 当轮组前锋靠近立面时 (触碰点约在 stairStepX 附近)
          const flipStartX = stairStepX - 35;
          const flipEndX = flipStartX + 85;

          if (xCenter >= flipStartX && xCenter <= flipEndX) {
            isFlipping = true;
            flipProgress = (xCenter - flipStartX) / (flipEndX - flipStartX);
            
            // 使用平滑的 S 型缓动翻转函数
            const smoothT = Math.sin((flipProgress - 0.5) * Math.PI) * 0.5 + 0.5;
            
            // 转臂翻转 120° (每越过一阶翻转 2π/3)
            armAngle = (stepIdx * 120) + smoothT * 120;
            
            // 翻转时轮组中心的轨迹为一个倒立摆滚弧运动
            const groundBefore = GROUND_Y - stepIdx * STAIR_H - baseCenterYOffset;
            const groundAfter = GROUND_Y - (stepIdx + 1) * STAIR_H - baseCenterYOffset;
            
            // 高度平滑抬升 + 弧顶轻微拱起
            const arcLift = Math.sin(smoothT * Math.PI) * 12;
            yCenter = groundBefore + (groundAfter - groundBefore) * smoothT - arcLift;
            break;
          } else if (xCenter > flipEndX && stepIdx < 3 && xCenter < STAIR_X0 + (stepIdx + 1) * STAIR_W - 35) {
            // 台阶踏面平稳滚动段
            armAngle = (stepIdx + 1) * 120;
            yCenter = GROUND_Y - (stepIdx + 1) * STAIR_H - baseCenterYOffset;
          } else if (xCenter > STAIR_X0 + 3 * STAIR_W + 50) {
            armAngle = 4 * 120;
            yCenter = GROUND_Y - 4 * STAIR_H - baseCenterYOffset;
          }
        }

        return { x: xCenter, y: yCenter, armAngle, isFlipping, flipProgress };
      }

      /**
       * 主渲染与机构联动更新逻辑
       */
      function updateKinematics(progress) {
        // 全局小车 X 推进范围:从平地 X=110 到高台 X=880
        const startX = 110;
        const endX = 860;
        const frontX = startX + progress * (endX - startX);
        const rearX = frontX - WHEEL_BASE;

        // 1. 解算前后行星轮组位置与角度
        const frontState = solveTriStarKinematics(frontX);
        const rearState = solveTriStarKinematics(rearX);

        // 2. 更新前后轮组在 SVG 中的位置和旋转
        frontTriStar.setAttribute('transform', `translate(${frontState.x}, ${frontState.y}) rotate(${-frontState.armAngle})`);
        rearTriStar.setAttribute('transform', `translate(${rearState.x}, ${rearState.y}) rotate(${-rearState.armAngle})`);

        // 小轮自转(平地时快速滚动,翻转时行星轮系协同反转)
        const wheelRollAngle = frontX * 1.8;
        ['front-w0', 'front-w1', 'front-w2'].forEach(id => {
          const el = document.getElementById(id);
          if (el) el.setAttribute('transform', el.getAttribute('transform').split(' ')[0] + ` rotate(${wheelRollAngle})`);
        });
        ['rear-w0', 'rear-w1', 'rear-w2'].forEach(id => {
          const el = document.getElementById(id);
          if (el) el.setAttribute('transform', el.getAttribute('transform').split(' ')[0] + ` rotate(${wheelRollAngle})`);
        });

        // 3. 更新底盘主大梁 (连接前后轴)
        const dx = frontState.x - rearState.x;
        const dy = frontState.y - rearState.y;
        const chassisAngleRad = Math.atan2(dy, dx);
        const chassisAngleDeg = chassisAngleRad * (180 / Math.PI);
        const chassisLength = Math.sqrt(dx * dx + dy * dy);

        const chassisGroup = document.getElementById('chassis-group');
        chassisGroup.setAttribute('transform', `translate(${rearState.x}, ${rearState.y}) rotate(${chassisAngleDeg})`);
        chassisBeam.setAttribute('x2', chassisLength);
        chassisCore.setAttribute('x2', chassisLength);

        // 4. 被动阻尼调平机构求解 (利用平行四边形摆臂 + 前端液压阻尼)
        // 大梁上的两个固定铰点在全局坐标系中的位置:
        const mountRearGlobalX = rearState.x + Math.cos(chassisAngleRad) * 35;
        const mountRearGlobalY = rearState.y + Math.sin(chassisAngleRad) * 35;
        const mountDamperGlobalX = rearState.x + Math.cos(chassisAngleRad) * 145;
        const mountDamperGlobalY = rearState.y + Math.sin(chassisAngleRad) * 145;

        // 货箱平台期望保持水平 (仰角极小,阻尼吸收冲击)
        const targetPitch = 0; // 期望 0° 水平
        // 摆臂根据大梁倾角被动摆动,最大摆角限制在 ±12° 内
        const swingArmAngleDeg = -chassisAngleDeg; // 被动反向补偿
        const swingArmLength = 55;

        // 平台后部铰接点位置
        const platformRearX = mountRearGlobalX + Math.sin(swingArmAngleDeg * Math.PI / 180) * 8;
        const platformRearY = mountRearGlobalY - Math.cos(swingArmAngleDeg * Math.PI / 180) * swingArmLength;

        // 更新后摆臂连杆
        swingArm.setAttribute('x1', mountRearGlobalX);
        swingArm.setAttribute('y1', mountRearGlobalY);
        swingArm.setAttribute('x2', platformRearX);
        swingArm.setAttribute('y2', platformRearY);
        swingHingeTop.setAttribute('cx', platformRearX);
        swingHingeTop.setAttribute('cy', platformRearY);

        // 平台前铰接点 (水平距离 120px)
        const platformFrontX = platformRearX + 120;
        const platformFrontY = platformRearY; // 保持水平

        // 更新货箱平台位置 (被动保持绝对平稳)
        // 微小阻尼残余波动 (仿真真实惯性抑振)
        const dampingJitter = (frontState.isFlipping || rearState.isFlipping) ? Math.sin(Date.now() * 0.02) * 0.4 : 0;
        cargoPlatform.setAttribute('transform', `translate(${platformRearX}, ${platformRearY}) rotate(${dampingJitter})`);

        // 更新前液压阻尼器 (连接 mountDamper 与 platformFront)
        damperCylinder.setAttribute('x1', mountDamperGlobalX);
        damperCylinder.setAttribute('y1', mountDamperGlobalY);
        const damperMidX = mountDamperGlobalX + (platformFrontX - mountDamperGlobalX) * 0.55;
        const damperMidY = mountDamperGlobalY + (platformFrontY - mountDamperGlobalY) * 0.55;
        damperCylinder.setAttribute('x2', damperMidX);
        damperCylinder.setAttribute('y2', damperMidY);

        damperRod.setAttribute('x1', damperMidX);
        damperRod.setAttribute('y1', damperMidY);
        damperRod.setAttribute('x2', platformFrontX);
        damperRod.setAttribute('y2', platformFrontY);

        damperSpring.setAttribute('x1', mountDamperGlobalX + (damperMidX - mountDamperGlobalX) * 0.3);
        damperSpring.setAttribute('y1', mountDamperGlobalY + (damperMidY - mountDamperGlobalY) * 0.3);
        damperSpring.setAttribute('x2', platformFrontX - 10);
        damperSpring.setAttribute('y2', platformFrontY + 5);

        damperHingeTop.setAttribute('cx', platformFrontX);
        damperHingeTop.setAttribute('cy', platformFrontY);

        // 5. 视觉高亮与动态力矩/力矢量暗示 (TRIZ 破除矛盾核心动作)
        if (frontState.isFlipping) {
          frontTorqueArc.setAttribute('opacity', '1');
          frontForceArrow.setAttribute('opacity', '1');
          frontTorqueArc.setAttribute('transform', `rotate(${Date.now() * 0.2 % 360})`);
        } else {
          frontTorqueArc.setAttribute('opacity', '0');
          frontForceArrow.setAttribute('opacity', '0');
        }

        // 水平仪气泡微动 (反映高稳定度)
        const bubbleOffset = dampingJitter * 8;
        spiritBubble.setAttribute('cx', bubbleOffset.toFixed(2));

        // 6. 货箱水平轨迹留痕绘制
        if (cargoTrailPoints.length === 0 || Math.abs(cargoTrailPoints[cargoTrailPoints.length - 1].x - platformRearX) > 4) {
          cargoTrailPoints.push({ x: platformRearX + 60, y: platformRearY - 35 });
          if (cargoTrailPoints.length > 90) cargoTrailPoints.shift();
          
          if (cargoTrailPoints.length > 2) {
            let pathD = `M ${cargoTrailPoints[0].x} ${cargoTrailPoints[0].y}`;
            for (let i = 1; i < cargoTrailPoints.length; i++) {
              pathD += ` L ${cargoTrailPoints[i].x} ${cargoTrailPoints[i].y}`;
            }
            cargoTrail.setAttribute('d', pathD);
          }
        }

        // 7. 更新微型 HUD 与阶段徽标
        let currentPhase = "平地巡航";
        let phaseColor = "var(--accent-cyan)";
        if (frontState.isFlipping && !rearState.isFlipping) {
          currentPhase = "前星轮自适应翻阶";
          phaseColor = "var(--accent-orange)";
        } else if (!frontState.isFlipping && rearState.isFlipping) {
          currentPhase = "后星轮跟进跨越";
          phaseColor = "var(--accent-gold)";
        } else if (frontState.isFlipping && rearState.isFlipping) {
          currentPhase = "连续越障爬升";
          phaseColor = "var(--accent-green)";
        }

        phaseLabel.textContent = currentPhase;
        phaseLabel.style.color = phaseColor;
        phaseLabel.style.borderColor = phaseColor;

        // 遥测数据动态变化模拟
        telTorque.textContent = frontState.isFlipping ? (22.5 + Math.sin(progress * 40) * 3).toFixed(1) + " N·m" : "4.2 N·m";
        telDamper.textContent = (chassisAngleDeg * 0.42).toFixed(1) + " mm";
        telSwing.textContent = (-chassisAngleDeg).toFixed(1) + "°";
        telTilt.textContent = (Math.abs(dampingJitter)).toFixed(2) + "° (极稳)";
        telMode.textContent = currentPhase;

        timeSlider.value = Math.floor(progress * 1000);
      }

      /**
       * 主动画循环 (自动加载即播放,平滑循环)
       */
      function animationLoop(timestamp) {
        if (isPlaying) {
          const delta = timestamp - lastTimestamp;
          animProgress += delta / ANIM_DURATION;
          if (animProgress >= 1.0) {
            animProgress = 0;
            cargoTrailPoints.length = 0; // 重置轨迹线
          }
          updateKinematics(animProgress);
        }
        lastTimestamp = timestamp;
        requestAnimationFrame(animationLoop);
      }

      // 启动自循环动画
      requestAnimationFrame((ts) => {
        lastTimestamp = ts;
        animationLoop(ts);
      });

      // 交互控制:播放/暂停
      btnPlay.addEventListener('click', () => {
        isPlaying = !isPlaying;
        if (isPlaying) {
          btnPlay.classList.add('active');
          btnPlay.innerHTML = '<span id="play-icon">⏸</span> 暂停';
          lastTimestamp = performance.now();
        } else {
          btnPlay.classList.remove('active');
          btnPlay.innerHTML = '<span id="play-icon">▶</span> 播放';
        }
      });

      // 交互控制:进度条拖动
      timeSlider.addEventListener('input', (e) => {
        animProgress = parseFloat(e.target.value) / 1000;
        updateKinematics(animProgress);
      });

      // 阶段快捷定位按钮
      document.getElementById('btn-mode-flat').addEventListener('click', () => {
        animProgress = 0.08;
        updateKinematics(animProgress);
      });
      document.getElementById('btn-mode-climb').addEventListener('click', () => {
        animProgress = 0.38; // 翻第一级台阶瞬间
        updateKinematics(animProgress);
      });
      document.getElementById('btn-mode-damping').addEventListener('click', () => {
        animProgress = 0.62; // 前后轮都在不同高度台阶,大梁倾角最大,阻尼发挥极致
        updateKinematics(animProgress);
      });

    })();
  </script>
</body>
</html>
积分规则:每轮对话扣10分