feat: 重构

This commit is contained in:
zhanghao 2026-08-25 10:23:56 +08:00
parent c567b1cab4
commit 83d817e9e5
389 changed files with 16701 additions and 39836 deletions

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = 招商车研AI测评机器人模拟测试平台 VITE_APP_TITLE = 招商车研机器人智能测试管理系统
# 开发环境配置 # 开发环境配置
VITE_APP_ENV = 'development' VITE_APP_ENV = 'development'
@ -7,8 +7,8 @@ VITE_APP_ENV = 'development'
# 招商车研物联网平台/开发环境 # 招商车研物联网平台/开发环境
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
VITE_API_URL = http://192.168.0.201:13080 VITE_API_URL = http://192.168.0.222:14080
VITE_WS_URL = ws://192.168.0.201:13080/ws VITE_WS_URL = ws://192.168.0.222:14080/ws
VITE_PORT = 5174
# explanation VITE_INSPECTION_TYPE = "inspection"
VITE_INSPECTION_TYPE = "inspection" VITE_MINIO_URL = "http://192.168.28.10:9000/cmvr-iot/"

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = 智能座舱测评AI机器人 VITE_APP_TITLE = 招商车研机器人智能测试管理系统
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'production' VITE_APP_ENV = 'production'
@ -10,11 +10,8 @@ VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip
#node-red 服务地址
VITE_NODE_RED_URL = 'http://10.148.108.59:13080' VITE_NODE_RED_URL = 'http://10.148.108.59:13080'
VITE_API_URL = http://192.168.28.10:13080 VITE_API_URL = http://192.168.28.10:13080
VITE_WS_URL = ws://192.168.0.201:13080/ws VITE_WS_URL = ws://192.168.0.201:13080/ws
VITE_INSPECTION_TYPE = "inspection"
# explanation VITE_MINIO_URL = "http://192.168.28.10:9000/cmvr-iot/"
VITE_INSPECTION_TYPE = "inspection"

View File

@ -1,13 +1,16 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = 招商车研物联网平台管理系统 VITE_APP_TITLE = 招商车研机器人智能测试管理系统
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'staging' VITE_APP_ENV = 'staging'
# 招商车研物联网平台管理系统/生产环境 # 招商车研物联网平台/测试环境
VITE_APP_BASE_API = '/stage-api' VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip
VITE_API_URL = http://10.148.121.100:13080 VITE_API_URL = http://10.148.121.100:13080
VITE_WS_URL = ws://192.168.0.201:13080/ws VITE_WS_URL = ws://192.168.0.201:13080/ws
VITE_INSPECTION_TYPE = "inspection"
VITE_MINIO_URL = "http://192.168.28.10:9000/cmvr-iot/"

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html

5
.gitignore vendored
View File

@ -18,9 +18,8 @@ selenium-debug.log
*.njsproj *.njsproj
*.sln *.sln
*.local *.local
.history
package-lock.json package-lock.json
yarn.lock yarn.lock
bin/
pnpm-lock.yaml .history

125
README.md
View File

@ -1,35 +1,102 @@
# CMVR IoT 管理控制台
## 前端运行 招商车研物联网平台 Vue 3 管理端。项目以 RuoYi-Vue3 3.9.2 为新版基础框架,完整迁移原 `cmvr-iot-ui` 的业务页面、API、机器人模型和运行配置,并连接 `RuoYi-Vue-master` 中的 Spring Boot 4 后端。
旧前端仅作为迁移来源,不参与本项目构建。
## 功能范围
- 系统管理:用户、角色、部门、岗位、菜单、字典、参数、通知和文件。
- 系统监控:在线用户、操作日志、登录日志、缓存、服务、Quartz 和 Druid。
- 设备管理:设备注册、终端、机器人、相机、机械臂、灵巧手、机器人头部、麦克风、扬声器和电机。
- 测试平台:测试项目、任务配置、任务编排、检测项、任务实例和执行流程。
- 智能巡检:机器人、地图、点位、任务、执行实例、巡检结果、告警和驾驶舱。
- 交互评价:语音交互、触控交互、评价指标、方案、项目和语料。
- 智能座舱:车机界面、车辆配置、功能配置、流程编辑和执行评价。
- 语料与媒体:语料管理、音频上传、图片预览、视频播放和 WebSocket 实时消息。
- 开发工具:代码生成、表单构建和 Knife4j 接口文档。
## 技术栈
| 组件 | 版本 |
| --- | --- |
| Vue | 3.5.26 |
| Vite | 6.4.1 |
| Element Plus | 2.13.1 |
| Pinia | 3.0.4 |
| Vue Router | 4.6.4 |
| 可视化 | ECharts、Vue Flow、Three.js、Monaco Editor、XGPlayer |
## 环境要求
- Node.js 20 LTS
- pnpm 10
- 后端 `RuoYi-Vue-master/cmvr-iot-admin`
## 开发运行
先启动后端,确认 `http://localhost:13080` 可以访问,然后执行:
```bash ```bash
# 安装依赖 pnpm install
yarn --registry=https://registry.npmmirror.com pnpm dev
# 启动服务
yarn dev
# 构建测试环境 yarn build:stage
# 构建生产环境 yarn build:prod
# 前端访问地址 http://localhost:80
``` ```
## 内置功能 默认地址:
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 - 前端:`http://localhost:80`
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 - 后端:`http://localhost:13080`
3. 岗位管理:配置系统用户所属担任职务。 - Knife4j:`http://localhost:13080/doc.html`
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 开发配置位于 `.env.development`:
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 参数管理:对系统动态配置常用参数。 ```dotenv
8. 通知公告:系统通知公告信息发布维护。 VITE_APP_TITLE=招商车研物联网平台管理系统
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 VITE_APP_BASE_API=/dev-api
10. 登录日志:系统登录日志记录查询包含登录异常。 VITE_API_URL=http://localhost:13080
11. 在线用户:当前系统中活跃用户状态监控。 VITE_WS_URL=ws://localhost:13080/ws
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 VITE_PORT=80
13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 ```
14. 系统接口:根据业务代码自动生成相关的api接口文档。
15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 ## 构建
16. 缓存监控:对系统的缓存信息查询,命令统计等。
17. 在线构建器:拖动表单元素生成相应的HTML代码。 ```bash
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 pnpm build:dev
pnpm build:stage
pnpm build:prod
pnpm preview
```
生产构建输出到 `dist`。部署时需要由 Nginx 或网关转发 `/prod-api`,并支持 `/ws` WebSocket、文件上传和媒体请求。
## 目录说明
```text
public/models 机器人 URDF 和网格模型
public/inspection 巡检机械臂模型
src/adapters URDF/Xacro 模型适配
src/api REST API 封装
src/components 公共及业务组件
src/router 公共路由和隐藏业务路由
src/store Pinia 状态管理
src/views/device 设备管理与设备控制
src/views/test 测试业务
src/views/flow 流程编排
src/views/inspection 智能巡检
src/views/evaluate 评价管理
src/views/vi 语音交互
src/views/is 智能座舱
src/views/corpusManger 语料管理
```
业务菜单由后端 `/getRouters` 动态返回。数据库菜单中的 `component` 必须与 `src/views` 下的实际页面路径一致,权限字符必须与后端控制器保持一致。
## 配置说明
- `.env.development`:本地开发地址。
- `.env.staging`:测试环境地址。
- `.env.production`:生产环境地址、Node-RED 和 MinIO。
- `vite.config.js`:代理、端口、Monaco 和构建分包。
- `src/settings.js`:布局、页签和版权配置。
生产密码、访问密钥和内部网络配置应通过部署环境注入,不要提交新的敏感信息。

12
bin/build.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 打包Web工程,生成dist文件。
echo.
%~d0
cd %~dp0
cd ..
yarn build:prod
pause

12
bin/package.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 安装Web工程,生成node_modules文件。
echo.
%~d0
cd %~dp0
cd ..
yarn --registry=https://registry.npmmirror.com
pause

12
bin/run-web.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 使用 Vite 命令运行 Web 工程。
echo.
%~d0
cd %~dp0
cd ..
yarn dev
pause

View File

@ -7,7 +7,7 @@
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<title>招商车研物联网平台管理系统</title> <title>%VITE_APP_TITLE%</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]--> <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style> <style>
html, html,

View File

@ -1,32 +1,36 @@
{ {
"name": "CMVR-IOT-UI", "name": "cmvr-iot-aima",
"version": "3.8.8", "version": "1.0.0",
"description": "CMVR-IOT平台管理系统前端UI框架", "description": "招商车研物联网平台管理系统前端",
"author": "CMVR", "author": "CMVR",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build:dev": "vite build --mode development", "build:dev": "vite build --mode development",
"build:prod": "vite build --mode production", "build:prod": "vite build",
"build:staging": "vite build --mode staging --verbose", "build:stage": "vite build --mode staging",
"build:staging": "vite build --mode staging",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.3.1", "@cmvr/iot-common": "1.0.0",
"@logicflow/core": "^2.0.13", "@element-plus/icons-vue": "2.3.2",
"@logicflow/extension": "^2.0.18", "@vue-flow/background": "^1.3.2",
"@vue-flow/controls": "^1.1.3",
"@vue-flow/core": "^1.48.2",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.11.0", "@vueuse/core": "14.1.0",
"ace-builds": "^1.43.0", "ace-builds": "^1.43.0",
"axios": "0.28.1", "autofit.js": "^3.2.8",
"axios": "1.13.2",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"echarts": "5.5.1", "echarts": "5.6.0",
"element-plus": "2.9.4", "element-plus": "2.13.1",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.6.2", "fuse.js": "7.1.0",
"js-beautify": "1.14.11", "js-beautify": "1.15.4",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
"jsencrypt": "3.3.2", "jsencrypt": "3.3.2",
"json-editor-vue": "^0.18.1", "json-editor-vue": "^0.18.1",
@ -35,32 +39,38 @@
"monaco-editor": "^0.55.1", "monaco-editor": "^0.55.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pako": "^2.1.0", "pako": "^2.1.0",
"pinia": "2.1.7", "pinia": "3.0.4",
"pnpm": "^10.23.0",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.1",
"sockjs-client": "^1.6.1", "sockjs-client": "^1.6.1",
"sortablejs": "^1.15.6",
"splitpanes": "3.1.5", "splitpanes": "3.1.5",
"three": "^0.181.2", "three": "^0.181.2",
"urdf-loader": "^0.12.6", "urdf-loader": "^0.12.6",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vue": "3.4.31", "vue": "3.5.26",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-router": "4.4.0", "vue-router": "4.6.4",
"vue3-ace-editor": "^2.2.4", "vue3-ace-editor": "^2.2.4",
"vue3-json-viewer": "2.3.0", "vue3-json-viewer": "2.3.0",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"xacro-parser": "^0.3.11",
"xgplayer": "^3.0.22" "xgplayer": "^3.0.22"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "5.0.5", "@vitejs/plugin-vue": "5.2.4",
"file-loader": "^6.2.0", "sass-embedded": "1.97.2",
"sass": "1.77.5", "unplugin-auto-import": "0.18.6",
"unplugin-auto-import": "0.17.6",
"unplugin-vue-setup-extend-plus": "1.0.1", "unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "5.3.2", "vite": "6.4.1",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-svg-icons": "2.0.1" "vite-plugin-svg-icons": "2.0.1"
}, },
"packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531" "overrides": {
"quill": "2.0.2"
},
"resolutions": {
"quill": "2.0.2"
},
"packageManager": "pnpm@10.24.0"
} }

6000
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

6
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,6 @@
allowBuilds:
core-js: true
es5-ext: true
esbuild: true
json-editor-vue: true
vue-demi: true

View File

@ -0,0 +1,465 @@
<?xml version="1.0"?>
<robot name="elfin10" xmlns:xacro="http://wiki.ros.org/xacro">
<xacro:arg name="use_real_hardware" default="true" />
<xacro:arg name="use_fake_hardware" default="false" />
<!-- Load TRANSMISSION file: -->
<xacro:include filename="file://$(find elfin_description)/elfin10_transmission.xacro" />
<!-- Load GAZEBO/ROS2_CONTROL file: -->
<xacro:include filename="file://$(find elfin_description)/elfin10_gazebo.xacro" />
<xacro:property name="PI" value="3.1415926535897931"/>
<xacro:property name="density" value="3.09"/>
<!-- <xacro:macro name="elfin10"> -->
<!-- TRANSMISSION: -->
<xacro:elfin10_transmission />
<!-- GAZEBO - ROS2_CONTROL: -->
<xacro:elfin10_gazebo
use_real_hardware="$(arg use_real_hardware)"
use_fake_hardware="$(arg use_fake_hardware)"/>
<link name="world"/>
<joint name="world_base" type="fixed">
<origin
xyz="0 0 0"
rpy="0 0 -1.5708" />
<parent
link="world" />
<child
link="elfin_base_link" />
</joint>
<link name="elfin_base_link"/>
<joint name="elfin_base_joint" type="fixed">
<origin
xyz="0 0 0"
rpy="0 0 ${PI/2}" />
<parent
link="elfin_base_link" />
<child
link="elfin_base" />
</joint>
<link
name="elfin_base">
<inertial>
<origin
xyz="-0.00226511349377665 4.35718066723588E-06 0.0325128562537015"
rpy="0 0 0" />
<mass
value="1.66727740473724" />
<inertia
ixx="0.004269288474386"
ixy="6.02518130623876E-08"
ixz="-6.92087963593712E-05"
iyy="0.00385585336301628"
iyz="-5.51423740998761E-08"
izz="0.0068204473327682" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_base.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_base.STL" />
</geometry>
</collision>
</link>
<link
name="elfin_link1">
<inertial>
<origin
xyz="7.61162863471406E-07 -0.00300107309756385 -0.0432743915921636"
rpy="0 0 0" />
<mass
value="6.3589066662676" />
<inertia
ixx="0.0391771076676677"
ixy="5.46819690041203E-08"
ixz="4.18972540516346E-07"
iyy="0.0381555138034643"
iyz="0.00661206821297882"
izz="0.0211340101406971" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link1.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link1.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint1"
type="revolute">
<origin
xyz="0 0 0.26"
rpy="0 0 0" />
<parent
link="elfin_base" />
<child
link="elfin_link1" />
<axis
xyz="0 0 1" />
<limit
lower="-3.14"
upper="3.14"
effort="420"
velocity="1.57" />
</joint>
<link
name="elfin_link2">
<inertial>
<origin
xyz="-1.29217317440473E-07 0.204406209458582 0.145205671136993"
rpy="0 0 0" />
<mass
value="5.51072381215317" />
<inertia
ixx="0.140886684844275"
ixy="-1.98882818733046E-05"
ixz="1.28793862225363E-06"
iyy="0.00904523320332792"
iyz="0.00556623571013066"
izz="0.143882970137024" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link2.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link2.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint2"
type="revolute">
<origin
xyz="0 0 0"
rpy="1.5708 0 0" />
<parent
link="elfin_link1" />
<child
link="elfin_link2" />
<axis
xyz="0 0 1" />
<limit
lower="-2.35"
upper="2.35"
effort="420"
velocity="1.57" />
</joint>
<link
name="elfin_link3">
<inertial>
<origin
xyz="0.0357493010718184 -2.74303992683623E-06 -0.00441107040289549"
rpy="0 0 0" />
<mass
value="3.25128088148268" />
<inertia
ixx="0.00712273850158261"
ixy="4.14573354600121E-07"
ixz="-0.00240614658407673"
iyy="0.0131139013038093"
iyz="-1.53858261863385E-07"
izz="0.0123861174875263" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link3.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link3.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint3"
type="revolute">
<origin
xyz="0 0.48 0"
rpy="-3.1416 0 1.5708" />
<parent
link="elfin_link2" />
<child
link="elfin_link3" />
<axis
xyz="0 0 1" />
<limit
lower="-2.61"
upper="2.61"
effort="200"
velocity="1.57" />
</joint>
<link
name="elfin_link4">
<inertial>
<origin
xyz="3.8972274666868E-06 -0.065883038527668 0.300149807420176"
rpy="0 0 0" />
<mass
value="2.45076028364132" />
<inertia
ixx="0.0366043963749035"
ixy="2.14481800816891E-07"
ixz="1.74370308297691E-06"
iyy="0.0331005868546169"
iyz="0.00876542795872678"
izz="0.00689303506560623" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link4.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link4.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint4"
type="revolute">
<origin
xyz="0 0 0"
rpy="1.5708 0 1.5708" />
<parent
link="elfin_link3" />
<child
link="elfin_link4" />
<axis
xyz="0 0 1" />
<limit
lower="-3.14"
upper="3.14"
effort="200"
velocity="1.57" />
</joint>
<link
name="elfin_link5">
<inertial>
<origin
xyz="5.37084413168812E-06 -0.0262437975997385 -0.00353971828905618"
rpy="0 0 0" />
<mass
value="1.39234539037872" />
<inertia
ixx="0.0033625821599978"
ixy="2.21090591006111E-07"
ixz="-5.5969383984273E-07"
iyy="0.00182229285631246"
iyz="0.000639319386824375"
izz="0.00292731816323284" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link5.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link5.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint5"
type="revolute">
<origin
xyz="0 0 0.52"
rpy="-1.5708 0 0" />
<parent
link="elfin_link4" />
<child
link="elfin_link5" />
<axis
xyz="0 0 1" />
<limit
lower="-2.56"
upper="2.56"
effort="69"
velocity="1.57" />
</joint>
<link
name="elfin_link6">
<inertial>
<origin
xyz="-8.45231478862452E-06 -0.000388392932234965 0.144636177508013"
rpy="0 0 0" />
<mass
value="0.297803050744826" />
<inertia
ixx="0.000151919382929214"
ixy="-1.8598001023495E-09"
ixz="6.95653480101813E-08"
iyy="0.000155217204136347"
iyz="-6.63866631888914E-08"
izz="0.00027009779924127" />
</inertial>
<visual>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link6.STL" />
</geometry>
<material
name="">
<color
rgba="0.752941176470588 0.752941176470588 0.752941176470588 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh
filename="file://$(find elfin_description)/meshes/elfin10/elfin_link6.STL" />
</geometry>
</collision>
</link>
<joint
name="elfin_joint6"
type="revolute">
<origin
xyz="0 0 0"
rpy="1.5708 0 0" />
<parent
link="elfin_link5" />
<child
link="elfin_link6" />
<axis
xyz="0 0 1" />
<limit
lower="-3.14"
upper="3.14"
effort="69"
velocity="1.57" />
</joint>
<link
name="elfin_end_link"/>
<joint
name="elfin_end_joint"
type="fixed">
<origin
xyz="0 0.0 0.1735"
rpy="0 0 0" />
<parent
link="elfin_link6" />
<child
link="elfin_end_link" />
<axis
xyz="0 0 0" />
</joint>
<link name="elfin_dummy_gripper"/>
<joint name="elfin_dummy_joint" type="fixed">
<origin
xyz="0 0.109 0"
rpy="${-PI/2} ${-PI/2} 0" />
<parent
link="elfin_link6" />
<child
link="elfin_dummy_gripper" />
</joint>
</robot>

View File

@ -0,0 +1,134 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="elfin10_gazebo"
params="use_fake_hardware:=false
use_real_hardware:=true">
<gazebo>
<plugin filename="libgazebo_ros2_control.so" name="gazebo_ros2_control">
<robot_sim_type>gazebo_ros2_control/GazeboSystem</robot_sim_type>
<parameters>$(find elfin10_ros2_gazebo)/config/elfin_arm_controller.yaml</parameters>
</plugin>
</gazebo>
<ros2_control name="GazeboSystem" type="system">
<hardware>
<xacro:if value="${use_real_hardware}">
<plugin>elfin_hardware_interface/ElfinHWInterface</plugin>
</xacro:if>
<xacro:unless value="${use_real_hardware}">
<xacro:if value="${use_fake_hardware}">
<plugin>fake_components/GenericSystem</plugin>
</xacro:if>
<xacro:unless value="${use_fake_hardware}">
<plugin>gazebo_ros2_control/GazeboSystem</plugin>
</xacro:unless>
</xacro:unless>
</hardware>
<joint name="elfin_joint1">
<command_interface name="position">
<param name="min">-3.14</param>
<param name="max">3.14</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
<joint name="elfin_joint2">
<command_interface name="position">
<param name="min">-2.35</param>
<param name="max">2.35</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
<joint name="elfin_joint3">
<command_interface name="position">
<param name="min">-2.61</param>
<param name="max">2.61</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
<joint name="elfin_joint4">
<command_interface name="position">
<param name="min">-3.14</param>
<param name="max">3.14</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
<joint name="elfin_joint5">
<command_interface name="position">
<param name="min">-2.56</param>
<param name="max">2.56</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
<joint name="elfin_joint6">
<command_interface name="position">
<param name="min">-3.14</param>
<param name="max">3.14</param>
</command_interface>
<command_interface name="velocity">
<param name="min">-1.57</param>
<param name="max">1.57</param>
</command_interface>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
</ros2_control>
<gazebo reference="elfin_link2">
<visual name='visual'>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/Grey</name>
</script>
</material>
</visual>
</gazebo>
<gazebo reference="elfin_link4">
<visual name='visual'>
<material>
<script>
<uri>file://media/materials/scripts/gazebo.material</uri>
<name>Gazebo/Grey</name>
</script>
</material>
</visual>
</gazebo>
</xacro:macro>
</robot>

View File

@ -0,0 +1,69 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://wiki.ros.org/xacro">
<xacro:macro name="elfin10_transmission" >
<transmission name="elfin_joint1_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint1">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint1_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="elfin_joint2_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint2">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint2_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="elfin_joint3_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint3">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint3_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="elfin_joint4_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint4">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint4_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="elfin_joint5_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint5">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint5_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
<transmission name="elfin_joint6_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="elfin_joint6">
<hardwareInterface>hardware_interface/PositionJointInterface</hardwareInterface>
</joint>
<actuator name="elfin_joint6_motor">
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
</xacro:macro>
</robot>

660
public/models/dual_arm.urdf Normal file
View 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
View 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>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

461
src/adapters/URDFAdapter.js Normal file
View File

@ -0,0 +1,461 @@
/**
* URDF Adapter
* Converts urdf-loaders result to unified model
*/
import * as THREE from 'three';
import { UnifiedRobotModel, Link, Joint, JointLimits, VisualGeometry, CollisionGeometry, InertialProperties } from '@/models/UnifiedRobotModel.js';
export class URDFAdapter {
/**
* Convert urdf-loaders robot object to unified model
* @param {THREE.Group} robot - Robot object returned by urdf-loaders
* @param {string} urdfXML - Original URDF XML content (optional, for extracting inertial data)
* @returns {UnifiedRobotModel}
*/
static convert(robot, urdfXML = null) {
const model = new UnifiedRobotModel();
model.name = robot.name || 'robot';
model.threeObject = robot;
// Mark model type as URDF
if (!robot.userData) robot.userData = {};
robot.userData.type = 'urdf';
if (!robot.links || !robot.joints) {
console.warn('URDF model missing links or joints information');
return model;
}
// If XML provided, parse inertial data
let inertialData = {};
if (urdfXML) {
inertialData = this.parseInertialFromXML(urdfXML);
}
// Convert links
Object.values(robot.links).forEach(urdfLink => {
const link = this.convertLink(urdfLink);
// If urdf-loader didn't parse inertial, get from XML
if (!link.inertial && inertialData[urdfLink.name]) {
link.inertial = inertialData[urdfLink.name];
}
model.addLink(link);
});
// Convert joints
Object.values(robot.joints).forEach(urdfJoint => {
const joint = this.convertJoint(urdfJoint);
model.addJoint(joint);
});
// If XML provided, supplement effort and velocity from XML (urdf-loaders may not have parsed)
if (urdfXML) {
this.supplementJointLimitsFromXML(model, urdfXML);
}
// Find root link (link that is not a child of any joint)
const allChildren = new Set(
Array.from(model.joints.values()).map(j => j.child).filter(c => c)
);
const rootLinks = Array.from(model.links.keys()).filter(
name => !allChildren.has(name)
);
if (rootLinks.length > 0) {
model.rootLink = rootLinks[0];
}
// Enhance materials for better lighting (MuJoCo style)
this.enhanceMaterials(robot);
return model;
}
/**
* Enhance materials for better lighting (MuJoCo style)
* Applies consistent shininess and specular properties to all materials
* Directly modifies materials in place to ensure changes persist
*/
static enhanceMaterials(robotObject) {
robotObject.traverse((child) => {
if (child.isMesh && child.material) {
// Handle material arrays
if (Array.isArray(child.material)) {
child.material = child.material.map(mat => {
return this.enhanceSingleMaterial(mat);
});
} else {
child.material = this.enhanceSingleMaterial(child.material);
}
}
});
}
/**
* Enhance a single material with better lighting properties
* Returns enhanced material (may be cloned or modified in place)
* Saves original properties for lighting toggle
*/
static enhanceSingleMaterial(material) {
if (material.isMeshPhongMaterial || material.isMeshStandardMaterial) {
// Save original properties if not already saved (for lighting toggle)
if (material.userData.originalShininess === undefined) {
material.userData.originalShininess = material.shininess !== undefined ? material.shininess : 30;
// IMPORTANT: Save original color to preserve URDF material colors
if (!material.userData.originalColor && material.color) {
material.userData.originalColor = material.color.clone();
}
// Save original specular - if material had no specular, save null
if (!material.specular) {
material.userData.originalSpecular = null;
} else if (material.specular.isColor) {
const spec = material.specular;
if (spec.r < 0.1 && spec.g < 0.1 && spec.b < 0.1) {
material.userData.originalSpecular = null; // Likely default
} else {
material.userData.originalSpecular = spec.clone();
}
} else if (typeof material.specular === 'number') {
if (material.specular === 0x111111 || material.specular < 0x111111) {
material.userData.originalSpecular = null;
} else {
material.userData.originalSpecular = new THREE.Color(material.specular);
}
} else {
material.userData.originalSpecular = null;
}
}
// IMPORTANT: Preserve original color from URDF material definitions
// Do not modify material.color - urdf-loaders already sets the correct color
// Apply enhanced lighting (default enabled)
// Increase shininess for better highlights
if (material.shininess === undefined || material.shininess < 50) {
material.shininess = 50;
}
// Enhance specular reflection - ensure it's a Color object with proper values
if (!material.specular) {
material.specular = new THREE.Color(0.3, 0.3, 0.3);
} else if (material.specular.isColor) {
// If it's already a Color object, update values
if (material.specular.r < 0.2 || material.specular.g < 0.2 || material.specular.b < 0.2) {
material.specular.setRGB(0.3, 0.3, 0.3);
}
} else if (typeof material.specular === 'number') {
// Convert number to Color object
if (material.specular < 0x333333) {
material.specular = new THREE.Color(0.3, 0.3, 0.3);
} else {
// Convert hex to Color
material.specular = new THREE.Color(material.specular);
if (material.specular.r < 0.2) {
material.specular.setRGB(0.3, 0.3, 0.3);
}
}
}
// Mark material as needing update
material.needsUpdate = true;
return material;
} else if (material.type === 'MeshBasicMaterial') {
// Convert MeshBasicMaterial to MeshPhongMaterial
const oldMaterial = material;
const envMap = typeof window !== 'undefined' && window.app?.sceneManager?.environmentManager?.getEnvironmentMap();
const newMaterial = new THREE.MeshPhongMaterial({
color: oldMaterial.color,
map: oldMaterial.map,
transparent: oldMaterial.transparent,
opacity: oldMaterial.opacity,
side: oldMaterial.side,
shininess: 50,
specular: new THREE.Color(0.3, 0.3, 0.3),
envMap: envMap || null,
reflectivity: envMap ? 0.3 : 0
});
// Save original properties for lighting toggle
newMaterial.userData.originalShininess = 30;
newMaterial.userData.originalSpecular = null; // MeshBasicMaterial had no specular
return newMaterial;
}
return material;
}
static convertLink(urdfLink) {
const link = new Link(urdfLink.name);
link.threeObject = urdfLink;
// Convert inertial properties
if (urdfLink.inertial) {
link.inertial = this.convertInertial(urdfLink.inertial);
}
// Note: urdf-loaders has already converted visual and collision to Three.js objects
// We mainly extract metadata, actual meshes are in threeObject
return link;
}
static convertJoint(urdfJoint) {
// URDF joint object has jointType property (not type)
const jointType = urdfJoint.jointType || urdfJoint.type || 'fixed';
const joint = new Joint(urdfJoint.name, jointType);
// Extract parent name (urdf-loader returns Three.js object reference)
joint.parent = urdfJoint.parent?.name || null;
// child may not be in urdfJoint.child, but in Three.js children array
// In Three.js scene graph, Joint is parent node, Child Link is Joint's child node
if (urdfJoint.child && urdfJoint.child.name) {
joint.child = urdfJoint.child.name;
} else if (urdfJoint.children && urdfJoint.children.length > 0) {
// Find Link object from children array
const childLink = urdfJoint.children.find(child =>
child.isURDFLink || child.type === 'URDFLink'
);
if (childLink) {
joint.child = childLink.name;
}
}
joint.threeObject = urdfJoint;
// Convert origin
if (urdfJoint.origin) {
joint.origin = {
xyz: urdfJoint.origin.xyz || [0, 0, 0],
rpy: urdfJoint.origin.rpy || [0, 0, 0]
};
}
// Convert axis
if (urdfJoint.axis) {
joint.axis = { xyz: urdfJoint.axis.xyz || [0, 0, 1] };
}
// Convert limits
if (urdfJoint.limit) {
joint.limits = this.convertLimits(urdfJoint.limit);
}
// Get current value
if (urdfJoint.angle !== undefined) {
joint.currentValue = urdfJoint.angle;
} else if (urdfJoint.jointValue !== undefined) {
joint.currentValue = urdfJoint.jointValue;
}
return joint;
}
static convertLimits(limit) {
const limits = new JointLimits();
if (limit.lower !== undefined) limits.lower = limit.lower;
if (limit.upper !== undefined) limits.upper = limit.upper;
if (limit.effort !== undefined) limits.effort = limit.effort;
if (limit.velocity !== undefined) limits.velocity = limit.velocity;
return limits;
}
/**
* Supplement joint effort and velocity information from URDF XML
* (because urdf-loaders may not have parsed these attributes)
*/
static supplementJointLimitsFromXML(model, urdfXML) {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(urdfXML, 'text/xml');
const jointElements = doc.querySelectorAll('joint');
jointElements.forEach(jointEl => {
const jointName = jointEl.getAttribute('name');
const joint = model.joints.get(jointName);
if (joint) {
const limitEl = jointEl.querySelector('limit');
if (limitEl) {
if (!joint.limits) {
joint.limits = new JointLimits();
}
// Read effort and velocity
const effort = limitEl.getAttribute('effort');
const velocity = limitEl.getAttribute('velocity');
if (effort !== null) {
joint.limits.effort = parseFloat(effort);
}
if (velocity !== null) {
joint.limits.velocity = parseFloat(velocity);
}
// Also ensure lower and upper are correctly set
const lower = limitEl.getAttribute('lower');
const upper = limitEl.getAttribute('upper');
if (lower !== null) {
joint.limits.lower = parseFloat(lower);
}
if (upper !== null) {
joint.limits.upper = parseFloat(upper);
}
}
}
});
} catch (error) {
console.error('Failed to supplement joint limit information from XML:', error);
}
}
static convertInertial(inertial) {
const props = new InertialProperties();
if (inertial.mass !== undefined) props.mass = inertial.mass;
if (inertial.origin) {
props.origin = {
xyz: inertial.origin.xyz || [0, 0, 0],
rpy: inertial.origin.rpy || [0, 0, 0]
};
}
if (inertial.ixx !== undefined) props.ixx = inertial.ixx;
if (inertial.iyy !== undefined) props.iyy = inertial.iyy;
if (inertial.izz !== undefined) props.izz = inertial.izz;
if (inertial.ixy !== undefined) props.ixy = inertial.ixy;
if (inertial.ixz !== undefined) props.ixz = inertial.ixz;
if (inertial.iyz !== undefined) props.iyz = inertial.iyz;
return props;
}
/**
* Parse inertial data from URDF XML
* @param {string} xmlContent - URDF XML content
* @returns {Object} Mapping from link names to inertial data
*/
static parseInertialFromXML(xmlContent) {
const inertialData = {};
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlContent, 'text/xml');
// Get all link elements
const links = xmlDoc.getElementsByTagName('link');
for (let i = 0; i < links.length; i++) {
const linkElement = links[i];
const linkName = linkElement.getAttribute('name');
// Find inertial element
const inertialElement = linkElement.getElementsByTagName('inertial')[0];
if (!inertialElement) continue;
const inertial = new InertialProperties();
// Parse mass
const massElement = inertialElement.getElementsByTagName('mass')[0];
if (massElement) {
inertial.mass = parseFloat(massElement.getAttribute('value'));
}
// Parse origin
const originElement = inertialElement.getElementsByTagName('origin')[0];
if (originElement) {
const xyz = originElement.getAttribute('xyz');
const rpy = originElement.getAttribute('rpy');
inertial.origin = {
xyz: xyz ? xyz.split(' ').map(parseFloat) : [0, 0, 0],
rpy: rpy ? rpy.split(' ').map(parseFloat) : [0, 0, 0]
};
} else {
inertial.origin = { xyz: [0, 0, 0], rpy: [0, 0, 0] };
}
// Parse inertia
const inertiaElement = inertialElement.getElementsByTagName('inertia')[0];
if (inertiaElement) {
inertial.ixx = parseFloat(inertiaElement.getAttribute('ixx')) || 0;
inertial.iyy = parseFloat(inertiaElement.getAttribute('iyy')) || 0;
inertial.izz = parseFloat(inertiaElement.getAttribute('izz')) || 0;
inertial.ixy = parseFloat(inertiaElement.getAttribute('ixy')) || 0;
inertial.ixz = parseFloat(inertiaElement.getAttribute('ixz')) || 0;
inertial.iyz = parseFloat(inertiaElement.getAttribute('iyz')) || 0;
}
inertialData[linkName] = inertial;
}
} catch (error) {
console.error('Failed to parse URDF XML inertial data:', error);
}
return inertialData;
}
/**
* Set joint angle (using urdf-loaders' setJointValue method)
* Reference URDFClasses.js setJointValue implementation
*/
static setJointAngle(joint, angle, ignoreLimits = false) {
joint.currentValue = angle;
// URDF format: use urdf-loader's setJointValue method
if (joint.threeObject) {
// If ignoring limits, temporarily modify URDF joint object's limit values
let originalLimits = null;
if (ignoreLimits && joint.threeObject.limit) {
originalLimits = {
lower: joint.threeObject.limit.lower,
upper: joint.threeObject.limit.upper
};
joint.threeObject.limit.lower = -Math.PI * 2;
joint.threeObject.limit.upper = Math.PI * 2;
}
// Prefer setJointValue method (urdf-loader's standard method)
if (typeof joint.threeObject.setJointValue === 'function') {
joint.threeObject.setJointValue(angle);
// Restore original limits
if (originalLimits && joint.threeObject.limit) {
joint.threeObject.limit.lower = originalLimits.lower;
joint.threeObject.limit.upper = originalLimits.upper;
}
return;
} else if (typeof joint.threeObject.setAngle === 'function') {
joint.threeObject.setAngle(angle);
// Restore original limits
if (originalLimits && joint.threeObject.limit) {
joint.threeObject.limit.lower = originalLimits.lower;
joint.threeObject.limit.upper = originalLimits.upper;
}
return;
}
// Restore original limits (if none of the above methods executed)
if (originalLimits && joint.threeObject.limit) {
joint.threeObject.limit.lower = originalLimits.lower;
joint.threeObject.limit.upper = originalLimits.upper;
}
// If none available, manually set rotation
// Note: For URDF, we usually shouldn't reach here, as urdf-loader should provide setJointValue
console.warn(`Joint ${joint.name} has no setJointValue or setAngle method, attempting manual setup`);
if (joint.type === 'revolute' || joint.type === 'continuous') {
const axis = joint.axis ? new THREE.Vector3(...joint.axis.xyz).normalize() : new THREE.Vector3(0, 0, 1);
// Note: joint.threeObject may not be a Three.js object, cannot directly set rotation
if (joint.threeObject.rotation) {
joint.threeObject.rotation.setFromAxisAngle(axis, angle);
}
} else if (joint.type === 'prismatic') {
const axis = joint.axis ? new THREE.Vector3(...joint.axis.xyz).normalize() : new THREE.Vector3(1, 0, 0);
if (joint.threeObject.position) {
joint.threeObject.position.copy(axis.multiplyScalar(angle));
}
}
} else {
console.warn(`Joint ${joint.name} has no threeObject`);
}
}
}

