feat: 加载STL模型
This commit is contained in:
parent
8ca84bbbad
commit
11f369452c
@ -39,6 +39,8 @@
|
||||
"socket.io-client": "^4.8.1",
|
||||
"sockjs-client": "^1.6.1",
|
||||
"splitpanes": "3.1.5",
|
||||
"three": "^0.181.2",
|
||||
"urdf-loader": "^0.12.6",
|
||||
"uuid": "^11.1.0",
|
||||
"vue": "3.4.31",
|
||||
"vue-cropper": "1.1.1",
|
||||
|
||||
660
public/models/dual_arm.urdf
Normal file
660
public/models/dual_arm.urdf
Normal file
@ -0,0 +1,660 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<robot name="dual_arm">
|
||||
<mujoco>
|
||||
<compiler
|
||||
meshdir="meshes"
|
||||
balanceinertia="true"
|
||||
discardvisual="false" />
|
||||
</mujoco>
|
||||
|
||||
|
||||
<link name="base_link">
|
||||
<visual>
|
||||
<origin xyz="0 0 0.6" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<cylinder radius="0.05" length="1.2"/>
|
||||
</geometry>
|
||||
<material name="gray">
|
||||
<color rgba="0.5 0.5 0.5 1.0"/>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision>
|
||||
<origin xyz="0 0 0.6" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<cylinder radius="0.05" length="1.2"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<inertial>
|
||||
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<mass value="25.4469"/>
|
||||
|
||||
<inertia
|
||||
ixx="3.06953"
|
||||
ixy="0.0"
|
||||
ixz="0.0"
|
||||
iyy="3.06953"
|
||||
iyz="0.0"
|
||||
izz="0.03181"/>
|
||||
</inertial>
|
||||
</link>
|
||||
|
||||
<joint name="base_fixed" type="fixed">
|
||||
<origin rpy="0 0 0" xyz="0 0 1.2"/>
|
||||
<parent link="base_link"/>
|
||||
<child link="PELVIS_S"/>
|
||||
</joint>
|
||||
|
||||
<link name="PELVIS_S">
|
||||
<inertial>
|
||||
<origin xyz="3.78529087037144E-05 3.81781425684836E-07 0.0386396273530852" rpy="0 0 0" />
|
||||
<mass value="2.10624590271277" />
|
||||
<inertia
|
||||
ixx="0.00165706865324979"
|
||||
ixy="3.13663044821662E-09"
|
||||
ixz="6.84209533216046E-07"
|
||||
iyy="0.00136736758630241"
|
||||
iyz="-1.01014607878816E-10"
|
||||
izz="0.00168295663089359" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="L_SHOULDER_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00982258725282134 0.0704593083751867 1.15261874861217E-06" rpy="0 0 0" />
|
||||
<mass value="0.880737519698403" />
|
||||
<inertia
|
||||
ixx="0.000583190308378148"
|
||||
ixy="-1.53153074560473E-05"
|
||||
ixz="6.58466471754072E-09"
|
||||
iyy="0.000445532440067177"
|
||||
iyz="6.37001404038516E-09"
|
||||
izz="0.000465648071069952" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.898039215686275 0.917647058823529 0.929411764705882 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_P" type="revolute">
|
||||
<origin xyz="0 0.0945 0.042" rpy="0 0 0" />
|
||||
<parent link="PELVIS_S" />
|
||||
<child link="L_SHOULDER_P_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="-1.57" upper="1.57" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="L_SHOULDER_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0346025282975857 0.091739327988169 -1.67085072999562E-08" rpy="0 0 0" />
|
||||
<mass value="0.594788424442483" />
|
||||
<inertia
|
||||
ixx="0.000380970396712656"
|
||||
ixy="4.80751844573946E-05"
|
||||
ixz="-1.34913746586865E-11"
|
||||
iyy="0.000320962178597474"
|
||||
iyz="-1.00039763442409E-09"
|
||||
izz="0.000414771047901155" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_R" type="revolute">
|
||||
<origin xyz="0.035 0.0765 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_P_S" />
|
||||
<child link="L_SHOULDER_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-2" upper="2" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="L_SHOULDER_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00440976862014801 0.0863620459174068 9.50748668682166E-09"
|
||||
rpy="0 0 0" />
|
||||
<mass value="0.563406026626801" />
|
||||
<inertia
|
||||
ixx="0.000327003834287552"
|
||||
ixy="-1.8057438966771E-05"
|
||||
ixz="7.28778136267901E-10"
|
||||
iyy="0.000213830709361531"
|
||||
iyz="1.49273668517817E-10"
|
||||
izz="0.000297341029639189" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_Y" type="revolute">
|
||||
<origin xyz="-0.035 0.1475 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_R_S" />
|
||||
<child link="L_SHOULDER_Y_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="-2.18" upper="0" effort="80" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="L_ELBOW_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0335624237303443 0.0603199964106564 2.99655911639718E-07" rpy="0 0 0" />
|
||||
<mass value="0.393571904406493" />
|
||||
<inertia
|
||||
ixx="0.00017277119386253"
|
||||
ixy="2.34549801867355E-05"
|
||||
ixz="-1.90560556659271E-09"
|
||||
iyy="0.000155340245267897"
|
||||
iyz="8.82493073600007E-09"
|
||||
izz="0.00018104232734159" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_ELBOW_R" type="revolute">
|
||||
<origin xyz="0.034 0.1025 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_Y_S" />
|
||||
<child link="L_ELBOW_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-2.05" upper="0" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-1.39659173115092E-10 0.0675972604744393 0.019200551565574" rpy="0 0 0" />
|
||||
<mass value="0.442332465815496" />
|
||||
<inertia
|
||||
ixx="0.000476754055455895"
|
||||
ixy="-4.61505824713347E-15"
|
||||
ixz="6.03808112272229E-18"
|
||||
iyy="0.000103466585850499"
|
||||
iyz="-4.88426705501198E-05"
|
||||
izz="0.000482956345754213" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_P" type="revolute">
|
||||
<origin xyz="-0.034 0.0965 0" rpy="0 0 0" />
|
||||
<parent link="L_ELBOW_R_S" />
|
||||
<child link="L_WRIST_P_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="0" upper="3.14" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00464135887331864 -5.06426789392833E-10 -0.0341253783666609" rpy="0 0 0" />
|
||||
<mass value="0.23573847772002" />
|
||||
<inertia
|
||||
ixx="5.10686940455785E-05"
|
||||
ixy="7.45706654358429E-16"
|
||||
ixz="6.2619568923368E-06"
|
||||
iyy="6.00636019624519E-05"
|
||||
iyz="1.27989654155383E-16"
|
||||
izz="5.32182903609189E-05" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_Y" type="revolute">
|
||||
<origin xyz="0 0.1525 0.039" rpy="0 0 0" />
|
||||
<parent link="L_WRIST_P_S" />
|
||||
<child link="L_WRIST_Y_S" />
|
||||
<axis xyz="0 0 1" />
|
||||
<limit lower="-0.78" upper="0.78" effort="50" velocity="0.79" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0161477357620243 0.0955046558857351 -0.00499392489444117" rpy="0 0 0" />
|
||||
<mass value="0.504894112043562" />
|
||||
<inertia
|
||||
ixx="0.000186833711781125"
|
||||
ixy="-3.99488705622731E-06"
|
||||
ixz="-1.51920720398336E-06"
|
||||
iyy="0.000179960980467837"
|
||||
iyz="3.6992669535716E-06"
|
||||
izz="0.000280756101568308" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_R" type="revolute">
|
||||
<origin xyz="0.0258 0 -0.039" rpy="0 0 0" />
|
||||
<parent link="L_WRIST_Y_S" />
|
||||
<child link="L_WRIST_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-1.57" upper="0.26" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="R_SHOULDER_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00982258725282141 -0.0704593093873431 -1.15069920925137E-06" rpy="0 0 0" />
|
||||
<mass value="0.880737519698404" />
|
||||
<inertia
|
||||
ixx="0.000583190308378149"
|
||||
ixy="1.53153074560471E-05"
|
||||
ixz="-6.58466471736542E-09"
|
||||
iyy="0.000445532440067178"
|
||||
iyz="6.37001403998779E-09"
|
||||
izz="0.000465648071069953" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_P" type="revolute">
|
||||
<origin xyz="0 -0.0945 0.042" rpy="0 0 0" />
|
||||
<parent link="PELVIS_S" />
|
||||
<child link="R_SHOULDER_P_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="R_SHOULDER_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0346025282975784 -0.09173932900033 1.86280643132974E-08" rpy="0 0 0" />
|
||||
<mass value="0.59478842444248" />
|
||||
<inertia
|
||||
ixx="0.000380970396712653"
|
||||
ixy="-4.80751844573946E-05"
|
||||
ixz="1.34913746041655E-11"
|
||||
iyy="0.000320962178597472"
|
||||
iyz="-1.00039763417375E-09"
|
||||
izz="0.000414771047901152" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_R" type="revolute">
|
||||
<origin xyz="0.035 -0.0765 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_P_S" />
|
||||
<child link="R_SHOULDER_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-0.78" upper="1.57" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="R_SHOULDER_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00440976862014946 -0.0863620469295699 -7.58791862676134E-09" rpy="0 0 0" />
|
||||
<mass value="0.563406026626801" />
|
||||
<inertia
|
||||
ixx="0.000327003834287551"
|
||||
ixy="1.80574389667711E-05"
|
||||
ixz="-7.28778136077729E-10"
|
||||
iyy="0.000213830709361532"
|
||||
iyz="1.49273668428957E-10"
|
||||
izz="0.000297341029639189" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
<material
|
||||
name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_Y" type="revolute">
|
||||
<origin xyz="-0.035 -0.1475 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_R_S" />
|
||||
<child link="R_SHOULDER_Y_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="80" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="R_ELBOW_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0335624237303424 -0.0603199974228191 -2.97736340082455E-07" rpy="0 0 0" />
|
||||
<mass value="0.393571904406492" />
|
||||
<inertia
|
||||
ixx="0.000172771193862529"
|
||||
ixy="-2.34549801867353E-05"
|
||||
ixz="1.90560556668771E-09"
|
||||
iyy="0.000155340245267897"
|
||||
iyz="8.82493073602971E-09"
|
||||
izz="0.00018104232734159" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_ELBOW_R" type="revolute">
|
||||
<origin xyz="0.034 -0.1025 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_Y_S" />
|
||||
<child link="R_ELBOW_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="0" upper="2.05" effort="80" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-1.39656577968772E-10 -0.0675972614865965 0.0192005515655728" rpy="0 0 0" />
|
||||
<mass value="0.442332465815497" />
|
||||
<inertia
|
||||
ixx="0.000476754055455896"
|
||||
ixy="-4.61462558956188E-15"
|
||||
ixz="-5.91762926004267E-18"
|
||||
iyy="0.0001034665858505"
|
||||
iyz="4.88426705501212E-05"
|
||||
izz="0.000482956345754214" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_P" type="revolute">
|
||||
<origin xyz="-0.034 -0.0965 0" rpy="0 0 0" />
|
||||
<parent link="R_ELBOW_R_S" />
|
||||
<child link="R_WRIST_P_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00464135887330083 -5.06426456325926E-10 -0.0341253783666614" rpy="0 0 0" />
|
||||
<mass value="0.235738477720019" />
|
||||
<inertia
|
||||
ixx="5.1068694045578E-05"
|
||||
ixy="7.45771487459288E-16"
|
||||
ixz="6.26195689233664E-06"
|
||||
iyy="6.00636019624515E-05"
|
||||
iyz="1.27828046342987E-16"
|
||||
izz="5.32182903609188E-05" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_Y" type="revolute">
|
||||
<origin xyz="0 -0.1525 0.039" rpy="0 0 0" />
|
||||
<parent link="R_WRIST_P_S" />
|
||||
<child link="R_WRIST_Y_S" />
|
||||
<axis xyz="0 0 1" />
|
||||
<limit lower="-0.78" upper="0.78" effort="50" velocity="0.79" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0201642233698132 -0.11074968386657 -0.00598955339232021" rpy="0 0 0" />
|
||||
<mass value="0.504366058218534" />
|
||||
<inertia
|
||||
ixx="0.000185559065855467"
|
||||
ixy="5.75889766751509E-06"
|
||||
ixz="2.40683898454438E-06"
|
||||
iyy="0.000131246007872084"
|
||||
iyz="1.60533277040148E-06"
|
||||
izz="0.000271800951396149" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
<material
|
||||
name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_R" type="revolute">
|
||||
<origin xyz="0.03 0 -0.039" rpy="0 0 0" />
|
||||
<parent link="R_WRIST_Y_S" />
|
||||
<child link="R_WRIST_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-0.26" upper="1.57" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="R_FINGER_TIP">
|
||||
<inertial>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<mass value="0"/>
|
||||
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.004"/>
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0 1 1 1"/> <!-- 绿色 -->
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.005"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_FINGER_TIP_FIXED" type="fixed">
|
||||
<origin xyz="0.00684256 -0.284077 0.00801525" rpy="0 0 0"/>
|
||||
<parent link="R_WRIST_R_S"/>
|
||||
<child link="R_FINGER_TIP"/>
|
||||
<axis xyz="0 0 1"/>
|
||||
</joint>
|
||||
|
||||
<link name="R_CAM">
|
||||
<inertial>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<mass value="0"/>
|
||||
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.004"/>
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0 1 0 1"/> <!-- 绿色 -->
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.005"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_CAM_FIXED" type="fixed">
|
||||
<origin xyz="-0.01212 -0.17655 0.07506" rpy="-1.5707963267 0 3.1415926535"/>
|
||||
<parent link="R_WRIST_R_S"/>
|
||||
<child link="R_CAM"/>
|
||||
<axis xyz="0 0 1"/>
|
||||
</joint>
|
||||
|
||||
</robot>
|
||||
281
public/models/left_arm.urdf
Normal file
281
public/models/left_arm.urdf
Normal file
@ -0,0 +1,281 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<robot name="left_arm">
|
||||
<mujoco>
|
||||
<compiler
|
||||
meshdir="meshes"
|
||||
balanceinertia="true"
|
||||
discardvisual="false" />
|
||||
</mujoco>
|
||||
<link name="base_link">
|
||||
<visual>
|
||||
<geometry>
|
||||
<cylinder radius="0.05" length="1.2"/>
|
||||
</geometry>
|
||||
<material name="gray">
|
||||
<color rgba="0.5 0.5 0.5 1.0"/>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision>
|
||||
<geometry>
|
||||
<cylinder radius="0.05" length="1.2"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<inertial>
|
||||
<mass value="20.0"/>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
|
||||
</inertial>
|
||||
</link>
|
||||
|
||||
<joint name="base_fixed" type="fixed">
|
||||
<origin rpy="0 0 0.0" xyz="0 0 0.6"/>
|
||||
<parent link="base_link"/>
|
||||
<child link="PELVIS_S"/>
|
||||
<axis xyz="0 0 0"/>
|
||||
</joint>
|
||||
|
||||
<link name="PELVIS_S">
|
||||
<inertial>
|
||||
<origin xyz="3.78529087037144E-05 3.81781425684836E-07 0.0386396273530852" rpy="0 0 0" />
|
||||
<mass value="2.10624590271277" />
|
||||
<inertia ixx="0.00165706865324979" ixy="3.13663044821662E-09" ixz="6.84209533216046E-07" iyy="0.00136736758630241" iyz="-1.01014607878816E-10" izz="0.00168295663089359" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_P" type="revolute">
|
||||
<origin xyz="0 0.0945 0.042" rpy="0 0 0" />
|
||||
<parent link="PELVIS_S" />
|
||||
<child link="L_SHOULDER_P_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="100" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="L_SHOULDER_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00982258725282134 0.0704593083751867 1.15261874861217E-06" rpy="0 0 0" />
|
||||
<mass value="0.880737519698403" />
|
||||
<inertia ixx="0.000583190308378148" ixy="-1.53153074560473E-05" ixz="6.58466471754072E-09" iyy="0.000445532440067177" iyz="6.37001404038516E-09" izz="0.000465648071069952" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
<material
|
||||
name="">
|
||||
<color rgba="0.898039215686275 0.917647058823529 0.929411764705882 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_R" type="revolute">
|
||||
<origin xyz="0.035 0.0765 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_P_S" />
|
||||
<child link="L_SHOULDER_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="100" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="L_SHOULDER_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0346025282975857 0.091739327988169 -1.67085072999562E-08" rpy="0 0 0" />
|
||||
<mass value="0.594788424442483" />
|
||||
<inertia ixx="0.000380970396712656" ixy="4.80751844573946E-05" ixz="-1.34913746586865E-11" iyy="0.000320962178597474" iyz="-1.00039763442409E-09" izz="0.000414771047901155" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_SHOULDER_Y" type="revolute">
|
||||
<origin xyz="-0.035 0.1475 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_R_S" />
|
||||
<child link="L_SHOULDER_Y_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="49" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="L_SHOULDER_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00440976862014801 0.0863620459174068 9.50748668682166E-09" rpy="0 0 0" />
|
||||
<mass value="0.563406026626801" />
|
||||
<inertia ixx="0.000327003834287552" ixy="-1.8057438966771E-05" ixz="7.28778136267901E-10" iyy="0.000213830709361531" iyz="1.49273668517817E-10" izz="0.000297341029639189" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_ELBOW_R" type="revolute">
|
||||
<origin xyz="0.034 0.1025 0" rpy="0 0 0" />
|
||||
<parent link="L_SHOULDER_Y_S" />
|
||||
<child link="L_ELBOW_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="49" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="L_ELBOW_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0335624237303443 0.0603199964106564 2.99655911639718E-07" rpy="0 0 0" />
|
||||
<mass value="0.393571904406493" />
|
||||
<inertia ixx="0.00017277119386253" ixy="2.34549801867355E-05" ixz="-1.90560556659271E-09" iyy="0.000155340245267897" iyz="8.82493073600007E-09" izz="0.00018104232734159" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_P" type="revolute">
|
||||
<origin xyz="-0.034 0.0965 0" rpy="0 0 0" />
|
||||
<parent link="L_ELBOW_R_S" />
|
||||
<child link="L_WRIST_P_S" />
|
||||
<axis xyz="0 1 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.19" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-1.39659173115092E-10 0.0675972604744393 0.019200551565574" rpy="0 0 0" />
|
||||
<mass value="0.442332465815496" />
|
||||
<inertia ixx="0.000476754055455895" ixy="-4.61505824713347E-15" ixz="6.03808112272229E-18" iyy="0.000103466585850499" iyz="-4.88426705501198E-05" izz="0.000482956345754213" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_Y" type="revolute">
|
||||
<origin xyz="0 0.1525 0.039" rpy="0 0 0" />
|
||||
<parent link="L_WRIST_P_S" />
|
||||
<child link="L_WRIST_Y_S" />
|
||||
<axis xyz="0 0 1" />
|
||||
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00464135887331864 -5.06426789392833E-10 -0.0341253783666609" rpy="0 0 0" />
|
||||
<mass value="0.23573847772002" />
|
||||
<inertia ixx="5.10686940455785E-05" ixy="7.45706654358429E-16" ixz="6.2619568923368E-06" iyy="6.00636019624519E-05" iyz="1.27989654155383E-16" izz="5.32182903609189E-05" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="L_WRIST_R" type="revolute">
|
||||
<origin xyz="0.0258 0 -0.039" rpy="0 0 0" />
|
||||
<parent link="L_WRIST_Y_S" />
|
||||
<child link="L_WRIST_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="L_WRIST_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0161477357620243 0.0955046558857351 -0.00499392489444117" rpy="0 0 0" />
|
||||
<mass value="0.504894112043562" />
|
||||
<inertia ixx="0.000186833711781125" ixy="-3.99488705622731E-06" ixz="-1.51920720398336E-06" iyy="0.000179960980467837" iyz="3.6992669535716E-06" izz="0.000280756101568308" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/L_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
|
||||
</robot>
|
||||
BIN
public/models/meshes/L_ELBOW_R_S.STL
Normal file
BIN
public/models/meshes/L_ELBOW_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_SHOULDER_P_S.STL
Normal file
BIN
public/models/meshes/L_SHOULDER_P_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_SHOULDER_R_S.STL
Normal file
BIN
public/models/meshes/L_SHOULDER_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_SHOULDER_Y_S.STL
Normal file
BIN
public/models/meshes/L_SHOULDER_Y_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_WRIST_P_S.STL
Normal file
BIN
public/models/meshes/L_WRIST_P_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_WRIST_R_S.STL
Normal file
BIN
public/models/meshes/L_WRIST_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/L_WRIST_Y_S.STL
Normal file
BIN
public/models/meshes/L_WRIST_Y_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/NECK_P_S.STL
Normal file
BIN
public/models/meshes/NECK_P_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/NECK_R_S.STL
Normal file
BIN
public/models/meshes/NECK_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/NECK_Y_S.STL
Normal file
BIN
public/models/meshes/NECK_Y_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/PELVIS_S.STL
Normal file
BIN
public/models/meshes/PELVIS_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_ELBOW_R_S.STL
Normal file
BIN
public/models/meshes/R_ELBOW_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_SHOULDER_P_S.STL
Normal file
BIN
public/models/meshes/R_SHOULDER_P_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_SHOULDER_R_S.STL
Normal file
BIN
public/models/meshes/R_SHOULDER_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_SHOULDER_Y_S.STL
Normal file
BIN
public/models/meshes/R_SHOULDER_Y_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_WRIST_P_S.STL
Normal file
BIN
public/models/meshes/R_WRIST_P_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_WRIST_R_S.STL
Normal file
BIN
public/models/meshes/R_WRIST_R_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/R_WRIST_Y_S.STL
Normal file
BIN
public/models/meshes/R_WRIST_Y_S.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/base_link.STL
Normal file
BIN
public/models/meshes/base_link.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/index_force_sensor_1.STL
Normal file
BIN
public/models/meshes/index_force_sensor_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/index_force_sensor_2.STL
Normal file
BIN
public/models/meshes/index_force_sensor_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/index_force_sensor_3.STL
Normal file
BIN
public/models/meshes/index_force_sensor_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/little_force_sensor_1.STL
Normal file
BIN
public/models/meshes/little_force_sensor_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/little_force_sensor_2.STL
Normal file
BIN
public/models/meshes/little_force_sensor_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/little_force_sensor_3.STL
Normal file
BIN
public/models/meshes/little_force_sensor_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/middle_force_sensor_1.STL
Normal file
BIN
public/models/meshes/middle_force_sensor_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/middle_force_sensor_2.STL
Normal file
BIN
public/models/meshes/middle_force_sensor_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/middle_force_sensor_3.STL
Normal file
BIN
public/models/meshes/middle_force_sensor_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/palm_force_sensor.STL
Normal file
BIN
public/models/meshes/palm_force_sensor.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_index_1.STL
Normal file
BIN
public/models/meshes/right_index_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_index_2.STL
Normal file
BIN
public/models/meshes/right_index_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_little_1.STL
Normal file
BIN
public/models/meshes/right_little_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_little_2.STL
Normal file
BIN
public/models/meshes/right_little_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_middle_1.STL
Normal file
BIN
public/models/meshes/right_middle_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_middle_2.STL
Normal file
BIN
public/models/meshes/right_middle_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_ring_1.STL
Normal file
BIN
public/models/meshes/right_ring_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_ring_2.STL
Normal file
BIN
public/models/meshes/right_ring_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_thumb_1.STL
Normal file
BIN
public/models/meshes/right_thumb_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_thumb_2.STL
Normal file
BIN
public/models/meshes/right_thumb_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_thumb_3.STL
Normal file
BIN
public/models/meshes/right_thumb_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/right_thumb_4.STL
Normal file
BIN
public/models/meshes/right_thumb_4.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/ring_force_sensor_1.STL
Normal file
BIN
public/models/meshes/ring_force_sensor_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/ring_force_sensor_2.STL
Normal file
BIN
public/models/meshes/ring_force_sensor_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/ring_force_sensor_3.STL
Normal file
BIN
public/models/meshes/ring_force_sensor_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/thumb_force_sensor_1.STL
Normal file
BIN
public/models/meshes/thumb_force_sensor_1.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/thumb_force_sensor_2.STL
Normal file
BIN
public/models/meshes/thumb_force_sensor_2.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/thumb_force_sensor_3.STL
Normal file
BIN
public/models/meshes/thumb_force_sensor_3.STL
Normal file
Binary file not shown.
BIN
public/models/meshes/thumb_force_sensor_4.STL
Normal file
BIN
public/models/meshes/thumb_force_sensor_4.STL
Normal file
Binary file not shown.
322
public/models/right_arm.urdf
Normal file
322
public/models/right_arm.urdf
Normal file
@ -0,0 +1,322 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<robot name="right_arm">
|
||||
<mujoco>
|
||||
<compiler
|
||||
meshdir="meshes"
|
||||
balanceinertia="true"
|
||||
discardvisual="false" />
|
||||
</mujoco>
|
||||
<link name="PELVIS_S">
|
||||
<inertial>
|
||||
<origin xyz="3.78529e-05 3.81781e-07 0.0386396" rpy="0 0 0"/>
|
||||
<mass value="2.10624590271277"/>
|
||||
<inertia
|
||||
ixx="0.00165706865324979" ixy="3.13663e-09" ixz="6.84210e-07"
|
||||
iyy="0.00136736758630241" iyz="-1.01015e-10" izz="0.00168295663089359"/>
|
||||
</inertial>
|
||||
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL"/>
|
||||
</geometry>
|
||||
<material name="light_gray">
|
||||
<color rgba="0.698 0.698 0.698 1"/>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<mesh filename="meshes/PELVIS_S.STL"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="R_SHOULDER_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00982258725282141 -0.0704593093873431 -1.15069920925137E-06" rpy="0 0 0" />
|
||||
<mass value="0.880737519698404" />
|
||||
<inertia
|
||||
ixx="0.000583190308378149"
|
||||
ixy="1.53153074560471E-05"
|
||||
ixz="-6.58466471736542E-09"
|
||||
iyy="0.000445532440067178"
|
||||
iyz="6.37001403998779E-09"
|
||||
izz="0.000465648071069953" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin
|
||||
xyz="0 0 0"
|
||||
rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_P" type="revolute">
|
||||
<origin xyz="0 -0.0945 0.042" rpy="0 0 0" />
|
||||
<parent link="PELVIS_S" />
|
||||
<child link="R_SHOULDER_P_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="-1.57" upper="1.57" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="R_SHOULDER_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0346025282975784 -0.09173932900033 1.86280643132974E-08" rpy="0 0 0" />
|
||||
<mass value="0.59478842444248" />
|
||||
<inertia
|
||||
ixx="0.000380970396712653" ixy="-4.80751844573946E-05" ixz="1.34913746041655E-11"
|
||||
iyy="0.000320962178597472" iyz="-1.00039763417375E-09" izz="0.000414771047901152" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_R" type="revolute">
|
||||
<origin xyz="0.035 -0.0765 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_P_S" />
|
||||
<child link="R_SHOULDER_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-2" upper="2" effort="120" velocity="3.351" />
|
||||
</joint>
|
||||
|
||||
<link name="R_SHOULDER_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00440976862014946 -0.0863620469295699 -7.58791862676134E-09" rpy="0 0 0" />
|
||||
<mass value="0.563406026626801" />
|
||||
<inertia
|
||||
ixx="0.000327003834287551"
|
||||
ixy="1.80574389667711E-05"
|
||||
ixz="-7.28778136077729E-10"
|
||||
iyy="0.000213830709361532"
|
||||
iyz="1.49273668428957E-10"
|
||||
izz="0.000297341029639189" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_SHOULDER_Y" type="revolute">
|
||||
<origin xyz="-0.035 -0.1475 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_R_S" />
|
||||
<child link="R_SHOULDER_Y_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="0" upper="3.14" effort="80" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="R_ELBOW_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0335624237303424 -0.0603199974228191 -2.97736340082455E-07" rpy="0 0 0" />
|
||||
<mass value="0.393571904406492" />
|
||||
<inertia
|
||||
ixx="0.000172771193862529"
|
||||
ixy="-2.34549801867353E-05"
|
||||
ixz="1.90560556668771E-09"
|
||||
iyy="0.000155340245267897"
|
||||
iyz="8.82493073602971E-09"
|
||||
izz="0.00018104232734159" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_ELBOW_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_ELBOW_R" type="revolute">
|
||||
<origin xyz="0.034 -0.1025 0" rpy="0 0 0" />
|
||||
<parent link="R_SHOULDER_Y_S" />
|
||||
<child link="R_ELBOW_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="0" upper="2.18" effort="80" velocity="3.8758" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_P_S">
|
||||
<inertial>
|
||||
<origin xyz="-1.39656577968772E-10 -0.0675972614865965 0.0192005515655728" rpy="0 0 0" />
|
||||
<mass value="0.442332465815497" />
|
||||
<inertia
|
||||
ixx="0.000476754055455896"
|
||||
ixy="-4.61462558956188E-15"
|
||||
ixz="-5.91762926004267E-18"
|
||||
iyy="0.0001034665858505"
|
||||
iyz="4.88426705501212E-05"
|
||||
izz="0.000482956345754214" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_P_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_P" type="revolute">
|
||||
<origin xyz="-0.034 -0.0965 0" rpy="0 0 0" />
|
||||
<parent link="R_ELBOW_R_S" />
|
||||
<child link="R_WRIST_P_S" />
|
||||
<axis xyz="0 -1 0" />
|
||||
<limit lower="-3.14" upper="0" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_Y_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.00464135887330083 -5.06426456325926E-10 -0.0341253783666614" rpy="0 0 0" />
|
||||
<mass value="0.235738477720019" />
|
||||
<inertia
|
||||
ixx="5.1068694045578E-05"
|
||||
ixy="7.45771487459288E-16"
|
||||
ixz="6.26195689233664E-06"
|
||||
iyy="6.00636019624515E-05"
|
||||
iyz="1.27828046342987E-16"
|
||||
izz="5.32182903609188E-05" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_Y_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_Y" type="revolute">
|
||||
<origin xyz="0 -0.1525 0.039" rpy="0 0 0" />
|
||||
<parent link="R_WRIST_P_S" />
|
||||
<child link="R_WRIST_Y_S" />
|
||||
<axis xyz="0 0 1" />
|
||||
<limit lower="0" upper="0.78" effort="50" velocity="0.79" />
|
||||
</joint>
|
||||
|
||||
<link name="R_WRIST_R_S">
|
||||
<inertial>
|
||||
<origin xyz="-0.0201642233698132 -0.11074968386657 -0.00598955339232021" rpy="0 0 0" />
|
||||
<mass value="0.204366058218534" />
|
||||
<inertia
|
||||
ixx="0.000185559065855467"
|
||||
ixy="5.75889766751509E-06"
|
||||
ixz="2.40683898454438E-06"
|
||||
iyy="0.000131246007872084"
|
||||
iyz="1.60533277040148E-06"
|
||||
izz="0.000271800951396149" />
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="meshes/R_WRIST_R_S.STL" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_WRIST_R" type="revolute">
|
||||
<origin xyz="0.03 0 -0.039" rpy="0 0 0" />
|
||||
<parent link="R_WRIST_Y_S" />
|
||||
<child link="R_WRIST_R_S" />
|
||||
<axis xyz="1 0 0" />
|
||||
<limit lower="-0.26" upper="1.57" effort="50" velocity="4.71" />
|
||||
</joint>
|
||||
|
||||
<link name="R_FINGER_TIP">
|
||||
<inertial>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<mass value="0"/>
|
||||
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
|
||||
</inertial>
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.002"/>
|
||||
</geometry>
|
||||
<material name="">
|
||||
<color rgba="0 1 0 1"/> <!-- 绿色 -->
|
||||
</material>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
||||
<geometry>
|
||||
<sphere radius="0.005"/>
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<joint name="R_FINGER_TIP_FIXED" type="fixed">
|
||||
<origin xyz="-0.01212 -0.17655 0.07506" rpy="3.14159 0 -1.5708"/>
|
||||
<parent link="R_WRIST_R_S"/>
|
||||
<child link="R_FINGER_TIP"/>
|
||||
</joint>
|
||||
</robot>
|
||||
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="joint-control" v-for="joint in jointList" :key="joint.name">
|
||||
<div class="joint-header">
|
||||
<span class="joint-name">{{ joint.displayName }}</span>
|
||||
<span class="joint-type">{{ joint.type.toUpperCase() }}</span>
|
||||
</div>
|
||||
|
||||
<div class="joint-info">
|
||||
<span class="angle-display">{{ formatAngle(joint.value) }}</span>
|
||||
<span class="limits">[{{ formatAngle(joint.min) }}, {{ formatAngle(joint.max) }}]</span>
|
||||
</div>
|
||||
|
||||
<div class="slider-container">
|
||||
<el-slider size="small" v-model="joint.value" :min="joint.min" :max="joint.max" :step="joint.step" @input="(value) => updateJointAngle(joint.name, value)"/>
|
||||
<div class="slider-labels">
|
||||
<span>{{ formatAngle(joint.min) }}</span>
|
||||
<span>{{ formatAngle(joint.max) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
jointList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['updateJointAngle'])
|
||||
|
||||
const updateJointAngle = (name, value) => {
|
||||
emits('updateJointAngle', { name, value })
|
||||
}
|
||||
|
||||
/**
|
||||
* 角度格式化
|
||||
*/
|
||||
const formatAngle = (radians) => {
|
||||
const degrees = (radians * 180 / Math.PI).toFixed(1)
|
||||
return `${degrees}°`
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.joint-control {
|
||||
border-radius: 6px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #cfcfcf;
|
||||
|
||||
.joint-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.joint-name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.joint-type {
|
||||
font-size: 11px;
|
||||
background: rgba(52, 152, 219, 0.3);
|
||||
color: #3498db;
|
||||
padding: 3px 8px;
|
||||
border-radius: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.joint-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
font-size: 13px;
|
||||
|
||||
.angle-display {
|
||||
color: #f1c40f;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.limits {
|
||||
color: #95a5a6;
|
||||
font-size: 11px;
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-container {
|
||||
padding: 0 5px;
|
||||
|
||||
.joint-slider {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
-webkit-appearance: none;
|
||||
background: #34495e;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: #ecf0f1;
|
||||
cursor: pointer;
|
||||
border: 2px solid #3498db;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
color: #7f8c8d;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,394 @@
|
||||
<template>
|
||||
<!-- 模板部分保持不变 -->
|
||||
<div class="urdf-viewer-container">
|
||||
|
||||
<div ref="viewerContainer" class="urdf-viewer"></div>
|
||||
|
||||
<div v-if="isLoading" class="loading-overlay">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>正在解析URDF并加载模型...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, watch, reactive, computed } from 'vue'
|
||||
import * as THREE from 'three'
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
||||
import URDFLoader from 'urdf-loader'
|
||||
|
||||
const props = defineProps({
|
||||
basePath: { type: String, required: true },
|
||||
urdfPath: { type: String, required: true },
|
||||
modelColor: { type: String, default: '#cbcbcb' },
|
||||
showJointLimits: { type: Boolean, default: true }
|
||||
})
|
||||
|
||||
const emits = defineEmits(['computedChange'])
|
||||
|
||||
const viewerContainer = ref(null)
|
||||
const isLoading = ref(false)
|
||||
|
||||
// Three.js 核心对象
|
||||
let scene = null
|
||||
let camera = null
|
||||
let renderer = null
|
||||
let controls = null
|
||||
let robot = null
|
||||
|
||||
// 关节控制相关状态
|
||||
const jointControls = reactive([])
|
||||
const availableJoints = ref({})
|
||||
|
||||
/**
|
||||
* 从URDF XML中提取关节信息(使用浏览器原生DOMParser)
|
||||
*/
|
||||
const extractJointInfoFromURDF = (urdfXml) => {
|
||||
try {
|
||||
const joints = []
|
||||
const parser = new DOMParser()
|
||||
const xmlDoc = parser.parseFromString(urdfXml, 'text/xml')
|
||||
|
||||
// 检查解析错误
|
||||
const parseError = xmlDoc.getElementsByTagName('parsererror')
|
||||
if (parseError.length > 0) {
|
||||
throw new Error('XML解析错误: ' + parseError[0].textContent)
|
||||
}
|
||||
|
||||
// 获取所有joint元素
|
||||
const jointElements = xmlDoc.getElementsByTagName('joint')
|
||||
|
||||
for (let i = 0; i < jointElements.length; i++) {
|
||||
const jointElement = jointElements[i]
|
||||
const name = jointElement.getAttribute('name')
|
||||
const type = jointElement.getAttribute('type')
|
||||
|
||||
// 只处理可动关节
|
||||
if (type && ['revolute', 'continuous', 'prismatic'].includes(type)) {
|
||||
const jointInfo = {
|
||||
name: name,
|
||||
displayName: name.replace(/_/g, ' '),
|
||||
type: type,
|
||||
value: 0,
|
||||
step: 0.01
|
||||
}
|
||||
|
||||
// 提取关节限制
|
||||
const limitElements = jointElement.getElementsByTagName('limit')
|
||||
if (limitElements.length > 0) {
|
||||
const limit = limitElements[0]
|
||||
const lower = limit.getAttribute('lower')
|
||||
const upper = limit.getAttribute('upper')
|
||||
const effort = limit.getAttribute('effort')
|
||||
const velocity = limit.getAttribute('velocity')
|
||||
|
||||
// 处理旋转关节
|
||||
if (type === 'revolute' || type === 'continuous') {
|
||||
jointInfo.min = lower !== null ? parseFloat(lower) :
|
||||
(type === 'revolute' ? -Math.PI : -Math.PI)
|
||||
jointInfo.max = upper !== null ? parseFloat(upper) :
|
||||
(type === 'revolute' ? Math.PI : Math.PI)
|
||||
}
|
||||
// 处理平移关节
|
||||
else if (type === 'prismatic') {
|
||||
jointInfo.min = lower !== null ? parseFloat(lower) : -1.0
|
||||
jointInfo.max = upper !== null ? parseFloat(upper) : 1.0
|
||||
jointInfo.step = 0.001
|
||||
}
|
||||
|
||||
if (effort) jointInfo.maxEffort = parseFloat(effort)
|
||||
if (velocity) jointInfo.maxVelocity = parseFloat(velocity)
|
||||
} else {
|
||||
// 如果没有限制,设置默认范围
|
||||
if (type === 'continuous') {
|
||||
jointInfo.min = -Math.PI
|
||||
jointInfo.max = Math.PI
|
||||
} else if (type === 'revolute') {
|
||||
jointInfo.min = -Math.PI / 2
|
||||
jointInfo.max = Math.PI / 2
|
||||
} else if (type === 'prismatic') {
|
||||
jointInfo.min = -0.5
|
||||
jointInfo.max = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// 提取关节轴
|
||||
const axisElements = jointElement.getElementsByTagName('axis')
|
||||
if (axisElements.length > 0) {
|
||||
const axis = axisElements[0].getAttribute('xyz')
|
||||
if (axis) {
|
||||
const axisValues = axis.split(' ').map(Number)
|
||||
jointInfo.axis = new THREE.Vector3(...axisValues)
|
||||
}
|
||||
}
|
||||
|
||||
// 提取关节原点
|
||||
const originElements = jointElement.getElementsByTagName('origin')
|
||||
if (originElements.length > 0) {
|
||||
const origin = originElements[0]
|
||||
const xyz = origin.getAttribute('xyz')
|
||||
const rpy = origin.getAttribute('rpy')
|
||||
|
||||
if (xyz) jointInfo.origin = xyz.split(' ').map(Number)
|
||||
if (rpy) jointInfo.orientation = rpy.split(' ').map(Number)
|
||||
}
|
||||
|
||||
joints.push(jointInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// 按关节名称排序
|
||||
joints.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
console.log('从URDF提取的关节信息:', joints)
|
||||
return joints
|
||||
|
||||
} catch (error) {
|
||||
console.error('解析URDF失败:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Three.js场景
|
||||
*/
|
||||
const initScene = () => {
|
||||
const container = viewerContainer.value
|
||||
|
||||
scene = new THREE.Scene()
|
||||
scene.background = new THREE.Color(0xf0f0f0)
|
||||
|
||||
camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
container.clientWidth / container.clientHeight,
|
||||
0.01,
|
||||
1000
|
||||
)
|
||||
camera.position.set(2, 2, 3)
|
||||
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true })
|
||||
renderer.setSize(container.clientWidth, container.clientHeight)
|
||||
container.appendChild(renderer.domElement)
|
||||
|
||||
// 光源
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6)
|
||||
scene.add(ambientLight)
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
|
||||
directionalLight.position.set(10, 20, 10)
|
||||
scene.add(directionalLight)
|
||||
|
||||
controls = new OrbitControls(camera, renderer.domElement)
|
||||
controls.enableDamping = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载URDF机器人模型
|
||||
*/
|
||||
const loadRobot = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
try {
|
||||
// 清除现有模型
|
||||
if (robot) {
|
||||
scene.remove(robot)
|
||||
jointControls.length = 0
|
||||
availableJoints.value = {}
|
||||
}
|
||||
|
||||
// 1. 加载URDF文件内容
|
||||
const urdfUrl = `${props.basePath}${props.urdfPath}`
|
||||
const response = await fetch(urdfUrl)
|
||||
const urdfXml = await response.text()
|
||||
|
||||
// 2. 解析URDF提取关节信息(同步调用)
|
||||
const extractedJoints = extractJointInfoFromURDF(urdfXml)
|
||||
|
||||
// 3. 使用URDFLoader加载模型
|
||||
const manager = new THREE.LoadingManager()
|
||||
const loader = new URDFLoader(manager)
|
||||
|
||||
loader.packages = { '': props.basePath }
|
||||
|
||||
robot = await new Promise((resolve, reject) => {
|
||||
loader.load(urdfUrl, resolve, undefined, reject)
|
||||
})
|
||||
|
||||
// 4. 坐标轴修正
|
||||
robot.rotation.x = -Math.PI / 2
|
||||
robot.rotation.z = -Math.PI / 2
|
||||
robot.updateMatrixWorld(true)
|
||||
|
||||
// 应用颜色
|
||||
robot.traverse((child) => {
|
||||
if (child.isMesh && child.material) {
|
||||
child.material.color.set(props.modelColor)
|
||||
}
|
||||
})
|
||||
|
||||
scene.add(robot)
|
||||
|
||||
// 5. 初始化关节控制系统
|
||||
availableJoints.value = robot.joints
|
||||
|
||||
// 将提取的关节信息与加载的关节匹配
|
||||
extractedJoints.forEach(jointInfo => {
|
||||
if (availableJoints.value[jointInfo.name]) {
|
||||
// 获取当前关节值
|
||||
const currentValue = availableJoints.value[jointInfo.name].jointValue || 0
|
||||
|
||||
// 确保初始值在限制范围内
|
||||
let initialValue = currentValue
|
||||
if (props.showJointLimits) {
|
||||
initialValue = Math.max(jointInfo.min, Math.min(jointInfo.max, currentValue))
|
||||
}
|
||||
|
||||
// 添加到控制列表
|
||||
jointControls.push({
|
||||
...jointInfo,
|
||||
value: initialValue
|
||||
})
|
||||
|
||||
// 设置初始关节位置
|
||||
availableJoints.value[jointInfo.name].setJointValue(initialValue)
|
||||
} else {
|
||||
console.warn(`关节 ${jointInfo.name} 在URDF模型中不存在或不可控`)
|
||||
}
|
||||
})
|
||||
|
||||
fitCameraToObject(robot)
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载URDF模型失败:', error)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新关节角度
|
||||
*/
|
||||
const updateJointAngle = (jointName, angle) => {
|
||||
if (availableJoints.value[jointName]) {
|
||||
try {
|
||||
// 应用限制(如果启用)
|
||||
let clampedAngle = angle
|
||||
if (props.showJointLimits) {
|
||||
const jointInfo = jointControls.find(j => j.name === jointName)
|
||||
if (jointInfo) {
|
||||
clampedAngle = Math.max(jointInfo.min, Math.min(jointInfo.max, angle))
|
||||
}
|
||||
}
|
||||
|
||||
// 应用关节角度
|
||||
availableJoints.value[jointName].setJointValue(clampedAngle)
|
||||
|
||||
// 更新UI中的值
|
||||
const jointControl = jointControls.find(j => j.name === jointName)
|
||||
if (jointControl) {
|
||||
jointControl.value = clampedAngle
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`设置关节 ${jointName} 角度失败:`, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整相机视角
|
||||
*/
|
||||
const fitCameraToObject = (object) => {
|
||||
const boundingBox = new THREE.Box3().setFromObject(object)
|
||||
const center = boundingBox.getCenter(new THREE.Vector3())
|
||||
const size = boundingBox.getSize(new THREE.Vector3())
|
||||
|
||||
const maxSize = Math.max(size.x, size.y, size.z)
|
||||
const fitHeightDistance = maxSize / (2 * Math.atan((Math.PI * camera.fov) / 360))
|
||||
const fitWidthDistance = fitHeightDistance / camera.aspect
|
||||
const distance = 1.5 * Math.max(fitHeightDistance, fitWidthDistance)
|
||||
|
||||
const direction = new THREE.Vector3(0, 1, 1).normalize()
|
||||
controls.target.copy(center)
|
||||
camera.position.copy(center).add(direction.multiplyScalar(distance))
|
||||
controls.update()
|
||||
}
|
||||
|
||||
/**
|
||||
* 动画循环
|
||||
*/
|
||||
const animate = () => {
|
||||
requestAnimationFrame(animate)
|
||||
controls.update()
|
||||
renderer.render(scene, camera)
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口大小变化处理
|
||||
*/
|
||||
const onWindowResize = () => {
|
||||
const container = viewerContainer.value
|
||||
camera.aspect = container.clientWidth / container.clientHeight
|
||||
camera.updateProjectionMatrix()
|
||||
renderer.setSize(container.clientWidth, container.clientHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
const dispose = () => {
|
||||
window.removeEventListener('resize', onWindowResize)
|
||||
controls?.dispose()
|
||||
renderer?.dispose()
|
||||
}
|
||||
|
||||
// 监听属性变化
|
||||
watch(
|
||||
() => [props.basePath, props.urdfPath],
|
||||
() => {
|
||||
loadRobot()
|
||||
}
|
||||
)
|
||||
|
||||
watch(jointControls, (newVal) => {
|
||||
emits('computedChange', newVal)
|
||||
})
|
||||
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
initScene()
|
||||
loadRobot()
|
||||
window.addEventListener('resize', onWindowResize)
|
||||
animate()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
dispose()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
updateJointAngle
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 样式部分保持不变 */
|
||||
.urdf-viewer-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.urdf-viewer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.loading-overlay p {
|
||||
font-size: 16px;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
</style>
|
||||
@ -1,565 +0,0 @@
|
||||
<script setup>
|
||||
import {useRoute} from "vue-router"
|
||||
import dayjs from "dayjs";
|
||||
import {deviceTeach, deviceUpdateProfile} from "@/api/device/register.js";
|
||||
import {formatNumber} from "@/views/device/register/components/index.js";
|
||||
import {convertNumbersToStringAndRemoveNulls} from "@/utils/fn.js";
|
||||
|
||||
const data = reactive({
|
||||
form: {
|
||||
workModule: 1,//工作模式
|
||||
posStep: 1,//位置步进
|
||||
postureStep: 1,//姿态步进
|
||||
jointStep: 1,//关节步进
|
||||
joint1: 0.000012,//关节1
|
||||
joint2: 0.000012,//
|
||||
joint3: 0.000012,//
|
||||
joint4: 0.000012,//
|
||||
joint5: 0.000012,//
|
||||
joint6: 0.000012,//关节6
|
||||
x: 11,//
|
||||
y: 11,//
|
||||
z: 11,//
|
||||
rx: 11,//
|
||||
ry: 11,//
|
||||
rz: 11,//
|
||||
arm: 1,//目标
|
||||
coordinate: 1,//坐标系
|
||||
},
|
||||
speed: 20,//速度
|
||||
zeroPos: {//零位姿态
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
rz: 0,
|
||||
},
|
||||
initPos: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1,
|
||||
rx: 1,
|
||||
ry: 1,
|
||||
rz: 1,
|
||||
},//初始姿态
|
||||
armList: [
|
||||
{
|
||||
label: '机械臂1',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '机械臂2',
|
||||
value: 2
|
||||
}
|
||||
],
|
||||
coordinateList: [
|
||||
{
|
||||
label: 'x轴',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: 'y轴',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: 'z轴',
|
||||
value: 3
|
||||
}
|
||||
],
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
})
|
||||
|
||||
const {
|
||||
form, time,
|
||||
zeroPos,
|
||||
initPos,
|
||||
armList,
|
||||
coordinateList
|
||||
} = toRefs(data)
|
||||
|
||||
const route = useRoute()
|
||||
let timer = null
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(timer)
|
||||
})
|
||||
|
||||
//获取机械臂参数
|
||||
const getDeviceInfo = () => {
|
||||
deviceTeach(devId.value).then((res) => {
|
||||
let data = formatNumber(res.data)//字符类型转数字类型
|
||||
Object.assign(form.value, data)
|
||||
//设置初始位置
|
||||
initPos.value.x = data.x
|
||||
initPos.value.y = data.y
|
||||
initPos.value.z = data.z
|
||||
initPos.value.rx = data.rx
|
||||
initPos.value.ry = data.ry
|
||||
initPos.value.rz = data.rz
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDeviceInfo()
|
||||
const posControls = document.querySelectorAll(".btn")
|
||||
//监听按钮点击事件
|
||||
posControls.forEach((item) => {
|
||||
item.addEventListener('click', (e) => {
|
||||
const target = e.currentTarget.classList[1]
|
||||
const vals = target.split("_")//x_0 rx_0
|
||||
const pos = vals[0]
|
||||
const calc = !!Number(vals[1])
|
||||
if (calc) {
|
||||
form.value[pos] += 0.01 * data.speed
|
||||
} else {
|
||||
form.value[pos] -= 0.01 * data.speed
|
||||
}
|
||||
})
|
||||
})
|
||||
//监听失焦事件
|
||||
// const warp = document.querySelector(".mechanical-arm")
|
||||
// warp.addEventListener('focusout', handleFocus, false)
|
||||
|
||||
timer = setInterval(() => {
|
||||
time.value = dayjs().format("YYYY-MM-DD HH:mm:ss")
|
||||
getDeviceInfo()
|
||||
}, 1000)
|
||||
})
|
||||
watch(() => JSON.parse(JSON.stringify(form.value)), (newData, oldData) => {
|
||||
// const change = findDifferences(oldData, newData)
|
||||
const data = convertNumbersToStringAndRemoveNulls(newData)
|
||||
deviceUpdateProfile({idDeDeviceRegistration: devId.value, ...data}).then((res)=>{
|
||||
console.log(res)
|
||||
})
|
||||
})
|
||||
|
||||
const handleFocus = (e) => {
|
||||
const type = e.target.type
|
||||
if (type === "number") {
|
||||
// console.log("数字框失焦")
|
||||
}
|
||||
}
|
||||
|
||||
const devId = computed(() => {
|
||||
return route.path.split("/")[2]
|
||||
})
|
||||
const deviceModel = computed(() => {
|
||||
return route.path.split("/")[1]
|
||||
})
|
||||
|
||||
const handleResets = (type) => {
|
||||
if (type === "zero") {
|
||||
Object.assign(form.value, zeroPos.value)
|
||||
return
|
||||
}
|
||||
if (type === "init") {
|
||||
Object.assign(form.value, initPos.value)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mechanical-arm">
|
||||
<div class="top flex between">
|
||||
<div class="left " style="width: 38%">
|
||||
<div class="card" style="height: 100%">
|
||||
<div class="title">机械臂</div>
|
||||
<div class="body">机械臂图片</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center" style="width: 22%">
|
||||
<div class="card">
|
||||
<div class="title">工作模式</div>
|
||||
<div class="body">
|
||||
<el-radio-group v-model="form.workModule">
|
||||
<el-radio :value="1">真实机械臂</el-radio>
|
||||
<el-radio :value="2">仿真机械臂</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="margin-top: 10px">
|
||||
<div class="title">步进模式</div>
|
||||
<div class="mb10">
|
||||
<div class="mb5 action-label">位置步进( mm )</div>
|
||||
<el-input-number style="width: 100%;" v-model="form.posStep" :step="2"/>
|
||||
</div>
|
||||
|
||||
<div class="mb10">
|
||||
<div class="mb5 action-label">姿态步进( deg )</div>
|
||||
<el-input-number style="width: 100%;" v-model="form.postureStep" :step="2"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb5 action-label">关节步进( deg )</div>
|
||||
<el-input-number style="width: 100%;" v-model="form.jointStep" :step="2"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right " style="width: 38%">
|
||||
<div class="card" style="height: 100%">
|
||||
<div class="title">位置控制</div>
|
||||
<div class="body">
|
||||
<div class="btn-wrap pos-control" style="transform: rotateX(40deg);height: calc(100% - 70px)">
|
||||
<div class="btn z_0">
|
||||
<span>Z-</span>
|
||||
<svg t="1747126605366" class="turn-bottom" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn x_0">
|
||||
<span> X-</span>
|
||||
<svg t="1747126605366" class="turn-up" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn z_1">
|
||||
<span>Z+</span>
|
||||
<svg t="1747126605366" class="turn-up" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn y_0">
|
||||
<span>Y-</span>
|
||||
<svg t="1747126605366" class="turn-left" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
<div class="btn y_1">
|
||||
<span>Y+</span>
|
||||
<svg t="1747126605366" class="turn-right" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
<div class="btn x_1">
|
||||
<span>X+</span>
|
||||
<svg t="1747126605366" class="turn-bottom" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb10 action-label">参考坐标系</div>
|
||||
<el-select
|
||||
|
||||
v-model="form.coordinate"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in coordinateList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom flex between">
|
||||
<div class="left " style="width: 30%">
|
||||
<div class="card" style="height: 100%">
|
||||
<div class="title">机械臂位置姿态</div>
|
||||
<div class="body">
|
||||
<div class="flex mb10">
|
||||
<div class="left flex1">
|
||||
<div class="pos-title mb10">位置 ( m )</div>
|
||||
<div class="mb10"> X: {{ form.x.toFixed(6) }}</div>
|
||||
<div class="mb10"> Y: {{ form.y.toFixed(6) }}</div>
|
||||
<div class="mb10"> Z: {{ form.z.toFixed(6) }}</div>
|
||||
</div>
|
||||
<div class="right flex1">
|
||||
<div class="pos-title mb10">姿态 ( deg )</div>
|
||||
<div class="mb10"> RX: {{ form.rx.toFixed(6) }}</div>
|
||||
<div class="mb10"> RY: {{ form.ry.toFixed(6) }}</div>
|
||||
<div class="mb10"> RZ: {{ form.rz.toFixed(6) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb10 action-label">目标</div>
|
||||
<el-select
|
||||
v-model="form.arm"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in armList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center " style="width: 30%">
|
||||
<div class="card" style="height: 100%">
|
||||
<div class="title">关节控制单位( deg )</div>
|
||||
<div class="body">
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节1</div>
|
||||
<el-input-number v-model="form.joint1" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节2</div>
|
||||
<el-input-number v-model="form.joint2" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节3</div>
|
||||
<el-input-number v-model="form.joint3" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节4</div>
|
||||
<el-input-number v-model="form.joint4" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节5</div>
|
||||
<el-input-number v-model="form.joint5" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
<div class="mb10 action-label-pos">
|
||||
<div class="action-label">关节6</div>
|
||||
<el-input-number v-model="form.joint6" :step="0.000001" :precision="6"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right " style="width: 38%">
|
||||
<div class="card" style="height: 100%">
|
||||
<div class="title">姿态控制</div>
|
||||
<div class="body">
|
||||
<div class="btn-wrap">
|
||||
<div class="btn rz_0 c">
|
||||
<span>Z-</span>
|
||||
<svg t="1747126605366" class="turn-lb" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn rx_0 c">
|
||||
<span>X-</span>
|
||||
<svg t="1747126605366" class="turn-up" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn rz_1 c">
|
||||
<span>Z+</span>
|
||||
<svg t="1747126605366" class="turn-rb" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn ry_0 c">
|
||||
<span> Y-</span>
|
||||
<svg t="1747126605366" class="turn-left" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
<div class="btn ry_1 c">
|
||||
<span>Y+</span>
|
||||
<svg t="1747126605366" class="turn-right" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
<div class="btn rx_1 c">
|
||||
<span> X+</span>
|
||||
<svg t="1747126605366" class="turn-bottom" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="1461" width="32" height="32">
|
||||
<path
|
||||
d="M311.432533 448.170667H163.84L510.293333 3.413333 856.746667 448.170667h-147.592534L760.832 1006.933333H259.754667z"
|
||||
fill="#4076ff" p-id="1462"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions flex align-center between">
|
||||
<div class="left">
|
||||
<el-button @click="handleResets('zero')">零位姿态</el-button>
|
||||
<el-button @click="handleResets('init')">初始位姿</el-button>
|
||||
</div>
|
||||
<div class="center">
|
||||
{{ time }}
|
||||
</div>
|
||||
<div class="right flex align-center">
|
||||
<div style="width: 100px;user-select: none">速度</div>
|
||||
<el-slider size="small" :show-tooltip="false" v-model="data.speed"/>
|
||||
<div style="margin-left: 20px"> {{ data.speed }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mechanical-arm {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.top {
|
||||
padding: 10px 10px 0;
|
||||
height: 48%;
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.card:last-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
padding: 0 10px;
|
||||
height: 44%;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.actions {
|
||||
height: 6%;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
|
||||
padding: 0 10px;
|
||||
|
||||
.right {
|
||||
width: 300px;
|
||||
|
||||
}
|
||||
|
||||
.center {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.action-label {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.action-label-pos {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.el-input-number {
|
||||
width: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 10px;
|
||||
|
||||
.title {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 900;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.body {
|
||||
height: calc(100% - 29px);
|
||||
overflow-y: auto;
|
||||
|
||||
.pos-title {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.btn-wrap {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
.btn {
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
transform-origin: center center;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.turn-lb {
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
|
||||
.turn-rb {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.turn-left {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.turn-right {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.turn-bottom {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -1,28 +1,10 @@
|
||||
<script setup>
|
||||
import { reactive, toRefs, onMounted, onUnmounted, watch, computed, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import dayjs from "dayjs";
|
||||
import { deviceTeach } from "@/api/device/register.js";
|
||||
import { formatNumber } from "@/views/device/register/components/index.js";
|
||||
import { convertNumbersToStringAndRemoveNulls } from "@/utils/fn.js";
|
||||
import {
|
||||
moveJ,
|
||||
status
|
||||
} from '@/api/device/arm';
|
||||
import { reactive, toRefs, onUnmounted, ref, onMounted } from "vue";
|
||||
import UrdfViewer from "./components/UrdfViewer.vue";
|
||||
import JointControl from "./components/JointControl.vue";
|
||||
|
||||
const data = reactive({
|
||||
form: {
|
||||
workModule: 1,
|
||||
posStep: 1,
|
||||
postureStep: 1,
|
||||
jointStep: 1,
|
||||
joint1: 0.000012,
|
||||
joint2: 0.000012,
|
||||
joint3: 0.000012,
|
||||
joint4: 0.000012,
|
||||
joint5: 0.000012,
|
||||
joint6: 0.000012,
|
||||
joint7: 0.000012,
|
||||
x: 11,
|
||||
y: 11,
|
||||
z: 11,
|
||||
@ -30,207 +12,153 @@ const data = reactive({
|
||||
ry: 11,
|
||||
rz: 11,
|
||||
arm: 1,
|
||||
coordinate: 1,
|
||||
},
|
||||
speed: 20,
|
||||
zeroPos: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
rz: 0,
|
||||
},
|
||||
initPos: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1,
|
||||
rx: 1,
|
||||
ry: 1,
|
||||
rz: 1,
|
||||
},
|
||||
armList: [
|
||||
{ label: '目标1', value: 1 },
|
||||
{ label: '目标2', value: 2 },
|
||||
{ label: '目标3', value: 3 },
|
||||
{ label: "目标1", value: 1 },
|
||||
{ label: "目标2", value: 2 },
|
||||
{ label: "目标3", value: 3 },
|
||||
],
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
const terminalId = ref('25449ff3fcc7b27da5f69462c5efcec2');
|
||||
const deviceId = ref('spk1');
|
||||
const { form, time, zeroPos, initPos, armList } = toRefs(data);
|
||||
const route = useRoute();
|
||||
|
||||
const { form, armList } = toRefs(data);
|
||||
|
||||
const leftJointList = ref(null);
|
||||
const rightJointList = ref(null);
|
||||
const computedChange = (val) => {
|
||||
leftJointList.value = val.filter((item) => {
|
||||
return item.name[0] === "L";
|
||||
});
|
||||
rightJointList.value = val.filter((item) => {
|
||||
return item.name[0] === "R";
|
||||
});
|
||||
};
|
||||
|
||||
const urdfViewerRef = ref(null);
|
||||
|
||||
const updateJointAngle = ({ name, value }) => {
|
||||
if (urdfViewerRef.value) {
|
||||
urdfViewerRef.value.updateJointAngle(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
const coordinateSystem = ref(null); // 用于获取容器元素
|
||||
const buttonPositions = ref([]); // 存储按钮的动态位置
|
||||
|
||||
// 调整后的原始坐标(基于默认图片尺寸 1025x817px)
|
||||
const initialPositions = [
|
||||
{ target: "z_plus", x: 500, y: 80, label: "Z+" },
|
||||
{ target: "rz_plus", x: 675, y: 124, label: "RZ+" },
|
||||
{ target: "x_plus", x: 796, y: 245, label: "X+" },
|
||||
{ target: "ry_plus", x: 840, y: 410, label: "RY+" },
|
||||
{ target: "y_minus", x: 796, y: 570, label: "Y-" },
|
||||
{ target: "ry_minus", x: 675, y: 696, label: "RY-" },
|
||||
{ target: "z_minus", x: 500, y: 745, label: "Z-" },
|
||||
{ target: "rx_minus", x: 345, y: 696, label: "RX-" },
|
||||
{ target: "x_minus", x: 206, y: 570, label: "X-" },
|
||||
{ target: "rx_plus", x: 180, y: 410, label: "RX+" },
|
||||
{ target: "y_plus", x: 204, y: 245, label: "Y+" },
|
||||
{ target: "rz_minus", x: 345, y: 124, label: "RZ-" },
|
||||
const buttonDirections = [
|
||||
{ target: "z_plus", direction: "top", label: "Z+" }, // left
|
||||
{ target: "rz_plus", direction: "top-right", label: "RZ+" },
|
||||
{ target: "x_plus", direction: "right", label: "X+" }, // bottom
|
||||
{ target: "ry_plus", direction: "bottom-right", label: "RY+" },
|
||||
{ target: "y_minus", direction: "bottom", label: "Y-" },
|
||||
{ target: "ry_minus", direction: "bottom-left", label: "RY-" },
|
||||
{ target: "z_minus", direction: "bottom", label: "Z-" },
|
||||
{ target: "rx_minus", direction: "bottom-left", label: "RX-" },
|
||||
{ target: "x_minus", direction: "left", label: "X-" },
|
||||
{ target: "rx_plus", direction: "top-left", label: "RX+" },
|
||||
{ target: "y_plus", direction: "left", label: "Y+" }, // right
|
||||
{ target: "rz_minus", direction: "top-left", label: "RZ-" },
|
||||
];
|
||||
|
||||
// 默认图片尺寸
|
||||
const ORIGINAL_IMAGE_WIDTH = 1025;
|
||||
const ORIGINAL_IMAGE_HEIGHT = 817;
|
||||
|
||||
let timer = null;
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(timer);
|
||||
});
|
||||
|
||||
const getDeviceInfo = () => {
|
||||
deviceTeach(devId.value).then((res) => {
|
||||
let dataRes = formatNumber(res.data);
|
||||
Object.assign(form.value, dataRes);
|
||||
initPos.value.x = dataRes.x;
|
||||
initPos.value.y = dataRes.y;
|
||||
initPos.value.z = dataRes.z;
|
||||
initPos.value.rx = dataRes.rx;
|
||||
initPos.value.ry = dataRes.ry;
|
||||
initPos.value.rz = dataRes.rz;
|
||||
});
|
||||
};
|
||||
|
||||
const updateButtonPositions = () => {
|
||||
if (coordinateSystem.value) {
|
||||
const { width, height } = coordinateSystem.value.getBoundingClientRect();
|
||||
// 计算图片的实际显示尺寸(考虑 background-size: contain)
|
||||
const imageAspectRatio = ORIGINAL_IMAGE_WIDTH / ORIGINAL_IMAGE_HEIGHT; // 1025 / 817 ≈ 1.255
|
||||
const containerAspectRatio = width / height;
|
||||
const containerRect = coordinateSystem.value.getBoundingClientRect();
|
||||
const containerWidth = containerRect.width;
|
||||
const containerHeight = containerRect.height;
|
||||
|
||||
let imageWidth, imageHeight, offsetX, offsetY;
|
||||
// 计算图片的实际显示尺寸(考虑 background-size: contain)
|
||||
const imageAspectRatio = ORIGINAL_IMAGE_WIDTH / ORIGINAL_IMAGE_HEIGHT;
|
||||
const containerAspectRatio = containerWidth / containerHeight;
|
||||
|
||||
let imageWidth, imageHeight, imageLeft, imageTop;
|
||||
if (containerAspectRatio > imageAspectRatio) {
|
||||
// 容器较宽,高度限制图片大小,上下有留白
|
||||
imageHeight = height;
|
||||
imageWidth = height * imageAspectRatio;
|
||||
offsetX = (width - imageWidth) / 2; // 水平居中
|
||||
offsetY = 0; // 顶部对齐
|
||||
imageHeight = containerHeight;
|
||||
imageWidth = imageHeight * imageAspectRatio;
|
||||
imageLeft = (containerWidth - imageWidth) / 2;
|
||||
imageTop = 0;
|
||||
} else {
|
||||
// 容器较窄,宽度限制图片大小,左右有留白
|
||||
imageWidth = width;
|
||||
imageHeight = width / imageAspectRatio;
|
||||
offsetX = 0; // 左对齐
|
||||
offsetY = (height - imageHeight) / 2; // 垂直居中
|
||||
imageWidth = containerWidth;
|
||||
imageHeight = imageWidth / imageAspectRatio;
|
||||
imageLeft = 0;
|
||||
imageTop = (containerHeight - imageHeight) / 2;
|
||||
}
|
||||
|
||||
// 计算缩放比例(基于图片实际显示尺寸)
|
||||
const scaleX = imageWidth / ORIGINAL_IMAGE_WIDTH;
|
||||
const scaleY = imageHeight / ORIGINAL_IMAGE_HEIGHT;
|
||||
// 计算图片中心坐标
|
||||
const centerX = imageLeft + imageWidth / 2;
|
||||
const centerY = imageTop + imageHeight / 2;
|
||||
|
||||
// 计算圆的半径(根据图片尺寸的较小值比例确定,可调整比例系数)
|
||||
const radiusScale = 0.85; // 半径系数,0-1之间,越大半径越大
|
||||
const radius = Math.min(imageWidth, imageHeight) * radiusScale / 2;
|
||||
|
||||
// 定义方位对应的角度(弧度制),top为0度,顺时针增加
|
||||
const directionAngles = {
|
||||
"top": 0,
|
||||
"top-right": Math.PI / 6, // 30度
|
||||
"right": Math.PI / 3, // 60度
|
||||
"bottom-right": Math.PI / 2, // 90度
|
||||
"bottom": 2 * Math.PI / 3, // 120度
|
||||
"bottom-left": 5 * Math.PI / 6, // 150度
|
||||
"left": Math.PI, // 180度
|
||||
"top-left": 7 * Math.PI / 6, // 210度
|
||||
};
|
||||
|
||||
// 调整角度以均匀分布12个按钮(360/12=30度,即Math.PI/6弧度)
|
||||
const totalButtons = buttonDirections.length;
|
||||
const angleStep = 2 * Math.PI / totalButtons;
|
||||
|
||||
// 更新按钮位置
|
||||
buttonPositions.value = initialPositions.map((pos) => ({
|
||||
...pos,
|
||||
left: pos.x * scaleX + offsetX, // 按比例缩放 x 坐标并加上水平偏移
|
||||
top: pos.y * scaleY + offsetY, // 按比例缩放 y 坐标并加上垂直偏移
|
||||
}));
|
||||
buttonPositions.value = buttonDirections.map((btn, index) => {
|
||||
// 计算每个按钮的角度(从top开始顺时针排列)
|
||||
const angle = index * angleStep;
|
||||
// 计算按钮的坐标
|
||||
const x = centerX + radius * Math.sin(angle);
|
||||
const y = centerY - radius * Math.cos(angle);
|
||||
return {
|
||||
...btn,
|
||||
left: x,
|
||||
top: y,
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getDeviceInfo();
|
||||
// 初始计算按钮位置
|
||||
updateButtonPositions();
|
||||
// 添加按钮事件监听
|
||||
const posControls = document.querySelectorAll(".pos-btn");
|
||||
posControls.forEach((item) => {
|
||||
item.addEventListener('click', (e) => {
|
||||
const target = e.currentTarget.dataset.target;
|
||||
const [pos, direction] = target.split("_");
|
||||
const step = (pos === 'x' || pos === 'y' || pos === 'z') ? form.value.posStep : form.value.postureStep;
|
||||
const delta = direction === 'plus' ? step : -step;
|
||||
form.value[pos] += delta * (data.speed / 100);
|
||||
});
|
||||
});
|
||||
|
||||
// 监听窗口大小变化,更新按钮位置
|
||||
window.addEventListener('resize', updateButtonPositions);
|
||||
window.addEventListener("resize", updateButtonPositions);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', updateButtonPositions);
|
||||
window.removeEventListener("resize", updateButtonPositions);
|
||||
});
|
||||
|
||||
watch(() => JSON.parse(JSON.stringify(form.value)), (newData) => {
|
||||
const dataToSend = convertNumbersToStringAndRemoveNulls(newData);
|
||||
moveJ({
|
||||
"deviceId": deviceId.value,
|
||||
"terminalId": terminalId.value,
|
||||
"acc": 0.8,
|
||||
"vel": 0.8,
|
||||
"cmds": [
|
||||
{
|
||||
"jointName": "R_SHOULDER_P",
|
||||
"rad": dataToSend.joint1,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_SHOULDER_R",
|
||||
"rad": dataToSend.joint2,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_SHOULDER_Y",
|
||||
"rad": dataToSend.joint3,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_ELBOW_R",
|
||||
"rad": dataToSend.joint4,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_WRIST_P",
|
||||
"rad": dataToSend.joint5,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_WRIST_Y",
|
||||
"rad": dataToSend.joint6,
|
||||
"vel": 1.0
|
||||
},
|
||||
{
|
||||
"jointName": "R_WRIST_R",
|
||||
"rad": dataToSend.joint7,
|
||||
"vel": 1.0
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
const devId = computed(() => {
|
||||
return route.path.split("/")[2];
|
||||
});
|
||||
|
||||
const handleResets = (type) => {
|
||||
if (type === "zero") {
|
||||
Object.assign(form.value, zeroPos.value);
|
||||
return;
|
||||
}
|
||||
if (type === "init") {
|
||||
Object.assign(form.value, initPos.value);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mechanical-arm">
|
||||
<div class="top card">
|
||||
<div class="controls flex align-center" style="justify-content: flex-start;">
|
||||
<div class="controls flex align-center" style="justify-content: flex-start">
|
||||
<div class="control-label">目标</div>
|
||||
<el-select v-model="form.arm" placeholder="选择目标" style="width: 100px; margin-right: 20px;">
|
||||
<el-option v-for="item in armList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
<el-select
|
||||
v-model="form.arm"
|
||||
placeholder="选择目标"
|
||||
style="width: 100px; margin-right: 20px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in armList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button @click="handleResets('zero')" style="margin-right: 10px;">零位姿态</el-button>
|
||||
<el-button @click="handleResets('zero')" style="margin-right: 10px"
|
||||
>零位姿态</el-button
|
||||
>
|
||||
<el-button @click="handleResets('init')">初始位置</el-button>
|
||||
</div>
|
||||
<div class="pose-info flex align-center">
|
||||
@ -242,9 +170,35 @@ const handleResets = (type) => {
|
||||
<div class="pose-item">RZ: {{ form.rz.toFixed(6) }} deg</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom flex">
|
||||
<div class="left card" style="flex: 1; position: relative;">
|
||||
<div class="title">姿态与位置控制</div>
|
||||
<div class="bottom">
|
||||
<div class="left">
|
||||
<UrdfViewer
|
||||
ref="urdfViewerRef"
|
||||
:base-path="'/public/models/'"
|
||||
:urdf-path="'dual_arm.urdf'"
|
||||
:model-color="'#8a8ae9'"
|
||||
@computedChange="computedChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="top">
|
||||
<div class="secondary-title">
|
||||
<div class="label">左手</div>
|
||||
<div class="label">右手</div>
|
||||
</div>
|
||||
<div class="jointControl-container">
|
||||
<JointControl
|
||||
:jointList="leftJointList"
|
||||
@updateJointAngle="updateJointAngle"
|
||||
/>
|
||||
<JointControl
|
||||
:jointList="rightJointList"
|
||||
@updateJointAngle="updateJointAngle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="left card" style="position: relative">
|
||||
<div class="coordinate-system" ref="coordinateSystem">
|
||||
<div class="control-buttons">
|
||||
<button
|
||||
@ -259,50 +213,7 @@ const handleResets = (type) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right card" style="flex: 1;">
|
||||
<div class="title">关节控制 (deg)</div>
|
||||
<div class="input-list">
|
||||
<div class="input-item">
|
||||
<span>关节1</span>
|
||||
<el-input-number v-model="form.joint1" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节2</span>
|
||||
<el-input-number v-model="form.joint2" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节3</span>
|
||||
<el-input-number v-model="form.joint3" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节4</span>
|
||||
<el-input-number v-model="form.joint4" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节5</span>
|
||||
<el-input-number v-model="form.joint5" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节6</span>
|
||||
<el-input-number v-model="form.joint6" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节7</span>
|
||||
<el-input-number v-model="form.joint7" :step="form.jointStep" :precision="6" />
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<span>关节步进</span>
|
||||
<el-input-number v-model="form.jointStep" :step="0.1" :precision="1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer card flex align-center between">
|
||||
<div class="time">{{ time }}</div>
|
||||
<div class="speed flex align-center">
|
||||
<span>速度</span>
|
||||
<el-slider v-model="data.speed" :min="0" :max="100" style="width: 200px; margin: 0 10px;" />
|
||||
<span>{{ data.speed }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -341,20 +252,59 @@ const handleResets = (type) => {
|
||||
}
|
||||
|
||||
.bottom {
|
||||
flex: 1;
|
||||
gap: 20px;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
user-select: none;
|
||||
}
|
||||
height: calc(100% - 120px);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.left {
|
||||
flex: 2;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.top {
|
||||
flex: 1;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 0 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.container-title {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.secondary-title {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.jointControl-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
height: calc(100% - 75px);
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
flex: 1;
|
||||
|
||||
.card {
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.coordinate-system {
|
||||
flex: 1;
|
||||
@ -362,8 +312,8 @@ const handleResets = (type) => {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
background-color: #FFF;
|
||||
background-image: url('@/assets/images/arm.png');
|
||||
background-color: #fff;
|
||||
background-image: url("@/assets/images/arm.png");
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
@ -393,43 +343,6 @@ const handleResets = (type) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.input-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
.input-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
width: 80px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.el-input-number {
|
||||
width: calc(100% - 90px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 50px;
|
||||
|
||||
.time {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.speed {
|
||||
gap: 10px;
|
||||
|
||||
span {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user