[ROS 系列学习教程] 建模与仿真 - URDF 建模实践

news2024/12/28 4:12:43

在这里插入图片描述

ROS 系列学习教程(总目录)

本文目录

  • 一、机器人结构组成
  • 二、新建功能包
  • 三、编写launch文件
  • 四、创建底盘
  • 五、添加轮子
  • 六、添加其他部件
  • 七、解决部分实体位于地面以下的问题

前文介绍了URDF建模与URDF语法,接下来介绍怎么使用URDF从零构建一个机器人模型并在rviz中显示。

一、机器人结构组成

最终效果如下图:

在这里插入图片描述

机器人由如下部分组成:

  • 底盘 * 1
  • 主动轮 * 2
  • 从动轮(脚轮)* 2
  • 激光雷达 * 1
  • RGB相机 * 1

二、新建功能包

为面向零基础的同学,使教学清晰,新建一个功能包用于学习该章节,新建功能包方法见前文,功能包结构如下:

在这里插入图片描述

其中,

  • config :存放rviz配置文件
  • launch :存放launch文件
  • meshes :存放模型渲染文件
  • models :存放模型文件
  • src与include :存放源文件和头文件

关于ROS工作空间与功能包的创建,详见 ROS Hello World

三、编写launch文件

如前文所述,rviz显示urdf模型需要先把模型参数注册到参数服务器,然后打开rviz,在rviz中配置好后才能正常显示模型。这些步骤可以手动一步一步完成,也可以编写launch文件快速执行。

另外,对于包含多个link的模型,需要发布link间的jointtf关系,以使rviz可以确定link间的空间位置。ROS提供了 joint_state_publisherrobot_state_publisher 两个功能包来实现linkjointtf关系的发布,如没有安装这两个功能包,可以使用如下命令安装(以noetic为例):

sudo apt install ros-noetic-joint-state-publisher
sudo apt install ros-noetic-robot-state-publisher

launch文件内容如下:

<launch>
    <param name="robot_description" textfile="$(find simulation_learning)/models/urdf/mbot_base.urdf" />

    <!-- 设置GUI参数,显示关节控制插件 -->
    <param name="use_gui" value="true" />

    <!-- 运行joint_state_publisher节点,发布机器人的关节状态  -->
    <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />

    <!-- 运行robot_state_publisher节点,发布tf  -->
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />

    <!-- 运行rviz可视化界面,并加载配置 -->
    <node name="rviz" pkg="rviz" type="rviz" args="-d $(find simulation_learning)/config/mbot_urdf.rviz" required="true" />
</launch>