View File

@ -0,0 +1,616 @@
/**
* Xacro Adapter
*
* Parses ROS Xacro files and converts them to URDF format using xacro-parser.
*
* Supported Features:
* - Property definitions and substitutions (xacro:property)
* - Macro definitions with parameters (xacro:macro)
* - Conditional blocks (xacro:if, xacro:unless)
* - File inclusions (xacro:include) with package:// and relative paths
* - Python-style boolean constants (True/False)
* - Arithmetic expressions and property evaluation
*
* Compatibility:
* - ROS Jade and later (inOrder=true, requirePrefix=true, localProperties=true)
* - Automatically injects True/False constants for compatibility with ROS xacro files
*
* Usage:
* - Upload all related xacro files (main file and included files)
* - The adapter automatically resolves file inclusions from the uploaded file map
* - Mesh files are resolved using package:// paths or relative paths
*/
import { XacroParser } from 'xacro-parser';
import { URDFAdapter } from './URDFAdapter.js';
export class XacroAdapter {
/**
* Parse xacro content and convert to unified model
* @param {string} xacroContent - Xacro file content
* @param {string} fileName - Xacro file name (for working path)
* @param {Map} fileMap - File map (path -> File object)
* @param {File} file - Original file object (optional)
* @returns {Promise<UnifiedRobotModel>}
*/
static async parse(xacroContent, fileName, fileMap = null, file = null) {
try {
// Create xacro parser
const parser = new XacroParser();
// Configure parser for ROS Jade and later (default settings)
parser.inOrder = true;
parser.requirePrefix = true;
parser.localProperties = true;
// Set working path (directory where xacro file is located)
const workingPath = fileName.includes('/')
? fileName.substring(0, fileName.lastIndexOf('/') + 1)
: '';
parser.workingPath = workingPath;
// Inject Python-style boolean constants as xacro properties
// Some xacro files use True/False (capitalized) in conditions
xacroContent = this.injectBooleanConstants(xacroContent);
// Extract and set xacro arguments with their default values
// Also add common ROS arguments that might be used without definition
const xacroArgs = this.extractXacroArguments(xacroContent);
// Add common ROS arguments with sensible defaults if not already defined
if (!xacroArgs.hasOwnProperty('DEBUG')) {
xacroArgs.DEBUG = 'false';
}
if (!xacroArgs.hasOwnProperty('SELF_COLLIDE')) {
xacroArgs.SELF_COLLIDE = 'false';
}
parser.arguments = xacroArgs;
// If fileMap provided, setup custom file loader
if (fileMap) {
parser.getFileContents = async (path) => {
return await this.loadFileFromMap(path, fileMap, workingPath);
};
}
// Parse xacro to URDF XML
const urdfXML = await parser.parse(xacroContent);
// Convert XMLDocument to string
const serializer = new XMLSerializer();
let urdfString = serializer.serializeToString(urdfXML);
// Clean up the XML string - remove empty xmlns attributes that might cause issues
urdfString = urdfString.replace(/\sxmlns=""/g, '');
// Re-parse the URDF string with DOMParser to create a clean XMLDocument
// This removes any xacro-specific nodes that urdf-loader might not handle
const domParser = new DOMParser();
const cleanUrdfXML = domParser.parseFromString(urdfString, 'text/xml');
// Check for parsing errors
const parseError = cleanUrdfXML.querySelector('parsererror');
if (parseError) {
throw new Error('Generated URDF has invalid XML: ' + parseError.textContent);
}
// Remove problematic elements that urdf-loader might not handle well
// Remove gazebo elements (plugins, sensors, etc.)
const gazeboElements = cleanUrdfXML.querySelectorAll('gazebo');
gazeboElements.forEach(el => el.parentNode?.removeChild(el));
// Remove transmission elements (these are for Gazebo/ROS control)
const transmissionElements = cleanUrdfXML.querySelectorAll('transmission');
transmissionElements.forEach(el => el.parentNode?.removeChild(el));
// Remove visual/collision elements with empty geometry tags
this.removeEmptyGeometry(cleanUrdfXML);
// Clean up empty text nodes and comments that might cause issues
this.cleanXMLNodes(cleanUrdfXML.documentElement);
// Convert the clean XMLDocument back to string for URDFLoader
const finalUrdfString = serializer.serializeToString(cleanUrdfXML);
// Now use existing URDF loading infrastructure
// Import URDFLoader dynamically
const urdfModule = await import('urdf-loader');
const URDFLoader = urdfModule.URDFLoader || urdfModule.default || urdfModule;
return new Promise((resolve, reject) => {
const loader = new URDFLoader();
loader.parseCollision = true;
// Extract directory where URDF file is located
const urdfDir = workingPath;
// If file map provided, setup resource loader (same as URDF loading)
if (fileMap) {
// Parse URDF content, find all used package names
const packages = this.extractPackagesFromURDF(finalUrdfString);
// Build package map
const packageMap = {};
packages.forEach(pkg => {
packageMap[pkg] = pkg;
});
packageMap[''] = '';
loader.packages = packageMap;
// Set URL Modifier (same as URDF loading)
const urlModifier = (url) => {
// Handle blob URLs
if (url.startsWith('blob:')) {
const blobMatch = url.match(/^blob:https?:\/\/[^\/]+\/(.+)$/);
if (blobMatch && blobMatch[1]) {
const fileName = blobMatch[1];
if (/\.(jpg|jpeg|png|gif|bmp|tga|tiff|webp|dae|stl|obj|gltf|glb)$/i.test(fileName)) {
url = fileName;
} else {
return url;
}
} else {
return url;
}
}
const isTextureFile = /\.(jpg|jpeg|png|gif|bmp|tga|tiff|webp)$/i.test(url);
const isMeshFile = /\.(dae|stl|obj|gltf|glb)$/i.test(url);
let meshPath = url;
// Remove http:// or https:// prefix
if (meshPath.startsWith('http://') || meshPath.startsWith('https://')) {
try {
const urlObj = new URL(meshPath);
meshPath = urlObj.pathname;
if (meshPath.startsWith('/')) {
meshPath = meshPath.substring(1);
}
} catch (e) {
// Invalid URL, use as-is
}
}
// Remove package:// prefix
if (meshPath.startsWith('package://')) {
meshPath = meshPath.replace(/^package:\/\//, '');
const parts = meshPath.split('/');
if (parts.length > 1) {
meshPath = parts.slice(1).join('/');
}
}
// Remove leading ./
meshPath = meshPath.replace(/^\.\//, '');
// Handle relative paths
let normalizedPath = meshPath;
if (meshPath.includes('../')) {
const parts = meshPath.split('/');
const resolvedParts = [];
for (const part of parts) {
if (part === '..') {
resolvedParts.pop();
} else if (part !== '.' && part !== '') {
resolvedParts.push(part);
}
}
normalizedPath = resolvedParts.join('/');
}
// Build full path
const fullPath = urdfDir + normalizedPath;
const altPath = urdfDir + meshPath;
// Find file in fileMap
let matchedFile = fileMap.get(fullPath);
if (!matchedFile && altPath !== fullPath) {
matchedFile = fileMap.get(altPath);
}
if (!matchedFile) {
matchedFile = fileMap.get(normalizedPath);
}
if (!matchedFile) {
matchedFile = fileMap.get(meshPath);
}
if (!matchedFile) {
const targetFileName = normalizedPath.split('/').pop() || meshPath.split('/').pop();
for (const [key, file] of fileMap.entries()) {
const keyFileName = key.split('/').pop();
if (keyFileName === targetFileName) {
matchedFile = file;
break;
}
}
}
if (matchedFile) {
const bloburl = URL.createObjectURL(matchedFile);
return bloburl;
}
return url;
};
loader.manager.setURLModifier(urlModifier);
// Custom loadMeshCb (same as URDF loading)
const originalLoadMeshCb = loader.loadMeshCb || loader.defaultMeshLoader.bind(loader);
loader.loadMeshCb = (path, manager, done) => {
this.findFileInMapByPath(path, fileMap, urdfDir).then(file => {
if (file) {
const ext = (file.name || path).toLowerCase().split('.').pop();
this.loadMeshFileAsync(file, ext, manager).then(meshObject => {
if (meshObject) {
done(meshObject, null);
} else {
done(null, new Error(`Failed to load mesh file: ${path}`));
}
}).catch(err => {
console.error(`Failed to load mesh: ${path}`, err);
done(null, err);
});
} else {
let stlPath = path
stlPath = stlPath.replace('file:///', 'inspection/elfin10')
originalLoadMeshCb(path, manager, done);
}
}).catch(error => {
console.error(`Failed to find file: ${path}`, error);
originalLoadMeshCb(path, manager, done);
});
};
}
// Create temporary URL for URDF content
const blob = new Blob([finalUrdfString], { type: 'text/xml' });
const url = URL.createObjectURL(blob);
loader.load(url, (robot) => {
URL.revokeObjectURL(url);
// Convert to unified model using URDFAdapter
try {
const model = URDFAdapter.convert(robot, finalUrdfString);
resolve(model);
} catch (error) {
console.error('[XacroAdapter] URDF conversion error:', error);
reject(new Error('URDF conversion failed: ' + error.message));
}
}, undefined, (error) => {
URL.revokeObjectURL(url);
console.error('[XacroAdapter] URDF loading error:', error);
reject(new Error('URDF loading failed: ' + (error.message || error)));
});
});
} catch (error) {
console.error('[XacroAdapter] Xacro parsing error:', error);
throw new Error('Xacro parsing failed: ' + error.message);
}
}
/**
* Load file from fileMap for xacro includes
* @param {string} path - File path
* @param {Map} fileMap - File map
* @param {string} workingPath - Working directory
* @returns {Promise<string>}
*/
static async loadFileFromMap(path, fileMap, workingPath) {
// Clean path - remove leading slash if present
let cleanPath = path;
// if (cleanPath.startsWith('/')) {
// cleanPath = cleanPath.substring(1);
// }
// // Remove leading ./
// cleanPath = cleanPath.replace(/^\.\//, '');
cleanPath = cleanPath.split('///')[1];
// Try different path combinations
const possiblePaths = [
cleanPath,
workingPath + cleanPath,
path,
workingPath + path.replace(/^\/+/, ''),
// Also try without the first directory component
cleanPath.includes('/') ? cleanPath.substring(cleanPath.indexOf('/') + 1) : cleanPath,
];
// Try each path
for (const tryPath of possiblePaths) {
const file = fileMap.get(tryPath);
if (file) {
const content = await file.text();
return content;
}
}
// Try filename only match
const fileName = cleanPath.split('/').pop();
for (const [key, file] of fileMap.entries()) {
const keyFileName = key.split('/').pop();
if (keyFileName === fileName) {
const content = await file.text();
return content;
}
}
console.error('[XacroAdapter] Cannot find included file:', path);
throw new Error(`Cannot find included file: ${path}`);
}
/**
* Remove visual/collision elements with empty geometry tags
* xacro-parser may not fully expand conditional geometry (xacro:if)
* We'll just remove these empty visual elements rather than try to fix them
* @param {XMLDocument} xmlDoc - XML document to clean
*/
static removeEmptyGeometry(xmlDoc) {
// Find all geometry elements
const geometryElements = xmlDoc.querySelectorAll('geometry');
geometryElements.forEach(geom => {
// Check if geometry is empty (no child elements)
if (!geom.children || geom.children.length === 0) {
// Find the parent visual or collision element
let parent = geom.parentNode;
if (parent) {
const grandParent = parent.parentNode;
if (grandParent) {
if (parent.nodeName === 'visual' || parent.nodeName === 'collision') {
// Remove empty visual/collision elements
grandParent.removeChild(parent);
}
}
}
}
});
}
/**
* Recursively clean XML nodes - remove empty text nodes and comments
* @param {Element} element - Element to clean
*/
static cleanXMLNodes(element) {
if (!element || !element.childNodes) return;
const nodesToRemove = [];
// Collect nodes to remove
for (let i = 0; i < element.childNodes.length; i++) {
const node = element.childNodes[i];
// Remove comments
if (node.nodeType === Node.COMMENT_NODE) {
nodesToRemove.push(node);
}
// Remove empty or whitespace-only text nodes
else if (node.nodeType === Node.TEXT_NODE) {
if (!node.nodeValue || node.nodeValue.trim() === '') {
nodesToRemove.push(node);
}
}
// Recursively clean element nodes
else if (node.nodeType === Node.ELEMENT_NODE) {
this.cleanXMLNodes(node);
}
}
// Remove collected nodes
nodesToRemove.forEach(node => {
element.removeChild(node);
});
}
/**
* Extract package names from URDF content
* @param {string} urdfContent - URDF content
* @returns {Set<string>}
*/
static extractPackagesFromURDF(urdfContent) {
const packages = new Set();
const packageRegex = /package:\/\/([^\/]+)/g;
let match;
while ((match = packageRegex.exec(urdfContent)) !== null) {
packages.add(match[1]);
}
return packages;
}
/**
* Find file in fileMap by path
* @param {string} path - File path
* @param {Map} fileMap - File map
* @param {string} urdfDir - URDF directory
* @returns {Promise<File|null>}
*/
static async findFileInMapByPath(path, fileMap, urdfDir) {
let meshPath = path;
// Remove blob: prefix
meshPath = meshPath.replace(/^blob:[^\/]+\//, '');
// Remove package:// prefix
if (meshPath.startsWith('package://')) {
meshPath = meshPath.replace(/^package:\/\//, '');
const parts = meshPath.split('/');
if (parts.length > 1) {
meshPath = parts.slice(1).join('/');
}
}
// Remove leading ./
meshPath = meshPath.replace(/^\.\//, '');
// Build full path
const fullPath = urdfDir + meshPath;
// Try full path
let file = fileMap.get(fullPath);
if (file) return file;
// Try path without directory
file = fileMap.get(meshPath);
if (file) return file;
// Try filename match
const targetFileName = meshPath.split('/').pop();
for (const [key, f] of fileMap.entries()) {
const keyFileName = key.split('/').pop();
if (keyFileName === targetFileName) {
return f;
}
}
return null;
}
/**
* Load mesh file asynchronously
* @param {File} file - File object
* @param {string} ext - File extension
* @param {THREE.LoadingManager} manager - Loading manager
* @returns {Promise<THREE.Object3D>}
*/
static async loadMeshFileAsync(file, ext, manager) {
const THREE = await import('three');
const blobUrl = URL.createObjectURL(file);
try {
let meshObject = null;
switch (ext) {
case 'stl': {
const { STLLoader } = await import('three/examples/jsm/loaders/STLLoader.js');
const stlLoader = new STLLoader(manager);
const stlGeometry = await new Promise((resolve, reject) => {
stlLoader.load(blobUrl, resolve, undefined, reject);
});
const stlMaterial = new THREE.MeshPhongMaterial();
meshObject = new THREE.Mesh(stlGeometry, stlMaterial);
break;
}
case 'dae': {
const { ColladaLoader } = await import('three/examples/jsm/loaders/ColladaLoader.js');
const colladaLoader = new ColladaLoader(manager);
const colladaModel = await new Promise((resolve, reject) => {
colladaLoader.load(blobUrl, resolve, undefined, reject);
});
meshObject = colladaModel.scene;
// Remove lights
if (meshObject && meshObject.traverse) {
const lightsToRemove = [];
meshObject.traverse(child => {
if (child.isLight) {
lightsToRemove.push(child);
}
});
lightsToRemove.forEach(light => {
if (light.parent) {
light.parent.remove(light);
}
});
}
break;
}
case 'obj': {
const { OBJLoader } = await import('three/examples/jsm/loaders/OBJLoader.js');
const objLoader = new OBJLoader(manager);
meshObject = await new Promise((resolve, reject) => {
objLoader.load(blobUrl, resolve, undefined, reject);
});
break;
}
case 'gltf':
case 'glb': {
const { GLTFLoader } = await import('three/examples/jsm/loaders/GLTFLoader.js');
const gltfLoader = new GLTFLoader(manager);
const gltfModel = await new Promise((resolve, reject) => {
gltfLoader.load(blobUrl, resolve, undefined, reject);
});
meshObject = gltfModel.scene;
break;
}
default:
console.warn(`Unsupported file format: ${ext}`);
URL.revokeObjectURL(blobUrl);
return null;
}
URL.revokeObjectURL(blobUrl);
return meshObject;
} catch (error) {
URL.revokeObjectURL(blobUrl);
console.error(`Failed to load mesh file: ${file.name}`, error);
throw error;
}
}
/**
* Inject Python-style boolean constants (True/False) into xacro content
* Some xacro files use capitalized True/False in conditional expressions
* The parameters are passed as strings ("True", "False") but compared to constants
* We define the constants to match the string values for comparison to work
* @param {string} xacroContent - Original xacro content
* @returns {string} - Modified xacro content with boolean constants defined
*/
static injectBooleanConstants(xacroContent) {
// Find the robot tag opening
const robotTagMatch = xacroContent.match(/(<robot[^>]*>)/);
if (!robotTagMatch) {
return xacroContent;
}
// Define True/False as string properties for comparison
// When mirror_dae="True" is passed, it becomes the string "True"
// We want ${mirror_dae == True} to work, so True must also be "True"
const booleanProperties = `
<!-- Injected by XacroAdapter: Python-style boolean constants -->
<xacro:property name="True" value="True"/>
<xacro:property name="False" value="False"/>
`;
const insertPosition = robotTagMatch.index + robotTagMatch[0].length;
return xacroContent.substring(0, insertPosition) +
booleanProperties +
xacroContent.substring(insertPosition);
}
/**
* Extract xacro arguments and their default values from xacro content
* Xacro files can define arguments using <xacro:arg name="..." default="..."/>
* These need to be provided to the parser via parser.arguments
* @param {string} xacroContent - Xacro file content
* @returns {Object} - Object with argument names as keys and default values
*/
static extractXacroArguments(xacroContent) {
const args = {};
// Match <xacro:arg name="NAME" default="VALUE"/>
// Also match <arg name="NAME" default="VALUE"/> (without xacro: prefix)
const argPattern = /<(?:xacro:)?arg\s+name=["']([^"']+)["'](?:\s+default=["']([^"']*)["'])?/g;
let match;
while ((match = argPattern.exec(xacroContent)) !== null) {
const argName = match[1];
const defaultValue = match[2] || 'false'; // Default to 'false' if no default specified
args[argName] = defaultValue;
}
return args;
}
}

View File

@ -0,0 +1,46 @@
import request from '@/utils/request'
export function addCategory(data) {
return request({
url: '/tts/corpus/category',
method: 'post',
data: data
})
}
export function getCategoryTreeApi() {
return request({
url: '/tts/corpus/category/tree',
method: 'get'
})
}
export function updateCategoryTreeApi(data) {
return request({
url: '/tts/corpus/category',
method: 'put',
data: data
})
}
export function deleteCategory(id) {
return request({
url: `/tts/corpus/category/${id}`,
method: 'delete',
})
}
export function getCorpusListApi(params) {
return request({
url: '/tts/corpus/list',
method: 'get',
params: params
})
}
export function getDashboardApi() {
return request({
url: '/tts/corpus/dashboard/stats',
method: 'get'
})
}

View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
export function taskApi(data) {
return request({
url: '/tts/task',
method: 'post',
data: data
})
}
export function taskListApi(params) {
return request({
url: '/tts/task/list',
method: 'get',
params: params
})
}
export function getDashboardApi(params) {
return request({
url: '/tts/task/dashboard/stats',
method: 'get'
})
}
export function downloadWavApi(id) {
return request({
url: `/tts/task/audio/${id}`,
method: 'get',
responseType: 'blob'
})
}
export function deleteTask(ids) {
return request({
url: `/tts/task/${ids}`,
method: 'delete'
})
}
export function regenerateApi(id) {
return request({
url: `/tts/task/regenerate/${id}`,
method: 'post'
})
}
export function generalizationApi(data) {
return request({
url: '/tts/task/llm/query',
method: 'post',
data: data
})
}
export function batchTaskApi(data) {
return request({
url: '/tts/task/batch',
method: 'post',
data: data
})
}
export function saveTaskApi(data) {
return request({
url: `/tts/task/save-to-corpus/${data.taskId}/${data.categoryId}`,
method: 'post'
})
}

View File

@ -15,4 +15,12 @@ export function status(data) {
method: 'post', method: 'post',
data: data data: data
}) })
} }
export function clearFault(params) {
return request({
url: '/api/arm/clearFault',
method: 'get',
params
})
}

9
src/api/device/camera.js Normal file
View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getRgbStreamUrl(robotId, deviceId) {
return request({
url: '/api/edge/camera/rgb-stream-url',
method: 'get',
params: { robotId, deviceId }
})
}

View File

@ -1,45 +0,0 @@
import request from '@/utils/request'
// 查询设备配置信息列表
export function listProfile(query) {
return request({
url: '/device/profile/list',
method: 'get',
params: query
})
}
// 查询设备配置信息详细
export function getProfile(query) {
return request({
url: '/device/profile/parameterInfo/',
method: 'get',
params: query
})
}
// 新增设备配置信息
export function addProfile(data) {
return request({
url: '/device/profile',
method: 'post',
data: data
})
}
// 修改设备配置信息
export function updateProfile(data) {
return request({
url: '/device/profile',
method: 'put',
data: data
})
}
// 删除设备配置信息
export function delProfile(id) {
return request({
url: '/device/profile/' + id,
method: 'delete'
})
}

View File

@ -1,146 +0,0 @@
import request from '@/utils/request'
// 查询设备注册列表
export function listRegister(query) {
return request({
url: '/device/register/list',
method: 'get',
params: query
})
}
// 查询设备注册详细
export function getRegister(id) {
return request({
url: '/device/register/' + id,
method: 'get'
})
}
// 新增设备注册
export function addRegister(data) {
return request({
url: '/device/register',
method: 'post',
data: data
})
}
// 修改设备注册
export function updateRegister(data) {
return request({
url: '/device/register',
method: 'put',
data: data
})
}
// 删除设备注册
export function delRegister(id) {
return request({
url: '/device/register/' + id,
method: 'delete'
})
}
// 设备示教
export function deviceTeach(id) {
return request({
url: '/device/profile/' + id,
method: 'get',
})
}
// 设备示教参数修改
export function deviceUpdateProfile(data) {
return request({
url: '/device/profile/updateProfile',
method: 'put',
data: data,
})
}
// 新增音色
export function createTimbre(data) {
return request({
url: '/show/tts/create',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
data: data,
})
}
// 获取音色
export function getTts() {
return request({
url: '/show/tts/query',
headers: {
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
method: 'get',
})
}
// 生产语料
export function createCorpus(data) {
return request({
url: '/show/tts/corpus',
headers: {
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
method: 'post',
data: data
})
}
export function getSynthesize(data, config = {}) {
return request({
url: '/show/tts/synthesize',
headers: {
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
responseType: 'blob',
method: 'post',
data: data
}, {
...config
})
}
export function createAdvancedCorpus(data) {
return request({
url: '/show/tts/corpus/advanced',
headers: {
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
method: 'post',
data: data
})
}
export function getAdvancedSynthesize(data, config = {}) {
return request({
url: '/show/tts/synthesize/advanced',
headers: {
Authorization: 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFiNmEyY2Y0LWM3MjQtNDgyMy1hM2NiLTk4N2NhZWNmMzZiNCJ9.oq-JVRbQuq_ujQ2V0h2jXC3woHPdMQKhnYJ8ixRm-C6Ez4GqJWyHYgmnkw5dbDyhWGdIUH02uv6XT8UiboHD4g',
isToken: false
},
responseType: 'blob',
method: 'post',
data: data
}, {
...config
})
}
export const getFlowById = (id) => {
return request.get(import.meta.env.VITE_NODE_RED_URL + '/flow/' + id, {})
}

View File

@ -1,44 +0,0 @@
import request from '@/utils/request'
// 查询机器人配置列表
export function listRobot(query) {
return request({
url: '/device/robot/list',
method: 'get',
params: query
})
}
// 查询机器人配置详细
export function getRobot(id) {
return request({
url: '/device/robot/' + id,
method: 'get'
})
}
// 新增机器人配置
export function addRobot(data) {
return request({
url: '/device/robot',
method: 'post',
data: data
})
}
// 修改机器人配置
export function updateRobot(data) {
return request({
url: '/device/robot',
method: 'put',
data: data
})
}
// 删除机器人配置
export function delRobot(id) {
return request({
url: '/device/robot/' + id,
method: 'delete'
})
}

31
src/api/device/system.js Normal file
View File

@ -0,0 +1,31 @@
import request from '@/utils/request'
export function getSafetyState(robotId) {
return request({
url: '/api/system/safetyState',
method: 'get',
params: { robotId },
})
}
/**
* 恢复机器人运行状态;payload 与旧 recoverSafetyState 保持一致,便于调用方渐进迁移。
*/
export function restoreOperationalState(data) {
return request({
url: '/api/system/restoreOperationalState',
method: 'post',
data,
})
}
/**
* @deprecated 请改用 restoreOperationalState,旧接口仅保留给未迁移调用方。
*/
export function recoverSafetyState(data) {
return request({
url: '/api/system/recoverSafetyState',
method: 'post',
data,
})
}

View File

@ -1,86 +0,0 @@
import request from '@/utils/request'
// 查询设备终端配置列表
export function listTerminal(query) {
return request({
url: '/device/terminal/list',
method: 'get',
params: query
})
}
// 查询设备终端配置详细
export function getTerminal(id) {
return request({
url: '/device/terminal/' + id,
method: 'get'
})
}
// 新增设备终端配置
export function addTerminal(data) {
return request({
url: '/device/terminal',
method: 'post',
data: data
})
}
// 修改设备终端配置
export function updateTerminal(data) {
return request({
url: '/device/terminal',
method: 'put',
data: data
})
}
// 删除设备终端配置
export function delTerminal(id) {
return request({
url: '/device/terminal/' + id,
method: 'delete'
})
}
// 获取实例信息
export function getInstInfo(id) {
return request({
url: '/test/inst/context/' + id,
method: 'get'
})
}
// 暂停任务
export function pauseInst(id) {
return request({
url: `/test/inst/pause/${id}`,
method: 'post'
})
}
// 恢复任务
export function resumeInst(id) {
return request({
url: `/test/inst/resume/${id}`,
method: 'post'
})
}
// 恢复任务
export function stopInst(id) {
return request({
url: `/test/inst/stop/${id}`,
method: 'post'
})
}
export function getFlowParamsApi(taskId) {
return request({
url: '/test/orchestration',
method: 'get',
params: {
taskId
}
})
}

View File

@ -9,6 +9,34 @@ export function flowDeploy(data) {
}) })
} }
export function flowSaveDraft(data) {
return request({ url: '/flow/draft', method: 'put', data })
}
export function flowVersionList(itemId) {
return request({ url: `/flow/versions/${itemId}`, method: 'get' })
}
export function flowVersionDetail(versionId) {
return request({ url: `/flow/version/${versionId}`, method: 'get' })
}
export function flowSubFlowOptions(currentItemId) {
return request({
url: '/flow/subflows',
method: 'get',
params: { currentItemId }
})
}
export function flowRestoreDraft(versionId, data) {
return request({ url: `/flow/version/${versionId}/restore-draft`, method: 'post', data })
}
export function flowRollbackVersion(versionId, data) {
return request({ url: `/flow/version/${versionId}/rollback`, method: 'post', data })
}
export function flowExecute(data) { export function flowExecute(data) {
return request({ return request({
url: '/flow/execute', url: '/flow/execute',
@ -68,4 +96,28 @@ export function getArmStatus(params) {
method: 'get', method: 'get',
params: params params: params
}) })
} }
export function getAgvStatus(params) {
return request({
url: '/api/agv/getRuntimeState',
method: 'get',
params: params
})
}
export function getAgvStations(params) {
return request({
url: '/api/agv/listStations',
method: 'get',
params: params
})
}
export function getArmJointState(params) {
return request({
url: '/api/arm/getJointState',
method: 'get',
params: params
})
}

5
src/api/flow/nodeRed.js Normal file
View File

@ -0,0 +1,5 @@
import request from '@/utils/request'
export function getNodeRedFlowById(id) {
return request.get(`${import.meta.env.VITE_NODE_RED_URL}/flow/${id}`, {})
}

View File

@ -0,0 +1,97 @@
import request from '@/utils/request'
export function getPoseApi(params) {
return request({
url: '/api/arm/getPose',
method: 'get',
params: params
})
}
export function getJointStateApi(params) {
return request({
url: '/api/arm/getJointState',
method: 'get',
params: params
})
}
export function speedLApi(data) {
return request({
url: '/api/arm/speedL',
method: 'post',
data: data
})
}
export function moveJApi(data) {
return request({
url: '/api/arm/moveJ',
method: 'post',
data: data
})
}
export function stopMotionApi(params) {
return request({
url: '/api/arm/stopMotion',
method: 'get',
params: params
})
}
export function torqueOnApi(params) {
return request({
url: '/api/arm/torqueOn',
method: 'get',
params: params
})
}
export function speedJApi(data) {
return request({
url: '/api/arm/speedJ',
method: 'post',
data: data
})
}
export function clearFault(params) {
return request({
url: '/api/arm/clearFault',
method: 'get',
params: params
})
}
export function getMicVolume(params) {
return request({
url: '/api/Microphone/volume',
method: 'get',
params: params
})
}
export function setMicVolume(data) {
return request({
url: '/api/Microphone/volume',
method: 'post',
data: data
})
}
export function getSpeakerVolume(params) {
return request({
url: '/api/Speaker/volume',
method: 'get',
params: params
})
}
export function setSpeakerVolume(data) {
return request({
url: '/api/Speaker/volume',
method: 'post',
data: data
})
}

View File

@ -1,33 +0,0 @@
import request from '@/utils/request'
export function getMapList(params) {
return request({
url: '/inspection/map/list',
method: 'get',
params: params
})
}
export function addMap(data) {
return request({
url: '/inspection/map',
method: 'post',
data: data
})
}
export function updateMap(data) {
return request({
url: '/inspection/map',
method: 'put',
data: data
})
}
export function deleteMap(id) {
return request({
url: `/inspection/map/${id}`,
method: 'delete'
})
}

View File

@ -29,4 +29,11 @@ export function deletePoint(id) {
url: `/inspection/waypoint/${id}`, url: `/inspection/waypoint/${id}`,
method: 'delete' method: 'delete'
}) })
} }
export function copyPoint(id) {
return request({
url: `/inspection/waypoint/copy/${id}`,
method: 'post'
})
}

