找回密码
 立即注册
查看: 184|回复: 1

URDF模型验证(Unity篇)

[复制链接]
发表于 2022-11-14 08:02 | 显示全部楼层 |阅读模式
一、简介

导出URDF模型后,我们需要验证导出模型的正确性,但以往都是在ROS下的Gazebo上进行验证,这就导致我们需要在WindowsUbuntu间来回切换,为简化流程,本文将介绍在windows下Unity里的验证方法。
二、Unity验证流程

2.1 Unity&Robotics简介




众所周知,Unity是一个综合型游戏开发引擎,可以创建2D或3D游戏,渲染交互式动画,格式化建筑,也能做VR/AR。随着数字孪生的热门,Unity也着手开发了机器人的版块。

  • 官方主页
  • Github地址
大家可能会疑惑一个游戏开发引擎,如何能够开发高精度机器人仿真板块,其实,Unity目前集成了Nvidia Physx4的底层物理引擎,同时支持TGS解算器,于2020年更新的Articulation Body更是把机器人物理仿真的稳定性大大提升(...答主在这一波版本更新之后才顺利完成的毕设);考虑到机器人老牌ROS系统的应用,Unity开发者也做了大量的工作,开发了高效低延时的Unity&ROS通讯系统。总之,目前Unity&Robotics是一个较为完善的机器人仿真系统,也具备良好的开发生态。
2.2 验证流程

首先将模型导入到Unity里,这里会用到Unity的插件URDF Importer, 按照Github上的流程便能顺利安装,如果因网络问题从Git URL下载不下来,可以先下载这个Repo,再手动安装即可。
安装结束后,将导出的模型文件拖到Asset文件下,这里需要注意一下文件的层级关系,推荐以下层级。
-Asset
\quad-URDF
\quad\quad-materials
\quad\quad-meshes
\quad\quad-robot.urdf



按照如上层级安排好后,注意下URDF文件里mesh和material的目录位置,可直接改为../meshes/yourMesh.stl和../materials/yourMat.dae,然后便可顺利导入模型。



导入后,检查模型是否有缺失,若有缺失可查看meshs文件夹的模型,一般mesh模型文件为1kb大小的基本确定导出有错误,可参考我的上一篇文章进行修改。之后检查关节的正确性,导入后模型初始会配有两个组件,基础组件Urdf Robot和默认控制器Controller,这个默认控制器个人觉得不是很好用,后面我会将自用的控制器分享给大家。



下面以四足机器人为例介绍检查关节的流程,第一步先点击Urdf Robot组件的Generate为各个关节生成名字,然后设置baselink的属性,选择四足的驱干link,勾选Is Base Link和Immovable,然后拖动模型悬空,此时模型是可以维持悬空状态,由于没有设置关节属性,所以关节“无力”摆动着。



下一步配置关节属性,上面提到目前Unity里机器人各个link是以Articulation Body的形式存在的,关节驱动叫ArticulationDrive,可能大家很陌生,实际上它就是一个简单的Stiffness&Damping驱动控制,或者叫它PD控制器,驱动力的计算方式如下:
F = stiffness * (currentPosition - target) - damping * (currentVelocity - targetVelocity)



每一个关节ArticulationDrive有如上属性需要设置,比较关键的有关节上下限、PD控制器参数以及力的限制,这些参数可在父节点控制器统一设置,完整控制器代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Robotics.UrdfImporter;

public class JointTest : MonoBehaviour
{
    //PD参数设置有两种方式,isJointSame = true各个关节参数一样,为false可自定义关节参数
    public bool isJointSame = true;
    public float sameStiffness = 0.0f;
    public float sameDamping = 0.0f;
    public float [] stiffness;
    public float [] damping;
    //以下的参数均是默认统一设置
    public float linearDamping = 0.0f;
    public float angularDamping = 0.0f;
    public float jointFriction = 0.0f;
    public float forceLimit = 100.0f;
    public float velocityLimit = 1000.0f;
    //可在该组件下设置各关节目标角度并记录当前真实角度
    public float [] targetPos;
    public float [] currentPos;

    private ArticulationBody[] articulationChain;
    private ArticulationBody[] joints;
   
    private int numAction = 0;
    private int cnt = 0;

    void Start()
    {
        articulationChain = this.GetComponentsInChildren<ArticulationBody>();
        List<ArticulationBody> jointlist = new List<ArticulationBody>();
        foreach (ArticulationBody joint in articulationChain)
        {
            //fixed类型关节或baselink节点无自由度,不参与关节设置
            if(joint.jointPosition.dofCount>0)
            {   
                joint.jointFriction = jointFriction;
                joint.angularDamping = angularDamping;
                joint.linearDamping = linearDamping;
                joint.maxJointVelocity = velocityLimit;

                ArticulationDrive currentDrive = joint.xDrive;
                currentDrive.forceLimit = forceLimit;
                //两种PD参数设置
                if(isJointSame){
                    currentDrive.stiffness = sameStiffness;
                    currentDrive.damping = sameDamping;
                }
                else{
                    currentDrive.stiffness = stiffness[cnt];
                    currentDrive.damping = damping[cnt];
                    cnt++;
                }
                joint.xDrive = currentDrive;
                //监视器观察关节名称,方便Debug
                Debug.Log(joint.name);
                jointlist.Add(joint);
            }
        }
        numAction = jointlist.Count;
        joints = jointlist.ToArray();
    }
    //每一帧设置目标关节角
    void Update()
    {
        acquireDofPos();
        for (int i = 0; i < numAction; i++)
        {
            ArticulationDrive currentDrive = joints.xDrive;
            currentDrive.target = targetPos;
            joints.xDrive = currentDrive;
        }        
    }
    //获取真实关节角度
    void acquireDofPos()
    {
        for (int i = 0; i < joints.Length; i++)
        {
            ArticulationBody joint = joints;
            float rad = joint.jointPosition[0];
            currentPos = rad*Mathf.Rad2Deg;
        }
    }
}



将上述控制器组件替换默认控制器组件,根据仿真模型设置关节驱动参数,更改各关节目标角度值,可检查关节运动方向的正确性。若关节旋转轴以及旋转方向错误,可在URDF文件里尝试修改,不行再考虑重新导出。



总结

本文介绍了在Unity里如何检验URDF的正确性,免去因模型问题来回切换系统的烦恼,简化流程,提升工作效率。同时推荐下Unity的机器人仿真,作为一个游戏引擎,它的内容设计与场景搭建是十分便利的,游戏涉及的脚本功能可以囊括机器人仿真需求,底层Physx4物理引擎提供高精度的模拟,Unity&Robotics也是开发人员准备长期维护的一个项目,项目资源的稳定更新也给与Researcher信心,是一个不错的选择。
感谢看到这里,下一篇将介绍在Mujoco里如何检验仿真模型的正确性。
本文使用 Zhihu On VSCode 创作并发布

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-11-14 08:07 | 显示全部楼层
unity的URDF插件GitHub下载不了?
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-30 07:00 , Processed in 0.091778 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表