From 05d8405188a9748994bf1a23c2b996cf1e9ef44d Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 25 Apr 2025 19:40:15 +0530 Subject: [PATCH] armbot trigger --- .../instances/animator/roboticArmAnimator.tsx | 62 ++++++- .../armInstance/roboticArmInstance.tsx | 175 +++++++++++++++--- .../instances/ikInstance/ikInstance.tsx | 85 ++++++++- .../roboticArm/instances/ikInstances.tsx | 14 -- .../instances/roboticArmInstances.tsx | 12 +- .../simulation/roboticArm/roboticArm.tsx | 91 +++++++-- app/src/store/simulation/useArmBotStore.ts | 13 +- app/src/store/simulation/useVehicleStore.ts | 1 + 8 files changed, 382 insertions(+), 71 deletions(-) delete mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 6b35a43..fd7590e 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,6 +1,64 @@ -import React from 'react' +import React, { useEffect, useMemo, useRef, useState } from 'react' +import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; +import { useFrame, useThree } from '@react-three/fiber'; +import * as THREE from "three" +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; + +function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, targetBone, robot, logStatus, groupRef, processes, armBotCurveRef, path }: any) { + const { armBots } = useArmBotStore(); + const { scene } = useThree(); + const restSpeed = 0.1; + const restPosition = new THREE.Vector3(0, 2, 1.6); + const initialCurveRef = useRef(null); + const initialStartPositionRef = useRef(null); + const [initialProgress, setInitialProgress] = useState(0); + const [progress, setProgress] = useState(0); + const [needsInitialMovement, setNeedsInitialMovement] = useState(true); + const [isInitializing, setIsInitializing] = useState(true); + const { isPlaying } = usePlayButtonStore(); + const statusRef = useRef("idle"); + // Create a ref for initialProgress + const initialProgressRef = useRef(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + + useEffect(() => { + setCurrentPath(path) + }, [path]) + + useEffect(() => { + + }, [currentPath]) + + useFrame((_, delta) => { + if (!ikSolver || !currentPath || currentPath.length === 0) return; + + const bone = ikSolver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); + if (!bone) return; + + // Ensure currentPath is a valid array of 3D points, create a CatmullRomCurve3 from it + const curve = new THREE.CatmullRomCurve3( + currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2])) + ); + + const next = initialProgressRef.current + delta * 0.5; + if (next >= 1) { + bone.position.copy(restPosition); + HandleCallback(); // Call the callback when the path is completed + initialProgressRef.current = 0; // Set ref to 1 when done + } else { + + const point = curve.getPoint(next); // Get the interpolated point from the curve + bone.position.copy(point); // Update the bone position along the curve + initialProgressRef.current = next; // Update progress + } + + ikSolver.update(); + }); + + -function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase }: any) { return ( <> ) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 42b775a..86eee6a 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,58 +1,179 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; import { usePlayButtonStore } 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 { Vector3 } from "three"; +import * as THREE from "three"; + +interface Process { + triggerId: string; + startPoint?: Vector3; + endPoint?: Vector3; + speed: number; +} +function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { -function RoboticArmInstance({ armBot }: any) { const { isPlaying } = usePlayButtonStore(); const [currentPhase, setCurrentPhase] = useState<(string)>("init"); - console.log('currentPhase: ', currentPhase); - const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + const { scene } = useThree(); + const targetBone = "Target"; + const { activeModule } = useModuleStore(); + const [ikSolver, setIkSolver] = useState(null); + const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); + const { floorItems } = useFloorItems(); + const groupRef = useRef(null); + const [processes, setProcesses] = useState([]); + const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] }) + const restPosition = new THREE.Vector3(0, 2, 1.6); + let armBotCurveRef = useRef(null) + const [path, setPath] = useState<[number, number, number][]>([]); useEffect(() => { + let armItems = floorItems?.filter((val: any) => + val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" + ); + // Get the first matching item + let armItem = armItems?.[0]; + if (armItem) { + const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); + if (targetMesh) { + targetMesh.visible = activeModule !== "simulation" + } + } + const targetBones = ikSolver?.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); - console.log('isPlaying: ', isPlaying); if (isPlaying) { //Moving armBot from initial point to rest position. - - if (armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { - addCurrentAction(armBot.modelUuid, 'action-001'); - setCurrentPhase("moving-to-rest"); - + if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") { + + setArmBotActive(robot.modelUuid, true) + setArmBotState(robot.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(robot.modelUuid, "Starting from init to rest") } //Waiting for trigger. - if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "moving-to-rest") { - setCurrentPhase("rest"); + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { + console.log("trigger"); + setTimeout(() => { + addCurrentAction(robot.modelUuid, 'action-003'); + }, 3000); } - // Moving armBot from rest position to pick up point. - if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "rest") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && robot.currentAction) { + if (robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("rest-to-start"); + const startPoint = robot.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(robot.modelUuid, "Starting from rest to start") } - //Moving arm from start point to end point. - if (armBot?.isActive && armBot?.state == "running " && currentPhase == "rest-to-start ") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("start-to-end"); + const startPoint = robot.point.actions[0].process.startPoint; + const endPoint = robot.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) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + logStatus(robot.modelUuid, "Starting from start to end") } - //Moving arm from end point to idle. - if (armBot?.isActive && armBot?.state == "running" && currentPhase == "end-to-start") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("end-to-rest"); + const endPoint = robot.point.actions[0].process.endPoint; + if (endPoint) { + let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition + ); + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + logStatus(robot.modelUuid, "Starting from end to rest") } - } - }, [currentPhase, armBot, isPlaying]) + }, [currentPhase, robot, 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 == "idle" && currentPhase == "init") { - addCurrentAction('armbot-xyz-001', 'action-001'); + if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { + console.log("Callback triggered: rest"); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("rest"); + setPath([]) } + else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") { + console.log("Callback triggered: pick."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("picking"); + setPath([]) + } + else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") { + console.log("Callback triggered: drop."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("dropping"); + setPath([]) + } + else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") { + console.log("Callback triggered: rest, cycle completed."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("rest"); + setPath([]) + removeCurrentAction(robot.modelUuid) + } + } + const logStatus = (id: string, status: string) => { + console.log(id +","+ status); } return ( <> - - + + ) diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index 52a8610..a8d8782 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -1,8 +1,87 @@ -import React from 'react' +import React, { useEffect, useMemo, useRef, useState } from 'react' +import * as THREE from "three"; +import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; +import { clone } from "three/examples/jsm/utils/SkeletonUtils"; +import { useFrame, useLoader, useThree } from "@react-three/fiber"; +import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver"; +type IKInstanceProps = { + modelUrl: string; + ikSolver: any; + setIkSolver: any + robot: any; + groupRef: React.RefObject; + processes: any; + setArmBotCurvePoints: any +}; +function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) { + const { scene } = useThree(); + const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { + const draco = new DRACOLoader(); + draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/"); + loader.setDRACOLoader(draco); + }); + const cloned = useMemo(() => clone(gltf?.scene), [gltf]); + const targetBoneName = "Target"; + const skinnedMeshName = "link_0"; + useEffect(() => { + if (!gltf) return; + const OOI: any = {}; + cloned.traverse((n: any) => { + if (n.name === targetBoneName) OOI.Target_Bone = n; + if (n.name === skinnedMeshName) OOI.Skinned_Mesh = n; + }); + if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return; + const iks = [ + { + target: 7, + effector: 6, + links: [ + { + index: 5, + enabled: true, + rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0), + rotationMax: new THREE.Vector3(Math.PI / 2, 0, 0), + }, + { + index: 4, + enabled: true, + rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0), + rotationMax: new THREE.Vector3(0, 0, 0), + }, + { + index: 3, + enabled: true, + rotationMin: new THREE.Vector3(0, 0, 0), + rotationMax: new THREE.Vector3(2, 0, 0), + }, + { index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) }, + { index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) }, + ], + }, + ]; + + const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks); + setIkSolver(solver); + + const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); + + // scene.add(groupRef.current) + + + }, [gltf]); -function IKInstance() { return ( - <> + <> + + + + ) } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx deleted file mode 100644 index d44ddd2..0000000 --- a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import IKInstance from './ikInstance/ikInstance'; - -function IkInstances() { - return ( - <> - - - - - ) -} - -export default IkInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 1f963c8..1089fa5 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -5,17 +5,11 @@ import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; function RoboticArmInstances() { const { armBots } = useArmBotStore(); - return ( <> - { - armBots?.map((robot: any) => ( - - - ) - ) - - } + {armBots?.map((robot: ArmBotStatus) => ( + + ))} ) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 4295ac7..dcf01da 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,21 +1,86 @@ import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; +import { useFloorItems } from "../../../store/store"; function RoboticArm() { - const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + const { armBots, addArmBot, removeArmBot } = useArmBotStore(); + const { floorItems } = useFloorItems(); const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", - // currentAction: { - // actionUuid: "action-001", - // actionName: "Pick Component", - // }, modelUuid: "armbot-xyz-001", modelName: "ArmBot-X200", - position: [0, 0, 0], - rotation: [91.94347308985614, 0, 6.742905194869091], + position: [91.94347308985614, 0, 6.742905194869091], + rotation: [0, 0, 0], + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-003", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: [5.52543010919071, 1, -8.433681161200905], + endPoint: [10.52543010919071, 1, -12.433681161200905], + }, + triggers: [ + { + triggerUuid: "trigger-001", + triggerName: "Start Trigger", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "Conveyor A1", + modelUuid: "conveyor-01", + }, + triggeredPoint: { + pointName: "Start Point", + pointUuid: "conveyor-01-point-001", + }, + triggeredAction: { + actionName: "Move Forward", + actionUuid: "conveyor-action-01", + }, + }, + }, + { + triggerUuid: "trigger-002", + triggerName: "Complete Trigger", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "StaticMachine B2", + modelUuid: "machine-02", + }, + triggeredPoint: { + pointName: "Receive Point", + pointUuid: "machine-02-point-001", + }, + triggeredAction: { + actionName: "Process Part", + actionUuid: "machine-action-01", + }, + }, + }, + ], + }, + ], + }, + }, + { + state: "idle", + modelUuid: "armbot-xyz-002", + modelName: "ArmBot-X200", + position: [95.94347308985614, 0, 6.742905194869091], + rotation: [0, 0, 0], type: "roboticArm", speed: 1.5, point: { @@ -28,8 +93,8 @@ function RoboticArm() { actionName: "Pick Component", actionType: "pickAndPlace", process: { - startPoint: [1.2, 0.3, 0.5], - endPoint: [-0.8, 1.1, 0.7], + startPoint: [2.52543010919071, 0, 8.433681161200905], + endPoint: [95.3438373267953, 0, 9.0279187421610025], }, triggers: [ { @@ -80,20 +145,20 @@ function RoboticArm() { ]; useEffect(() => { + + removeArmBot(armBotStatusSample[0].modelUuid); addArmBot('123', armBotStatusSample[0]); + // addArmBot('123', armBotStatusSample[1]); // addCurrentAction('armbot-xyz-001', 'action-001'); }, []); - useEffect(() => { - console.log('armBots: ', armBots); + // }, [armBots]); return ( <> - - ); } diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index d907f21..642762f 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -21,7 +21,7 @@ interface ArmBotStore { updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void; setArmBotActive: (modelUuid: string, isActive: boolean) => void; - + setArmBotState: (modelUuid: string, newState: ArmBotStatus['state']) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; @@ -75,7 +75,6 @@ export const useArmBotStore = create()( actionUuid: action.actionUuid, actionName: action.actionName, }; - armBot.isActive = true; } } }); @@ -86,7 +85,6 @@ export const useArmBotStore = create()( const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { armBot.currentAction = undefined; - armBot.isActive = false; } }); }, @@ -142,6 +140,15 @@ export const useArmBotStore = create()( }); }, + setArmBotState: (modelUuid, newState) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.state = newState; + } + }); + }, + incrementActiveTime: (modelUuid, incrementBy) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index ce28916..874a74c 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -1,3 +1,4 @@ + import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer';