温故知新,机器人进化论之系统操作系统(ROS)与统一机器人描述格式URDF、Xacro
什么是ROS
ROS(Robot Operating System
)是一种广泛使用的开源机器人操作系统,它为机器人应用开发提供了基础架构和工具。尽管名字中包含"操作系统"(Operating System
),但ROS其实并不是一个传统意义上的操作系统。它是一个集成的框架,帮助开发者创建机器人应用程序。
消息传递和通信
ROS提供了一个强大的通信架构,允许不同的机器人组件(如传感器、控制器、执行器等)进行信息交换。它使用发布/订阅和客户端/服务端模型来实现节点之间的通信。
通过roscore
启动中心化的消息传递系统,节点可以在系统中发送、接收消息或调用服务。
节点和包(Packages)
ROS系统由多个“节点”组成。每个节点是一个独立的进程,执行机器人特定任务(例如控制、感知、运动规划等)。
所有的节点都组织在包(Package
)中。每个包包含相关的代码、配置文件和其他资源。
硬件抽象层
ROS提供了硬件抽象层,使得机器人应用可以在不同的硬件平台上运行,而不需要修改大量代码。这种方式提高了代码的可移植性。
工具和库
ROS提供了大量的工具和库,帮助开发者进行机器人开发。这些工具包括:
rviz
:用于可视化机器人状态和传感器数据gazebo
:一个强大的机器人仿真平台,支持物理模拟rqt
:用于GUI开发的工具,提供了可视化的调试界面rosbag
:用于记录和回放机器人的传感器数据和消息
支持多种语言
ROS主要使用C++和Python编写,但也支持其他语言的接口(如Java、Lisp等),使得开发者可以使用自己熟悉的语言进行开发。
广泛的社区和生态系统
由于ROS是开源的,它拥有庞大的开发者社区,很多开发者分享自己的代码、工具和库。这些资源可以加速机器人开发。
ROS的生态系统包括许多常见的机器人模型、算法、仿真环境、传感器驱动和控制算法等。
多机器人系统
ROS支持多机器人系统,可以通过简单的配置实现多个机器人之间的协作和信息共享。
多个版本
目前,ROS有多个版本,主要有两个大版本:
- ROS1:最初的ROS版本,广泛用于机器人开发,并且拥有丰富的社区支持。
- ROS2:是ROS1的继任者,改进了性能、安全性、实时性和跨平台支持(如支持Windows和实时操作系统)。ROS2逐渐成为新项目的首选。
重要组成
- URDF(Unified Robot Description Format)
URDF是ROS中用来描述机器人模型的标准文件格式。它定义了机器人各个组件(如链接、关节、传感器等)的物理属性和运动学结构。
通过URDF,开发者可以在仿真中创建机器人模型,或者将其用于控制和运动规划。
- Xacro(XML Macros)
Xacro是一种扩展的XML格式,用来生成URDF文件。它通过提供参数化和宏功能,简化了复杂机器人的建模过程。
- RViz
RViz是一个3D可视化工具,用于显示机器人在实际运行中的状态、传感器数据、地图、轨迹等。它可以实时更新,帮助开发者调试和监控机器人行为。
- Gazebo
Gazebo是一个开源的仿真平台,它与ROS紧密集成,用于模拟机器人在各种环境中的行为。它支持物理引擎、传感器模拟和多机器人系统仿真。
- MoveIt!
MoveIt!是一个广泛使用的机器人运动规划库,支持路径规划、避障、动力学求解等功能。它通过ROS与机器人控制系统进行集成。
什么是URDF
URDF是统一机器人描述格式(Unified Robot Description Format
),用于描述机器人的物理结构、动力学属性和传感器等信息。它是机器人操作系统(ROS)中广泛使用的一种格式,通常用来定义机器人的模型。
作用
URDF描述机器人如下内容:
- 链接(Links)
表示机器人的刚体部分,如车轮、机械臂关节的连杆。
- 关节(Joints)
连接两个链接,定义它们之间的运动关系,如旋转关节(revolute)、滑动关节(prismatic)等。
- 惯性(Inertia)
定义每个部件的质量和惯性属性,用于动力学仿真。
- 视觉(Visual)
定义机器人部件的外观,通常通过网格文件(如STL或DAE)。
- 碰撞(Collision)
定义机器人部件的碰撞模型,用于物理引擎计算。
- 传感器和其他扩展
可以附加插件支持传感器、控制器等功能。
约定
URDF是基于XML的,主要有以下结构和规则:
基本结构
<robot name="robot_name">
<!-- 链接 -->
<link name="link1">
<visual>
<geometry>
<box size="1 1 1" />
</geometry>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
</link>
<!-- 关节 -->
<joint name="joint1" type="revolute">
<parent link="link1"/>
<child link="link2"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
</joint>
</robot>
常用标签
<robot>
: 顶层标签,定义机器人名称。<link>
: 描述单个部件(刚体)的几何、惯性、碰撞模型等。<joint>
: 描述部件之间的连接关系,包括运动约束。<material>
: 定义外观颜色或纹理。<geometry>
: 定义几何形状(立方体、圆柱体、球体、网格文件等)。
常用约束
- 树形结构:URDF中的机器人模型必须是树形结构,不允许循环依赖。
- 坐标系:每个链接、关节和插件都定义在一个三维坐标系下,通过origin标签设置位置和方向。
- 单位:使用国际单位制(SI),如米、千克、秒等。
资源
学习资源
ROS提供了详细的教程,涵盖了从零开始创建视觉模型、定义关节、添加物理属性以及使用Xacro优化文件的内容。这些教程是初学者入门的理想选择
ROS提供了开源的URDF教程代码,可以通过GitHub获取。这些示例包括RViz的可视化模型和Gazebo的仿真配置。
学习步骤
- 基础XML语法:掌握XML文件的基本格式和书写规范。
- 从简单模型开始:从一个简单的机器人(如两个链接和一个关节)开始练习。
- 引入复杂元素:逐步添加惯性、碰撞模型、材质、传感器等元素。
- 结合仿真和可视化工具:使用工具如RViz、Gazebo、MoveIt!来验证模型效果。
实践工具
- URDF可视化工具
RViz:ROS内置可视化工具,检查URDF的结构和属性。
- 仿真环境
Gazebo:结合URDF进行物理仿真。
- Mesh编辑工具
Blender或SolidWorks制作和导出机器人模型的网格文件。
示例项目
URDF的扩展工具(Xacro)
什么是Xacro
Xacro是一种高效生成URDF文件的工具,通过Xacro可以更灵活地创建复杂、动态的机器人模型,而URDF则是最终格式,用于描述机器人结构并加载到ROS的仿真和控制环境中。
在很多URDF文件,我们会看到最终的文件后缀名是.xacro
文件后缀为.xacro
表示这是一个Xacro
文件,它是一种基于XML的宏扩展语言,全称为XML Macros
。
Xacro
是ROS中用于生成URDF文件的工具。它允许通过参数化和复用减少重复代码,从而更高效地管理复杂机器人模型
为什么使用.xacro文件
- 参数化
你可以定义变量(如机器人的尺寸、质量)并根据需求动态调整模型,而无需手动修改每个URDF文件。
- 减少重复
如果一个机器人有多个相似的组件(如机械臂的多个关节),Xacro能通过宏模板生成这些组件,而不需要重复定义。
- 模块化设计
使用<xacro:include>
可以组合多个文件,方便将机器人描述分成不同部分,如底盘、机械臂等。
- 动态生成
在加载URDF时,Xacro文件会被解析并转换为标准的URDF格式供工具(如Gazebo和RViz)使用。
如何将.xacro转换为URDF文件
使用ROS提供的xacro工具:
rosrun xacro xacro your_file.xacro > output_file.urdf
这将把.xacro
文件转换为标准的.urdf
文件,供仿真器或可视化工具直接使用。
示例
一个简单的Xacro文件可能如下:
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="example_robot">
<xacro:property name="link_length" value="1.0"/>
<link name="base_link">
<visual>
<geometry>
<box size="${link_length} 0.2 0.1"/>
</geometry>
</visual>
</link>
</robot>
这里的${link_length}
是一个参数,可以动态修改其值生成不同的机器人模型。
和URDF之间的关系和区别
URDF是一种基于XML的静态文件格式,用于定义机器人的物理、视觉和运动属性。它是机器人模型的最终描述文件。
适用于
- 静态、简单的结构:直接定义机器人的各部分(如链接和关节)。
- 适合小型、简单的机器人模型。
- 无法重复代码,无法进行参数化。
<robot name="simple_robot">
<link name="base_link"/>
<joint name="base_joint" type="fixed">
<parent link="base_link"/>
<child link="child_link"/>
</joint>
</robot>
Xacro是一种基于XML的宏语言,专门用来生成URDF文件。它在语法上扩展了XML,允许使用变量、宏、条件和循环等高级功能。
适用于
- 参数化:可以通过变量定义尺寸、质量等动态参数。
- 模块化设计:通过
<xacro:include>
包含其他文件,支持将机器人模型分解为多个模块。 - 简化重复:使用宏(
xacro:macro
)复用相同的代码片段。 - 动态生成:Xacro文件在运行时被解析并转换为标准的URDF文件。
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="param_robot">
<xacro:property name="link_length" value="1.0"/>
<link name="base_link">
<visual>
<geometry>
<box size="${link_length} 0.1 0.1"/>
</geometry>
</visual>
</link>
</robot>
C#手动解析
1. 加载URDF文件
using System.Xml;
XmlDocument urdfDoc = new XmlDocument();
urdfDoc.Load("path_to_urdf_file.urdf"); // 替换为你的 URDF 文件路径
2. 解析URDF文件中的节点
URDF文件由<robot>
根节点和多个<link>
、<joint>
子节点组成。可以通过XPath或递归方式获取这些节点。
- 解析机器人名称
XmlNode robotNode = urdfDoc.SelectSingleNode("/robot");
string robotName = robotNode.Attributes["name"].Value;
Console.WriteLine("Robot Name: " + robotName);
- 遍历所有链接节点
XmlNodeList linkNodes = urdfDoc.SelectNodes("/robot/link");
foreach (XmlNode link in linkNodes)
{
string linkName = link.Attributes["name"].Value;
Console.WriteLine("Link: " + linkName);
}
- 遍历关节节点
XmlNodeList jointNodes = urdfDoc.SelectNodes("/robot/joint");
foreach (XmlNode joint in jointNodes)
{
string jointName = joint.Attributes["name"].Value;
string jointType = joint.Attributes["type"].Value;
Console.WriteLine($"Joint: {jointName}, Type: {jointType}");
}
3. 处理几何和其他信息
URDF中的几何数据(如<visual>
和<collision>
)可能包含嵌套信息,例如网格文件路径、大小等。可以递归解析这些嵌套节点。
foreach (XmlNode link in linkNodes)
{
XmlNode visualNode = link.SelectSingleNode("visual");
if (visualNode != null)
{
XmlNode geometryNode = visualNode.SelectSingleNode("geometry");
XmlNode meshNode = geometryNode?.SelectSingleNode("mesh");
if (meshNode != null)
{
string meshFile = meshNode.Attributes["filename"].Value;
Console.WriteLine($"Mesh file for link {link.Attributes["name"].Value}: {meshFile}");
}
}
}
4. 封装成类或数据结构
将URDF数据解析为C#类(如Robot
,Link
,Joint
)以便操作:
class Robot
{
public string Name { get; set; }
public List<Link> Links { get; set; }
public List<Joint> Joints { get; set; }
}
class Link
{
public string Name { get; set; }
public string MeshFile { get; set; }
}
class Joint
{
public string Name { get; set; }
public string Type { get; set; }
public string ParentLink { get; set; }
public string ChildLink { get; set; }
}
解析后填充这些类,便于进一步使用
5. 扩展支持动态仿真
如果你计划将解析后的URDF数据与物理引擎集成(例如Unity或Gazebo),可以将数据转换为这些框架支持的格式或接口。例如:
- 使用Unity的GameObject动态加载URDF几何模型。
- 与物理引擎(如Bullet或PhysX)对接。
第三方库支持
urdfdom(C++库)
如果通过C++/CLI调用更底层的URDF库(如urdfdom),可以解析复杂URDF文件。
RosSharp(Unity-ROS工具包)
一个C#项目,用于解析和运行ROS与Unity的桥接,支持URDF。
通过ROSSharp与ROS交互
ROSSharp是一个由社区开发的库,旨在为C#提供对ROS系统的支持。ROSSharp提供了ROS通信协议的C#实现,允许你通过ROS与C#代码进行交互。你可以用它来连接ROS网络、发布和订阅消息,以及发送服务请求。
安装ROSSharp
- ROSSharp官方GitHub仓库:
你可以克隆这个仓库,或者在Visual Studio中创建一个新的C#项目并将ROSSharp添加为依赖项。
- 使用NuGet安装:
打开VisualStudio,进入“工具”->“NuGet包管理器”->“管理解决方案的NuGet包”。
搜索ROSSharp
,然后将其添加到你的项目中。
示例代码
using System;
using ROSSharp.RosBridgeClient;
public class RosSubscriber
{
private RosSocket rosSocket;
public void Start()
{
rosSocket = new RosSocket("ws://localhost:9090"); // ROS Master 的 WebSocket 地址
string topicName = "/chatter";
rosSocket.Subscribe<std_msgs.String>(topicName, MessageReceived);
}
private void MessageReceived(std_msgs.String message)
{
Console.WriteLine("Received message: " + message.data);
}
}
连接ROS Master:通过RosSocket连接到ROSMaster(通常运行在ws://localhost:9090
)。
订阅话题:你可以订阅ROS中的任何话题,如/chatter,并定义如何处理接收到的消息。
ROSBridge和WebSocket
为了让C#与ROS通信,ROSBridge是一个非常有用的工具。ROSBridge是一个ROS包,它提供了一个WebSocket接口,可以让外部应用(如C#)与ROS节点进行通信。ROSBridge使用WebSocket协议,在网络上以JSON格式发送ROS消息。
安装ROSBridge
在你的ROS环境中,安装并启动ROSBridge:
sudo apt-get install ros-noetic-rosbridge-suite
roslaunch rosbridge_server rosbridge_websocket.launch
这会在ws://localhost:9090
上启动一个WebSocket服务器,允许其他程序与ROS进行通信。
C#客户端与ROSBridge交互
在C#中,你可以使用WebSocketSharp库与ROSBridge进行WebSocket通信。通过WebSocket连接后,C#应用就可以发送和接收ROS消息。
WebSocketSharp安装:
你可以通过NuGet包管理器安装WebSocketSharp:
Install-Package WebSocketSharp
示例代码:
using WebSocketSharp;
using Newtonsoft.Json;
using System;
public class RosBridgeClient
{
private WebSocket ws;
public void Start()
{
ws = new WebSocket("ws://localhost:9090");
ws.OnMessage += (sender, e) => { MessageReceived(e.Data); };
ws.Connect();
// 订阅话题
var subscribeMessage = new
{
op = "subscribe",
topic = "/chatter"
};
ws.Send(JsonConvert.SerializeObject(subscribeMessage));
}
private void MessageReceived(string message)
{
Console.WriteLine("Received: " + message);
}
}
使用ROS2和C#
如果你在使用ROS2,虽然ROS2本身并不直接支持C#,但你可以通过一些第三方库(例如ros2-dotnet)实现与ROS2的交互。
ros2-dotnet是一个实验性项目,旨在提供ROS2和C#之间的通信。你可以通过以下链接找到它:
GitHub仓库:https://github.com/ros2-dotnet/ros2_dotnet
如何使用:
- 克隆ros2_dotnet仓库,按照文档进行编译和安装。
- 使用C#通过ROS2的DDS通信模型与ROS2节点进行交互。