URDFLoader简介

课程链接:www.bilibili.com/cheese/play...

课程目标

  • 认识urdf
  • 使用urdf-loader 加载urdf 模型
  • 了解urdf-loader 无法实现的功能

1-URDF 简介

URDF(Unified Robot Description Format,统一机器人描述格式)是一种基于 XML 的文件格式,用于描述机器人的结构、关节、连杆、传感器等物理和运动学属性。

示例

xml 复制代码
<?xml version="1.0"?>
<robot name="multipleshapes">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>
    
  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
  </joint>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
    </visual>
  </link>
</robot>

效果如下:

URDF文件可以通过父子关系架构出一棵图形树,从而实现父关节带动子关节的运动。

  • link 译作连杆,是机器人的刚性部件,它是有实际模型的。
  • joint 译作关节,可暂且将其理解为一个坐标系的概念,它不是一个实物,它连接着2个link。
  • URDF图形树不会闭环。
  • link 的子节点只能是joint,joint的子节点只能是link。
  • 1个link可以有多个joint子级,但只能有1个joint父级。
  • 1个joint只能有1个link子级,1个link父级。

大家可以在ros2 的官方文档看到更多关于URDF的介绍。

2-urdf-loader 的下载

urdf-loader 是由Garrett Johnson 开发的一个用于加载urdf 文件的工具。

urdf-loader 的js 版本是基于three.js 开发的。

接下来咱们说一下其具体的用法。

1.我们可以直接把urdf-loader 下载下来看看。

bash 复制代码
git clone https://github.com/gkjohnson/urdf-loaders.git

2.在urdf-loaders中运行以下命令。

bash 复制代码
#进入项目
cd javascript

#安装依赖
npm i

#启动项目
npm start

3.查看项目案例。

注:在实际开发中,我们一般是用npm 安装urdf-loader的。

css 复制代码
npm i urdf-loader

urdf-loader 在github 中的案例适合我们去学习其用法。

3-urdf-loader 的基本用法

我们可以去 javascript/example/src/simple.js 里看一下urdf-loader 基础版的用法。

urdf-loader 是基于three.js 开发的,three.js 场景的搭建我就不在多说了,咱们直接看urdf-loader 部分。

ini 复制代码
let robot;
const manager = new LoadingManager();
const loader = new URDFLoader(manager);
loader.load('../../../urdf/T12/urdf/T12_flipped.URDF', result => {
    robot = result;
});
// wait until all the geometry has loaded to add the model to the scene
manager.onLoad = () => {
    robot.rotation.x = Math.PI / 2;
    robot.traverse(c => {
        c.castShadow = true;
    });
    for (let i = 1; i <= 6; i++) {
        robot.joints[`HP${ i }`].setJointValue(MathUtils.degToRad(30));
        robot.joints[`KP${ i }`].setJointValue(MathUtils.degToRad(120));
        robot.joints[`AP${ i }`].setJointValue(MathUtils.degToRad(-60));
    }
    robot.updateMatrixWorld(true);
    const bb = new Box3();
    bb.setFromObject(robot);
    robot.position.y -= bb.min.y;
    scene.add(robot);
};

解释代码

1.URDFLoader 就是urdf 加载工具。

2.urdf 的加载监听。

ini 复制代码
const loader = new URDFLoader(manager);
loader.load('../../../urdf/T12/urdf/T12_flipped.URDF', result => {
    robot = result;
});

URDFLoader的load 可以监听urdf 文件的加载,在其回调函数中的robot 就是将urdf 解析后的three.js 图形对象。

但是此时的robot图形对象里还没有真正的模型,真正的模型需要等模型文件加载完成之后,才能被添加到robot。

3.使用LoadingManager 监听所有文件的加载。

在urdf 文件中,一般会关联着许多的子文件,如模型文件、贴图文件等。

如下面的 中,就关联着一个Body.STL 模型。

xml 复制代码
<link name="Body">
    ...
    <visual>
      ...
      <geometry>
          <mesh filename="../meshes/Body.STL" />
      </geometry>
      ...
    </visual>
</link>

因此,URDFLoader 需要LoadingManager 监听所有文件是否都加载成功。

manager.onLoad() 就是所有文件都加载成功后触发的方法。

ini 复制代码
const loader = new URDFLoader(manager);
manager.onLoad = () => {
    ...
}

在URDFLoader的源码中,所有子文件的加载都是受LoadingManager 管理的。

ini 复制代码
const loader = new THREE.TextureLoader(manager);
const loader = new STLLoader(manager);

3.适配模型坐标系。

在urdf 的坐标系中,一般z轴是朝上的。

而在three.js 的坐标系中,y 轴是朝上的。

因此,在上面的代码中,将robot 绕x轴旋转了90度。

ini 复制代码
robot.rotation.x = Math.PI / 2;

4.通过robot.traverse() 方法调整robot中的模型。

ini 复制代码
robot.traverse(c => {
    c.castShadow = true;
});

在此方法里,我们可以设置模型的各种属性,比如材质。

5.robot.joints`HP${ i }`.setJointValue() 演示了根据关节名设置关节的旋转弧度的方法。

6.将模型最底部的位置对齐到地面,也就是高度为0 的位置。

ini 复制代码
const bb = new Box3();
bb.setFromObject(robot);
robot.position.y -= bb.min.y;

4-URDF 模型的拖拽控制

在完整版示例里,我们可以使用鼠标拖拽URDF模型的link,使其绕父关节旋转。

在javascript/src/urdf-manipulator-element.js 中可以看到拖拽相关的代码。

kotlin 复制代码
const dragControls = new PointerURDFDragControls(this.scene, this.camera, el);
dragControls.onDragStart = joint => {
    this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: joint.name }));
    this.controls.enabled = false;
    this.redraw();
};
dragControls.onDragEnd = joint => {
    this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: joint.name }));
    this.controls.enabled = true;
    this.redraw();
};
dragControls.updateJoint = (joint, angle) => {
    this.setJointValue(joint.name, angle);
};
dragControls.onHover = joint => {
    highlightLinkGeometry(joint, false);
    this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: joint.name }));
    this.redraw();
};
dragControls.onUnhover = joint => {
    highlightLinkGeometry(joint, true);
    this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: joint.name }));
    this.redraw();
};

解释代码

PointerURDFDragControls 是urdf-loader项目封装好的拖拽控制对象。

kotlin 复制代码
const dragControls = new PointerURDFDragControls(this.scene, this.camera, el);

在拖拽过程中,PointerURDFDragControls 会触发以下事件:

  • onDragStart 拖拽开始
  • onDragEnd 拖拽结束
  • updateJoint 关节的弧度发生改变
  • onHover 鼠标划入
  • onUnhover 鼠标划出

当前案例在onDragStart 和onDragEnd 中会控制了OrbitControls 的有效性,避免相机轨道的拖拽和关节拖拽的冲突;

在updateJoint 中实现了关节旋转和dom表单的同步更新;

在onHover 和onUnhover 中实现了鼠标划上的物体的高亮。

5-urdf-loader 无法实现的功能

在实际的工作中,urdf-loader 并不能满足所有的开发需求,而能否实现机器人可视化中灵活多变的需求,会决定你在相关领域的专业程度。

接下来给大家分享几个我在实际工作中常见的需求:

  • 适配urdf 文件中不同类型的资源路径。
xml 复制代码
<geometry>
    <mesh filename="package://example-robot-data/robots/panda_description/meshes/visual/finger.stl" />
</geometry>
  • 鼠标划上模型时,提示link 信息、离link 最近的父级或祖父级的可活动的joint 信息。

  • 在拖拽机器人关节的时候,显示关节的变换轨迹。

  • 显示机器人的坐标系、碰撞体、质心和惯性矩。

  • 机器人实时动画缓冲功能。

总结

这一课我们认识了URDF 文件的基本结构,知道了通过urdf-loader加载和渲染URDF 模型的方法,以及如何拖拽旋转URDF关节。

与此同时,我还说了urdf-loader 无法实现的一些功能,这些功能就是我们接下来的课程重点。

相关推荐
前端之虎陈随易8 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he8 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
kyriewen8 小时前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒8 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
陈天伟教授8 小时前
FreeCAD 启动后小窗口闪现即退的解决思路
人工智能·机器人·工业设计
workflower9 小时前
设备单元级(L1)实施路径
人工智能·线性代数·矩阵·机器人·开源
大圣编程10 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang10 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆10 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜11 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端