277 lines
13 KiB
TypeScript
277 lines
13 KiB
TypeScript
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 useModuleStore from '../../../../../store/useModuleStore';
|
|
import * as THREE from "three";
|
|
import { useSelectedAction, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
|
|
import { useProductStore } from '../../../../../store/simulation/useProductStore';
|
|
|
|
|
|
function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
|
|
|
const [currentPhase, setCurrentPhase] = useState<(string)>("init");
|
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
|
const [ikSolver, setIkSolver] = useState<any>(null);
|
|
const { scene } = useThree();
|
|
const restPosition = new THREE.Vector3(0, 1.75, -1.6);
|
|
const targetBone = "Target";
|
|
const groupRef = useRef<any>(null);
|
|
const pauseTimeRef = useRef<number | null>(null);
|
|
const isPausedRef = useRef<boolean>(false);
|
|
let startTime: number;
|
|
//zustand
|
|
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
|
const { getActionByUuid } = useProductStore();
|
|
const { selectedProduct } = useSelectedProduct();
|
|
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 < 1000) {
|
|
// 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(() => {
|
|
if (isReset || !isPlaying) {
|
|
logStatus(armBot.modelUuid, "Simulation Play Reset Successfully")
|
|
setArmBotActive(armBot.modelUuid, false)
|
|
setArmBotState(armBot.modelUuid, "idle")
|
|
setCurrentPhase("init");
|
|
setPath([])
|
|
removeCurrentAction(armBot.modelUuid)
|
|
isPausedRef.current = false
|
|
pauseTimeRef.current = null
|
|
startTime = 0
|
|
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone
|
|
);
|
|
if (targetBones && isPlaying) {
|
|
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.")
|
|
}
|
|
}
|
|
// setReset(false);
|
|
}
|
|
}, [isReset, isPlaying])
|
|
|
|
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 (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, targetBones.position)
|
|
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(() => {
|
|
addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid);
|
|
}, 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(targetBones.position, 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 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])
|
|
|
|
|
|
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 (
|
|
<>
|
|
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
|
|
<RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
|
|
logStatus={logStatus} path={path} currentPhase={currentPhase} />
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default RoboticArmInstance;
|