armbot animator movements and path updated
This commit is contained in:
parent
bda6cbe8be
commit
bb7315edeb
|
@ -1,7 +1,7 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useFrame } from '@react-three/fiber';
|
import { useFrame } from '@react-three/fiber';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Line } from '@react-three/drei';
|
import { Line, Text } from '@react-three/drei';
|
||||||
import {
|
import {
|
||||||
useAnimationPlaySpeed,
|
useAnimationPlaySpeed,
|
||||||
usePauseButtonStore,
|
usePauseButtonStore,
|
||||||
|
@ -124,7 +124,6 @@ function RoboticArmAnimator({
|
||||||
// Handle nearest points and final path (including arc points)
|
// Handle nearest points and final path (including arc points)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (circlePoints.length > 0 && currentPath.length > 0) {
|
if (circlePoints.length > 0 && currentPath.length > 0) {
|
||||||
|
|
||||||
const start = currentPath[0];
|
const start = currentPath[0];
|
||||||
const end = currentPath[currentPath.length - 1];
|
const end = currentPath[currentPath.length - 1];
|
||||||
|
|
||||||
|
@ -137,31 +136,50 @@ function RoboticArmAnimator({
|
||||||
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
||||||
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
||||||
|
|
||||||
const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64;
|
const totalSegments = 64;
|
||||||
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64;
|
const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + totalSegments) % totalSegments;
|
||||||
const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance;
|
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + totalSegments) % totalSegments;
|
||||||
|
|
||||||
|
// Prepare degrees
|
||||||
|
const degreesList = generateRingPointsWithDegrees(CIRCLE_RADIUS, totalSegments);
|
||||||
|
|
||||||
|
// Helper function to collect points and check forbidden degrees
|
||||||
|
const collectArcPoints = (startIdx: number, endIdx: number, clockwise: boolean) => {
|
||||||
|
const arcPoints: [number, number, number][] = [];
|
||||||
|
let i = startIdx;
|
||||||
|
|
||||||
|
while (i !== (endIdx + (clockwise ? 1 : -1) + totalSegments) % totalSegments) {
|
||||||
|
const { degree, position } = degreesList[i];
|
||||||
|
|
||||||
|
// Skip over
|
||||||
|
arcPoints.push(position);
|
||||||
|
i = (i + (clockwise ? 1 : -1) + totalSegments) % totalSegments;
|
||||||
|
}
|
||||||
|
return arcPoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasForbiddenDegrees = (arc: [number, number, number][]) => {
|
||||||
|
return arc.some(p => {
|
||||||
|
const idx = findNearestIndex(p, circlePoints);
|
||||||
|
const degree = degreesList[idx]?.degree || 0;
|
||||||
|
return degree >= 271 && degree <= 300; // Forbidden range: 271° to 300°
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Try both directions
|
||||||
|
const arcClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, true);
|
||||||
|
const arcCounterClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, false);
|
||||||
|
|
||||||
|
const clockwiseForbidden = hasForbiddenDegrees(arcClockwise);
|
||||||
|
const counterClockwiseForbidden = hasForbiddenDegrees(arcCounterClockwise);
|
||||||
|
|
||||||
let arcPoints: [number, number, number][] = [];
|
let arcPoints: [number, number, number][] = [];
|
||||||
|
|
||||||
if (clockwiseIsShorter) {
|
if (!clockwiseForbidden && (clockwiseDistance <= counterClockwiseDistance || counterClockwiseForbidden)) {
|
||||||
if (indexOfNearestStart <= indexOfNearestEnd) {
|
arcPoints = arcClockwise;
|
||||||
arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1);
|
|
||||||
} else {
|
} else {
|
||||||
arcPoints = [
|
arcPoints = arcCounterClockwise;
|
||||||
...circlePoints.slice(indexOfNearestStart, 64),
|
|
||||||
...circlePoints.slice(0, indexOfNearestEnd + 1)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (indexOfNearestStart >= indexOfNearestEnd) {
|
|
||||||
for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) {
|
|
||||||
arcPoints.push(circlePoints[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) {
|
|
||||||
arcPoints.push(circlePoints[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathVectors = [
|
const pathVectors = [
|
||||||
|
@ -174,9 +192,7 @@ function RoboticArmAnimator({
|
||||||
new THREE.Vector3(end[0], end[1], end[2])
|
new THREE.Vector3(end[0], end[1], end[2])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
|
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pathVectors.length - 1; i++) {
|
for (let i = 0; i < pathVectors.length - 1; i++) {
|
||||||
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
|
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
|
||||||
}
|
}
|
||||||
|
@ -186,16 +202,12 @@ function RoboticArmAnimator({
|
||||||
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
|
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
|
||||||
totalDistanceRef.current = totalDistance;
|
totalDistanceRef.current = totalDistance;
|
||||||
|
|
||||||
const movementSpeed = speed * armBot.speed;
|
|
||||||
const totalMoveTime = totalDistance / movementSpeed;
|
|
||||||
|
|
||||||
const segmentTimes = segmentDistances.map(distance => (distance / totalDistance) * totalMoveTime);
|
|
||||||
|
|
||||||
setCustomCurvePoints(pathVectors);
|
setCustomCurvePoints(pathVectors);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [circlePoints, currentPath]);
|
}, [circlePoints, currentPath]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Frame update for animation
|
// Frame update for animation
|
||||||
useFrame((state, delta) => {
|
useFrame((state, delta) => {
|
||||||
if (!ikSolver) return;
|
if (!ikSolver) return;
|
||||||
|
@ -266,10 +278,52 @@ function RoboticArmAnimator({
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
)}
|
)}
|
||||||
<mesh position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]} rotation={[-Math.PI / 2, 0, 0]}>
|
<group position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]}>
|
||||||
|
{/* Green ring */}
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
|
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
|
||||||
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
|
{/* Markers at 90°, 180°, 270°, 360° */}
|
||||||
|
{[90, 180, 270, 360].map((degree, index) => {
|
||||||
|
const rad = (degree * Math.PI) / 180;
|
||||||
|
const x = CIRCLE_RADIUS * Math.cos(rad);
|
||||||
|
const z = CIRCLE_RADIUS * Math.sin(rad);
|
||||||
|
const y = 0; // same plane as the ring (Y axis)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh key={index} position={[x, y, z]}>
|
||||||
|
<sphereGeometry args={[0.05, 16, 16]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{/* Optional: Text Labels */}
|
||||||
|
|
||||||
|
{[90, 180, 270, 360].map((degree, index) => {
|
||||||
|
const rad = (degree * Math.PI) / 180;
|
||||||
|
const x = CIRCLE_RADIUS * Math.cos(rad);
|
||||||
|
const z = CIRCLE_RADIUS * Math.sin(rad);
|
||||||
|
const y = 0.15; // lift the text slightly above the ring
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
key={`text-${index}`}
|
||||||
|
position={[x, y, z]}
|
||||||
|
fontSize={0.2}
|
||||||
|
color="yellow"
|
||||||
|
anchorX="center"
|
||||||
|
anchorY="middle"
|
||||||
|
>
|
||||||
|
{degree}°
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,17 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(firstFrame);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
logStatus(armBot.modelUuid, "Simulation Play Exited")
|
||||||
|
setArmBotActive(armBot.modelUuid, false)
|
||||||
|
setArmBotState(armBot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("init");
|
||||||
|
setPath([])
|
||||||
|
isPausedRef.current = false
|
||||||
|
pauseTimeRef.current = null
|
||||||
|
isPausedRef.current = false
|
||||||
|
startTime = 0
|
||||||
|
removeCurrentAction(armBot.modelUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [currentPhase, armBot, isPlaying, ikSolver])
|
}, [currentPhase, armBot, isPlaying, ikSolver])
|
||||||
|
|
|
@ -139,15 +139,16 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow only angles between 90° and 270°
|
// Allow only angles between 90° and 270°
|
||||||
if (angleDeg < 95 || angleDeg > 270) {
|
if (angleDeg < 0 || angleDeg > 270) {
|
||||||
// Clamp to nearest boundary (90° or 270°)
|
// Clamp to nearest boundary (90° or 270°)
|
||||||
const distanceTo90 = Math.abs(angleDeg - 95);
|
const distanceTo90 = Math.abs(angleDeg - 0);
|
||||||
const distanceTo270 = Math.abs(angleDeg - 270);
|
const distanceTo270 = Math.abs(angleDeg - 270);
|
||||||
|
|
||||||
if (distanceTo90 < distanceTo270) {
|
if (distanceTo90 < distanceTo270) {
|
||||||
angleDeg = 95;
|
angleDeg = 0;
|
||||||
} else {
|
} else {
|
||||||
angleDeg = 270;
|
return
|
||||||
|
// angleDeg = 270;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update angle in radians
|
// Update angle in radians
|
||||||
|
|
Loading…
Reference in New Issue