import React, { useEffect, useRef, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; import { useThree } from "@react-three/fiber"; import { useFloorItems } from '../../../../../store/store'; import useModuleStore from '../../../../../store/useModuleStore'; import * as THREE from "three"; import { useSelectedAction } from '../../../../../store/simulation/useSimulationStore'; function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const [currentPhase, setCurrentPhase] = useState<(string)>("init"); const [path, setPath] = useState<[number, number, number][]>([]); const [ikSolver, setIkSolver] = useState(null); const { scene } = useThree(); const restPosition = new THREE.Vector3(0, 1.75, -1.6); const targetBone = "Target"; const groupRef = useRef(null); const pauseTimeRef = useRef(null); const isPausedRef = useRef(false); let startTime: number; //zustand const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); const { floorItems } = useFloorItems(); const { activeModule } = useModuleStore(); const { isPlaying } = usePlayButtonStore(); const { isReset, setReset } = useResetButtonStore(); const { isPaused } = usePauseButtonStore(); const { selectedAction } = useSelectedAction(); function firstFrame() { startTime = performance.now(); step(); } function step() { if (isPausedRef.current) { if (!pauseTimeRef.current) { pauseTimeRef.current = performance.now(); } requestAnimationFrame(() => step()); return; } if (pauseTimeRef.current) { const pauseDuration = performance.now() - pauseTimeRef.current; startTime += pauseDuration; pauseTimeRef.current = null; } const elapsedTime = performance.now() - startTime; if (elapsedTime < 1500) { // Wait until 1500ms has passed requestAnimationFrame(step); return; } if(currentPhase==="picking"){ setArmBotActive(armBot.modelUuid, true); setArmBotState(armBot.modelUuid, "running"); setCurrentPhase("start-to-end"); startTime=0 const startPoint = armBot.point.actions[0].process.startPoint; const endPoint = armBot.point.actions[0].process.endPoint; if (startPoint && endPoint) { let curve = createCurveBetweenTwoPoints( new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]), new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])); if (curve) { logStatus(armBot.modelUuid, "picking the object"); setPath(curve.points.map(point => [point.x, point.y, point.z])) } } logStatus(armBot.modelUuid, "Moving armBot from start point to end position.") }else if(currentPhase==="dropping"){ setArmBotActive(armBot.modelUuid, true); setArmBotState(armBot.modelUuid, "running"); setCurrentPhase("end-to-rest"); startTime=0; const endPoint = armBot.point.actions[0].process.endPoint; if (endPoint) { let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition); if (curve) { logStatus(armBot.modelUuid, "dropping the object"); setPath(curve.points.map(point => [point.x, point.y, point.z])); } } logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") } } useEffect(() => { isPausedRef.current = isPaused; }, [isPaused]); useEffect(() => { const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); if (targetMesh) { targetMesh.visible = activeModule !== "simulation" } const targetBones = ikSolver?.mesh.skeleton.bones.find( (b: any) => b.name === targetBone ); if (isReset) { logStatus(armBot.modelUuid, "Simulation Play Reset Successfully") removeCurrentAction(armBot.modelUuid) setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); isPausedRef.current=false pauseTimeRef.current=null isPausedRef.current=false startTime=0 if (targetBones) { let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) if (curve) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } setReset(false); logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } if (isPlaying) { //Moving armBot from initial point to rest position. if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); if (targetBones) { let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) if (curve) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } //Waiting for trigger. else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") const timeoutId = setTimeout(() => { let actionId=armBot.point.actions[0].actionUuid addCurrentAction(armBot.modelUuid,actionId); // addCurrentAction(armBot.modelUuid, selectedAction?.actionId); }, 3000); return () => clearTimeout(timeoutId); } else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) { if (armBot.currentAction) { setArmBotActive(armBot.modelUuid, true); setArmBotState(armBot.modelUuid, "running"); setCurrentPhase("rest-to-start"); const startPoint = armBot.point.actions[0].process.startPoint; if (startPoint) { let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); if (curve) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } } logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.") } else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) { requestAnimationFrame(firstFrame); // setArmBotActive(armBot.modelUuid, true); // setArmBotState(armBot.modelUuid, "running"); // setCurrentPhase("start-to-end"); // const startPoint = armBot.point.actions[0].process.startPoint; // const endPoint = armBot.point.actions[0].process.endPoint; // if (startPoint && endPoint) { // let curve = createCurveBetweenTwoPoints( // new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]), // new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])); // if (curve) { // setTimeout(() => { // logStatus(armBot.modelUuid, "picking the object"); // setPath(curve.points.map(point => [point.x, point.y, point.z])); // }, 1500) // } // } // logStatus(armBot.modelUuid, "Moving armBot from start point to end position.") } else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) { requestAnimationFrame(firstFrame); // setArmBotActive(armBot.modelUuid, true); // setArmBotState(armBot.modelUuid, "running"); // setCurrentPhase("end-to-rest"); // const endPoint = armBot.point.actions[0].process.endPoint; // if (endPoint) { // let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition); // if (curve) { // setTimeout(() => { // logStatus(armBot.modelUuid, "dropping the object"); // setPath(curve.points.map(point => [point.x, point.y, point.z])); // }, 1500) // } // } // logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") } } else { logStatus(armBot.modelUuid, "Simulation Play Stopped") setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("init"); setPath([]) removeCurrentAction(armBot.modelUuid) } }, [currentPhase, armBot, isPlaying, ikSolver, isReset]) function createCurveBetweenTwoPoints(p1: any, p2: any) { const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5); // mid.y += 0.5; const points = [p1, mid, p2]; return new THREE.CatmullRomCurve3(points); } const HandleCallback = () => { if (armBot.isActive && armBot.state == "running" && currentPhase == "init-to-rest") { logStatus(armBot.modelUuid, "Callback triggered: rest"); setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) } else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") { logStatus(armBot.modelUuid, "Callback triggered: pick."); setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("picking"); setPath([]) } else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") { logStatus(armBot.modelUuid, "Callback triggered: drop."); setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("dropping"); setPath([]) } else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") { logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed."); setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) removeCurrentAction(armBot.modelUuid) } } const logStatus = (id: string, status: string) => { // } return ( <> ) } export default RoboticArmInstance;