armbot animator movements and path updated

This commit is contained in:
Gomathi 2025-05-06 11:30:32 +05:30
parent bda6cbe8be
commit bb7315edeb
3 changed files with 107 additions and 41 deletions

View File

@ -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 {
arcPoints = [
...circlePoints.slice(indexOfNearestStart, 64),
...circlePoints.slice(0, indexOfNearestEnd + 1)
];
}
} else { } else {
if (indexOfNearestStart >= indexOfNearestEnd) { arcPoints = arcCounterClockwise;
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]]}>
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} /> {/* Green ring */}
<meshBasicMaterial color="green" side={THREE.DoubleSide} /> <mesh rotation={[-Math.PI / 2, 0, 0]}>
</mesh> <ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
</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>
</> </>
); );
} }

View File

@ -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])

View File

@ -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