View File

@ -0,0 +1,23 @@
import request from '@/utils/request'
/**
* 查询巡检结果列表。
*/
export function getInspectionResultList(params) {
return request({
url: '/inspection/result/list',
method: 'get',
params
})
}
/**
* 提交人工复核结果。
*/
export function reviewInspectionResult(id, data) {
return request({
url: `/inspection/result/${id}/review`,
method: 'put',
data
})
}

View File

@ -1,57 +0,0 @@
import request from '@/utils/request'
export function getRobotList(params) {
return request({
url: '/inspection/robot/list',
method: 'get',
params: params
})
}
export function addRobot(data) {
return request({
url: '/inspection/robot',
method: 'post',
data: data
})
}
export function updateRobot(data) {
return request({
url: '/inspection/robot',
method: 'put',
data: data
})
}
export function deleteRobot(id) {
return request({
url: `/inspection/robot/${id}`,
method: 'delete'
})
}
/**
* 获取机器人地图
* @param {*} robotId
* @returns
*/
export function getMapByRobot(robotId) {
return request({
url: `/inspection/robot/${robotId}/maps`,
method: 'get'
})
}
/**
* 获取地图JSON数据
* @param {*} params
* @returns
*/
export function getMapJson(params) {
return request({
url: `/inspection/robot/${params.robotId}/download-map`,
method: 'get',
params
})
}

