Simon Shi的小站

人工智能,机器学习, 强化学习,大模型,自动驾驶

0%

ROS(Robot Operating System,机器人操作系统)是一个为机器人软件开发提供支持的灵活框架。它为机器人软件开发者提供了一套广泛的工具和库,使得他们能够更容易地构建和运行机器人应用。

# 一小时实践入门 ROS—机器人操作系统

学习计划

学习ROS (Robot Operating System) 在一小时内是非常紧凑的,但你可以通过实践来尽快掌握基础。以下是一个基本的一小时学习计划,以项目实践为目标:

1. 环境设置

  • 安装ROS

  • 用docker快速安装ROS的基本版本。

  • 设置环境变量。

2. 基本概念

  • 节点 (Nodes)

  • 创建一个简单的节点。

  • 运行节点,并观察输出。

  • 主题 (Topics)

  • 创建一个简单的主题发布者和订阅者。

  • 发布和订阅消息。

3. 实践项目

  • 创建一个简单的机器人模拟

  • 选择一个简单的机器人模型,如一个两轮机器人。

  • 在ROS中加载机器人模型。

  • 使用Gazebo控制机器人移动并监控机器人的状态和位置。

这个计划需要你在一个实际的ROS环境中操作。

环境配置

docker快速安装ROS Gazebo

  • DockerDesktop安装

  • Dockerfile编写(参照Gazebo 上手 wsl)编译成image

  • Windows中安装和启动VcXsrv

    • 启动xLaunch
  • 运行Docker容器

  • 创建项目工作空间

    • mkdir -p ~/catkin_ws/src
      cd ~/catkin_ws/src
      catkin_init_workspace
      
      1
      2
      3
      4

      - ```shell
      cd ~/catkin_ws
      catkin_make

配置环境变量

ros_environment.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# Source ROS setup script
source /opt/ros/noetic/setup.bash

# Source workspace setup script
source ~/catkin_ws/devel/setup.bash

# Set ROS Master URI
# Replace 'localhost' with your ROS Master's IP if it's on a different machine
export ROS_MASTER_URI=http://localhost:11311

# Set ROS Hostname
# Replace 'localhost' with this machine's IP if this machine is not the ROS Master
export ROS_HOSTNAME=localhost

# Set ROS IP
# Replace 'localhost' with this machine's IP
export ROS_IP=localhost

# Set Gazebo Plugin Path
export GAZEBO_PLUGIN_PATH=/opt/ros/noetic/lib:$GAZEBO_PLUGIN_PATH

运行生效环境配置

1
source ros_environment.sh
  • 通过 source命令,它加载了ROS和你的工作空间的设置脚本。
  • 它设置了 ROS_MASTER_URIROS_HOSTNAME和 ROS_IP环境变量,以确保你的ROS节点可以正确地通信。

每次启动新的终端或ROS容器时,都应执行 source ros_environment.sh命令以确保环境变量正确设置。为了简化这个过程,你可能想要将 source ros_environment.sh命令添加到你的 .bashrc文件中,这样它会在每次启动新终端时自动执行。

基本概念

创建一个简单节点

1.创建一个新的ROS包 首先,在你的工作空间的 src 目录中创建一个新的ROS包。我们将此包命名为 simple_node_package,并依赖于 roscpp 和 std_msgs

1
2
cd ~/catkin_ws/src
catkin_create_pkg simple_node_package roscpp std_msgs

2.编写简单的ROS节点 现在,创建一个名为 simple_node.cpp 的文件,并填写以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
// 初始化ROS节点
ros::init(argc, argv, "simple_node");

// 创建节点句柄
ros::NodeHandle nh;

// 创建一个发布者对象
ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);

// 设置循环频率
ros::Rate loop_rate(10);

while (ros::ok())
{
// 创建一个消息对象
std_msgs::String msg;
msg.data = "Hello, ROS!";

// 发布消息
chatter_pub.publish(msg);

// 处理任何可用的回调函数
ros::spinOnce();

// 按照设定的频率休眠
loop_rate.sleep();
}

return 0;
}

然后将其复制到 simple_node_package 包中src目录中。

3.修改CMakeLists.txt 为了编译你的节点,你需要修改 simple_node_package 包的 CMakeLists.txt 文件。把这两行代码加到文件的最后,

文件名:CMakeLists.txt

1
2
3
4
(原代码)

add_executable(simple_node src/simple_node.cpp)
target_link_libraries(simple_node ${catkin_LIBRARIES})

4.构建编译:

1
2
cd ~/catkin_ws
catkin_make

5 RosCore运行

1
roscore

6 新节点运行(在新的终端中)

1
2
3
4
docker exec -it <container_name> /bin/bash

source /data/ros_environment.sh
rosrun simple_node_package simple_node

运行节点,观察输出

运行和观察ROS节点输出相对简单。在上一步中,你已经创建了一个名为 simple_node的节点,它发布”Hello, ROS!”消息到 chatter主题。现在我们将运行该节点并观察其输出。

1.观察输出 现在,我们和之前一样docker exec -it <container_name> /bin/bash 再打开第三个终端。

在第三个新的终端中,你可以使用 rostopic命令来监听 chatter主题并观察节点的输出:

1
2
source /data/ros_environment.sh
rostopic echo /chatter

你应该看到每秒10条”Hello, ROS!”消息,如下所示:

2 查看节点和主题信息 你还可以使用 rosnode和 rostopic命令来获取有关运行中节点和主题的更多信息。

  • 查看运行中的节点列表:rosnode list
  • 查看特定节点的信息(例如 simple_node): rosnode info /simple_node
  • 查看特定主题的信息(例如 chatter):rostopic info /chatter

创建一个简单的主题发布者和接收者

在ROS中,节点可以通过发布和订阅主题来交换消息。下面我们将创建一个简单的主题发布者和订阅者。我们将继续使用之前创建的 simple_node_package包。

1.创建发布者 首先,我们创建一个名为 publisher_node.cpp的文件来发布消息到一个名为 chatter的主题。

文件名:publisher_node.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
ros::init(argc, argv, "publisher_node");
ros::NodeHandle nh;

// 创建了一个发布者对象,该对象可以发布消息到名为 chatter的主题。1000是队列大小,它确定了在订阅者能够处理之前可以缓冲的消息数量。
ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);

while (ros::ok())
{
std_msgs::String msg;
msg.data = "Hello, ROS!";

chatter_pub.publish(msg); / /发布到 chatter主题

ros::spinOnce();
loop_rate.sleep();
}

return 0;
}

2.创建订阅者 接下来,我们创建一个名为 subscriber_node.cpp的文件来订阅 chatter主题并打印接收到的消息。(文件的操作和前面的一样,不再赘述)

文件名:subscriber_node.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "ros/ros.h"
#include "std_msgs/String.h"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
ros::init(argc, argv, "subscriber_node");
ros::NodeHandle nh;
//订阅了名为 chatter的主题。1000是队列大小,它确定了可以在处理之前缓冲的消息数量。
ros::Subscriber sub = nh.subscribe("chatter", 1000, chatterCallback);

ros::spin();

return 0;
}

3.更新CMakeLists.txt 现在,更新 simple_node_package包的 CMakeLists.txt文件以包含新的节点。

文件名:CMakeLists.txt

1
2
3
4
5
6
7
(原来的代码)

add_executable(publisher_node src/publisher_node.cpp)
target_link_libraries(publisher_node ${catkin_LIBRARIES})

add_executable(subscriber_node src/subscriber_node.cpp)
target_link_libraries(subscriber_node ${catkin_LIBRARIES})

4.构建工作空间 返回到你的工作空间的根目录,并运行 catkin_make来构建你的工作空间和新节点:

1
2
cd ~/catkin_ws
catkin_make

5.运行发布者和订阅者节点 确保你的ROS核心正在运行(前面说过的roscore),然后在两个不同的终端中分别运行发布者和订阅者节点:

终端一

1
2
source ~/catkin_ws/devel/setup.bash
rosrun simple_node_package publisher_node

终端二

1
2
source ~/catkin_ws/devel/setup.bash
rosrun simple_node_package subscriber_node

现在,你应该能在订阅者节点的终端中看到每秒10条”Hello, ROS!”消息,表明发布者和订阅者节点正在正确地交换消息。

实践项目Robot controller

在ROS中,通常使用URDF(Unified Robot Description Format,统一机器人描述格式)或者xacro(XML Macros,XML宏)来描述机器人模型。在这一步中,我们将创建一个简单的两轮机器人模型。

两轮ROBOT模型

1 创建ROS pkg

1
2
cd ~/catkin_ws/src
catkin_create_pkg your_robot_package roscpp rospy std_msgs sensor_msgs gazebo_ros gazebo_plugins

2 创建URDF文件

在新创建的 your_robot_package包中创建一个名为 two_wheel_robot.urdf的文件来描述你的两轮机器人。

将这个文件放到~/catkin_ws/src/your_robot_package/urdf/two_wheel_robot.urdf

two_wheel_robot.urdf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0"?>

<robot name="two_wheel_robot">

<!-- Base Link -->
<link name="base_link">
<visual>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</visual>
<collision>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="10"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>

<!-- Left Wheel -->
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.15 0" rpy="1.57079632679 0 0"/> <!-- Rotate the wheel to be perpendicular to the ground -->
<axis xyz="0 0 1"/>
</joint>
<link name="left_wheel">
<visual>
<geometry>
<cylinder length="0.05" radius="0.1"/>
</geometry>
</visual>
<collision>
<geometry>
<cylinder length="0.05" radius="0.1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="0.025" ixy="0" ixz="0" iyy="0.025" iyz="0" izz="0.025"/>
</inertial>
</link>

<!-- Right Wheel -->
<joint name="right_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.15 0" rpy="1.57079632679 0 0"/> <!-- Rotate the wheel to be perpendicular to the ground -->
<axis xyz="0 0 1"/>
</joint>
<link name="right_wheel">
<visual>
<geometry>
<cylinder length="0.05" radius="0.1"/>
</geometry>
</visual>
<collision>
<geometry>
<cylinder length="0.05" radius="0.1"/>
</geometry>
</collision>
<inertial>
<mass value="1"/>
<inertia ixx="0.025" ixy="0" ixz="0" iyy="0.025" iyz="0" izz="0.025"/>
</inertial>
</link>

<gazebo>
<plugin name="gazebo_ros_diff_drive" filename="libgazebo_ros_diff_drive.so">
<updateRate>100.0</updateRate>
<leftJoint>left_wheel_joint</leftJoint>
<rightJoint>right_wheel_joint</rightJoint>
<wheelSeparation>0.3</wheelSeparation> <!-- This should be the distance between your wheels -->
<wheelDiameter>0.2</wheelDiameter> <!-- This should be the diameter of your wheels -->
<torque>20</torque> <!-- You may need to adjust this value -->
<commandTopic>cmd_vel</commandTopic>
<odometryTopic>odom</odometryTopic>
<odometryFrame>odom</odometryFrame>
<robotBaseFrame>base_link</robotBaseFrame>
</plugin>
</gazebo>

</robot>

在这个URDF文件中,我们定义了一个简单的两轮机器人,它有一个基础链接(base_link)和两个连续关节,每个关节连接一个轮子。

3 查看机器人模型

为了查看你的机器人模型,你可以使用 urdf包中的 urdf_viewer工具。

首先需要下载 urdf_tutorial ros包,解压放到~/catkin_ws/src/urdf_tutorial目录中。

然后执行

1
catkin_make

查看模型

1
roslaunch urdf_tutorial display.launch model:='$(find your_robot_package)/urdf/two_wheel_robot.urdf'

这个命令会启动RViz,并加载你的两轮机器人模型。在RViz中,你应该能看到你的两轮机器人模型,并可以通过旋转和缩放来检查它的各个部分。

通过创建和查看URDF文件,你可以获得对ROS中机器人模型描述的基本理解,并可以开始为你的两轮机器人添加更多复杂的特性和组件。

控制ROBOT移动

控制机器人移动通常涉及编写一个ROS节点,该节点发布到机器人的速度命令主题。对于简单的两轮机器人,通常会有一个名为 cmd_vel的主题,它接收 geometry_msgs/Twist类型的消息来控制机器人的线速度和角速度。

1.创建控制节点 创建一个新的文件名为 robot_controller.cpp的文件,在 your_robot_package/src 目录中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"

int main(int argc, char **argv)
{
ros::init(argc, argv, "robot_controller");
ros::NodeHandle nh;

ros::Publisher cmd_vel_pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 10);

ros::Rate loop_rate(10);

while (ros::ok())
{
geometry_msgs::Twist cmd_vel_msg;
cmd_vel_msg.linear.x = -0.5; // 0.5 m/s forward
cmd_vel_msg.angular.z = 0.1; // 0.1 rad/s rotation

cmd_vel_pub.publish(cmd_vel_msg);

ros::spinOnce();
loop_rate.sleep();
}

return 0;
}

在这段代码中,我们创建了一个名为 robot_controller的ROS节点,它发布 geometry_msgs/Twist消息到 cmd_vel主题,以控制机器人的线速度和角速度。

2.更新CMakeLists.txt 修改 your_robot_package 包的 CMakeLists.txt文件以包含新的控制节点。

文件名: CMakeLists.txt

1
2
3
4
(原代码)

add_executable(robot_controller src/robot_controller.cpp)
target_link_libraries(robot_controller ${catkin_LIBRARIES})

3.构建你的工作空间 返回到你的工作空间的根目录,并运行 catkin_make来构建你的工作空间和新控制节点:

1
2
cd ~/catkin_ws
catkin_make

4.运行控制节点 在一个新的终端中,运行你的控制节点来发布速度命令:(需要提前运行roscore

1
2
source ~/data/ros_environment.sh
rosrun your_robot_package robot_controller

现在,你的控制节点应该在 cmd_vel主题上发布速度命令。

然后和上面一样,我们打开一个新的终端,然后查看 cmd_vel主题的消息:

新终端

1
2
source ~/data/ros_environment.sh
rostopic echo /cmd_vel

Gazebo监控机器人的状况

创建一个启动文件 (launch文件) 来加载机器人模型和控制器。在该包中的launch文件夹(需新建)中创建一个文件名为robot.launch的文件,并将以下内容复制到该文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<launch>
<!-- Load the URDF into the ROS Parameter Server -->
<param name="robot_description" textfile="$(find your_robot_package)/urdf/two_wheel_robot.urdf" />

<!-- Launch Gazebo with the robot model -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="worlds/empty.world"/>
<arg name="paused" value="false"/>
</include>

<!-- Spawn robot model -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -model two_wheel_robot" />

<!-- Load the controller -->
<node name="robot_controller" pkg="your_robot_package" type="robot_controller" output="screen"/>

</launch>

编译你的ROS包:

1
2
cd ~/catkin_ws 
catkin_make

启动Gazebo和机器人控制器:

1
roslaunch your_robot_package robot.launch 

在执行上述步骤后,你应该能够在Gazebo中看到你的机器人模型,并能够通过ROS来控制它。在robot_controller.cpp中,你可以使用ROS的消息和服务来读取传感器数据、发送控制命令和与机器人交互。同时,你可以看到机器人在Gazebo中的实时模拟表现。

这只是一个基本的设置,具体的实现可能需要根据你的机器人模型和控制器代码进行调整。例如,你可能需要配置机器人的传感器和控制器,或者修改Gazebo和ROS的启动文件以适应你的特定需求。

学习计划

# 一小时实践入门Gazebo

在一小时内基本掌握Gazebo可能是很具挑战的,但可以通过以下步骤尽快上手,尤其是以项目实践为目的:

环境搭建和安装

  • 下载并安装Gazebo
  • 设置基本的环境变量和配置

基本概念和界面熟悉

  • 快速浏览Gazebo的基本概念,如模型、世界、插件等
  • 熟悉Gazebo的用户界面和基本功能

载入和探索现有模型

  • 从Gazebo的模型库中载入一些基本模型
  • 熟悉模型的基本操作和属性设置

创建简单的场景

  • 创建一个简单的Gazebo世界,包括地面、一些障碍物和一个机器人模型
  • 保存和载入你创建的场景

运行基本的仿真

  • 启动仿真,观察场景中的物理交互
  • 使用基本的控制命令,如移动机器人等

以上步骤可能需要适当的预先知识和快速的学习能力。为了确保在短时间内获得最好的学习效果,建议选择具有明确目标和范围的项目实践。在实践过程中,你可能会遇到一些问题,记得利用网络资源如社区论坛和Stack Overflow来寻找解决方案。通过快速实践和解决问题,你将能够在较短的时间内掌握Gazebo的基本应用。

环境搭建 安装

docker安装

  • 此处省略

创建Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 使用官方的ROS镜像作为基础镜像
FROM ros:noetic-ros-base

# 添加ROS源
RUN echo "deb http://packages.ros.org/ros/ubuntu focal main" > /etc/apt/sources.list.d/ros1-latest.list

# 导入ROS的公钥
RUN apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

# 更新apt包列表
RUN apt-get update

# 安装 RViz 和其他 ROS 工具
RUN apt-get install -y \
ros-noetic-rviz \
ros-noetic-xacro \
ros-noetic-joint-state-publisher-gui \
ros-noetic-robot-state-publisher

# 安装 Gazebo 11 和相关的开发包
RUN apt-get install -y \
gazebo11 \
libgazebo11-dev

# 安装 Gazebo ROS 包
RUN apt-get install -y \
ros-noetic-gazebo-ros-pkgs \
ros-noetic-gazebo-ros-control

# 设置容器的主命令为bash终端
CMD ["/bin/bash"]

创建并运行 Docker 容器:

在 Dockerfile 的同一目录中打开终端,运行以下命令以构建 Docker 映像:

1
docker build -t gazebo11:latest .

配置 X11 服务器:

我使用 VcXsrv 来作为可视化服务器。

启动 X11 服务器,并允许来自所有网络的连接。

  1. 安装 VcXsrv:首先需要下载并安装 VcXsrv。安装过程中可能需要选择完整安装,并指定目标文件夹​1​。
  2. 运行 XLaunch:通过运行 VcXsrv 中的 XLaunch 程序来启动 X 服务器。在显示设置中,选择“多窗口”选项,并点击下一步。在客户端启动中,检查“不启动客户端”选项,并点击下一步。在额外设置中,确保启用“禁用访问控制”,并点击下一步​3​,直到完成。

启动容器:

一旦映像构建完成,运行以下命令以启动 Docker 容器,并连接到 X server:

我这里挂载了 F:\DockerFile\gazebo 目录,进行数据的保存和读取。

1
docker run -v F:\DockerFile\gazebo:/data -it --name gazebo11-container -e DISPLAY=host.docker.internal:0 gazebo11:latest

这时容器应该运行了。

其他终端:

现在,你可以通过 Docker desktop 中的 Exec 界面来执行其他命令。

或者通过 Docker 的 exec 命令附加一个新的终端到正在运行的容器:

1
docker exec -it gazebo11-container /bin/bash

这条命令会打开一个新的 Bash 终端,你可以在这个终端中执行任何你想要的命令,就像在一个常规的 Linux 系统中那样。

启动gazebo:

执行 gazebo &

一旦你的 X11 服务器配置完成,你应该能够看到 Gazebo 的图形界面从 Docker 容器中显示出来。

这种方法应该能够让你在 Docker 容器中运行 Gazebo,同时在主机系统上显示其图形界面。请注意,可能还需要进行一些额外的配置和调整以确保所有功能都能正确运行,特别是如果你的网络环境比较复杂或有特殊的安全配置。

基本概念和界面熟悉

Gazebo的基本概念,如模型,世界,插件等

  • 模型

  • 世界

  • 插件

  • 传感器:模拟真实世界传感器的虚拟设备,例如相机,雷达,激光雷达,它们可以感知仿真世界种的其它模型和环境

  • 视觉和物理属性

  • 通信接口

熟悉Gazebo的用户解码和基本功能

  • 主界面

  • 工具栏

  • 模型库

  • 插件和控件

  • 属性面板

  • 主题和布局

  • 日志和错误输出

模型载入

  • 打开模型库

  • 加载模型

  • 保存世界

模型操作和属性设置

  • 选择模型

  • 移动,旋转,缩放

  • 打开属性面板

  • 添加/删除链接和关节

  • 保存模型

创建场景

simple_world.world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="simple_world">

<!-- Ground plane -->
<include>
<uri>model://ground_plane</uri>
</include>

<!-- Obstacles -->
<model name="obstacle1">
<pose>2 0 0.5 0 0 0</pose>
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</visual>
</link>
</model>

<model name="obstacle2">
<pose>-2 0 0.5 0 0 0</pose>
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</visual>
</link>
</model>

<!-- Simple Robot -->
<model name="simple_robot">
<pose>0 0 0.1 1.57079632679 0 0</pose>
<link name="base_link">
<collision name="collision">
<geometry>
<cylinder>
<radius>0.2</radius>
<length>0.1</length>
</cylinder>
</geometry>
</collision>
<visual name="visual">
<geometry>
<cylinder>
<radius>0.2</radius>
<length>0.1</length>
</cylinder>
</geometry>
</visual>
<inertial>
<mass>10</mass>
<inertia>
<ixx>0.0175</ixx>
<iyy>0.0175</iyy>
<izz>0.0175</izz>
</inertia>
</inertial>
</link>
<plugin name="force_controller" filename="libgazebo_ros_force.so">
<updateRate>100.0</updateRate>
<robotNamespace>/my_robot</robotNamespace>
<bodyName>base_link</bodyName>
<topicName>/force</topicName>
</plugin>
</model>

</world>
</sdf>

在这个 simple_world.world 文件中,我们创建了以下元素:

  1. 地面平面 (ground_plane): 使用 <include> 标签从模型库中包含了一个基本的地面平面模型。
  2. 障碍物 (obstacle1 和 obstacle2): 创建了两个静态的箱形障碍物,并通过 <pose> 标签设置了它们的位置。
  3. 简单的机器人 (simple_robot): 创建了一个简单的机器人模型,该模型包含一个基本的圆柱形体。

你可以通过将这个文件保存到你的系统中,然后使用 Gazebo 命令行工具打开它来查看和交互这个简单的世界:

1
gazebo /data/worlds/simple_world.world

运行基本的仿真

启动仿真,观察场景中的物理交互

在 Gazebo 中启动仿真并观察场景中的物理交互是一个很直观的过程。你可以看到模型如何在受到物理规则(如重力、摩擦和碰撞)影响下运动和互动。以下是如何执行此操作的步骤:

  1. 启动 Gazebo: 首先,你需要启动 Gazebo 并加载你创建的世界。你可以通过命令行使用以下命令来做到这一点:gazebo /path/to/your/my_scene.world 其中 /path/to/your/ 是你保存 my_scene.world 文件的路径。
  2. 启动仿真: 在 Gazebo 的用户界面顶部,你会看到一个“播放”按钮(Play),点击它来启动仿真。现在,你应该能看到你的场景中的模型开始按照物理规则运动。例如,如果你的场景中有一个未固定的箱子,它应该会因为重力而掉到地上。
  3. 观察物理交互: 观察你的场景中的模型如何相互交互以及如何与环境交互。例如,你可以看到碰撞效果,如模型之间的碰撞或模型与地面的碰撞。你也可以尝试移动模型,看看它们如何响应你的交互以及它们如何在物理环境中运动。
  4. 调整仿真速度 (可选): 如果需要,你可以调整仿真速度以更仔细地观察物理交互。在 Gazebo 用户界面的顶部,你会看到一个滑块,可以用它来调整仿真速度。
  5. 暂停和重置仿真 (可选): 你也可以暂停仿真或重置仿真以返回到初始状态。在 Gazebo 用户界面的顶部,你会找到“暂停”(Pause)和“重置”(Reset)按钮。

通过上述步骤,你可以启动 Gazebo 仿真,观察并理解你的场景中的物理交互。这可以帮助你理解如何配置和调整你的模型以获得所需的仿真结果。

※使用基本的控制命令,如移动机器人等

在 Gazebo 中控制机器人通常需要编写和运行一些控制代码。一个常见的做法是使用 ROS (Robot Operating System) 与 Gazebo 协同工作,以发送控制命令并接收机器人的传感器数据。在这个例子中,我们将通过 ROS 使用简单的控制命令来移动机器人。

首先,确保你已经安装了 ROS 和 Gazebo,并且你的机器人模型已经配置为接受 ROS 控制命令。

创建ROS工作空间: 在ROS容器中,你需要创建一个新的工作空间来存放你的ROS项目。首先,创建一个新的目录来作为你的工作空间:

1
2
3
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

然后构建你的工作空间:

1
2
cd ~/catkin_ws
catkin_make

设置环境变量:

我将这个文件放到了之前加载的 F:\DockerFile\gazebo 中,然后在容器中在 /data 中可以找到该文件。

文件名:ros_environment.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# Source ROS setup script
source /opt/ros/noetic/setup.bash

# Source workspace setup script
source ~/catkin_ws/devel/setup.bash

# Set ROS Master URI
# Replace 'localhost' with your ROS Master's IP if it's on a different machine
export ROS_MASTER_URI=http://localhost:11311

# Set ROS Hostname
# Replace 'localhost' with this machine's IP if this machine is not the ROS Master
export ROS_HOSTNAME=localhost

# Set ROS IP
# Replace 'localhost' with this machine's IP
export ROS_IP=localhost

# Set Gazebo Plugin Path
export GAZEBO_PLUGIN_PATH=/opt/ros/noetic/lib:$GAZEBO_PLUGIN_PATH
  • 保存上述脚本到 ros_environment.sh文件。
  • 通过以下命令使环境变量设置生效:source /data/ros_environment.sh

创建 ROS Package:

创建一个新的 ROS package 用于存放你的控制代码。在你的 catkin workspace 中,运行以下命令:

1
2
cd ~/catkin_ws/src
catkin_create_pkg my_robot_controller rospy gazebo_ros gazebo_plugins std_msgs geometry_msgs

创建控制节点:

在你的 my_robot_controller package 中创建一个新的 Python 文件,命名为 robot_controller.py

文件名: robot_controller.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3

import rospy
from geometry_msgs.msg import Wrench

def apply_force():
# Initialize the node
rospy.init_node('force_applier', anonymous=True)

# Create a publisher to send force commands
pub = rospy.Publisher('/force', Wrench, queue_size=10)

# Create a Wrench message to send force and torque commands
cmd = Wrench()
cmd.force.x = 0.0
cmd.force.y = 0.0
cmd.force.z = 0.0
cmd.torque.x = 0.0
cmd.torque.y = 0.0
cmd.torque.z = 0.6 # Apply a torque of 0.6 N*m about the z-axis

rate = rospy.Rate(10) # 10 Hz
while not rospy.is_shutdown():
# Publish the command
pub.publish(cmd)
rate.sleep()

if __name__ == '__main__':
try:
apply_force()
except rospy.ROSInterruptException:
pass

运行控制节点:

在终端中,导航到你的 catkin workspace,并构建你的 package:

1
2
3
cd ~/catkin_ws
catkin_make
source /data/ros_environment.sh

现在运行你的控制节点来移动机器人:

1
rosrun my_robot_controller robot_controller.py

在这个例子中,robot_controller.py 脚本创建了一个 ROS 节点,该节点发布速度命令来移动机器人。/my_robot/cmd_vel 是你的机器人模型应该监听的话题,以接收速度命令。确保将此话题名称更改为与你的机器人模型匹配的话题名称。

然后打开一个新的终端,运行:

1
rosrun my_robot_controller robot_controller.py

然后就可以看到机器人转起来了:

REF

win11+WSL2配置gazebo - 知乎 (zhihu.com)

模拟

Gazebo,

Mujoco

Lsacc Sim

动力学仿真引擎——RaiSim

Lsacc Sim

NVIDIA Omniverse™ Isaac Sim是NVIDIA Omniverse™平台的一款机器人仿真工具包。Isaac Sim具备构建虚拟机器人世界和实验的关键功能。它为研究人员和从业人员提供了创建健壮、物理精确仿真和合成数据集所需的工具和工作流程。Isaac Sim通过ROS/ROS2支持导航和操控应用。它可以模拟RGB-D、Lidar和IMU等传感器的传感器数据,用于多种计算机视觉技术,如领域随机化、真值标签、分割和边界框。

实战

xiihoo小车

Mick小车

demo.py

1
2
3
4
5
6
7
8
9
10
11
12
from flask import Flask, request, jsonify, Respons

app = Flask(__name__)

@app.route('/hi', methods=['GET', 'POST'])
def hello_world():
logger.info('---hi Qiansi Tech SR')
return 'Qiansi Tech SR'

if __name__ == '__main__':
# Rel Server [gunnicor run in 9020]
app.run(port=9021) # test in 9021

client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def request_demo(test_on_server=False):
try:
# url = 'http://127.0.0.1:{}/cycle/hi'.format(args.port)
# url = 'http://cartoon.fuyuncc.com/cycle/hi'.format(args.port)
url = 'http://cartoon.fuyuncc.com/srserver/hi'
if test_on_server:
url = 'http://127.0.0.1:9021/hi'
print('-url', url)

r = requests.get(url)
print(r)
print(r.text)
except Exception as e:
print(e)

Transformer是一个利用注意力机制来提高模型训练速度的模型,因其适用于并行化计算以及本身模型的复杂程度使其在精度和性能上都要高于之前流行的循环神经网络。

标准的Transformer结构如下图所示,是一个编码器-解码器架构,其编码器和解码器均有一个编码层和若干相同的Transformer模块层堆叠组成。

HuggingFace transformers

from transformers import AutoModelForCausalLM, AutoTokenizer

from transformers.generation import GenerationConfig

Model

AutoModelForCausalLM 是一个自动模型加载器,主要用于自回归语言建模任务,如GPT系列模型。自回归意味着模型预测下一个词时仅依赖于它之前出现的词,这种特性常用于文本生成任务,比如聊天机器人、文章续写等。当你指定一个预训练模型的名称(如gpt2、gpt-neo、bert-gpt等),该类会自动加载对应的预训练模型及其适配的架构。

1
2
3
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained('model_name')

Token

1
2
3
4
5
6
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('model_name')

# 示例:将文本转化为模型可以接受的输入形式
input_ids = tokenizer("Hello, how are you?", return_tensors="pt")

下载工具

类别 方法 推荐程度 优点 缺点
基于URL 浏览器网页下载 ⭐⭐⭐ 通用性好 手动麻烦/无多线程
多线程下载器(hfd/IDM等) ⭐⭐⭐⭐⭐ 通用性好,鲁棒性好 手动麻烦
批量URL ariaN+(python爬虫) ⭐⭐⭐⭐⭐⭐ 简单(支持二级目录下载) 提前写好python脚本
CLI工具 git clone命令 ⭐⭐ 简单 无断点续传/冗余文件/无多线程
专用CLI工具 huggingface-cli+hf_transfer ⭐⭐⭐ 官方下载工具链,带加速功能 容错性低
huggingface-cli ⭐⭐⭐⭐⭐ 官方下载工具功能全 不支持多线程
Python方法 snapshot_download ⭐⭐⭐ 官方支持,功能全 脚本复杂
from_pretrained 官方支持,简单 不方便存储,功能不全
hf_hub_download 官方支持 不支持全量下载/无多线程

1、Flexgen

https://arxiv.org/abs/2303.06865

Flexgen LLM推理计算环节的量化分析

主要优化点为offload CPU 、CPU和GPU的并行计算、模型量化和多GPU并行

2、DeepSpeed

GitHub - microsoft/DeepSpeed: DeepSpeed is a deep learning optimization library that makes distributed training and inference easy, efficient, and effective.

GitHub - microsoft/DeepSpeedExamples: Example models using DeepSpeed

DeepSpeed 通过系统优化加速大模型推理

针对现有问题:

  1. 对大规模模型缺乏多 GPU 支持并满足延迟要求;
  2. 在小批量(small batch size)推理时,GPU 内核性能有限;
  3. 难以利用量化,既包括量化模型来减少模型大小,以及支持量化模型的高性能推理且无需专门硬件来减少延迟。

提出解决方案:

  1. 推理自适应并行性(Inference-adapted parallelism):允许用户通过适应多 GPU 推理的最佳并行策略来有效地服务大型模型,同时考虑推理延迟和成本。
  2. 针对推理优化的 CUDA 内核(Inference-optimized CUDA kernels):通过深度融合和新颖的内核调度充分利用 GPU 资源,从而提高每个 GPU 的效率。
  3. 有效的量化感知训练(Effective quantize-aware training):支持量化后的模型推理,如 INT8 推理,模型量化可以节省内存(memory)和减少延迟(latency),同时不损害准确性。

运行代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from argparse import ArgumentParser
from transformers import AutoModelForCausalLM, AutoTokenizer, AutoConfig
import deepspeed
import torch
from utils import DSPipeline

inputs = [
"DeepSpeed is a machine learning framework",
"He is working on",
"He has a",
"He got all",
"Everyone is happy and I can",
"The new movie that got Oscar this year",
"In the far far distance from our galaxy,",
"Peace is the only way"
]

pipe = DSPipeline(model_name=args.name,
dtype=torch.float16,
is_meta=args.use_meta_tensor,
device=args.local_rank,
checkpoint_path=args.checkpoint_path)

ds_kwargs = dict()

pipe.model = deepspeed.init_inference(pipe.model,
dtype=torch.int8,
mp_size=args.world_size,
replace_with_kernel_inject=args.use_kernel,
replace_method=args.replace_method,
max_tokens=args.max_tokens,
save_mp_checkpoint_path=args.save_mp_checkpoint_path,
**ds_kwargs
)

torch.cuda.synchronize()
outputs = pipe(inputs, num_tokens=args.max_new_tokens, do_sample=(not args.greedy))
torch.cuda.synchronize()

3、FasterTransformer

https://github.com/NVIDIA/FasterTransformer
https://github.com/cameronfr/FasterTransformer
https://zhuanlan.zhihu.com/p/626008090

  1. 为了减少kernel调用次数,将除了矩阵乘法的kernel都尽可能合并
  2. 针对大batch单独进行了kernel优化
  3. 支持选择最优的矩阵乘法
  4. 在使用FP16时使用half2类型,达到half两倍的访存带宽和计算吞吐
  5. 优化gelu、softmax、layernorm的实现以及选用rsqrt等

FT框架是用C++/CUDA编写的,依赖于高度优化的 cuBLAS、cuBLASLt 和 cuSPARSELt 库,这样可以在 GPU 上进行快速的 Transformer 推理。
调用较为繁琐,只跑通了LLaMA的C++版本demo,修改起来较为困难。

4、exllama学习

ZhiHu LLM推理1:exllama学习

通过Python/C++/CUDA 实现,与 4 位 GPTQ 权重一起使用,旨在在现代 GPU 上实现快速且内存高效。

5、vLLM

https://github.com/vllm-project/vllm
https://vllm.ai/

LLM推理2:vLLM源码学习

# 从理论到实践,深入理解 FlashAttention

vLLM 是在加州大学伯克利分校开发,配备了PagedAttention的vLLM重新定义了 LLM 服务的最新技术水平:它的吞吐量比 HuggingFace Transformers 高出 24 倍,且无需更改任何模型架构

通过Python/C++/CUDA 实现。

运行代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from vllm import LLM, SamplingParams

# Sample prompts.
prompts = [
"Hello, my name is",
"The president of the United States is",
"The capital of France is",
"The future of AI is",
]
# Create a sampling params object.
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)

# Create an LLM.
llm = LLM(model="facebook/opt-125m")
# Generate texts from the prompts. The output is a list of RequestOutput objects
# that contain the prompt, generated text, and other information.
outputs = llm.generate(prompts, sampling_params)
# Print the outputs.
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")

6、llama.cpp/koboldcpp

呵呵哒:LLM推理框架3:llama.cpp/koboldcpp学习

基于 GGML 模型的推理框架,采用了纯 C/C++代码,优势如下:

  • 无需任何额外依赖,相比 Python 代码对 PyTorch 等库的要求,C/C++ 直接编译出可执行文件,跳过不同硬件的繁杂准备;
  • 支持 Apple Silicon 芯片的 ARM NEON 加速,x86 平台则以 AVX2 替代;
  • 具有 F16 和 F32 的混合精度;
  • 支持 4-bit 量化;
  • 无需 GPU,可只用 CPU 运行;

Ref

LLM推理框架总结

LLM推理2:vLLM源码学习