独立渲染引擎就绪引擎就绪
<!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: #060B12;
--grid-color: rgba(0, 240, 255, 0.05);
--stair-color: #121A28;
--stair-edge: #00F0FF;
--chassis: #1F2836;
--neon-cyan: #00F0FF;
--neon-orange: #FF4400;
--text-main: #FFFFFF;
--text-dim: #7A8EAA;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: var(--bg-color);
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
color: var(--text-main);
user-select: none;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.hud-overlay {
position: absolute;
z-index: 10;
pointer-events: none;
text-transform: uppercase;
}
.hud-top-left {
top: 30px;
left: 30px;
}
.hud-bottom-left {
bottom: 30px;
left: 30px;
}
.hud-bottom-right {
bottom: 30px;
right: 30px;
text-align: right;
}
.hud-title {
font-size: 14px;
font-weight: bold;
color: var(--neon-cyan);
margin-bottom: 8px;
letter-spacing: 1px;
text-shadow: 0 0 10px rgba(0, 240, 255, 0.4);
}
.hud-text {
font-size: 11px;
color: var(--text-dim);
line-height: 1.6;
}
.hud-highlight {
color: var(--text-main);
font-weight: bold;
}
.hud-value {
font-size: 28px;
font-weight: bold;
color: var(--neon-cyan);
text-shadow: 0 0 15px rgba(0, 240, 255, 0.6);
margin-top: 5px;
font-variant-numeric: tabular-nums;
}
.tag-orange { color: var(--neon-orange); }
.tag-cyan { color: var(--neon-cyan); }
.scan-line {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(to bottom, transparent, rgba(0, 240, 255, 0.2), transparent);
opacity: 0.5;
z-index: 20;
animation: scan 4s linear infinite;
pointer-events: none;
}
@keyframes scan {
0% { transform: translateY(-10vh); }
100% { transform: translateY(110vh); }
}
@keyframes pulse-ring {
0% { stroke-width: 1; opacity: 0.8; transform: scale(0.9); }
50% { stroke-width: 2; opacity: 1; transform: scale(1.1); text-shadow: 0 0 10px var(--neon-cyan); }
100% { stroke-width: 1; opacity: 0.8; transform: scale(0.9); }
}
.gyro-ring {
transform-origin: center;
animation: pulse-ring 2s ease-in-out infinite;
}
</style>
</head>
<body>
<div class="scan-line"></div>
<!-- UI Overlays -->
<div class="hud-overlay hud-top-left">
<div class="hud-title">■ 系统 IFR 状态:零姿态偏移</div>
<div class="hud-text">
<span>核心原理</span> // <span class="hud-highlight">移动越障与姿态平衡物理绝对解耦</span><br>
<span>底层构型</span> // <span class="tag-orange">行星式四轮组 (被动翻滚跨级)</span><br>
<span>顶层构型</span> // <span class="tag-cyan">主动液压自平衡云台 (动态逆向补偿)</span><br>
<span>响应延迟</span> // < 50ms<br>
<span>控制目标</span> // 载货平台倾覆力矩始终为零
</div>
</div>
<div class="hud-overlay hud-bottom-left">
<div class="hud-text" style="color:var(--neon-orange)" id="ui-status">当前状态:平地巡航模式</div>
<div class="hud-title" style="margin-top: 10px;">三轴陀螺仪姿态角</div>
<div class="hud-value" id="ui-tilt">0.00°</div>
</div>
<div class="hud-overlay hud-bottom-right">
<div class="hud-text">
■ 视觉引导图例<br>
<span style="color:#FF4400;">██</span> 动态受力翻转件<br>
<span style="color:#00F0FF;">██</span> 主动补偿液压缸<br>
<span style="color:#FFFFFF;">██</span> 零姿态载货平台
</div>
</div>
<!-- SVG Canvas -->
<div id="canvas-container">
<svg id="main-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="neon-glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur1" />
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur2" />
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="neon-glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur1" />
<feMerge>
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<pattern id="grid-pattern" width="60" height="60" patternUnits="userSpaceOnUse">
<path d="M 60 0 L 0 0 0 60" fill="none" stroke="rgba(0, 240, 255, 0.07)" stroke-width="1"/>
<circle cx="0" cy="0" r="1.5" fill="rgba(0, 240, 255, 0.3)"/>
</pattern>
<!-- Small Wheel Component -->
<g id="small-wheel-comp">
<circle cx="0" cy="0" r="16" fill="#1A222E" stroke="#7A8EAA" stroke-width="3"/>
<circle cx="0" cy="0" r="6" fill="#FF4400"/>
<path d="M 0 -16 L 0 16 M -16 0 L 16 0" stroke="#7A8EAA" stroke-width="2" stroke-dasharray="3 3"/>
</g>
</defs>
<!-- Background Grid (Fixed to camera) -->
<rect width="100%" height="100%" fill="url(#grid-pattern)" />
<!-- Translating Scene -->
<g id="scene">
<!-- Dynamic Terrain Path -->
<path id="terrain" fill="var(--stair-color)" stroke="var(--stair-edge)" stroke-width="3" filter="url(#neon-glow-cyan)"/>
<!-- Inner Terrain Fill for solid look without glowing bottom -->
<path id="terrain-fill" fill="var(--stair-color)" stroke="none"/>
<!-- Robot Assembly -->
<g id="robot">
<!-- Rear Planetary Wheel Assembly -->
<g id="rear-assembly">
<g id="rear-bracket" filter="url(#neon-glow-orange)">
<path d="M -65 -12 L 65 -12 L 65 12 L -65 12 Z" fill="#FF4400"/>
<path d="M -12 -65 L 12 -65 L 12 65 L -12 65 Z" fill="#FF4400"/>
<circle cx="0" cy="0" r="18" fill="#121A28" stroke="#FF4400" stroke-width="4"/>
</g>
<!-- 4 Small Wheels -->
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
<!-- Front Planetary Wheel Assembly -->
<g id="front-assembly">
<g id="front-bracket" filter="url(#neon-glow-orange)">
<path d="M -65 -12 L 65 -12 L 65 12 L -65 12 Z" fill="#FF4400"/>
<path d="M -12 -65 L 12 -65 L 12 65 L -12 65 Z" fill="#FF4400"/>
<circle cx="0" cy="0" r="18" fill="#121A28" stroke="#FF4400" stroke-width="4"/>
</g>
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
<!-- Main Chassis -->
<g id="chassis">
<!-- Structural links between axles and chassis center (Visual only) -->
<line id="rear-link" x1="-160" y1="0" x2="0" y2="0" stroke="#334455" stroke-width="14" stroke-linecap="round"/>
<line id="front-link" x1="160" y1="0" x2="0" y2="0" stroke="#334455" stroke-width="14" stroke-linecap="round"/>
<!-- Chassis Body -->
<polygon points="-180,-30 180,-30 210,15 -210,15" fill="#1A222E" stroke="#4A5A72" stroke-width="3"/>
<path d="M -100 -20 L 100 -20" stroke="#FF4400" stroke-width="2" stroke-dasharray="10 5" opacity="0.6"/>
<!-- Hydraulic Cylinder Bases (Fixed to Chassis) -->
<!-- Left Base -->
<path d="M -125 -30 L -115 -30 L -115 -70 L -125 -70 Z" fill="#2A3648" stroke="#4A5A72" stroke-width="2"/>
<circle cx="-120" cy="-25" r="6" fill="#00F0FF"/>
<!-- Right Base -->
<path d="M 115 -30 L 125 -30 L 125 -70 L 115 -70 Z" fill="#2A3648" stroke="#4A5A72" stroke-width="2"/>
<circle cx="120" cy="-25" r="6" fill="#00F0FF"/>
<!-- Hydraulic Pistons (Dynamic) -->
<line id="hyd-left" x1="-120" y1="-70" x2="-120" y2="-120" stroke="#00F0FF" stroke-width="6" stroke-linecap="round" filter="url(#neon-glow-cyan)"/>
<line id="hyd-right" x1="120" y1="-70" x2="120" y2="-120" stroke="#00F0FF" stroke-width="6" stroke-linecap="round" filter="url(#neon-glow-cyan)"/>
<!-- Central Pivot Base -->
<path d="M -20 -30 L 20 -30 L 10 -80 L -10 -80 Z" fill="#2A3648"/>
<circle cx="0" cy="-80" r="8" fill="#00F0FF" filter="url(#neon-glow-cyan)"/>
<!-- Cargo Platform (Absolute Horizontal) -->
<g id="platform">
<!-- Platform Base -->
<rect x="-160" y="-10" width="320" height="12" rx="4" fill="#FFFFFF"/>
<rect x="-150" y="-4" width="300" height="4" fill="#E0E0E0"/>
<!-- Mount points on platform -->
<circle cx="-120" cy="0" r="5" fill="#FF4400"/>
<circle cx="120" cy="0" r="5" fill="#FF4400"/>
<circle cx="0" cy="0" r="6" fill="#00F0FF"/>
<!-- Cargo Container -->
<g transform="translate(0, -70)">
<rect x="-100" y="-50" width="200" height="110" rx="6" fill="rgba(0, 240, 255, 0.08)" stroke="#00F0FF" stroke-width="2" filter="url(#neon-glow-cyan)"/>
<path d="M -80 -40 L -40 -40 M 80 -40 L 40 -40" stroke="#00F0FF" stroke-width="3"/>
<!-- Gyroscope IFR Indicator -->
<g class="gyro-ring">
<circle cx="0" cy="5" r="25" fill="none" stroke="#00F0FF" stroke-width="2" stroke-dasharray="12 6"/>
<circle cx="0" cy="5" r="15" fill="none" stroke="#00F0FF" stroke-width="1.5"/>
<circle cx="0" cy="5" r="4" fill="#00F0FF" filter="url(#neon-glow-cyan)"/>
</g>
<text x="0" y="-20" text-anchor="middle" fill="#00F0FF" font-size="12" font-weight="bold" letter-spacing="2">ZERO-TILT CARGO</text>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<script>
// --- System Kinematics Configuration ---
const config = {
W: 320, // Wheelbase (Distance between front and rear planetary centers)
R: 65, // Planetary bracket radius
r: 16, // Small wheel radius
stairH: 140, // Step height
stairW: 900, // Distance between steps
climbDist: 140, // Horizontal distance over which the bracket climb rotation occurs
speed: 3.5, // Animation base speed (px per frame)
platformCenterY: -130 // Platform absolute center Y offset relative to chassis axle line
};
const groundClearance = config.R + config.r; // 81px
// Element references
const scene = document.getElementById('scene');
const terrain = document.getElementById('terrain');
const terrainFill = document.getElementById('terrain-fill');
const chassis = document.getElementById('chassis');
const platform = document.getElementById('platform');
const rearAssembly = document.getElementById('rear-assembly');
const frontAssembly = document.getElementById('front-assembly');
const rearBracket = document.getElementById('rear-bracket');
const frontBracket = document.getElementById('front-bracket');
const rearLink = document.getElementById('rear-link');
const frontLink = document.getElementById('front-link');
const hydLeft = document.getElementById('hyd-left');
const hydRight = document.getElementById('hyd-right');
const uiTilt = document.getElementById('ui-tilt');
const uiStatus = document.getElementById('ui-status');
const swRotators = document.querySelectorAll('.sw-rotator');
let cameraX = 0;
let cameraY = 0;
let globalTime = 0;
/**
* Calculates the absolute Y position of a planetary axle given its absolute X.
*/
function getAxleY(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseY = stepCount * -config.stairH;
let localY = 0;
// Stair physical corner is at localX = 400
// Climb starts earlier by (config.climbDist / 2)
const cornerX = 400;
const startClimbX = cornerX - 20;
if (localX > startClimbX && localX <= startClimbX + config.climbDist) {
// Cosine interpolation for smooth axle arc over the step
let t = (localX - startClimbX) / config.climbDist;
localY = -config.stairH * (0.5 - 0.5 * Math.cos(t * Math.PI));
} else if (localX > startClimbX + config.climbDist) {
localY = -config.stairH;
}
return baseY + localY;
}
/**
* Calculates the rotation angle of the planetary bracket.
*/
function getBracketAngle(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseAngle = stepCount * 90;
let climbAngle = 0;
const cornerX = 400;
const startClimbX = cornerX - 20;
if (localX > startClimbX && localX <= startClimbX + config.climbDist) {
let t = (localX - startClimbX) / config.climbDist;
climbAngle = 90 * t;
} else if (localX > startClimbX + config.climbDist) {
climbAngle = 90;
}
return baseAngle + climbAngle;
}
/**
* Generates the SVG path for rigid square stairs.
*/
function updateTerrainPath(cx) {
// Draw terrain from cx - 1500 to cx + 2000
let startX = Math.floor((cx - 1500) / config.stairW) * config.stairW;
let endX = cx + 2000;
let pathD = `M ${startX}, 3000 `;
for (let x = startX; x < endX; x += config.stairW) {
let yTop = Math.floor(x / config.stairW) * -config.stairH + groundClearance;
let yBot = yTop - config.stairH;
pathD += `L ${x}, ${yTop} L ${x + 400}, ${yTop} L ${x + 400}, ${yBot} L ${x + config.stairW}, ${yBot} `;
}
pathD += `L ${endX}, 3000 Z`;
terrain.setAttribute('d', pathD);
terrainFill.setAttribute('d', pathD);
}
function animate() {
globalTime += config.speed;
// 1. Calculate Rear Axle
let Rx = globalTime;
let Ry = getAxleY(Rx);
// 2. Iteratively solve for Front Axle to maintain constant rigid wheelbase W
let Fx = Rx + config.W;
for(let i = 0; i < 5; i++) {
let tempFy = getAxleY(Fx);
let currentDist = Math.hypot(Fx - Rx, tempFy - Ry);
let error = config.W - currentDist;
Fx += error * 0.9;
}
let Fy = getAxleY(Fx);
// 3. Chassis Kinematics (Center & Pitch Angle)
let Cx = (Rx + Fx) / 2;
let Cy = (Ry + Fy) / 2;
let thetaRad = Math.atan2(Fy - Ry, Fx - Rx);
let thetaDeg = thetaRad * 180 / Math.PI;
// 4. Update Camera / Scene Translation (Keep Robot Centered)
const screenCx = window.innerWidth / 2;
const screenCy = window.innerHeight / 2 + 50; // slightly lowered center
scene.setAttribute('transform', `translate(${screenCx - Cx}, ${screenCy - Cy})`);
// 5. Render Terrain
updateTerrainPath(Cx);
// 6. Update Robot Elements Positioning
// Transform assemblies relative to Chassis Center
rearAssembly.setAttribute('transform', `translate(${Rx - Cx}, ${Ry - Cy})`);
frontAssembly.setAttribute('transform', `translate(${Fx - Cx}, ${Fy - Cy})`);
// Connect links visually
rearLink.setAttribute('x1', Rx - Cx);
rearLink.setAttribute('y1', Ry - Cy);
frontLink.setAttribute('x1', Fx - Cx);
frontLink.setAttribute('y1', Fy - Cy);
// Rotate Planetary Brackets
let rAngle = getBracketAngle(Rx);
let fAngle = getBracketAngle(Fx);
rearBracket.setAttribute('transform', `rotate(${rAngle})`);
frontBracket.setAttribute('transform', `rotate(${fAngle})`);
// Rotate Small Wheels (Rolling effect)
let wheelSpin = globalTime * 2.5;
swRotators.forEach(sw => sw.setAttribute('transform', `rotate(${wheelSpin})`));
// Rotate Main Chassis
chassis.setAttribute('transform', `translate(${Cx}, ${Cy}) rotate(${thetaDeg})`);
// 7. Active IFR Hydraulic Stabilization Logic
// The platform must be strictly horizontal globally.
// Since it's a child of chassis, we apply a counter-rotation `-thetaDeg`.
platform.setAttribute('transform', `translate(0, ${config.platformCenterY}) rotate(${-thetaDeg})`);
// Calculate active hydraulic piston extensions
// Left/Right mounts are at (-120, 0) and (120, 0) relative to platform base.
let rad = -thetaRad;
// Left Piston Target (Platform Local to Chassis Local)
let pLeftX_local = -120 * Math.cos(rad);
let pLeftY_local = -120 * Math.sin(rad);
let leftTargetX = pLeftX_local;
let leftTargetY = config.platformCenterY + pLeftY_local;
hydLeft.setAttribute('x2', leftTargetX);
hydLeft.setAttribute('y2', leftTargetY);
// Right Piston Target
let pRightX_local = 120 * Math.cos(rad);
let pRightY_local = 120 * Math.sin(rad);
let rightTargetX = pRightX_local;
let rightTargetY = config.platformCenterY + pRightY_local;
hydRight.setAttribute('x2', rightTargetX);
hydRight.setAttribute('y2', rightTargetY);
// 8. Update HUD Info
uiTilt.textContent = Math.abs(thetaDeg).toFixed(2) + '°';
if (Math.abs(thetaDeg) > 1.5) {
uiStatus.textContent = "当前状态:[告警] 主动越障平衡介入中...";
uiStatus.style.color = "var(--neon-cyan)";
} else {
uiStatus.textContent = "当前状态:平地巡航模式";
uiStatus.style.color = "var(--neon-orange)";
}
requestAnimationFrame(animate);
}
// Handle Resize
window.addEventListener('resize', () => {
// Camera automatically adjusts in the animation loop based on innerWidth/innerHeight
});
// Start Loop
requestAnimationFrame(animate);
</script>
</body>
</html>
非常抱歉之前的版本在结构嵌套上出现了小失误,导致行星轮的坐标轴未能跟随十字支架公转,从而“隐藏”在了中心点。
为了完美展示“彻底解耦”这一 TRIZ 最终理想解(IFR),我重新设计了底盘的动力学嵌套逻辑。现在,行星轮系将清晰可见,你将直观地看到小轮自转与十字支架翻滚跨级的协同过程。同时,我进一步提升了赛博朋克工业风的视觉表现力,增加了“绝对水平激光基准线”和实时的液压杆伸缩动画,以凸显理想解状态。
以下是修复且全面升级后的高保真交互式原理动画代码:
<!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: #03060A;
--grid-line: rgba(0, 240, 255, 0.08);
--stair-fill: #0B111A;
--stair-stroke: #00F0FF;
--chassis-dark: #121824;
--chassis-light: #202A3C;
--neon-cyan: #00F0FF;
--neon-orange: #FF5500;
--text-main: #FFFFFF;
--text-dim: #5C7699;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, #08101A 0%, var(--bg-color) 100%);
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
color: var(--text-main);
user-select: none;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
/* UI 面板与排版限制:精简、边缘化、不遮挡动画 */
.hud-overlay {
position: absolute;
z-index: 10;
pointer-events: none;
}
.hud-top-left { top: 25px; left: 25px; }
.hud-bottom-left { bottom: 25px; left: 25px; }
.hud-top-right { top: 25px; right: 25px; text-align: right; }
.hud-title {
font-size: 13px;
font-weight: bold;
color: var(--neon-cyan);
margin-bottom: 6px;
letter-spacing: 1px;
text-shadow: 0 0 8px rgba(0, 240, 255, 0.5);
}
.hud-text {
font-size: 11px;
color: var(--text-dim);
line-height: 1.5;
background: rgba(3, 6, 10, 0.6);
padding: 10px 15px;
border-left: 2px solid var(--neon-cyan);
backdrop-filter: blur(4px);
}
.hud-highlight { color: var(--text-main); font-weight: bold; }
.tag-orange { color: var(--neon-orange); }
.tag-cyan { color: var(--neon-cyan); }
.hud-value-box {
background: rgba(0, 240, 255, 0.05);
border: 1px solid rgba(0, 240, 255, 0.2);
padding: 8px 15px;
margin-top: 10px;
display: inline-block;
}
.hud-value {
font-size: 24px;
font-weight: bold;
color: var(--neon-cyan);
text-shadow: 0 0 10px rgba(0, 240, 255, 0.5);
font-variant-numeric: tabular-nums;
}
.hud-sub {
font-size: 10px;
color: var(--neon-orange);
margin-top: 4px;
}
/* 绝对水平基准激光线 */
.laser-level {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: var(--neon-cyan);
box-shadow: 0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan);
opacity: 0.3;
z-index: 5;
pointer-events: none;
transform: translateY(-90px); /* 对齐货台高度 */
}
</style>
</head>
<body>
<div class="laser-level"></div>
<!-- UI 层 -->
<div class="hud-overlay hud-top-left">
<div class="hud-title">▼ 最终理想解 (IFR) 原理重构</div>
<div class="hud-text">
<span>设计原则</span> : <span class="hud-highlight">解耦“底层移动”与“顶层姿态”</span><br>
<span>被动翻越</span> : <span class="tag-orange">行星轮组 (撞击自适应翻滚)</span><br>
<span>主动补偿</span> : <span class="tag-cyan">三轴陀螺仪 + 液压云台逆向调平</span><br>
<span>消除矛盾</span> : 克服越障必需的剧烈姿态变化带来的货损倾覆
</div>
</div>
<div class="hud-overlay hud-top-right">
<div class="hud-text" style="border-left:none; border-right:2px solid var(--neon-orange);">
<span style="color:#FF5500;">■</span> 翻滚越障构件 (动态)<br>
<span style="color:#00F0FF;">■</span> 液压自平衡云台 (主动)<br>
<span style="color:#FFFFFF;">■</span> 零位移理想解平台
</div>
</div>
<div class="hud-overlay hud-bottom-left">
<div class="hud-value-box">
<div style="font-size: 10px; color: var(--text-dim);">顶层货台绝对倾角</div>
<div class="hud-value" id="ui-tilt">0.00°</div>
<div class="hud-sub" id="ui-status">▶ 状态:平地巡航</div>
</div>
</div>
<!-- 核心动画 SVG 层 -->
<div id="canvas-container">
<svg id="main-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<pattern id="grid" width="80" height="80" patternUnits="userSpaceOnUse">
<path d="M 80 0 L 0 0 0 80" fill="none" stroke="var(--grid-line)" stroke-width="1"/>
<circle cx="0" cy="0" r="1.5" fill="rgba(0, 240, 255, 0.4)"/>
</pattern>
<!-- 重构的行星小轮:高可见度、带齿纹轮毂以便观察自转 -->
<g id="small-wheel-comp">
<!-- 轮胎外圈 -->
<circle cx="0" cy="0" r="18" fill="#0A0E14" stroke="#FF5500" stroke-width="2"/>
<!-- 自转指示辐条 -->
<path d="M 0 -18 L 0 -8 M 0 18 L 0 8 M -18 0 L -8 0 M 18 0 L 8 0" stroke="#FF5500" stroke-width="3" stroke-linecap="round"/>
<circle cx="0" cy="0" r="14" fill="none" stroke="#202A3C" stroke-width="2"/>
<circle cx="0" cy="0" r="5" fill="#00F0FF" filter="url(#glow-cyan)"/>
</g>
</defs>
<!-- 固定背景网格 -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- 随镜头移动的场景 -->
<g id="scene">
<!-- 阶梯地形 -->
<path id="terrain" fill="var(--stair-fill)" stroke="var(--stair-stroke)" stroke-width="3" filter="url(#glow-cyan)"/>
<path id="terrain-fill" fill="var(--stair-fill)" stroke="none"/>
<!-- 机器人总成 -->
<g id="robot">
<!-- 后轮:行星轮组 -->
<g id="rear-assembly">
<!-- 行星轮系旋转主轴组 (包含支架与轮子) -->
<g id="rear-planetary">
<!-- 十字支架 -->
<g filter="url(#glow-orange)">
<path d="M -65 -10 L 65 -10 L 65 10 L -65 10 Z" fill="#FF5500"/>
<path d="M -10 -65 L 10 -65 L 10 65 L -10 65 Z" fill="#FF5500"/>
<circle cx="0" cy="0" r="22" fill="#121824" stroke="#FF5500" stroke-width="4"/>
</g>
<!-- 嵌套的小轮容器,保留位移,内部施加自转 -->
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
<!-- 悬挂连杆 (连接到中心) -->
<line x1="0" y1="0" x2="160" y2="-30" stroke="#202A3C" stroke-width="12" stroke-linecap="round"/>
</g>
<!-- 前轮:行星轮组 -->
<g id="front-assembly">
<g id="front-planetary">
<g filter="url(#glow-orange)">
<path d="M -65 -10 L 65 -10 L 65 10 L -65 10 Z" fill="#FF5500"/>
<path d="M -10 -65 L 10 -65 L 10 65 L -10 65 Z" fill="#FF5500"/>
<circle cx="0" cy="0" r="22" fill="#121824" stroke="#FF5500" stroke-width="4"/>
</g>
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
<!-- 悬挂连杆 -->
<line x1="0" y1="0" x2="-160" y2="-30" stroke="#202A3C" stroke-width="12" stroke-linecap="round"/>
</g>
<!-- 主底盘 (随地形倾斜) -->
<g id="chassis">
<!-- 底盘主体 -->
<polygon points="-180,-20 180,-20 200,10 -200,10" fill="#121824" stroke="#4A5A72" stroke-width="2"/>
<rect x="-50" y="-30" width="100" height="20" fill="#202A3C"/>
<!-- 主动液压自平衡系统 -->
<!-- 液压缸底座 -->
<rect x="-140" y="-25" width="20" height="15" fill="#202A3C"/>
<rect x="120" y="-25" width="20" height="15" fill="#202A3C"/>
<!-- 动态伸缩液压杆 -->
<line id="hyd-left" x1="-130" y1="-20" x2="-130" y2="-80" stroke="#00F0FF" stroke-width="8" stroke-linecap="round" filter="url(#glow-cyan)"/>
<line id="hyd-right" x1="130" y1="-20" x2="130" y2="-80" stroke="#00F0FF" stroke-width="8" stroke-linecap="round" filter="url(#glow-cyan)"/>
<!-- 中心铰接基座 -->
<path d="M -15 -30 L 15 -30 L 0 -80 Z" fill="#3B4C63"/>
<circle cx="0" cy="-80" r="6" fill="#00F0FF" filter="url(#glow-cyan)"/>
<!-- 载货云台:逆向补偿保持绝对水平 -->
<g id="platform">
<!-- 云台板 -->
<rect x="-160" y="-8" width="320" height="10" rx="3" fill="#FFFFFF"/>
<rect x="-155" y="-3" width="310" height="3" fill="#E0E0E0"/>
<!-- 液压杆上部球铰挂载点 -->
<circle cx="-130" cy="0" r="5" fill="#00F0FF"/>
<circle cx="130" cy="0" r="5" fill="#00F0FF"/>
<circle cx="0" cy="0" r="7" fill="#FF5500"/>
<!-- 精密货物箱 -->
<g transform="translate(0, -60)">
<!-- 陀螺仪外壳 -->
<rect x="-100" y="-50" width="200" height="100" rx="4" fill="rgba(0, 240, 255, 0.05)" stroke="#00F0FF" stroke-width="2" filter="url(#glow-cyan)"/>
<path d="M -80 -30 L -40 -30 M 80 -30 L 40 -30" stroke="#00F0FF" stroke-width="2"/>
<!-- 内部稳定悬浮球 -->
<circle cx="0" cy="0" r="25" fill="none" stroke="#00F0FF" stroke-width="2" stroke-dasharray="10 5"/>
<circle cx="0" cy="0" r="15" fill="none" stroke="#00F0FF" stroke-width="1"/>
<circle cx="0" cy="0" r="6" fill="#00F0FF" filter="url(#glow-cyan)"/>
<text x="0" y="-12" text-anchor="middle" fill="#00F0FF" font-size="10" font-weight="bold" letter-spacing="1">ZERO-TILT</text>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<script>
// --- 核心动力学与尺寸配置 ---
const config = {
W: 320, // 轴距 (前后行星轮中心距离)
R: 65, // 十字支架旋转半径
r: 18, // 行星小轮半径
stairH: 150, // 台阶高度
stairW: 800, // 台阶跨度 (平地长度)
speed: 3.5, // 基础行进速度
pivotY: -80 // 底盘到云台中心铰接点的高度
};
// 离地间隙:十字臂处于 '+' 姿态时,主轴距离地面的高度
const groundClearance = config.R + config.r; // 83px
// 定义台阶垂直面的 X 坐标 (局部坐标系)
const cornerX = 400;
// 行星轮在碰到台阶立面时开始“翻滚越级”的起始点
const startClimbX = cornerX - groundClearance;
// 翻滚动作水平推进距离 (约等于旋转跨越的过程)
const climbDist = 160;
// DOM 元素引用
const scene = document.getElementById('scene');
const terrain = document.getElementById('terrain');
const terrainFill = document.getElementById('terrain-fill');
const chassis = document.getElementById('chassis');
const platform = document.getElementById('platform');
const rearAssembly = document.getElementById('rear-assembly');
const frontAssembly = document.getElementById('front-assembly');
const rearPlanetary = document.getElementById('rear-planetary');
const frontPlanetary = document.getElementById('front-planetary');
const hydLeft = document.getElementById('hyd-left');
const hydRight = document.getElementById('hyd-right');
const uiTilt = document.getElementById('ui-tilt');
const uiStatus = document.getElementById('ui-status');
const swRotators = document.querySelectorAll('.sw-rotator');
let globalTime = 0;
/**
* 基于全局 X 坐标计算当前主轴的绝对 Y 坐标 (台阶跨越平滑函数)
*/
function getAxleY(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
// 基础地面高度随阶梯递减
let baseY = stepCount * -config.stairH - groundClearance;
if (localX <= startClimbX) {
return baseY;
} else if (localX > startClimbX && localX <= startClimbX + climbDist) {
// 利用 smoothstep 贝塞尔缓动模拟行星轮绕台阶顶点的起伏轨迹
let t = (localX - startClimbX) / climbDist;
let smoothT = t * t * (3 - 2 * t);
return baseY - config.stairH * smoothT;
} else {
return baseY - config.stairH;
}
}
/**
* 计算行星十字支架的被动翻转角度
*/
function getBracketAngle(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseAngle = stepCount * 90;
if (localX <= startClimbX) {
return baseAngle;
} else if (localX > startClimbX && localX <= startClimbX + climbDist) {
// 同步匹配翻越高度进行 90 度支架翻滚
let t = (localX - startClimbX) / climbDist;
let smoothT = t * t * (3 - 2 * t);
return baseAngle + 90 * smoothT;
} else {
return baseAngle + 90;
}
}
/**
* 动态生成楼梯 SVG 路径
*/
function updateTerrainPath(cx) {
let startX = Math.floor((cx - 1500) / config.stairW) * config.stairW;
let endX = cx + 2000;
let pathD = `M ${startX}, 2000 `;
for (let x = startX; x < endX; x += config.stairW) {
let yTop = Math.floor(x / config.stairW) * -config.stairH;
let yBot = yTop - config.stairH;
let stepX = x + cornerX;
pathD += `L ${x}, ${yTop} L ${stepX}, ${yTop} L ${stepX}, ${yBot} L ${x + config.stairW}, ${yBot} `;
}
pathD += `L ${endX}, 2000 Z`;
terrain.setAttribute('d', pathD);
terrainFill.setAttribute('d', pathD);
}
function animate() {
globalTime += config.speed;
// 1. 后轴驱动计算
let Rx = globalTime;
let Ry = getAxleY(Rx);
// 2. 基于刚性底盘连杆迭代约束前轴位置 (保证轴距恒定)
let Fx = Rx + config.W;
for(let i = 0; i < 5; i++) {
let tempFy = getAxleY(Fx);
let currentDist = Math.hypot(Fx - Rx, tempFy - Ry);
let error = config.W - currentDist;
Fx += error * ((Fx - Rx) / currentDist) * 0.8;
}
let Fy = getAxleY(Fx);
// 3. 计算底盘中心点与车体俯仰角 (剧烈变化的数据)
let Cx = (Rx + Fx) / 2;
let Cy = (Ry + Fy) / 2;
let thetaRad = Math.atan2(Fy - Ry, Fx - Rx);
let thetaDeg = thetaRad * 180 / Math.PI;
// 4. 镜头跟踪:确保车体始终居于视口中央
const screenCx = window.innerWidth / 2;
const screenCy = window.innerHeight / 2 + 30;
scene.setAttribute('transform', `translate(${screenCx - Cx}, ${screenCy - Cy})`);
// 5. 渲染地形背景
updateTerrainPath(Cx);
// 6. 应用底盘部件绝对位移与旋转
rearAssembly.setAttribute('transform', `translate(${Rx - Cx}, ${Ry - Cy})`);
frontAssembly.setAttribute('transform', `translate(${Fx - Cx}, ${Fy - Cy})`);
// [关键修复]:行星支架执行公转翻滚
let rAngle = getBracketAngle(Rx);
let fAngle = getBracketAngle(Fx);
rearPlanetary.setAttribute('transform', `rotate(${rAngle})`);
frontPlanetary.setAttribute('transform', `rotate(${fAngle})`);
// [关键修复]:小轮内部继续自转,不覆盖原本的端点平移坐标
let wheelSpin = globalTime * 3;
swRotators.forEach(sw => {
// 因为 sw 仅仅是一个使用 <use> 调用的子容器,可以直接对其覆盖自转
sw.setAttribute('transform', `rotate(${wheelSpin})`);
});
// 旋转主底盘受力
chassis.setAttribute('transform', `translate(${Cx}, ${Cy}) rotate(${thetaDeg})`);
// 7. IFR核心解:液压自平衡云台的绝对逆向补偿
// 货物平台始终保持与大地平行,抵消底盘的所有 theta 倾角
platform.setAttribute('transform', `translate(0, ${config.pivotY}) rotate(${-thetaDeg})`);
// 8. 精确实时的液压缸伸缩测算
let rad = -thetaRad;
let mountDist = 130;
// 平台左挂载点相对于底座中心旋转后的绝对坐标映射
let pLeftX = -mountDist * Math.cos(rad);
let pLeftY = config.pivotY - mountDist * Math.sin(rad);
hydLeft.setAttribute('x2', pLeftX);
hydLeft.setAttribute('y2', pLeftY);
// 平台右挂载点映射
let pRightX = mountDist * Math.cos(rad);
let pRightY = config.pivotY + mountDist * Math.sin(rad);
hydRight.setAttribute('x2', pRightX);
hydRight.setAttribute('y2', pRightY);
// 9. UI 状态监控刷新
uiTilt.textContent = Math.abs(thetaDeg).toFixed(2) + '°';
if (Math.abs(thetaDeg) > 1.0) {
uiStatus.textContent = "▶ 状态:[警报] 姿态激变!液压极速补偿中...";
uiStatus.style.color = "var(--neon-orange)";
document.querySelector('.laser-level').style.boxShadow = "0 0 15px #FF5500, 0 0 30px #FF5500";
document.querySelector('.laser-level').style.background = "#FF5500";
} else {
uiStatus.textContent = "▶ 状态:平地巡航 / 姿态归零";
uiStatus.style.color = "var(--neon-cyan)";
document.querySelector('.laser-level').style.boxShadow = "0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan)";
document.querySelector('.laser-level').style.background = "var(--neon-cyan)";
}
requestAnimationFrame(animate);
}
// 窗口尺寸自适应
window.addEventListener('resize', () => {
// 镜头计算依赖于 innerWidth,会在下一帧自动居中
});
// 启动动画循环
requestAnimationFrame(animate);
</script>
</body>
</html>
<!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: #050914;
--grid-color: rgba(0, 240, 255, 0.05);
--stair-color: #0A111C;
--stair-edge: #00F0FF;
--chassis: #1F2836;
--neon-cyan: #00F0FF;
--neon-orange: #FF4400;
--text-main: #FFFFFF;
--text-dim: #7A8EAA;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: var(--bg-color);
background-image: radial-gradient(circle at 50% 50%, #0A111C 0%, #030508 100%);
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
color: var(--text-main);
user-select: none;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.hud-overlay {
position: absolute;
z-index: 10;
pointer-events: none;
text-transform: uppercase;
}
.hud-top-left {
top: 30px;
left: 30px;
}
.hud-bottom-left {
bottom: 30px;
left: 30px;
}
.hud-bottom-right {
bottom: 30px;
right: 30px;
text-align: right;
}
.hud-title {
font-size: 14px;
font-weight: bold;
color: var(--neon-cyan);
margin-bottom: 8px;
letter-spacing: 1px;
text-shadow: 0 0 10px rgba(0, 240, 255, 0.4);
}
.hud-text {
font-size: 11px;
color: var(--text-dim);
line-height: 1.6;
}
.hud-highlight {
color: var(--text-main);
font-weight: bold;
}
.hud-value {
font-size: 28px;
font-weight: bold;
color: var(--neon-cyan);
text-shadow: 0 0 15px rgba(0, 240, 255, 0.6);
margin-top: 5px;
font-variant-numeric: tabular-nums;
}
.tag-orange { color: var(--neon-orange); }
.tag-cyan { color: var(--neon-cyan); }
.scan-line {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(to bottom, transparent, rgba(0, 240, 255, 0.4), transparent);
opacity: 0.3;
z-index: 20;
animation: scan 3s linear infinite;
pointer-events: none;
}
@keyframes scan {
0% { transform: translateY(-10vh); }
100% { transform: translateY(110vh); }
}
@keyframes pulse-ring {
0% { stroke-width: 1; opacity: 0.8; transform: scale(0.9); }
50% { stroke-width: 2; opacity: 1; transform: scale(1.1); text-shadow: 0 0 10px var(--neon-cyan); }
100% { stroke-width: 1; opacity: 0.8; transform: scale(0.9); }
}
.gyro-ring {
transform-origin: center;
animation: pulse-ring 2s ease-in-out infinite;
}
</style>
</head>
<body>
<div class="scan-line"></div>
<!-- UI Overlays -->
<div class="hud-overlay hud-top-left">
<div class="hud-title">■ 系统 IFR 状态:零姿态偏移</div>
<div class="hud-text">
<span>核心原理</span> // <span class="hud-highlight">移动越障与姿态平衡物理绝对解耦</span><br>
<span>底层构型</span> // <span class="tag-orange">行星式四轮组 (被动翻滚跨级)</span><br>
<span>顶层构型</span> // <span class="tag-cyan">主动液压自平衡云台 (动态逆向补偿)</span><br>
<span>响应延迟</span> // < 50ms<br>
<span>控制目标</span> // 载货平台倾覆力矩始终为零
</div>
</div>
<div class="hud-overlay hud-bottom-left">
<div class="hud-text" style="color:var(--neon-orange)" id="ui-status">当前状态:平地巡航模式</div>
<div class="hud-title" style="margin-top: 10px;">三轴陀螺仪姿态角</div>
<div class="hud-value" id="ui-tilt">0.00°</div>
</div>
<div class="hud-overlay hud-bottom-right">
<div class="hud-text">
■ 视觉引导图例<br>
<span style="color:#FF4400;">██</span> 行星受力翻转臂与随动轮<br>
<span style="color:#00F0FF;">██</span> 主动补偿液压缸<br>
<span style="color:#FFFFFF;">██</span> 零姿态载货平台
</div>
</div>
<!-- SVG Canvas -->
<div id="canvas-container">
<svg id="main-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="neon-glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur1" />
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur2" />
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="neon-glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" result="blur1" />
<feMerge>
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<pattern id="grid-pattern" width="80" height="80" patternUnits="userSpaceOnUse">
<path d="M 80 0 L 0 0 0 80" fill="none" stroke="rgba(0, 240, 255, 0.05)" stroke-width="1"/>
<circle cx="0" cy="0" r="1.5" fill="rgba(0, 240, 255, 0.2)"/>
</pattern>
<!-- Small Planetary Wheel Component -->
<g id="small-wheel-comp">
<!-- Outer Tire -->
<circle cx="0" cy="0" r="20" fill="#0A111C" stroke="#FF4400" stroke-width="3"/>
<!-- Inner mechanical rim -->
<circle cx="0" cy="0" r="14" fill="none" stroke="#FF4400" stroke-width="1.5" stroke-dasharray="4 4"/>
<!-- Hub -->
<circle cx="0" cy="0" r="6" fill="#FF4400" filter="url(#neon-glow-orange)"/>
<!-- Spokes -->
<path d="M 0 -20 L 0 20 M -20 0 L 20 0" stroke="#FF4400" stroke-width="2"/>
</g>
</defs>
<!-- Background Grid (Fixed to camera) -->
<rect width="100%" height="100%" fill="url(#grid-pattern)" />
<!-- Translating Scene -->
<g id="scene">
<!-- Dynamic Terrain Path -->
<path id="terrain" fill="var(--stair-color)" stroke="var(--stair-edge)" stroke-width="3" filter="url(#neon-glow-cyan)"/>
<path id="terrain-fill" fill="var(--stair-color)" stroke="none"/>
<!-- Robot Assembly -->
<g id="robot">
<!-- Rear Planetary Wheel Assembly -->
<g id="rear-assembly">
<!-- Group that rotates together: bracket + 4 wheels -->
<g id="rear-planetary-system">
<g id="rear-bracket" filter="url(#neon-glow-orange)">
<path d="M -65 -14 L 65 -14 L 65 14 L -65 14 Z" fill="#FF4400"/>
<path d="M -14 -65 L 14 -65 L 14 65 L -14 65 Z" fill="#FF4400"/>
<circle cx="0" cy="0" r="22" fill="#121A28" stroke="#FF4400" stroke-width="4"/>
</g>
<!-- 4 Small Wheels positioned at the ends of the bracket -->
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
</g>
<!-- Front Planetary Wheel Assembly -->
<g id="front-assembly">
<!-- Group that rotates together: bracket + 4 wheels -->
<g id="front-planetary-system">
<g id="front-bracket" filter="url(#neon-glow-orange)">
<path d="M -65 -14 L 65 -14 L 65 14 L -65 14 Z" fill="#FF4400"/>
<path d="M -14 -65 L 14 -65 L 14 65 L -14 65 Z" fill="#FF4400"/>
<circle cx="0" cy="0" r="22" fill="#121A28" stroke="#FF4400" stroke-width="4"/>
</g>
<!-- 4 Small Wheels positioned at the ends of the bracket -->
<g transform="translate(-65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(65, 0)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, -65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
<g transform="translate(0, 65)"><use href="#small-wheel-comp" class="sw-rotator"/></g>
</g>
</g>
<!-- Main Chassis -->
<g id="chassis">
<!-- Structural links between axles and chassis center (Visual only) -->
<line id="rear-link" x1="-160" y1="0" x2="0" y2="0" stroke="#334455" stroke-width="16" stroke-linecap="round"/>
<line id="front-link" x1="160" y1="0" x2="0" y2="0" stroke="#334455" stroke-width="16" stroke-linecap="round"/>
<!-- Chassis Body -->
<polygon points="-180,-30 180,-30 220,15 -220,15" fill="#1A222E" stroke="#4A5A72" stroke-width="3"/>
<path d="M -110 -20 L 110 -20" stroke="#FF4400" stroke-width="2" stroke-dasharray="10 6" opacity="0.8"/>
<!-- Hydraulic Cylinder Bases (Fixed to Chassis) -->
<path d="M -130 -30 L -110 -30 L -110 -70 L -130 -70 Z" fill="#2A3648" stroke="#4A5A72" stroke-width="2"/>
<circle cx="-120" cy="-25" r="7" fill="#00F0FF"/>
<path d="M 110 -30 L 130 -30 L 130 -70 L 110 -70 Z" fill="#2A3648" stroke="#4A5A72" stroke-width="2"/>
<circle cx="120" cy="-25" r="7" fill="#00F0FF"/>
<!-- Hydraulic Pistons (Dynamic) -->
<line id="hyd-left" x1="-120" y1="-70" x2="-120" y2="-120" stroke="#00F0FF" stroke-width="8" stroke-linecap="round" filter="url(#neon-glow-cyan)"/>
<line id="hyd-right" x1="120" y1="-70" x2="120" y2="-120" stroke="#00F0FF" stroke-width="8" stroke-linecap="round" filter="url(#neon-glow-cyan)"/>
<!-- Central Pivot Base -->
<path d="M -25 -30 L 25 -30 L 12 -80 L -12 -80 Z" fill="#2A3648"/>
<circle cx="0" cy="-80" r="10" fill="#00F0FF" filter="url(#neon-glow-cyan)"/>
<!-- Cargo Platform (Absolute Horizontal) -->
<g id="platform">
<!-- Platform Base -->
<rect x="-170" y="-12" width="340" height="14" rx="4" fill="#FFFFFF"/>
<rect x="-160" y="-4" width="320" height="4" fill="#E0E0E0"/>
<!-- Mount points on platform -->
<circle cx="-120" cy="0" r="6" fill="#FF4400"/>
<circle cx="120" cy="0" r="6" fill="#FF4400"/>
<circle cx="0" cy="0" r="8" fill="#00F0FF"/>
<!-- Cargo Container -->
<g transform="translate(0, -80)">
<rect x="-110" y="-60" width="220" height="128" rx="8" fill="rgba(0, 240, 255, 0.05)" stroke="#00F0FF" stroke-width="2" filter="url(#neon-glow-cyan)"/>
<path d="M -90 -45 L -40 -45 M 90 -45 L 40 -45" stroke="#00F0FF" stroke-width="3"/>
<!-- Gyroscope IFR Indicator -->
<g class="gyro-ring">
<circle cx="0" cy="5" r="30" fill="none" stroke="#00F0FF" stroke-width="2" stroke-dasharray="15 8"/>
<circle cx="0" cy="5" r="18" fill="none" stroke="#00F0FF" stroke-width="1.5"/>
<circle cx="0" cy="5" r="5" fill="#00F0FF" filter="url(#neon-glow-cyan)"/>
</g>
<text x="0" y="-20" text-anchor="middle" fill="#00F0FF" font-size="14" font-weight="bold" letter-spacing="3">ZERO-TILT CARGO</text>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<script>
// --- System Kinematics Configuration ---
const config = {
W: 320, // Wheelbase (Distance between front and rear planetary centers)
R: 65, // Planetary bracket radius
r: 20, // Small wheel radius
stairH: 140, // Step height
stairW: 900, // Distance between steps
speed: 3.5, // Animation base speed (px per frame)
platformCenterY: -130 // Platform absolute center Y offset relative to chassis axle line
};
const groundClearance = config.R + config.r; // 85px
// Climb calculations based on real collision geometry
const cornerX = 400;
const startClimbX = cornerX - config.R - 10; // Trigger slightly before wheel hits
const climbDist = config.R * 1.6; // Extended smooth climb duration
// Element references
const scene = document.getElementById('scene');
const terrain = document.getElementById('terrain');
const terrainFill = document.getElementById('terrain-fill');
const chassis = document.getElementById('chassis');
const platform = document.getElementById('platform');
const rearAssembly = document.getElementById('rear-assembly');
const frontAssembly = document.getElementById('front-assembly');
const rearPlanetarySystem = document.getElementById('rear-planetary-system');
const frontPlanetarySystem = document.getElementById('front-planetary-system');
const rearLink = document.getElementById('rear-link');
const frontLink = document.getElementById('front-link');
const hydLeft = document.getElementById('hyd-left');
const hydRight = document.getElementById('hyd-right');
const uiTilt = document.getElementById('ui-tilt');
const uiStatus = document.getElementById('ui-status');
const swRotators = document.querySelectorAll('.sw-rotator');
let globalTime = 0;
/**
* Calculates the absolute Y position of a planetary axle given its absolute X.
*/
function getAxleY(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseY = stepCount * -config.stairH;
let localY = 0;
if (localX > startClimbX && localX <= startClimbX + climbDist) {
// Smooth sine interpolation for realistic climb arc
let t = (localX - startClimbX) / climbDist;
localY = -config.stairH * (0.5 - 0.5 * Math.cos(t * Math.PI));
} else if (localX > startClimbX + climbDist) {
localY = -config.stairH;
}
return baseY + localY;
}
/**
* Calculates the rotation angle of the entire planetary system (bracket + wheels).
*/
function getBracketAngle(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseAngle = stepCount * 90;
let climbAngle = 0;
if (localX > startClimbX && localX <= startClimbX + climbDist) {
let t = (localX - startClimbX) / climbDist;
// Eased rotation syncing with the vertical climb
climbAngle = 90 * (0.5 - 0.5 * Math.cos(t * Math.PI));
} else if (localX > startClimbX + climbDist) {
climbAngle = 90;
}
return baseAngle + climbAngle;
}
/**
* Generates the SVG path for rigid square stairs.
*/
function updateTerrainPath(cx) {
let startX = Math.floor((cx - 1500) / config.stairW) * config.stairW;
let endX = cx + 2000;
let pathD = `M ${startX}, 3000 `;
for (let x = startX; x < endX; x += config.stairW) {
let yTop = Math.floor(x / config.stairW) * -config.stairH + groundClearance;
let yBot = yTop - config.stairH;
pathD += `L ${x}, ${yTop} L ${x + 400}, ${yTop} L ${x + 400}, ${yBot} L ${x + config.stairW}, ${yBot} `;
}
pathD += `L ${endX}, 3000 Z`;
terrain.setAttribute('d', pathD);
terrainFill.setAttribute('d', pathD);
}
function animate() {
globalTime += config.speed;
// 1. Calculate Rear Axle Position
let Rx = globalTime;
let Ry = getAxleY(Rx);
// 2. Iteratively solve for Front Axle to maintain constant rigid wheelbase W
let Fx = Rx + config.W;
for(let i = 0; i < 6; i++) {
let tempFy = getAxleY(Fx);
let currentDist = Math.hypot(Fx - Rx, tempFy - Ry);
let error = config.W - currentDist;
Fx += error * 0.9;
}
let Fy = getAxleY(Fx);
// 3. Chassis Kinematics (Center & Pitch Angle)
let Cx = (Rx + Fx) / 2;
let Cy = (Ry + Fy) / 2;
let thetaRad = Math.atan2(Fy - Ry, Fx - Rx);
let thetaDeg = thetaRad * 180 / Math.PI;
// 4. Update Camera / Scene Translation (Keep Robot Centered)
const screenCx = window.innerWidth / 2;
const screenCy = window.innerHeight / 2 + 50;
scene.setAttribute('transform', `translate(${screenCx - Cx}, ${screenCy - Cy})`);
// 5. Render Terrain
updateTerrainPath(Cx);
// 6. Update Robot Elements Positioning
rearAssembly.setAttribute('transform', `translate(${Rx - Cx}, ${Ry - Cy})`);
frontAssembly.setAttribute('transform', `translate(${Fx - Cx}, ${Fy - Cy})`);
rearLink.setAttribute('x1', Rx - Cx);
rearLink.setAttribute('y1', Ry - Cy);
frontLink.setAttribute('x1', Fx - Cx);
frontLink.setAttribute('y1', Fy - Cy);
// [Crucial Fix] Rotate entire planetary systems (bracket + all 4 wheels)
let rAngle = getBracketAngle(Rx);
let fAngle = getBracketAngle(Fx);
rearPlanetarySystem.setAttribute('transform', `rotate(${rAngle})`);
frontPlanetarySystem.setAttribute('transform', `rotate(${fAngle})`);
// Rotate Small Wheels individually around their own centers (Rolling effect)
let wheelSpin = globalTime * 3;
swRotators.forEach(sw => sw.setAttribute('transform', `rotate(${wheelSpin})`));
// Rotate Main Chassis body
chassis.setAttribute('transform', `translate(${Cx}, ${Cy}) rotate(${thetaDeg})`);
// 7. Active IFR Hydraulic Stabilization Logic
platform.setAttribute('transform', `translate(0, ${config.platformCenterY}) rotate(${-thetaDeg})`);
let rad = -thetaRad;
// Left Piston Vector Solving
let pLeftX_local = -120 * Math.cos(rad);
let pLeftY_local = -120 * Math.sin(rad);
hydLeft.setAttribute('x2', pLeftX_local);
hydLeft.setAttribute('y2', config.platformCenterY + pLeftY_local);
// Right Piston Vector Solving
let pRightX_local = 120 * Math.cos(rad);
let pRightY_local = 120 * Math.sin(rad);
hydRight.setAttribute('x2', pRightX_local);
hydRight.setAttribute('y2', config.platformCenterY + pRightY_local);
// 8. Update HUD Info
uiTilt.textContent = Math.abs(thetaDeg).toFixed(2) + '°';
if (Math.abs(thetaDeg) > 1.5) {
uiStatus.textContent = "当前状态:[告警] 主动越障平衡介入中...";
uiStatus.style.color = "var(--neon-cyan)";
} else {
uiStatus.textContent = "当前状态:平地巡航模式";
uiStatus.style.color = "var(--neon-orange)";
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>
</body>
</html>
<!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: #030509;
--grid-color: rgba(0, 240, 255, 0.04);
--stair-fill: #0A1018;
--stair-stroke: #00E5FF;
--chassis-dark: #121822;
--chassis-light: #1A2433;
--neon-cyan: #00E5FF;
--neon-orange: #FF4D00;
--text-main: #FFFFFF;
--text-dim: #4B6382;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, #08121C 0%, var(--bg-color) 100%);
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
color: var(--text-main);
user-select: none;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
/* 极简面板排版,严格限制大小避免遮挡核心动画 */
.hud-overlay {
position: absolute;
z-index: 10;
pointer-events: none;
background: rgba(3, 5, 9, 0.65);
border: 1px solid rgba(0, 229, 255, 0.15);
backdrop-filter: blur(6px);
padding: 12px 16px;
}
.hud-top-left { top: 20px; left: 20px; border-left: 3px solid var(--neon-cyan); }
.hud-bottom-right { bottom: 20px; right: 20px; border-right: 3px solid var(--neon-orange); text-align: right; }
.hud-bottom-left { bottom: 20px; left: 20px; border-left: 3px solid var(--neon-cyan); }
.hud-title {
font-size: 13px;
font-weight: bold;
color: var(--neon-cyan);
margin-bottom: 8px;
letter-spacing: 1.5px;
}
.hud-text {
font-size: 11px;
color: var(--text-dim);
line-height: 1.6;
}
.hud-highlight { color: var(--text-main); font-weight: bold; }
.tag-orange { color: var(--neon-orange); font-weight: bold; }
.tag-cyan { color: var(--neon-cyan); font-weight: bold; }
.hud-value {
font-size: 22px;
font-weight: bold;
color: var(--neon-cyan);
text-shadow: 0 0 10px rgba(0, 229, 255, 0.4);
font-variant-numeric: tabular-nums;
margin-top: 4px;
}
/* 绝对水平物理基准线 */
.laser-level {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: var(--neon-cyan);
box-shadow: 0 0 8px var(--neon-cyan), 0 0 16px var(--neon-cyan);
opacity: 0.35;
z-index: 5;
pointer-events: none;
transform: translateY(-130px);
}
.laser-glow {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 30px;
background: linear-gradient(to bottom, transparent, rgba(0, 229, 255, 0.05), transparent);
transform: translateY(-145px);
z-index: 4;
pointer-events: none;
}
</style>
</head>
<body>
<div class="laser-level" id="laser-line"></div>
<div class="laser-glow"></div>
<!-- UI 面板 -->
<div class="hud-overlay hud-top-left">
<div class="hud-title">▼ TRIZ最终理想解 / 功能解耦</div>
<div class="hud-text">
<span>物理状态</span> : <span class="hud-highlight">移动机构与姿态系统 100% 解耦</span><br>
<span>底层越障</span> : <span class="tag-orange">行星四轮组 (结构翻转跨级)</span><br>
<span>顶层姿态</span> : <span class="tag-cyan">主动液压云台 (全时逆向补偿)</span><br>
<span>核心机制</span> : 吸收底层底盘剧烈翻滚,输出顶层绝对平稳
</div>
</div>
<div class="hud-overlay hud-bottom-right">
<div class="hud-text">
<span style="color:#FF4D00;">██</span> 动态受力翻转悬挂<br>
<span style="color:#00E5FF;">██</span> 主动逆向液压补偿缸<br>
<span style="color:#FFFFFF;">██</span> 绝对零姿态理想平台
</div>
</div>
<div class="hud-overlay hud-bottom-left">
<div class="hud-text">底盘俯仰角追踪</div>
<div class="hud-value" id="ui-tilt">0.00°</div>
<div class="hud-text" id="ui-status" style="margin-top:4px; color:var(--neon-orange);">[平地巡航状态]</div>
</div>
<!-- 核心 SVG 动画区 -->
<div id="canvas-container">
<svg id="main-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<pattern id="grid" width="100" height="100" patternUnits="userSpaceOnUse">
<path d="M 100 0 L 0 0 0 100" fill="none" stroke="var(--grid-color)" stroke-width="1"/>
<circle cx="0" cy="0" r="1" fill="rgba(0, 229, 255, 0.3)"/>
</pattern>
<!-- 重型行星小轮组件 -->
<g id="wheel-unit">
<!-- 外侧越野胎面 -->
<circle cx="0" cy="0" r="22" fill="#0A0F14" stroke="#FF4D00" stroke-width="3"/>
<circle cx="0" cy="0" r="16" fill="none" stroke="#FF4D00" stroke-width="1" stroke-dasharray="4 4"/>
<!-- 机械辐条 -->
<path d="M 0 -22 L 0 22 M -22 0 L 22 0" stroke="#FF4D00" stroke-width="2.5"/>
<!-- 轮毂中心 -->
<circle cx="0" cy="0" r="6" fill="#00E5FF" filter="url(#glow-cyan)"/>
</g>
</defs>
<!-- 摄像机背景 -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- 全局场景容器 -->
<g id="scene">
<!-- 环境阶梯 -->
<path id="terrain" fill="var(--stair-fill)" stroke="var(--stair-stroke)" stroke-width="3" filter="url(#glow-cyan)"/>
<path id="terrain-fill" fill="var(--stair-fill)" stroke="none"/>
<!-- 机器人总成 (无根节点位移,全靠绝对坐标渲染) -->
<g id="robot">
<!-- 行星轮系:直接挂载在绝对坐标 -->
<!-- 后桥 -->
<g id="rear-assembly">
<g id="rear-planetary-bracket">
<!-- 翻转十字支架 -->
<g filter="url(#glow-orange)">
<path d="M -75 -15 L 75 -15 L 75 15 L -75 15 Z" fill="#FF4D00"/>
<path d="M -15 -75 L 15 -75 L 15 75 L -15 75 Z" fill="#FF4D00"/>
<circle cx="0" cy="0" r="24" fill="#121822" stroke="#FF4D00" stroke-width="4"/>
</g>
<!-- 4个独立自转的端点小轮 -->
<g transform="translate(-75, 0)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(75, 0)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(0, -75)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(0, 75)"><use href="#wheel-unit" class="wheel-spin"/></g>
</g>
</g>
<!-- 前桥 -->
<g id="front-assembly">
<g id="front-planetary-bracket">
<g filter="url(#glow-orange)">
<path d="M -75 -15 L 75 -15 L 75 15 L -75 15 Z" fill="#FF4D00"/>
<path d="M -15 -75 L 15 -75 L 15 75 L -15 75 Z" fill="#FF4D00"/>
<circle cx="0" cy="0" r="24" fill="#121822" stroke="#FF4D00" stroke-width="4"/>
</g>
<g transform="translate(-75, 0)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(75, 0)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(0, -75)"><use href="#wheel-unit" class="wheel-spin"/></g>
<g transform="translate(0, 75)"><use href="#wheel-unit" class="wheel-spin"/></g>
</g>
</g>
<!-- 底盘本体 (随形翻滚倾斜) -->
<g id="chassis">
<!-- 与前后轮轴硬连接的悬挂臂 -->
<line x1="-170" y1="0" x2="0" y2="0" stroke="#1A2433" stroke-width="20" stroke-linecap="round"/>
<line x1="170" y1="0" x2="0" y2="0" stroke="#1A2433" stroke-width="20" stroke-linecap="round"/>
<circle cx="-170" cy="0" r="10" fill="#FF4D00"/>
<circle cx="170" cy="0" r="10" fill="#FF4D00"/>
<!-- 主车架 -->
<polygon points="-190,-35 190,-35 220,15 -220,15" fill="#121822" stroke="#3A4A63" stroke-width="3"/>
<!-- 动态指示带 -->
<rect x="-100" y="-15" width="200" height="4" fill="#FF4D00" opacity="0.7"/>
<!-- 液压自稳定云台底座 -->
<path d="M -140 -35 L -110 -35 L -110 -80 L -140 -80 Z" fill="#1A2433"/>
<circle cx="-125" cy="-30" r="8" fill="#00E5FF"/>
<path d="M 110 -35 L 140 -35 L 140 -80 L 110 -80 Z" fill="#1A2433"/>
<circle cx="125" cy="-30" r="8" fill="#00E5FF"/>
<!-- 动态液压连杆 -->
<line id="hyd-left" x1="-125" y1="-80" x2="-125" y2="-130" stroke="#00E5FF" stroke-width="10" stroke-linecap="round" filter="url(#glow-cyan)"/>
<line id="hyd-right" x1="125" y1="-80" x2="125" y2="-130" stroke="#00E5FF" stroke-width="10" stroke-linecap="round" filter="url(#glow-cyan)"/>
<!-- 中心主控铰链 -->
<path d="M -30 -35 L 30 -35 L 15 -90 L -15 -90 Z" fill="#2A3A52"/>
<circle cx="0" cy="-90" r="12" fill="#00E5FF" filter="url(#glow-cyan)"/>
<!-- ★ 最终理想解货运云台 (完全抵消底盘倾斜,保持绝对水平) ★ -->
<g id="platform">
<!-- 水平承载面 -->
<rect x="-180" y="-15" width="360" height="15" rx="4" fill="#FFFFFF"/>
<rect x="-170" y="-5" width="340" height="5" fill="#E2E8F0"/>
<!-- 液压受力铰接点 -->
<circle cx="-125" cy="0" r="7" fill="#FF4D00"/>
<circle cx="125" cy="0" r="7" fill="#FF4D00"/>
<!-- 货舱实体 -->
<g transform="translate(0, -85)">
<rect x="-120" y="-60" width="240" height="130" rx="8" fill="rgba(0, 229, 255, 0.08)" stroke="#00E5FF" stroke-width="2" filter="url(#glow-cyan)"/>
<path d="M -100 -40 L -50 -40 M 100 -40 L 50 -40" stroke="#00E5FF" stroke-width="3"/>
<!-- IFR 陀螺仪视觉反馈 -->
<circle cx="0" cy="5" r="35" fill="none" stroke="#00E5FF" stroke-width="2" stroke-dasharray="10 6"/>
<circle cx="0" cy="5" r="22" fill="none" stroke="#00E5FF" stroke-width="1"/>
<circle cx="0" cy="5" r="6" fill="#00E5FF" filter="url(#glow-cyan)"/>
<text x="0" y="-20" text-anchor="middle" fill="#00E5FF" font-size="14" font-weight="bold" letter-spacing="2">ZERO-TILT</text>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<script>
// === 核心工程参数配置 ===
const config = {
W: 340, // 轴距 (前后十字支架中心点的刚性间距)
R: 75, // 行星轮十字支架回转半径
r: 22, // 行星小轮自身半径
stairH: 140, // 单级台阶高度
stairW: 1000, // 单级台阶平台深度
speed: 3.5, // 动画演进速度
climbDist: 150, // 完成一次翻越动作跨越的水平距离
pivotY: -130 // 载货云台挂载铰链在底盘坐标系中的绝对高度
};
const groundClearance = config.R + config.r; // 十字臂正置时,中心轴离地高度 97px
const cornerX = 400; // 台阶立面物理位置
// 运动学起跳触发点:轮胎接触到立面前一点开始主动翻转
const startClimbX = cornerX - config.R - 10;
// 绑定 DOM 元素
const scene = document.getElementById('scene');
const terrain = document.getElementById('terrain');
const terrainFill = document.getElementById('terrain-fill');
const chassis = document.getElementById('chassis');
const platform = document.getElementById('platform');
const rearAssembly = document.getElementById('rear-assembly');
const frontAssembly = document.getElementById('front-assembly');
const rearBracket = document.getElementById('rear-planetary-bracket');
const frontBracket = document.getElementById('front-planetary-bracket');
const hydLeft = document.getElementById('hyd-left');
const hydRight = document.getElementById('hyd-right');
const wheels = document.querySelectorAll('.wheel-spin');
const uiTilt = document.getElementById('ui-tilt');
const uiStatus = document.getElementById('ui-status');
const laserLine = document.getElementById('laser-line');
let globalTime = 0;
/**
* 几何函数:根据水平坐标计算轮轴在垂直方向应处的绝对高度
* 物理机理:模拟轮组滚过平地后,撞击台阶边缘被迫抬升的弧线
*/
function getAxleY(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseY = stepCount * -config.stairH; // 楼梯整体逐步抬高 (SVG y向负移动)
let climbY = 0;
if (localX > startClimbX && localX <= startClimbX + config.climbDist) {
// 使用 Cosine 缓动实现完美的半周期抬升模拟翻越弧线
let t = (localX - startClimbX) / config.climbDist;
climbY = -config.stairH * (0.5 - 0.5 * Math.cos(t * Math.PI));
} else if (localX > startClimbX + config.climbDist) {
climbY = -config.stairH;
}
return baseY + climbY;
}
/**
* 几何函数:计算十字支架强制翻转的角度
* 物理机理:底部小轮卡死,电机驱动整个十字臂旋转90度完成翻越
*/
function getBracketAngle(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseAngle = stepCount * 90;
let climbAngle = 0;
if (localX > startClimbX && localX <= startClimbX + config.climbDist) {
let t = (localX - startClimbX) / config.climbDist;
// 翻滚动作与抬升弧线绝对同步
climbAngle = 90 * (0.5 - 0.5 * Math.cos(t * Math.PI));
} else if (localX > startClimbX + config.climbDist) {
climbAngle = 90;
}
return baseAngle + climbAngle;
}
/**
* 渲染刚性阶梯地形
*/
function updateTerrainPath(cx) {
let startX = Math.floor((cx - 1500) / config.stairW) * config.stairW;
let endX = cx + 2500;
let pathD = `M ${startX}, 3000 `;
for (let x = startX; x < endX; x += config.stairW) {
let stepCount = Math.floor(x / config.stairW);
// 确保地形与轮轴的离地高度计算匹配
let groundY = stepCount * -config.stairH + groundClearance;
let nextGroundY = groundY - config.stairH;
let stepCorner = x + cornerX;
pathD += `L ${x}, ${groundY} L ${stepCorner}, ${groundY} L ${stepCorner}, ${nextGroundY} L ${x + config.stairW}, ${nextGroundY} `;
}
pathD += `L ${endX}, 3000 Z`;
terrain.setAttribute('d', pathD);
terrainFill.setAttribute('d', pathD);
}
function animate() {
globalTime += config.speed;
// 1. 求解后轴驱动点绝对坐标
let Rx = globalTime;
let Ry = getAxleY(Rx);
// 2. 迭代求解前轴位置:确保在跌宕起伏中【轴距 W 永远保持绝对刚性】
let Fx = Rx + config.W;
for(let i = 0; i < 8; i++) {
let tempFy = getAxleY(Fx);
let currentDist = Math.hypot(Fx - Rx, tempFy - Ry);
let error = config.W - currentDist;
Fx += error * 0.9;
}
let Fy = getAxleY(Fx);
// 3. 计算底盘中心锚点及整体俯仰角
let Cx = (Rx + Fx) / 2;
let Cy = (Ry + Fy) / 2;
let thetaRad = Math.atan2(Fy - Ry, Fx - Rx);
let thetaDeg = thetaRad * 180 / Math.PI;
// 4. 运镜追踪:保持车辆在屏幕中心
const screenCx = window.innerWidth / 2;
const screenCy = window.innerHeight / 2 + 80;
scene.setAttribute('transform', `translate(${screenCx - Cx}, ${screenCy - Cy})`);
// 5. 渲染当前视野段地形
updateTerrainPath(Cx);
// 6. 应用核心部件位移,彻底解决视觉分离问题
// 【关键】:将支架直接贴靠在场景绝对坐标,其几何距离刚好匹配底盘连杆长度
rearAssembly.setAttribute('transform', `translate(${Rx}, ${Ry})`);
frontAssembly.setAttribute('transform', `translate(${Fx}, ${Fy})`);
// 7. 同步触发十字支架翻转跳跃动作
let rAngle = getBracketAngle(Rx);
let fAngle = getBracketAngle(Fx);
rearBracket.setAttribute('transform', `rotate(${rAngle})`);
frontBracket.setAttribute('transform', `rotate(${fAngle})`);
// 端点小轮自由持续滚转
let wheelSpin = globalTime * 3;
wheels.forEach(w => w.setAttribute('transform', `rotate(${wheelSpin})`));
// 8. 倾斜底盘车架主体
chassis.setAttribute('transform', `translate(${Cx}, ${Cy}) rotate(${thetaDeg})`);
// 9. TRIZ 顶层主动补偿计算 (液压逆向动作)
// 货物平台通过与底盘的逆向等大反转 (-thetaDeg),抵消全部倾覆力矩
platform.setAttribute('transform', `translate(0, ${config.pivotY}) rotate(${-thetaDeg})`);
// 10. 精确解算液压伸缩杆空间矢量,模拟真实推挽
let rad = -thetaRad;
// 左缸连杆在云台局部坐标系的挂点位置是 (-125, 0)
// 计算经过旋转后映射到底盘坐标系的末端落点
let pLeftX = -125 * Math.cos(rad);
let pLeftY = config.pivotY - 125 * Math.sin(rad);
hydLeft.setAttribute('x2', pLeftX);
hydLeft.setAttribute('y2', pLeftY);
// 右缸连杆映射
let pRightX = 125 * Math.cos(rad);
let pRightY = config.pivotY + 125 * Math.sin(rad);
hydRight.setAttribute('x2', pRightX);
hydRight.setAttribute('y2', pRightY);
// 11. 更新交互态与告警 UI
let tiltVal = Math.abs(thetaDeg);
uiTilt.textContent = tiltVal.toFixed(2) + '°';
if (tiltVal > 1.5) {
uiStatus.textContent = "▶ 极端姿态:液压极速顶升补偿中...";
uiStatus.style.color = "var(--neon-cyan)";
laserLine.style.boxShadow = "0 0 15px var(--neon-cyan), 0 0 30px var(--neon-cyan)";
laserLine.style.opacity = "0.7";
} else {
uiStatus.textContent = "▶ 平地巡航:系统空载待命";
uiStatus.style.color = "var(--text-dim)";
laserLine.style.boxShadow = "0 0 5px var(--neon-cyan)";
laserLine.style.opacity = "0.3";
}
requestAnimationFrame(animate);
}
// 初始化驱动
requestAnimationFrame(animate);
</script>
</body>
</html>
为了彻底解决前两版中行星轮视觉脱节、结构不清晰的问题,本次设计完全按照你的要求进行了重构。
方案核心更新如下:
- 构型精准还原:将十字轮替换为经典的三轮行星构型(呈 Y 字形),每隔 120 度分布一个小轮。
- 中心刚性固定:行星轮支架的中心绝对锁定在车体底盘的主轴上。底盘采用了直接贯穿前后行星轮中心轴的连杆设计,在动画中你可以清晰地看到无论地势如何起伏,行星轮永远牢牢长在车上,绝不分离。
- 被动翻滚逻辑:平时在平地上,下方的一个小轮接地自转;遇到台阶时,受阻力矩触发,整个 Y 型支架围绕车轴翻滚 120 度,完成“跨步跃级”。
- IFR 绝对解耦:底层由于翻滚产生的剧烈震荡与俯仰倾角,依然由上方的主动液压陀螺仪云台瞬间逆向对冲,维持货物的“零姿态”。
以下是可直接运行的高保真重构代码:
<!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-base: #02050A;
--bg-glow: #08121D;
--grid: rgba(0, 240, 255, 0.05);
--stair-fill: #0F1621;
--stair-stroke: #00D5FF;
--mech-dark: #1A2230;
--mech-light: #2A364A;
--accent-cyan: #00D5FF;
--accent-orange: #FF4D00;
--text-main: #FFFFFF;
--text-dim: #647B99;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, var(--bg-glow) 0%, var(--bg-base) 100%);
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
color: var(--text-main);
user-select: none;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
/* 极简信息面板,避免遮挡核心动画 */
.hud {
position: absolute;
z-index: 10;
pointer-events: none;
}
.hud-top-left { top: 30px; left: 30px; }
.hud-bottom-left { bottom: 30px; left: 30px; }
.hud-top-right { top: 30px; right: 30px; text-align: right; }
.hud-title {
font-size: 14px;
font-weight: bold;
color: var(--accent-cyan);
margin-bottom: 8px;
letter-spacing: 2px;
text-shadow: 0 0 10px rgba(0, 213, 255, 0.4);
}
.hud-panel {
font-size: 11px;
color: var(--text-dim);
line-height: 1.6;
background: rgba(2, 5, 10, 0.7);
padding: 12px 18px;
border-left: 3px solid var(--accent-cyan);
backdrop-filter: blur(8px);
}
.highlight-c { color: var(--accent-cyan); font-weight: bold; }
.highlight-o { color: var(--accent-orange); font-weight: bold; }
.data-box {
background: rgba(0, 213, 255, 0.05);
border: 1px solid rgba(0, 213, 255, 0.2);
padding: 10px 20px;
margin-top: 10px;
display: inline-block;
}
.data-value {
font-size: 28px;
font-weight: bold;
color: var(--accent-cyan);
text-shadow: 0 0 12px rgba(0, 213, 255, 0.5);
font-variant-numeric: tabular-nums;
margin: 5px 0;
}
.data-status {
font-size: 11px;
color: var(--accent-orange);
letter-spacing: 1px;
}
/* 水平基准线 */
.laser-level {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: var(--accent-cyan);
box-shadow: 0 0 8px var(--accent-cyan), 0 0 20px var(--accent-cyan);
opacity: 0.25;
z-index: 5;
transform: translateY(-110px);
}
</style>
</head>
<body>
<div class="laser-level"></div>
<div class="hud hud-top-left">
<div class="hud-title">■ 移动与姿态解耦系统 (IFR)</div>
<div class="hud-panel">
<span>底层强悍越障</span> // <span class="highlight-o">三轮行星支架 (遇障被动翻滚 120°)</span><br>
<span>顶层刚性约束</span> // 行星轮中心轴绝对固定于底盘<br>
<span>姿态逆向对冲</span> // <span class="highlight-c">三轴陀螺仪 + 主动液压自平衡云台</span><br>
<span>最终理想解</span> // 保留越障能力,消除货损倾角矛盾
</div>
</div>
<div class="hud hud-top-right">
<div class="hud-panel" style="border-left:none; border-right:3px solid var(--accent-orange);">
<span style="color:#FF4D00;">■</span> 三星被动翻转臂<br>
<span style="color:#00D5FF;">■</span> 逆向补偿液压缸<br>
<span style="color:#FFFFFF;">■</span> 绝对水平货载域
</div>
</div>
<div class="hud hud-bottom-left">
<div class="data-box">
<div style="font-size: 11px; color: var(--text-dim);">顶层货台绝对倾角偏差</div>
<div class="data-value" id="ui-tilt">0.00°</div>
<div class="data-status" id="ui-status">● 状态监控:平地巡航</div>
</div>
</div>
<div id="canvas-container">
<svg id="main-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 霓虹发光滤镜 -->
<filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur1" />
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur2" />
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<pattern id="grid" width="60" height="60" patternUnits="userSpaceOnUse">
<path d="M 60 0 L 0 0 0 60" fill="none" stroke="var(--grid)" stroke-width="1"/>
<circle cx="0" cy="0" r="1" fill="rgba(0, 213, 255, 0.3)"/>
</pattern>
<!-- 重构的单个小行星轮 -->
<g id="small-wheel">
<circle cx="0" cy="0" r="18" fill="#0A0E14" stroke="#FF4D00" stroke-width="3"/>
<!-- 轮毂纹理(用于观察滚动) -->
<path d="M 0 -18 L 0 18 M -18 0 L 18 0 M -12.7 -12.7 L 12.7 12.7 M -12.7 12.7 L 12.7 -12.7" stroke="#FF4D00" stroke-width="1.5" opacity="0.6"/>
<circle cx="0" cy="0" r="12" fill="none" stroke="#2A364A" stroke-width="2"/>
<circle cx="0" cy="0" r="5" fill="#FF4D00" filter="url(#glow-orange)"/>
</g>
<!-- 重构的 Y 型(三轮)行星支架系统 -->
<g id="tri-star-system">
<!-- Y 型强固支架 -->
<g filter="url(#glow-orange)">
<!-- 三条悬臂 (角度: 90, -30, 210) -->
<line x1="0" y1="0" x2="0" y2="50" stroke="#FF4D00" stroke-width="18" stroke-linecap="round"/>
<line x1="0" y1="0" x2="43.3" y2="-25" stroke="#FF4D00" stroke-width="18" stroke-linecap="round"/>
<line x1="0" y1="0" x2="-43.3" y2="-25" stroke="#FF4D00" stroke-width="18" stroke-linecap="round"/>
<!-- 中心铰接固定点(锁定在车轴上的核心视觉件) -->
<circle cx="0" cy="0" r="18" fill="#1A2230" stroke="#FF4D00" stroke-width="4"/>
<circle cx="0" cy="0" r="8" fill="#00D5FF"/>
</g>
<!-- 三个小行星轮安装点 -->
<g transform="translate(0, 50)"><use href="#small-wheel" class="sw-rotator"/></g>
<g transform="translate(43.3, -25)"><use href="#small-wheel" class="sw-rotator"/></g>
<g transform="translate(-43.3, -25)"><use href="#small-wheel" class="sw-rotator"/></g>
</g>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
<g id="scene">
<!-- 地形 -->
<path id="terrain" fill="var(--stair-fill)" stroke="var(--stair-stroke)" stroke-width="3" filter="url(#glow-cyan)"/>
<path id="terrain-fill" fill="var(--stair-fill)" stroke="none"/>
<!-- 机器人整体装配 -->
<g id="robot">
<!-- 1. 主底盘梁(绝对刚性连杆,连接前后轮轴心) -->
<!-- 将底盘置于底层,确保行星轮装配在其上方,视觉上完全锁定 -->
<g id="chassis-beam">
<!-- 连接前后轮中心的贯穿梁 -->
<line id="main-beam" x1="-150" y1="0" x2="150" y2="0" stroke="#1A2230" stroke-width="32" stroke-linecap="round"/>
<line id="main-beam-hl" x1="-140" y1="0" x2="140" y2="0" stroke="#2A364A" stroke-width="12" stroke-linecap="round"/>
<!-- 悬挂与液压基座外壳 -->
<polygon points="-100,-16 100,-16 120,10 -120,10" fill="#1A2230" stroke="#4A5A72" stroke-width="2"/>
<!-- 液压底座 -->
<path d="M -95,-16 L -75,-16 L -75,-60 L -95,-60 Z" fill="#2A364A" stroke="#4A5A72" stroke-width="2"/>
<circle cx="-85" cy="-20" r="5" fill="#00D5FF"/>
<path d="M 75,-16 L 95,-16 L 95,-60 L 75,-60 Z" fill="#2A364A" stroke="#4A5A72" stroke-width="2"/>
<circle cx="85" cy="-20" r="5" fill="#00D5FF"/>
<!-- 动态伸缩的液压杆 -->
<line id="hyd-left" x1="-85" y1="-60" x2="-85" y2="-120" stroke="#00D5FF" stroke-width="8" stroke-linecap="round" filter="url(#glow-cyan)"/>
<line id="hyd-right" x1="85" y1="-60" x2="85" y2="-120" stroke="#00D5FF" stroke-width="8" stroke-linecap="round" filter="url(#glow-cyan)"/>
<!-- 云台中心铰链支撑塔 -->
<path d="M -15,-16 L 15,-16 L 8,-90 L -8,-90 Z" fill="#1A2230"/>
<circle cx="0" cy="-90" r="8" fill="#00D5FF" filter="url(#glow-cyan)"/>
<!-- 绝对水平载货云台 (平台相对底盘反向旋转保持平衡) -->
<g id="platform">
<rect x="-140" y="-8" width="280" height="12" rx="4" fill="#FFFFFF"/>
<rect x="-135" y="-3" width="270" height="4" fill="#D0D0D0"/>
<!-- 左右液压挂载点 -->
<circle cx="-85" cy="0" r="6" fill="#00D5FF"/>
<circle cx="85" cy="0" r="6" fill="#00D5FF"/>
<!-- 中心挂载点 -->
<circle cx="0" cy="0" r="8" fill="#FF4D00"/>
<!-- 货舱与 IFR 陀螺仪指示器 -->
<g transform="translate(0, -60)">
<rect x="-90" y="-45" width="180" height="95" rx="6" fill="rgba(0, 213, 255, 0.05)" stroke="#00D5FF" stroke-width="2" filter="url(#glow-cyan)"/>
<path d="M -70,-25 L -30,-25 M 70,-25 L 30,-25" stroke="#00D5FF" stroke-width="2"/>
<g class="gyro-ring" filter="url(#glow-cyan)">
<circle cx="0" cy="5" r="24" fill="none" stroke="#00D5FF" stroke-width="2" stroke-dasharray="10 5"/>
<circle cx="0" cy="5" r="14" fill="none" stroke="#00D5FF" stroke-width="1.5"/>
<circle cx="0" cy="5" r="5" fill="#00D5FF"/>
</g>
<text x="0" y="-15" text-anchor="middle" fill="#00D5FF" font-size="12" font-weight="bold" letter-spacing="2">ZERO TILT</text>
</g>
</g>
</g>
<!-- 2. 后轮三星总成 (绝对定位) -->
<g id="rear-planetary">
<use href="#tri-star-system"/>
</g>
<!-- 3. 前轮三星总成 (绝对定位) -->
<g id="front-planetary">
<use href="#tri-star-system"/>
</g>
</g>
</g>
</svg>
</div>
<script>
// --- 核心物理与尺寸参数 ---
const config = {
W: 300, // 底盘轴距 (前后轮中心距)
R: 50, // Y型支架旋转半径 (中心到小轮中心的距离)
r: 18, // 小轮半径
stairH: 110, // 阶梯高度
stairW: 850, // 阶梯水平间距
speed: 3.5, // 全局行进速度
pivotY: -90 // 底盘到载货台云台的铰接高度偏移
};
// Y型支架正常姿态时,底部小轮垂直向下,离地间隙为 R + r
const groundClearance = config.R + config.r; // 68px
// 碰撞计算
const cornerX = 400; // 台阶拐角局部X坐标
const startClimbX = cornerX - config.R - config.r; // 轮子触及墙壁开始翻滚
const climbDist = 160; // 跨越所需水平距离的缓动空间
const scene = document.getElementById('scene');
const terrain = document.getElementById('terrain');
const terrainFill = document.getElementById('terrain-fill');
const chassisBeam = document.getElementById('chassis-beam');
const platform = document.getElementById('platform');
const rearPlanetary = document.getElementById('rear-planetary');
const frontPlanetary = document.getElementById('front-planetary');
const hydLeft = document.getElementById('hyd-left');
const hydRight = document.getElementById('hyd-right');
const uiTilt = document.getElementById('ui-tilt');
const uiStatus = document.getElementById('ui-status');
const swRotators = document.querySelectorAll('.sw-rotator');
let globalTime = 0;
/**
* 缓动函数 - 使跨越过程平滑
*/
function easeInOut(t) {
return t * t * (3 - 2 * t);
}
/**
* 计算轮轴(即支架中心)基于全局X的绝对高度Y
*/
function getAxleY(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseY = stepCount * -config.stairH;
if (localX > startClimbX && localX <= startClimbX + climbDist) {
let t = (localX - startClimbX) / climbDist;
return baseY - config.stairH * easeInOut(t);
} else if (localX > startClimbX + climbDist) {
return baseY - config.stairH;
}
return baseY;
}
/**
* 计算三星支架翻滚的绝对角度
* 每次跨级翻滚 120 度
*/
function getBracketAngle(x) {
let localX = ((x % config.stairW) + config.stairW) % config.stairW;
let stepCount = Math.floor(x / config.stairW);
let baseAngle = stepCount * 120;
if (localX > startClimbX && localX <= startClimbX + climbDist) {
let t = (localX - startClimbX) / climbDist;
return baseAngle + 120 * easeInOut(t);
} else if (localX > startClimbX + climbDist) {
return baseAngle + 120;
}
return baseAngle;
}
/**
* 生成楼梯台阶路径
*/
function updateTerrainPath(cx) {
let startX = Math.floor((cx - 1500) / config.stairW) * config.stairW;
let endX = cx + 2000;
let pathD = `M ${startX}, 2000 `;
for (let x = startX; x < endX; x += config.stairW) {
let yTop = Math.floor(x / config.stairW) * -config.stairH + groundClearance;
let yBot = yTop - config.stairH;
let stepX = x + cornerX;
pathD += `L ${x}, ${yTop} L ${stepX}, ${yTop} L ${stepX}, ${yBot} L ${x + config.stairW}, ${yBot} `;
}
pathD += `L ${endX}, 2000 Z`;
terrain.setAttribute('d', pathD);
terrainFill.setAttribute('d', pathD);
}
function animate() {
globalTime += config.speed;
// 1. 计算后轴坐标
let Rx = globalTime;
let Ry = getAxleY(Rx);
// 2. 迭代前轴位置,确保底盘作为刚体,轴距精准保持 W 不变
let Fx = Rx + config.W;
for(let i = 0; i < 6; i++) {
let tempFy = getAxleY(Fx);
let currentDist = Math.hypot(Fx - Rx, tempFy - Ry);
let error = config.W - currentDist;
Fx += error * 0.9;
}
let Fy = getAxleY(Fx);
// 3. 底盘中心坐标与俯仰姿态角
let Cx = (Rx + Fx) / 2;
let Cy = (Ry + Fy) / 2;
let thetaRad = Math.atan2(Fy - Ry, Fx - Rx);
let thetaDeg = thetaRad * 180 / Math.PI;
// 4. 镜头跟踪锁定车体
const screenCx = window.innerWidth / 2;
const screenCy = window.innerHeight / 2 + 60;
scene.setAttribute('transform', `translate(${screenCx - Cx}, ${screenCy - Cy})`);
// 5. 渲染楼梯
updateTerrainPath(Cx);
// 6. 行星轮位置与姿态更新 (直接放置在轮轴计算点)
rearPlanetary.setAttribute('transform', `translate(${Rx}, ${Ry}) rotate(${getBracketAngle(Rx)})`);
frontPlanetary.setAttribute('transform', `translate(${Fx}, ${Fy}) rotate(${getBracketAngle(Fx)})`);
// 小轮自转:向前滚动为正向角度
let wheelSpin = globalTime * 4;
swRotators.forEach(sw => sw.setAttribute('transform', `rotate(${wheelSpin})`));
// 7. 底盘位姿更新 (位于 Cx, Cy)
chassisBeam.setAttribute('transform', `translate(${Cx}, ${Cy}) rotate(${thetaDeg})`);
// 8. 云台自调平 (完全消除 thetaDeg 的倾角影响,保持对地 0 度)
platform.setAttribute('transform', `translate(0, ${config.pivotY}) rotate(${-thetaDeg})`);
// 9. 主动补偿液压杆计算
let rad = -thetaRad;
let pLeftX = -85 * Math.cos(rad);
let pLeftY = -85 * Math.sin(rad);
hydLeft.setAttribute('x2', pLeftX);
hydLeft.setAttribute('y2', config.pivotY + pLeftY);
let pRightX = 85 * Math.cos(rad);
let pRightY = 85 * Math.sin(rad);
hydRight.setAttribute('x2', pRightX);
hydRight.setAttribute('y2', config.pivotY + pRightY);
// 10. UI 数据刷新
let tiltVal = Math.abs(thetaDeg).toFixed(2);
uiTilt.textContent = tiltVal + '°';
if (Math.abs(thetaDeg) > 0.5) {
uiStatus.textContent = "● 状态监控:极速液压对冲中...";
uiStatus.style.color = "var(--accent-orange)";
} else {
uiStatus.textContent = "● 状态监控:平地巡航";
uiStatus.style.color = "var(--accent-cyan)";
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