关于launch文件的具体描述,见[4.1 launch文件](#4.1 launch文件)

四、创建底盘

models/urdf中创建mbot_base.urdf文件,用于编写urdf模型。

底盘是一个圆柱体,半径为 0.2m,高为0.16m,urdf代码如下:

<?xml version="1.0"?>
<robot name="mbot">
    <link name="base_link">
        <visual>
            <origin xyz=" 0 0 0" rpy="0 0 0" />
            <geometry>
                <cylinder length="0.16" radius="0.20" />
            </geometry>
            <material name="yellow">
                <color rgba="1 0.4 0 1" />
            </material>
        </visual>
    </link>
</robot>

运行 launch 文件,结果如下:

在这里插入图片描述

这里注意base_link的原点位于圆柱体的几何中心,即有一半圆柱体是位于地面以下的,这一点到最后会解决,目前先把机器人模型搭建起来。

五、添加轮子

轮子是小一点的圆柱体,半径为 0.06m,高为0.025m

现在有了两个实体,底盘和一个轮子,需要使用joint说明他们之间的几何与运动关系,否则rviz解析urdf时会报错。

urdf代码如下:

<!-- 底盘实体描述 -->
<link name="base_link">
    <visual>
        <origin xyz=" 0 0 0" rpy="0 0 0" />
        <geometry>
            <cylinder length="0.16" radius="0.20" />
        </geometry>
        <material name="yellow">
            <color rgba="1 0.4 0 1" />
        </material>
    </visual>
</link>

<!-- 左轮与底盘的关节描述 -->
<joint name="left_wheel_joint" type="continuous">
    <origin xyz="0 0.19 -0.05" rpy="0 0 0" />
    <parent link="base_link" />
    <child link="left_wheel_link" />
    <axis xyz="0 1 0" />
</joint>

<!-- 左轮实体描述 -->
<link name="left_wheel_link">
    <visual>
        <origin xyz="0 0 0" rpy="1.5707 0 0" />
        <geometry>
            <cylinder radius="0.06" length="0.025" />
        </geometry>
        <material name="white">
            <color rgba="1 1 1 0.9" />
        </material>
    </visual>
</link>

其中,joint中的type描述了关节类型(机械中的运动副),该类型为旋转类型(机械中的旋转副),origin表示左轮原点相对于底盘原点的空间位姿偏移,parentchild分别表示该关节的父实体和子实体,由于该关节为旋转关节,使用axis定义旋转轴。关于joint的具体描述见 建模与仿真 - URDF 语法介绍。

运行 launch 文件,结果如下:

在这里插入图片描述

六、添加其他部件

其他部件同理,添加实体与相应的关节描述。

完整的urdf代码如下:

<?xml version="1.0"?>
<robot name="mbot">

    <!-- 底盘实体描述 -->
    <link name="base_link">
        <visual>
            <origin xyz=" 0 0 0" rpy="0 0 0" />
            <geometry>
                <cylinder length="0.16" radius="0.20" />
            </geometry>
            <material name="yellow">
                <color rgba="1 0.4 0 1" />
            </material>
        </visual>
    </link>

    <!-- 左轮与底盘的关节描述 -->
    <joint name="left_wheel_joint" type="continuous">
        <origin xyz="0 0.19 -0.05" rpy="0 0 0" />
        <parent link="base_link" />
        <child link="left_wheel_link" />
        <axis xyz="0 1 0" />
    </joint>

    <!-- 左轮实体描述 -->
    <link name="left_wheel_link">
        <visual>
            <origin xyz="0 0 0" rpy="1.5707 0 0" />
            <geometry>
                <cylinder radius="0.06" length="0.025" />
            </geometry>
            <material name="white">
                <color rgba="1 1 1 0.9" />
            </material>
        </visual>
    </link>

    <!-- 右轮与底盘的关节描述 -->
    <joint name="right_wheel_joint" type="continuous">
        <origin xyz="0 -0.19 -0.05" rpy="0 0 0" />
        <parent link="base_link" />
        <child link="right_wheel_link" />
        <axis xyz="0 1 0" />
    </joint>

    <!-- 右轮实体描述 -->
    <link name="right_wheel_link">
        <visual>
            <origin xyz="0 0 0" rpy="1.5707 0 0" />
            <geometry>
                <cylinder radius="0.06" length="0.025" />
            </geometry>
            <material name="white">
                <color rgba="1 1 1 0.9" />
            </material>
        </visual>
    </link>

    <!-- 前脚轮实体描述 -->
    <joint name="front_caster_joint" type="continuous">
        <origin xyz="0.18 0 -0.095" rpy="0 0 0" />
        <parent link="base_link" />
        <child link="front_caster_link" />
        <axis xyz="0 1 0" />
    </joint>

    <!-- 前脚轮和底盘的关节描述 -->
    <link name="front_caster_link">
        <visual>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <geometry>
                <sphere radius="0.015" />
            </geometry>
            <material name="black">
                <color rgba="0 0 0 0.95" />
            </material>
        </visual>
    </link>

    <!-- 后脚轮实体描述 -->
    <joint name="back_caster_joint" type="continuous">
        <origin xyz="-0.18 0 -0.095" rpy="0 0 0" />
        <parent link="base_link" />
        <child link="back_caster_link" />
        <axis xyz="0 1 0" />
    </joint>

    <!-- 后脚轮和底盘的关节描述 -->
    <link name="back_caster_link">
        <visual>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <geometry>
                <sphere radius="0.015" />
            </geometry>
            <material name="black">
                <color rgba="0 0 0 0.95" />
            </material>
        </visual>
    </link>

    <!-- 激光雷达实体描述 -->
    <link name="laser_link">
        <visual>
            <origin xyz=" 0 0 0 " rpy="0 0 0" />
            <geometry>
                <cylinder length="0.05" radius="0.05" />
            </geometry>
            <material name="gray">
                <color rgba="0.25 0.25 0.25 0.95" />
            </material>
        </visual>
    </link>

    <!-- 激光雷达和底盘的关节描述 -->
    <joint name="laser_joint" type="fixed">
        <origin xyz="0 0 0.105" rpy="0 0 0" />
        <parent link="base_link" />
        <child link="laser_link" />
    </joint>

    <!-- 相机实体描述 -->
    <link name="camera_link">
        <visual>
            <origin xyz=" 0 0 0 " rpy="0 1.57 0" />
            <geometry>
                <cylinder radius="0.02" length = "0.05"/>
            </geometry>
            <material name="gray">
                <color rgba="0.25 0.25 0.25 0.95"/>
            </material>
        </visual>
    </link>

    <!-- 相机和底盘的关节描述 -->
    <joint name="camera_joint" type="fixed">
        <origin xyz="0.18 0 0.055" rpy="0 0 0"/>
        <parent link="base_link"/>
        <child link="camera_link"/>
    </joint>

</robot>

运行 launch 文件,结果如下:

在这里插入图片描述

七、解决部分实体位于地面以下的问题

首先明确我们的 Fixed Framebase_linkFixed Frame 可以理解为世界坐标系,对于我们的设置就是base_link即当前的世界,rviz默认一切都是从世界中心诞生。

实体位于地面以下,是由于我们设置的其他实体都是以世界中心为参考而又认为地面在轮子下方,但rviz认为地面原点在世界中心,所以看起来和我们的认知有些冲突。

解决办法有多种,但基本都是改变base_link或其他实体与世界中心的关系。

方法一:

比较常见的一种:新增floor_link作为 Fixed Frame 世界坐标系,base_link作为他的子级。这种方法对现有已经完成的模型修改最少。

在urdf文件中新增如下内容即可:

<!-- 地面实体描述 -->
<link name="floor_link">
    <visual>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <geometry>
            <!-- 圆柱体高度尽量小,已达到可忽略的精度 -->
            <cylinder length="0.000001" radius="0.20" />
        </geometry>
        <material name="floor">
            <color rgba="1 0.4 0 0" />
        </material>
    </visual>
</link>

<!-- 底盘与地面的关节关系描述 -->
<joint name="base_joint" type="continuous">
    <origin xyz="0 0 0.11" rpy="0 0 0" />
    <parent link="floor_link" />
    <child link="base_link" />
    <axis xyz="0 1 0" />
</joint>

结果如下:

在这里插入图片描述

使用rviz查看TF关系如下:

在这里插入图片描述

新增的floor_link如图中框选,但这种方法在工程上很难测量base_link的实际位置,所以就有了方法二。

方法二:

floor_link直接命名为base_link,其他实体都以它为基准,但位置描述都要作相应的修改,这种方法对于现有已经完成的模型修改较多,对新工程比较友好,各实体的实际位置也很容易通过测量得到。

修改后的TF树如下,此时base_link位于世界原点,也是机器人底盘原点在地面的投影点。

在这里插入图片描述

机器人的外观显示和方法一一样:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能防疫电梯模拟控制系统设计-设计说明书

设计摘要&#xff1a; 本设计是基于单片机的智能防疫电梯模拟控制系统&#xff0c;主要实现了多项功能。首先&#xff0c;系统进行无接触测温&#xff0c;如果温度正常则可以启动电梯运行&#xff0c;如果温度异常则电梯会报警提示有乘客体温异常&#xff0c;电梯不会运行。其…

Java——CLASSPATH配置

什么是CLASSPATH&#xff1f; 答&#xff1a; classpath类似于windows中的系统环境变量path。 在windows中&#xff0c;如果要想在DOS命令窗口中执行一个程序。系统会先去当前文件路径下找对应命令的执行程序。如果找不到&#xff0c;就会到系统环境变量path中挨个遍历每一个路…

代码随想录算法训练营第二十五天:树的最后学习

代码随想录算法训练营第二十五天&#xff1a;树的最后学习 如果不对递归有深刻的理解&#xff0c;本题有点难 单纯移除一个节点那还不够&#xff0c;要修剪&#xff01; #669. 修剪二叉搜索树 力扣题目链接(opens new window) 给定一个二叉搜索树&#xff0c;同时给定最小边界…

vs2019 c++里用 typeid() . name () 与 typeid() . raw_name () 测试数据类型的区别

&#xff08;1&#xff09; 都知道&#xff0c;在 vs2019 里用 typeid 打印的类型不大准&#xff0c;会主动去掉一些修饰符&#xff0c; const 和引用 修饰符会被去掉。但也可以给咱们验证学到的代码知识提供一些参考。那么今天发现其还有 raw_name 成员函数&#xff0c;这个函…

Qt多文档程序的一种实现

注&#xff1a;文中所列代码质量不高&#xff0c;但不影响演示我的思路 实现思路说明 实现DemoApplication 相当于MFC中CWinAppEx的派生类&#xff0c;暂时没加什么功能。 DemoApplication.h #pragma once#include <QtWidgets/QApplication>//相当于MFC中CWinAppEx的派生…

【RAG 论文】IRCoT:基于 CoT 的交叉检索解决多步骤问题

论文&#xff1a;Interleaving Retrieval with Chain-of-Thought Reasoning for Knowledge-Intensive Multi-Step Questions ⭐⭐⭐⭐ ACL 2023, arXiv:2212.10509 Code: github.com/stonybrooknlp/ircot 论文速读 大多数 RAG 都是一次检索来辅助 LLM 生成&#xff0c;但是面对…

fastjson1.2.68对于文件操作的分析最全

fastjson1.2.68对于文件操作的分析 前言分析复制文件写入文件清空文件读取文件分析poc拓宽场景极限环境poc优化修改再次优化poc的分析 前言 这次分析也是分析了很久&#xff0c;因为每个链子都是自己去跟着分析了的&#xff0c;然后主要是去学习了一下怎么去挖链子 分析 前面…

洛谷P1364 医院设置

P1364 医院设置 题目描述 设有一棵二叉树&#xff0c;如图&#xff1a; 其中&#xff0c;圈中的数字表示结点中居民的人口。圈边上数字表示结点编号&#xff0c;现在要求在某个结点上建立一个医院&#xff0c;使所有居民所走的路程之和为最小&#xff0c;同时约定&#xff0c…

四、基于Stage模型的应用架构设计

前面我们了解了如何构建鸿蒙应用以及开发了第一个页面&#xff0c;这只是简单的demo&#xff1b;那么如何去设计&#xff0c;从0到1搭建一个真正的应用呢 一、基本概念 1、Stage模型基本概念 Stage模型概念图 AbilityStage&#xff1a;是一个Module级别的组件容器&#xff0…

红蓝对抗 网络安全 网络安全红蓝对抗演练

什么是红蓝对抗 在军事领域&#xff0c;演习是专指军队进行大规模的实兵演习&#xff0c;演习中通常分为红军、蓝军&#xff0c;演习多以红军守、蓝军进攻为主。类似于军事领域的红蓝军对抗&#xff0c;网络安全中&#xff0c;红蓝军对抗则是一方扮演黑客&#xff08;蓝军&…

BUUCTF靶场[MISC]wireshark、被嗅探的流量、神秘龙卷风、另一个世界

[misc]wireshark 考点&#xff1a;流量、追踪流 工具&#xff1a;wireshark 先看题目&#xff0c;管理员密码 将下载的文件用wireshark打开&#xff0c;查找flag 点击追踪tcp流&#xff0c;开始挨个查看flag [misc]被嗅探的流量 考点&#xff1a;流量、追踪流 工具&#xf…

类和对象、包等知识总结Java

类 类的概念&#xff1a;类是用来对一个实体&#xff08;对象&#xff09;进行描述的&#xff0c;主要描述该对象的属性&#xff0c;功能等。 类的定义和实例化 定义 定义类需要用到class关键字 &#xff08;大驼峰定义&#xff09;for example:class Dog... 初步了解一下…

2024年5月16日 十二生肖 今日运势

小运播报&#xff1a;2024年5月16日&#xff0c;星期四&#xff0c;农历四月初九 &#xff08;甲辰年己巳月庚辰日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;猴、鼠、鸡 需要注意&#xff1a;牛、兔、狗 喜神方位&#xff1a;西北方 财神方位&#xff1a;…

【2024年电工杯数学建模竞赛】选题分析+A题B题完整思路+代码分享

.2024年电工杯数学建模AB题选题思路 比赛开始第一时间在下面的资料裙分享&#xff1a; 点击链接加入群聊【2024数维杯数学建模ABC题资料汇总】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kBwulH5tSN2X7iLXzZHAJqRk9sYnegd0y&authKey2TSsuOgqXZQ%2FvTX4R59…

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件 ADS使用记录之使用RFPro进行版图联合仿真中已经简单介绍了使用RFPro对版图就行仿真的方法。但是&#xff0c;如果版图中含有一些非微带的结构&#xff0c;比如说电感、电容、晶体管呢&#xff0c;在此举例解释一下。 …

什么可以替代iframe?

网页嵌套中&#xff0c;iframe曾几何时不可一世&#xff0c;没有其他更好的选择&#xff01; iframe即内联框架&#xff0c;作为网页设计中的一种技术&#xff0c;允许在一个网页内部嵌套另一个独立的HTML文档。尽管它在某些场景下提供了便利&#xff0c;但也存在多方面的缺陷…

【Python报错】Python安装模块时报错Fatal error in launcher

【Python报错】Python安装模块时报错Fatal error in launcher 最近需要用到python下载一个小工具&#xff0c;自信敲下回车键本想看到黑乎乎的终端上会出现快速跳跃的命令代码&#xff0c;没想到&#xff0c;报错了...... Fatal error in launcher: Unable to create process …

全网最全的基于电机控制的38类simulink仿真全家桶----新手大礼包

整理了基于电机的38种simulink仿真全家桶&#xff0c;包含多种资料&#xff0c;类型齐全十分适合新手学习使用。包括但是不局限于以下&#xff1a; 1、基于多电平逆变器的无刷直流电机驱动simulink仿真 2、基于负载转矩的感应电机速度控制simulink仿真 3、基于滑膜观测器的永…

Unity与Andriod的交互

Unity与安卓的信息交互 这次分享的不同于传统的方式AndroidJavaClass("com.unity3d.player.UnityPlayer") 如果是新手的话&#xff0c;请看 交互新手教程 这里讲的是在Unity中调用java代码&#xff0c;或者在unity中传参到java中&#xff0c;在Java代码中运行。 以下…

二叉树遍历的实现

递归实现 先序遍历 代码实现 存储状态 中序遍历 后序遍历 算法分析 实质 复杂度 非递归算法实现 中序遍历 层次遍历 原理 实现