View File

@ -38,10 +38,18 @@ export function deleteRunTask(id) {
}) })
} }
export function startRunTask(id) { export function startRunTask(id, data) {
return request({ return request({
url: `/inspection/taskInstance/start/${id}`, url: `/inspection/taskInstance/start/${id}`,
method: 'put' method: 'put',
data
})
}
export function rerunRunTask(id) {
return request({
url: `/inspection/taskInstance/rerun/${id}`,
method: 'post'
}) })
} }
@ -72,4 +80,4 @@ export function getTaskLogListApi(params) {
method: 'get', method: 'get',
params: params params: params
}) })
} }

View File

@ -44,4 +44,11 @@ export function bindWaypointsToTask(taskId, waypointIds) {
method: 'post', method: 'post',
data: waypointIds data: waypointIds
}) })
} }
export function copyTask(id) {
return request({
url: `/inspection/task/copy/${id}`,
method: 'post'
})
}

View File

@ -1,5 +1,4 @@
import request from '@/utils/request' import request from '@/utils/request'
import { method } from 'lodash'
export function addTaskinstance(data) { export function addTaskinstance(data) {
return request({ return request({
@ -27,15 +26,23 @@ export function updateTaskinstance(data) {
export function deleteTaskinstance(ids) { export function deleteTaskinstance(ids) {
return request({ return request({
url: `/aima/taskinstance/{ids}`, url: `/aima/taskinstance/${ids}`,
method: 'delete' method: 'delete'
}) })
} }
export function startTaskinstance(id) { export function startTaskinstance(id, data) {
return request({ return request({
url: `/aima/taskinstance/start/${id}`, url: `/aima/taskinstance/start/${id}`,
method: 'put' method: 'put',
data
})
}
export function rerunTaskinstance(id) {
return request({
url: `/aima/taskinstance/rerun/${id}`,
method: 'post'
}) })
} }
@ -66,4 +73,4 @@ export function getTaskLogListApi(params) {
method: 'get', method: 'get',
params: params params: params
}) })
} }

View File

@ -44,4 +44,11 @@ export function bindTastCase(taskId, ids) {
method: 'post', method: 'post',
data: ids data: ids
}) })
} }
export function copyTask(id) {
return request({
url: `/aima/task/copy/${id}`,
method: 'post'
})
}

View File

@ -29,4 +29,11 @@ export function deleteTestCase(ids) {
url: `/aima/testcase/${ids}`, url: `/aima/testcase/${ids}`,
method: 'delete' method: 'delete'
}) })
} }
export function copyTestCase(id) {
return request({
url: `/aima/testcase/copy/${id}`,
method: 'post'
})
}

View File

@ -39,6 +39,15 @@ export function getInfo() {
}) })
} }
// 解锁屏幕
export function unlockScreen(password) {
return request({
url: '/unlockscreen',
method: 'post',
data: { password }
})
}
// 退出方法 // 退出方法
export function logout() { export function logout() {
return request({ return request({

View File

@ -0,0 +1,13 @@
import request from '@/utils/request'
export function listResourceDevices(params) {
return request({ url: '/resource/devices', method: 'get', params })
}
export function getResourceDevice(id) {
return request({ url: `/resource/devices/${encodeURIComponent(id)}`, method: 'get' })
}
export function updateResourceDevice(id, data) {
return request({ url: `/resource/devices/${encodeURIComponent(id)}`, method: 'put', data })
}

Some files were not shown because too many files have changed in this diff Show More