Compare commits

..

No commits in common. "e7298996d02739b0868c11f4d31ae406e919ba58" and "c6b7d5cadddeed5a253543723389d51162c264d3" have entirely different histories.

View File

@ -86,8 +86,8 @@ import * as THREE from 'three';
// --- Three.js scene --- // --- Three.js scene ---
const scene = new THREE.Scene(); const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 1.2, 5); camera.position.set(0, 2, 5);
camera.lookAt(0, 0.8, 0); camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight); renderer.setSize(window.innerWidth, window.innerHeight);
@ -107,67 +107,70 @@ scene.add(pointLight);
// Grid // Grid
scene.add(new THREE.GridHelper(10, 20, 0x222244, 0x111122)); scene.add(new THREE.GridHelper(10, 20, 0x222244, 0x111122));
// SaltyBot robot model — two-wheeled self-balancing robot // FC Board model
// Pivot at wheel axle (y=0); body rises upward; pitches ±pitch_deg around X axis.
const boardGroup = new THREE.Group(); const boardGroup = new THREE.Group();
// Main body (vertical rectangle, ~1.2 tall, center above wheel axle) // PCB
boardGroup.add(new THREE.Mesh( boardGroup.add(new THREE.Mesh(
new THREE.BoxGeometry(0.7, 1.2, 0.3), new THREE.BoxGeometry(1.6, 0.08, 1.6),
new THREE.MeshPhongMaterial({ color: 0x1a2a4a, specular: 0x334466 }) new THREE.MeshPhongMaterial({ color: 0x1a1a1a, specular: 0x333333 })
)); ));
boardGroup.children[boardGroup.children.length - 1].position.set(0, 0.7, 0);
// Left wheel // Copper traces
const wheelGeo = new THREE.CylinderGeometry(0.4, 0.4, 0.14, 20); const traceMat = new THREE.MeshPhongMaterial({ color: 0xcc8833, specular: 0xffaa44 });
const wheelMat = new THREE.MeshPhongMaterial({ color: 0x1a1a1a, specular: 0x333333 }); for (let i = -0.6; i <= 0.6; i += 0.3) {
const leftWheel = new THREE.Mesh(wheelGeo, wheelMat); const trace = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.005, 0.02), traceMat);
leftWheel.rotation.z = Math.PI / 2; trace.position.set(0, 0.043, i);
leftWheel.position.set(-0.47, 0, 0); boardGroup.add(trace);
boardGroup.add(leftWheel); }
// Right wheel // MCU chip
const rightWheel = new THREE.Mesh(wheelGeo, wheelMat); const mcu = new THREE.Mesh(
rightWheel.rotation.z = Math.PI / 2; new THREE.BoxGeometry(0.5, 0.06, 0.5),
rightWheel.position.set(0.47, 0, 0); new THREE.MeshPhongMaterial({ color: 0x222222, specular: 0x444444 })
boardGroup.add(rightWheel); );
mcu.position.set(0, 0.07, 0);
boardGroup.add(mcu);
// Wheel rims (blue accent) // IMU chip
const rimGeo = new THREE.TorusGeometry(0.37, 0.025, 8, 20); const imuChip = new THREE.Mesh(
const rimMat = new THREE.MeshPhongMaterial({ color: 0x0055cc, specular: 0x0088ff }); new THREE.BoxGeometry(0.2, 0.04, 0.2),
[[-0.54], [0.54]].forEach(([x]) => { new THREE.MeshPhongMaterial({ color: 0x331111, specular: 0x442222 })
const rim = new THREE.Mesh(rimGeo, rimMat); );
rim.rotation.z = Math.PI / 2; imuChip.position.set(-0.4, 0.06, -0.3);
rim.position.set(x, 0, 0); boardGroup.add(imuChip);
boardGroup.add(rim);
});
// Display panel on front face // USB connector
boardGroup.add(new THREE.Mesh( const usb = new THREE.Mesh(
new THREE.BoxGeometry(0.48, 0.36, 0.02), new THREE.BoxGeometry(0.35, 0.1, 0.15),
new THREE.MeshPhongMaterial({ color: 0x001133, specular: 0x003366, emissive: 0x000a1a }) new THREE.MeshPhongMaterial({ color: 0x888888, specular: 0xaaaaaa })
)); );
boardGroup.children[boardGroup.children.length - 1].position.set(0, 0.75, 0.16); usb.position.set(0, 0.06, -0.85);
boardGroup.add(usb);
// Status LED // Status LED
const ledMat = new THREE.MeshBasicMaterial({ color: 0xff0000 }); const ledMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const led = new THREE.Mesh(new THREE.SphereGeometry(0.04, 8, 8), ledMat); const led = new THREE.Mesh(new THREE.SphereGeometry(0.03, 8, 8), ledMat);
led.position.set(0.22, 1.1, 0.16); led.position.set(0.5, 0.06, 0.5);
boardGroup.add(led); boardGroup.add(led);
// Sensor stem (thin post above body) // Mounting holes
boardGroup.add(new THREE.Mesh( const holeMat = new THREE.MeshPhongMaterial({ color: 0x444444 });
new THREE.BoxGeometry(0.1, 0.28, 0.1), [[-0.55, -0.55], [-0.55, 0.55], [0.55, -0.55], [0.55, 0.55]].forEach(([x, z]) => {
new THREE.MeshPhongMaterial({ color: 0x2a2a2a, specular: 0x444444 }) const ring = new THREE.Mesh(new THREE.TorusGeometry(0.06, 0.015, 8, 16), holeMat);
)); ring.rotation.x = Math.PI / 2;
boardGroup.children[boardGroup.children.length - 1].position.set(0, 1.44, 0); ring.position.set(x, 0.05, z);
boardGroup.add(ring);
});
// Sensor head (camera/LIDAR box at top) // Forward arrow
boardGroup.add(new THREE.Mesh( const arrow = new THREE.Mesh(
new THREE.BoxGeometry(0.28, 0.16, 0.28), new THREE.ConeGeometry(0.08, 0.2, 8),
new THREE.MeshPhongMaterial({ color: 0x111122, specular: 0x333355 }) new THREE.MeshBasicMaterial({ color: 0xff4444, transparent: true, opacity: 0.8 })
)); );
boardGroup.children[boardGroup.children.length - 1].position.set(0, 1.66, 0); arrow.rotation.x = -Math.PI / 2;
arrow.position.set(0, 0.06, -0.65);
boardGroup.add(arrow);
scene.add(boardGroup); scene.add(boardGroup);