ROS笔记
一、基础概念和环境设置
-
ROS安装
-
//打开三个终端,分别运行以下命令以测试ROS是否安装成功 roscore rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key
-
创建工作空间
-
mkdir -p catkin_ws/src cd catkin_ws catkin_make source devel/setup.bash // 永久添加环境变量 gedit ~/.bashrc //在打开的文件最下面添加下面代码 source ~/catkin_ws/devel/setup.bash //返回终端重新source source ~/.bashrc
-
-
创建功能包
-
cd /path/to/your/catkin_ws/src //进入src空间 catkin_create_pkg <package_name> [depend1] [depend2] [depend3] //创建功能包和添加依赖 cd /path/to/your/catkin_ws //编译 catkin_make
-
-
第一个程序Hello World
-
catkin_create_pkg test roscpp rospy std_msgs //创建名为test的功能包
-
cd test //进入test功能包 mkdir scripts //创建文件夹,用来放python文件 cd scripts touch hello.py //创建python文件,代码在下方 cd .. //回到catkin_ws catkin_make //编译
-
#! /usr/bin/env python import rospy if __name__ == "__main__": rospy.init_node("Hello") rospy.loginfo("Hello World!")
-
roscore rosrun test hello.py //在两个终端打开,分别运行
-
-
launch文件
-
launch文件帮助我们一次启动多个节点
-
在test功能包下,建立launch文件夹,建立turtle.launch文件
-
<launch> <node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" /> <node name="turtle_teleop_key" pkg="turtlesim" type="turtle_teleop_key" output="screen"/> </launch>
-
roslaunch test turtle.launch
即可一次完成小乌龟控制程序,launch文件会自动启动roscore节点
-
-
计算图
-
rqt_graph能够创建一个显示当前系统运行情况的动态图形。ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程
-
roslaunch test turtle.launch rosrun rqt_graph rqt_graph
-
二、ROS核心概念
-
文件架构
-
-
WorkSpace --- 自定义的工作空间 |--- build:编译空间,用于存放CMake和catkin的缓存信息、配置信息和其他中间文件。 |--- devel:开发空间,用于存放编译后生成的目标文件,包括头文件、动态&静态链接库、可执行文件等。 |--- src: 源码 |-- package:功能包(ROS基本单元)包含多个节点、库与配置文件,包名所有字母小写,只能由字母、数字与下划线组成 |-- CMakeLists.txt 配置编译规则,比如源文件、依赖项、目标文件 |-- package.xml 包信息,比如:包名、版本、作者、依赖项...(以前版本是 manifest.xml) |-- scripts 存储python文件 |-- src 存储C++源文件 |-- include 头文件 |-- msg 消息通信格式文件 |-- srv 服务通信格式文件 |-- action 动作格式文件 |-- launch 可一次性运行多个节点 |-- config 配置信息 |-- CMakeLists.txt: 编译的基本配置
-
-
CMakeLists.txt
-
在ROS中,每个功能包都包含一个名为
CMakeLists.txt
的文件,用于定义如何构建功能包中的节点、库和其他资源。这个文件使用CMake构建系统的语法来配置编译选项、依赖关系和其他构建信息 -
cmake_minimum_required(VERSION 2.8.3) project(my_package) ## 找到catkin并包含它的项目配置 find_package(catkin REQUIRED COMPONENTS roscpp std_msgs ) ## 声明这是一个catkin包 catkin_package() ## 指定包含的头文件路径 include_directories( ${catkin_INCLUDE_DIRS} ) ## 编译并链接一个ROS节点 add_executable(hello_node src/hello.cpp) target_link_libraries(hello_node ${catkin_LIBRARIES}) ## 编译一个ROS库 add_library(my_library src/my_library.cpp) target_link_libraries(my_library ${catkin_LIBRARIES})
-
cmake_minimum_required
:指定需要的最低CMake版本。 -
project
:定义项目名称。 -
find_package
:查找并引入所需的ROS软件包(依赖)。 -
catkin_package
:声明这是一个catkin包。 -
include_directories
:指定包含的头文件路径。 -
add_executable
:定义一个ROS节点的可执行文件。 -
add_library
:定义一个ROS库。
可以在
add_executable
和add_library
部分添加更多的源文件,配置编译选项,指定依赖关系等。在修改完CMakeLists.txt
后,需要重新构建你的ROS工作空间,以使更改生效 -
-
-
package.xml
-
在ROS中,每个功能包都包含一个名为
package.xml
的文件,用于描述功能包的信息、依赖关系以及其他元数据。这个文件提供了功能包的元信息,使其能够被其他ROS工具和节点正确识别和使用。 -
<?xml version="1.0"?> <package> <name>my_package</name> <version>0.1.0</version> <description>My ROS package</description> <maintainer email="your.email@example.com">Your Name</maintainer> <license>MIT</license> <buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <build_depend>std_msgs</build_depend> <run_depend>roscpp</run_depend> <run_depend>std_msgs</run_depend> </package>
-
<name>
:指定功能包的名称。 -
<version>
:指定功能包的版本号。 -
<description>
:提供功能包的描述信息。 -
<maintainer>
:指定维护者的姓名和电子邮件地址。 -
<license>
:指定功能包的许可证类型。 -
<buildtool_depend>
:指定构建工具的依赖关系,通常是catkin
。 -
<build_depend>
:指定在构建时所需的其他功能包依赖。 -
<run_depend>
:指定在运行时所需的其他功能包依赖。
可以在
package.xml
文件中添加更多的信息,如节点的启动文件、节点参数等。在修改完package.xml
后,确保重新构建你的ROS工作空间,以使更改生效 -
-
-
话题通信
-
假设我们要创建两个节点:一个发布者节点和一个订阅者节点,它们通过一个名为 "
sensor_data
" 的话题进行通信。发布者节点会模拟传感器数据,而订阅者节点会接收并打印这些数据 -
catkin_create_pkg communication roscpp rospy std_msgs //新建通信功能包
在
src
目录下建立两个文件publisher.cpp
以及subscriber.cpp
-
#include <ros/ros.h> #include <std_msgs/Int32.h> // 导入需要使用的消息类型 int main(int argc, char **argv) { ros::init(argc, argv, "publisher_node"); // 初始化节点 ros::NodeHandle nh; ros::Publisher pub = nh.advertise<std_msgs::Int32>("sensor_data", 10); // 创建话题发布者,发布Int32类型的消息 ros::Rate rate(1); // 设置发布频率为1Hz while (ros::ok()) { std_msgs::Int32 sensor_msg; sensor_msg.data = 42; // 模拟传感器数据 ROS_INFO("Publishing: %d", sensor_msg.data); pub.publish(sensor_msg); // 发布传感器数据 rate.sleep(); } return 0; }
-
#include <ros/ros.h> #include <std_msgs/Int32.h> // 导入需要使用的消息类型 void callback(const std_msgs::Int32::ConstPtr& msg) { ROS_INFO("Received: %d", msg->data); // 打印接收到的数据 } int main(int argc, char **argv) { ros::init(argc, argv, "subscriber_node"); // 初始化节点 ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe("sensor_data", 10, callback); // 创建话题订阅者,订阅Int32类型的消息 ros::spin(); // 进入循环,等待消息到达 return 0; }
-
-
服务通信
-
自定义服务消息类型
-
进入
communication
功能包,创建srv文件夹以存放自定义服务通信数据类型,创建文件AddTwoInts.srv
-
int32 num1 //客户端数据 int32 num2 --- int32 sum //服务端数据
-
-
编辑配置文件
-
package.xml
-
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
-
-
CMakeLists.txt
-
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) # 需要加入 message_generation,必须有 std_msgs add_service_files( FILES AddTwoInts.srv ) #这里的AddTwoInts.srv要和你创建的srv文件名称一致,且必须时在srv目录下,否则编译会出现问题,生成消息时依赖于 std_msgs generate_messages( DEPENDENCIES std_msgs ) #这个配置的作用是添加生成消息的依赖,默认的时候要添加std_msgs catkin_package( # INCLUDE_DIRS include # LIBRARIES demo_msg CATKIN_DEPENDS roscpp rosmsg rospy message_runtime # DEPENDS system_lib ) #为catkin编译提供了依赖 message_runtime
-
-
返回工作空间,
catkin_make
-
查看头文件
-
../catkin_ws/devel/include/communication/AddTwoInts.h //C++头文件 ../catkin_ws/devel/lib/python3/dist-packages/communication/srv //python文件
-
-
导入
-
#include "communication/AddTwoInts.h" //C++ from communication.srv import AddTwoInts,AddTwoIntsRequest,AddTwoIntsResponse //python
-
-
-
服务通信C++实现,在
communication
功能包src文件夹下新建server.cpp
以及client.cpp
-
#include "ros/ros.h" #include "communication/AddTwoInts.h" bool addCallback(communication::AddTwoInts::Request& req, communication::AddTwoInts::Response& res) { res.sum = req.num1 + req.num2; ROS_INFO("Adding %ld + %ld = %ld", (long int)req.num1, (long int)req.num2, (long int)res.sum); return true; } int main(int argc, char** argv) { ros::init(argc, argv, "server"); ros::NodeHandle nh; ros::ServiceServer service = nh.advertiseService("AddTwoInts", addCallback); ROS_INFO("Ready to add two ints."); ros::spin(); return 0; }
-
#include "ros/ros.h" #include "communication/AddTwoInts.h" // 根据实际路径修改 int main(int argc, char** argv) { ros::init(argc, argv, "client"); if (argc != 3) { ROS_INFO("Usage: add_two_ints_client X Y"); return 1; } ros::NodeHandle nh; ros::ServiceClient client = nh.serviceClient<communication::AddTwoInts>("AddTwoInts"); communication::AddTwoInts srv; //创建请求对象 srv.request.num1 = atoll(argv[1]); srv.request.num2 = atoll(argv[2]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_two_ints"); return 1; } return 0; }
-
修改配置文件
CMakeLists.txt
-
add_executable(server src/server.cpp) target_link_libraries(server ${catkin_LIBRARIES}) add_executable(client src/client.cpp) target_link_libraries(client ${catkin_LIBRARIES}) add_dependencies(server ${PROJECT_NAME}_gencpp) add_dependencies(client ${PROJECT_NAME}_gencpp)
-
-
编译、运行节点
-
-
-
参数服务器
-
参数服务器是可通过网络访问的共享的多变量字典。它是节点存储参数的地方、用于配置参数、全局共享参数。参数服务器使用互联网传输,在节点管理器中运行,实现整个通信过程
-
可以通过
setparam()
来上传参数-
ros::init(argc, argv, "set_param_example"); //创建节点 ros::NodeHandle nh; //创建句柄 nh.setParam(param_name, param_value); //上传参数 //param_name:参数的名称,它是一个字符串,用于标识唯一的参数。通常情况下,参数名称会包括命名空间以防止冲突。 //param_value:参数的值,可以是整数、浮点数、字符串、列表、字典等不同类型的数据。
-
nh.setParam("integer_param", 42); nh.setParam("float_param", 3.14); nh.setParam("string_param", "Hello, ROS!"); std::vector<int> list_param = {1, 2, 3, 4, 5}; nh.setParam("list_param", list_param); std::map<std::string, std::string> dict_param = {{"key1", "value1"}, {"key2", "value2"}}; nh.setParam("dict_param", dict_param);
-
Python
实现 -
rospy.init_node('set_param_example') rospy.set_param(param_name, param_value)
-
rospy.set_param('integer_param', 42) rospy.set_param('float_param', 3.14) rospy.set_param('string_param', 'Hello, ROS!') rospy.set_param('list_param', [1, 2, 3, 4, 5]) rospy.set_param('dict_param', {'key1': 'value1', 'key2': 'value2'})
-
-
通过
getparam()
获取参数-
bool success = nh.getParam(param_name, param_value);
-
param_name
:要获取的参数的名称,它是一个字符串,用于标识参数的唯一标识符。通常情况下,参数名称会包括命名空间以防止冲突。param_value
:获取到的参数值,可以是整数、浮点数、字符串、列表、字典等不同类型的数据。success
(仅C++中):用于指示是否成功获取参数的布尔值。如果获取成功,success
为true
,否则为false
-
int integer_param; 定义变量以保存参数值 nh.getParam("integer_param", integer_param); // 获取整数类型参数
-
param_value = rospy.get_param(param_name) #python用法
-
-
三、ROS常用工具及函数
-
rosnode
-
rosnode list #列出所有节点 rosnode info node_name #获取节点信息 rosnode kill node_name #终止节点 rosnode log node_name #节点日志 rqt_graph #节点图 rosnode ping node_name #节点通信检查 rosnode cleanup #清除不可连接的节点
-
-
rostopic
-
rostopic bw #显示主题使用的带宽 rostopic delay #显示带有 header 的主题延迟 rostopic echo topic_name #打印消息到屏幕 rostopic find #根据类型查找主题 rostopic hz topic_name #显示主题的发布频率 rostopic info topic_name #显示主题相关信息 rostopic list #显示所有活动状态下的主题 rostopic pub #将数据发布到主题 #用法:rostopic pub /主题名称 消息类型 消息内容 #rostopic pub /chatter std_msgs gagaxixi rostopic type #打印主题类型
-
-
rosmsg
-
rosmsg show #显示消息描述 rosmsg info #显示消息信息 rosmsg list #列出所有消息 rosmsg md5 #显示 md5 加密后的消息 rosmsg package #显示某个功能包下的所有消息 rosmsg packages #列出包含消息的功能包
-
-
rosparam
-
rosparam set parameter_name parameter_value #将参数设置到参数服务器上 rosparam get parameter_name #获取参数 rosparam load file.yaml namespace #file.yaml 是参数文件的路径,namespace 是一个可选的命名空间,加载到参数服务器上 rosparam dump file.yaml namespace #将参数写出到外部文件 rosparam delete parameter_name #删除参数 rosparam list #列出所有参数 rosparam set namespace/parameter_name parameter_value #参数命名空间
-
-
ROS初始化,
rospy.init_node()
或ros::init()
-
ros::init(argc, argv, name, options) /* argc(必需):命令行参数数量。 argv(必需):命令行参数数组。 name(必需):指定节点的名称。这个名称必须在整个 ROS 系统中是唯一的。 options(可选,ros::init_options 枚举,默认为 ros::init_options::NoSigintHandler):用于指定初始化选项。可以是 ros::init_options::NoSigintHandler(禁用 SIGINT 信号处理程序)或 ros::init_options::AnonymousName(匿名节点,可以使一个节点启动多次,而不会杀死之前的节点) */
-
#include <ros/ros.h> int main(int argc, char** argv) { // 初始化ROS节点 ros::init(argc, argv, "my_node"); // 创建ROS节点句柄 ros::NodeHandle nh; // 在这里添加你的ROS节点逻辑 // 循环等待节点结束 ros::spin(); return 0; }
-
-
节点句柄
ros::NodeHandle
-
ros::NodeHandle nh; // 创建NodeHandle对象,可以使用这个 `nh` 对象来访问 ROS 系统的各种功能
-
-
话题对象
-
发布方对象
-
ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);
-
topic
:要发布消息的话题名称。 -
queue_size
:发布队列的大小,用于缓存待发布的消息。当缓冲区满时,旧消息会被丢弃。 -
latch
(可选,默认为false
):如果设置为true
,则会将最新发布的消息保持在话题中,新的订阅者会立即收到该消息。 -
advertise
函数返回一个ros::Publisher
类型的对象,你可以使用这个对象来发布消息到指定的话题。
-
-
ros::Publisher pub = nh.advertise<std_msgs::String>("my_topic", 10); //定义
-
ros::Publisher
: 这是ros::Publisher
类的类型,表示发布者对象的类型。ros::Publisher
用于管理发布消息到特定话题的操作。 -
pub
: 这是我们给发布者对象起的名称,你可以根据需要自定义。通过pub
,我们可以在代码中引用这个发布者对象。` -
nh
: 这是ros::NodeHandle
类的一个对象,用于与ROS系统进行交互。我们使用它来创建发布者对象。` -
advertise<std_msgs::String>
: 这是ros::NodeHandle
类的成员函数advertise
,用于创建发布者对象。在尖括号中,我们指定了消息类型std_msgs::String
,这表示我们将发布的消息类型为字符串。 -
"my_topic"
: 这是话题名称,我们将在该话题上发布消息。你可以替换为你想要发布消息的话题名称。 -
10
: 这是发布队列的大小,用于在缓冲区中存储待发布的消息。当缓冲区满时,旧消息会被丢弃。这个值可以根据你的需要进行调整。
-
-
订阅方对象
-
Subscriber subscribe(const std::string& topic, uint32_t queue_size, void(T::*fp)(const boost::shared_ptr<M const>&), T* obj, const TransportHints& transport_hints = TransportHints());
-
topic
:要订阅的话题名称。 -
queue_size
:订阅队列的大小,用于缓存待处理的消息。当队列满时,旧消息会被丢弃。 -
fp
:指向回调函数的指针,该函数将在订阅者接收到消息时被调用。 -
obj
:指向包含回调函数的对象的指针。 -
transport_hints
(可选,默认为空):传输选项,用于配置订阅的传输特性。 -
subscribe
函数返回一个ros::Subscriber
类型的对象,你可以使用这个对象来管理和操作订阅者。
-
-
ros::Subscriber sub = nh.subscribe("my_topic", 10, callback);
-
void callback(const std_msgs::String::ConstPtr& msg)
:这是回调函数,它会在订阅者接收到消息时被调用。我们使用ROS_INFO
打印接收到的消息(或者其他处理方式)。
-
-
发布消息
-
void publish(const boost::shared_ptr<M>& message, uint32_t queue_size = 0, bool latch = false);
-
message
:要发布的消息,通常使用消息类型的指针,例如boost::shared_ptr<std_msgs::String>
。 -
queue_size
:(可选)发布队列的大小,用于缓存待发布的消息。当队列满时,旧消息会被丢弃。 -
latch
:(可选,默认为false
)是否将消息保持在话题中,使新的订阅者在连接时立即接收到最新的消息
-
-
ros::Rate rate(10); // 10Hz,创建一个循环,以指定的频率发布消息 while (ros::ok()) { // 创建一个std_msgs::String类型的消息 std_msgs::String msg; msg.data = "Hello, ROS!"; // 发布消息 pub.publish(msg); // 休眠以维持发布频率 rate.sleep(); }
-
-
-
服务对象
-
服务器对象
-
ServiceServer advertiseService(const std::string& service, bool(T::*srv_func)(MReq&, MRes&), T* obj);
-
service
:要提供的服务的名称。 -
srv_func
:指向服务回调函数的指针,该函数将在接收到服务请求时被调用。 -
obj
:指向包含服务回调函数的对象的指针。 -
advertiseService
函数返回一个ros::ServiceServer
类型的对象,你可以使用这个对象来管理和操作服务器。
-
-
ros::ServiceServer server = nh.advertiseService("my_service", callback);
-
客户端对象
-
ServiceClient serviceClient(const std::string& service, const bool persistent = false, const M_string& header_values = M_string(), const ros::AdvertiseOptions& ops = ros::AdvertiseOptions());
-
service
:要调用的服务的名称。 -
persistent
:是否创建一个持久化的服务客户端。如果设置为true
,则客户端会在每次调用服务时保持连接。如果设置为false
,则每次调用服务都会创建一个新的连接。 -
header_values
:可选,头部信息的键值对,用于设置服务的消息头部。 -
ops
:可选,用于配置服务客户端的ros::AdvertiseOptions
。
-
-
ros::ServiceClient client = nh.serviceClient<your_package::YourService>("my_service");
-
服务通信
-
your_package::YourService::Request req; req.input_data = "Requesting service"; //客户端组织请求数据 your_package::YourService::Response res; // 发送请求并等待响应,call函数调用成功返回true if (client.call(req, res)) { ROS_INFO("Received response: %s", res.output_result.c_str()); } else { ROS_ERROR("Failed to call service"); } //服务器端处理请求 bool callback(your_package::YourService::Request& req, your_package::YourService::Response& res) { // 在这里编写服务回调函数的逻辑 res.output_result = "Processed: " + req.input_data; return true; // 返回 true 表示服务调用成功 }
-
-
回调函数
-
ros::spin();
ros::spin
函数是一个阻塞调用,会一直运行,直到节点被关闭。它用于等待并处理回调函数中的事件,例如接收到的消息或服务请求。通常情况下,你会在节点的主循环中使用ros::spin
,以便持续地监听和响应事件。 -
ros::spinOnce();
ros::spinOnce
函数用于处理一次回调函数中的事件。它通常在一个循环中调用,以便节点可以在等待事件的同时执行其他操作。调用ros::spinOnce
会检查是否有事件需要处理,然后执行相应的回调函数。
-
-
时间
-
ros::Time
-
ros::init(argc,argv,"hello_time"); ros::NodeHandle nh;//必须创建句柄,否则时间没有初始化,导致后续API调用失败 ros::Time right_now = ros::Time::now();//将当前时刻封装成对象 ROS_INFO("当前时刻:%.2f",right_now.toSec());//获取距离 1970年01月01日 00:00:00 的秒数 ROS_INFO("当前时刻:%d",right_now.sec);//获取距离 1970年01月01日 00:00:00 的秒数 ros::Time someTime(100,100000000);// 参数1:秒数 参数2:纳秒 ROS_INFO("时刻:%.2f",someTime.toSec()); //100.10 ros::Time someTime2(100.3);//直接传入 double 类型的秒数 ROS_INFO("时刻:%.2f",someTime2.toSec()); //100.30
-
//时间比较 ros::Time start_time = ros::Time::now(); // 执行一些操作... ros::Time end_time = ros::Time::now(); ros::Duration elapsed_time = end_time - start_time; ROS_INFO("Time elapsed: %.2f seconds", elapsed_time.toSec());
-
//时间同步,确保节点在分布式系统中保持一致的时间标记。 // 在节点 A 中 ros::Time event_time = ros::Time::now(); your_message.header.stamp = event_time; your_publisher.publish(your_message); // 在节点 B 中 void callback(const YourMessageType::ConstPtr& msg) { ros::Time event_time = msg->header.stamp; // 使用 event_time 进行处理 }
-
ros::Duration
-
//使用构造函数来创建 ros::Duration 对象,指定秒数和纳秒数作为参数 ros::Duration duration(2.5); // 2.5 seconds ros::Duration another_duration(1, 500000000); // 1.5 seconds //支持与其他时间间隔的比较和计算,例如加法、减法和乘法等 ros::Duration duration1(2.5); // 2.5 seconds ros::Duration duration2(1.5); // 1.5 seconds ros::Duration sum = duration1 + duration2; // 4 seconds ros::Duration difference = duration1 - duration2; // 1 second //与 ros::Time 一起使用,用于计算时间间隔和延迟 ros::Time start_time = ros::Time::now(); // 执行一些操作... ros::Time end_time = ros::Time::now(); ros::Duration elapsed_time = end_time - start_time; ROS_INFO("Time elapsed: %.2f seconds", elapsed_time.toSec());
-
循环频率
-
ros::Rate rate(1);//指定频率 while (true) { ROS_INFO("-----------code----------"); rate.sleep(); //休眠,休眠时间 = 1 / 频率。 }
-
-
日志消息
-
ROS_INFO
,向终端输出信息 -
ROS_INFO("Your log message here");
-
ROS_INFO
:输出一般信息。 -
ROS_WARN
:输出警告信息。 -
ROS_ERROR
:输出错误信息。
-
-
-
ros::ok()
:检查节点是否仍在运行
四、高级主题和应用
-
launch
文件详细用法-
launch
文件是一种用来启动和配置ROS节点的XML文件。它可以帮助你在一个命令中启动多个节点、设置参数和配置节点之间的关系,其能简化节点的配置与启动,提高ROS程序的启动效率 -
launch
文件标签-
<launch>
:这是launch文件的根标签,它包含了所有其他标签,定义了启动的节点和配置。 -
<node>
:用于启动一个ROS节点的标签-
<node name="node_name" 设置节点的名称,这必须是唯一的 pkg="package_name" 指定节点所在的ROS包名称 type="executable_name" 指定节点的可执行文件名称 output="output_option" 指定节点的输出类型,可以是screen(显示输出在终端)、log(输出到日志文件)、 logscreen(同时输出到终端和日志文件) ns="namespace" 设置节点的命名空间,用于隔离节点的名称 respawn="true_or_false" 设置为true时,如果节点退出,它将被自动重新启动 required="true_or_false" 设置为true时,如果节点退出,整个launch文件会被停止 args="arg1 arg2" 指定传递给节点可执行文件的参数,以空格分隔 clear_params="true_or_false" 设置为true时,节点启动前会清除与节点相关的参数 launch-prefix="command" 指定在启动节点之前要添加的前缀命令,用于调整节点的启动方式 > <!-- 子级标签 --> </node>
-
<node>
可以包含子级标签,包括<param>
、<rosparam>
、<remap>
等等
-
-
<param>
:用于设置节点的参数值。它可以包含以下属性:name
:参数的名称,value
:参数的值。-
name: 参数的名称,用于在参数服务器中唯一标识参数。示例:name="my_parameter" type: 参数的数据类型。可以是以下之一:string、bool、int、double、float、yaml 等。示例:type="double" value: 参数的初始值。根据参数的数据类型,设置相应的值。示例:value="3.14" command: 用于执行一个命令来设置参数的值。这在需要通过处理命令生成参数值时很有用。示例:command="$(find my_package)/scripts/set_parameter.py" textfile: 从文本文件中读取参数值。文本文件中的内容将被读取并作为参数的值。示例:textfile="$(find my_package)/config/my_parameter.txt" command: 用于在launch文件中执行一个命令,然后使用命令的输出值作为参数的值。示例:command="$(find my_package)/scripts/get_parameter_value.sh" command-args: 与 command 一起使用,用于指定命令的参数。示例:command="$(find my_package)/scripts/get_parameter_value.sh" command-args="param_name" rosparam: 使用rosparam命令来设置参数的值。示例:rosparam="my_parameter"
-
<node name="my_node" pkg="my_package" type="my_node_type"> <param name="param_name" value="param_value" /> <arg name="my_param" default="default_value" /> <param name="param_name" value="$(arg my_param)" /> </node>
-
将一个参数
param_name
设置为param_value
,并将它附加到名为my_node
的节点上。节点启动时,它可以通过ROS参数服务器访问这个参数 -
也可以使用
$(arg arg_name)
来从命令行参数中获取值,从而在运行时动态地设置参数 -
在Python中,可以使用
rospy.get_param("param_name")
来获取参数的值。
-
-
<remap>
:用于重映射ROS话题、服务、参数等的名称。它可以包含以下属性:from
:源名称,to
:目标名称-
<node name="my_node" pkg="my_package" type="my_node_type"> <remap from="old_topic" to="new_topic" /> </node>
-
将名为
my_node
的节点的一个话题从old_topic
重映射为new_topic
。这意味着在节点启动时,所有发布到old_topic
的消息将被重定向到new_topic
-
-
<group>
:用于创建一个节点组,允许你在同一个组中以特定的顺序启动节点-
<group ns="robot"> <node name="motion_controller" pkg="robot_control" type="motion_controller" output="screen" /> <node name="sensor_driver" pkg="sensors" type="sensor_driver" output="screen" /> <param name="robot_speed" value="0.5" /> <remap from="camera_topic" to="robot/camera_topic" /> </group>
-
在这个示例中,我们创建了一个名为
robot
的命名空间,将一个运动控制节点、一个传感器驱动节点、一个参数和一个重映射放置在这个命名空间下。这样做可以确保节点和相关配置不会与其他部分发生冲突。
-
-
<include>
:用于在launch文件中包含其他launch文件,以便组织和重用配置。-
<launch> <include file="$(find my_package)/launch/included_launch_file.launch"> <arg name="arg_name" value="arg_value" /> </include> </launch>
-
包含了
my_package
包中的included_launch_file.launch
文件,并传递了一个名为arg_name
的参数
-
-
<arg>
:用于定义launch文件中的参数,这些参数可以在运行时被传递或设置。-
<arg name="arg_name" default="default_value" /> <arg name="robot_name" default="my_robot" /> <arg name="use_camera" default="true" /> <arg name="target_speed" default="0.5" />
-
roslaunch my_package my_launch_file.launch robot_name:=my_custom_robot use_camera:=false target_speed:=1.0 #在命令行中传递参数,使用`roslaunch`命令的参数传递功能,我们通过命令行传递了参数值,覆盖了默认值
-
<arg>
和<param>
区别-
用途:
-
<arg>
标签用于定义参数,这些参数可以在命令行传递给launch文件,也可以在包含标签内部传递给被包含的launch文件。它主要用于在不同上下文中自定义配置。 -
<param>
标签用于设置节点的参数值。它主要用于在节点启动时为节点配置参数。
-
-
传递方式:
-
<arg>
标签通过命令行参数传递,可以在roslaunch
命令中使用参数名来覆盖默认值。 -
<param>
标签通过ROS参数服务器传递,节点在启动时从参数服务器加载参数的值。
-
-
上下文:
-
<arg>
标签通常用于整个launch文件的上下文,可以影响多个节点的配置。 -
<param>
标签通常用于单个节点的上下文,它只影响一个节点的参数设置。
-
-
使用场景:
-
使用
<arg>
标签适合在不同情况下自定义配置,比如在不同机器、不同实验中使用不同的参数值。 -
使用
<param>
标签适合在启动节点时设置其参数,以确保节点在启动时有正确的初始配置。
-
-
<launch> <!-- Using <arg> to define parameters that can be passed via command line --> <arg name="robot_name" default="my_robot" /> <arg name="target_speed" default="0.5" /> <!-- Using <param> to set parameters for a node --> <node name="my_node" pkg="my_package" type="my_node_type"> <param name="robot_name" value="$(arg robot_name)" /> <param name="speed" value="$(arg target_speed)" /> </node> </launch>
-
使用
<arg>
定义了robot_name
和target_speed
参数,并在<node>
标签内部使用<param>
将这些参数的值传递给节点
-
-
-
<rosparam>
:用于从ROS参数服务器加载参数值,<rosparam>
标签可以从 YAML 文件导入参数,或将参数导出到 YAML 文件,也可以用来删除参数,<rosparam>
标签在<node>
标签中时被视为私有-
<rosparam param="my_params" subst_value="true" command="load" file="$(find my_package)/config/my_params.yaml" />
-
将
my_params.yaml
文件中的参数加载到名为my_params
的参数名下。subst_value="true"
允许在参数值中进行ROS参数替换,使参数可以引用其他参数-
param
:指定参数的名称,将在ROS参数服务器中创建或覆盖这个参数。这个属性是必需的。 -
subst_value
:控制是否允许在参数值中进行ROS参数替换。如果设置为true
,则可以在参数值中使用$(param param_name)
来引用其他参数。默认值为false
。 -
command
:指定要执行的命令,用于加载参数。常见的命令有load
(从文件加载参数)和delete
(从ROS参数服务器删除参数)。这个属性是必需的。 -
file
:指定要加载的文件路径。这可以是绝对路径,也可以使用ROS软件包的$(find package_name)
来获取包路径。该属性通常与command="load"
一起使用,用于从文件加载参数值。 -
param_name
:用于command="delete"
时,指定要删除的参数名称
-
-
-
<env>
:在ROS launch文件中用于设置节点运行时的环境变量。这些环境变量可以影响节点的行为、配置和功能-
<node name="my_node" pkg="my_package" type="my_node_type"> <env name="ROS_MASTER_URI" value="http://localhost:11311" /> <env name="ROBOT_NAME" value="my_robot" /> </node>
-
为节点设置了两个环境变量,分别是
ROS_MASTER_URI
和ROBOT_NAME
-
-
<param if="$(arg condition)" />
:条件语句,根据条件来设置参数-
<launch> <arg name="use_param" default="false" /> <node name="my_node" pkg="my_package" type="my_node_type"> <param if="$(arg use_param)" name="param_name" value="param_value" /> </node> </launch>
-
roslaunch my_package my_launch_file.launch use_param:=true
-
因为
use_param
的值为true
,所以参数param_name
会被设置为param_value
。
-
-
<launch-prefix>
:用于为节点设置前缀命令,可用于调整节点的启动方式-
<node name="my_node" pkg="my_package" type="my_node_type"> <launch-prefix cmd="gdb -ex run --args" /> </node>
-
为节点设置了一个前缀命令,以便在启动节点之前运行
gdb -ex run --args
命令。这对于调试节点或在特定环境中运行节点很有用
-
-
-
-
节点重名
-
节点(Node)是一个独立的进程,用于执行特定的任务或功能。每个节点都有一个唯一的名称,以便在ROS系统中进行识别和通信,如果启动重名节点的话,之前已经存在的节点会被直接关闭。如果确实需要使用同名节点,那么可以使用命名空间或名称重映射,命名空间就是为名称添加前缀,名称重映射是为名称起别名。
-
实现策略包括
rosrun
命令、launch
文件、编码实现-
rosrun
命令 设置命名空间-
rosrun turtlesim turtlesim_node __ns:=/xxx rosrun turtlesim turtlesim_node __ns:=/yyy
使用
rosnode list
查看节点 -
/xxx/turtlesim /yyy/turtlesim
-
-
rosrun
命令 名称重映射-
rosrun turtlesim turtlesim_node __name:=t1 rosrun turtlesim turtlesim_node __name:=t2
-
-
-
-
launch
文件,实现节点重命名-
<launch> <node pkg="turtlesim" type="turtlesim_node" name="t1" /> <node pkg="turtlesim" type="turtlesim_node" name="t2" /> <node pkg="turtlesim" type="turtlesim_node" name="t1" ns="hello"/> </launch>
-
name
和ns
,二者分别是用于实现名称重映射与命名空间设置的,name
属性是必须的,ns
可选 -
/t1 /t2 /t1/hello
-
-
编码实现节点重命名
-
ros::init(argc,argv,"zhangsan",ros::init_options::AnonymousName); //C++重映射,会在名称后面添加时间戳 rospy.init_node("lisi",anonymous=True) //Python重映射
-
std::map<std::string, std::string> map; map["__ns"] = "xxxx"; ros::init(map,"wangqiang"); //使用命名空间
-
-
话题名称设置
-
rosrun
设置话题重映射,__name
来为节点指定一个不同的名称,并且可以使用参数_remap
来进行话题重映射-
rosrun package_name node_name __name:=new_node_name _remap:=old_topic_name:=new_topic_name
-
package_name
是包含要运行的节点的包的名称,node_name
是要运行的节点的名称,new_node_name
是你想要为节点重命名的名称,old_topic_name
是原始话题的名称,new_topic_name
是你想要为话题重命名的名称
-
-
launch
文件设置话题重映射-
<node pkg="xxx" type="xxx" name="xxx"> <remap from="原话题" to="新话题" /> </node>
-
-
编码设置话题名称
-
话题的名称与节点的命名空间、节点的名称是有一定关系的,话题名称大致可以分为三种类型:
-
全局(话题参考ROS系统,与节点命名空间平级)
-
相对(话题参考的是节点的命名空间,与节点名称平级)
-
私有(话题参考节点名称,是节点名称的子级)
-
-
//前期准备 1.初始化节点设置一个节点名称 ros::init(argc,argv,"hello") 2.设置不同类型的话题 3.启动节点时,传递一个 __ns:= nihao 4.节点启动后,使用 rostopic 查看话题信息
-
全局名称,以
/
开头的名称,和节点名称无关-
ros::Publisher pub = nh.advertise<std_msgs::String>("/chatter",1000); // 结果为:/chatter ros::Publisher pub = nh.advertise<std_msgs::String>("/chatter/money",1000); // 结果为:/chatter/money
-
-
相对名称,非
/
开头的名称,参考命名空间(与节点名称平级)来确定话题名称-
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000); //结果为:nihao/chatter ros::Publisher pub = nh.advertise<std_msgs::String>("chatter/money",1000); //结果为:nihao/chatter/money
-
-
私有名称,以
~
开头的名称-
ros::NodeHandle nh("~"); ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",1000); //结果为:/nihao/hello/chatter
-
-
-
-
ROS参数名称设置
-
rosrun
设置参数-
rosrun turtlesim turtlesim_node _A:=100 #添加一个A参数
-
rosparam list
查看节点信息,显示结果 -
/turtlesim/A /turtlesim/background_b /turtlesim/background_g /turtlesim/background_r
-
-
launch
文件设置参数-
<launch> <param name="p1" value="100" /> <node pkg="turtlesim" type="turtlesim_node" name="t1"> <param name="p2" value="100" /> </node> </launch>
-
/p1 /t1/p1
-
-
编码设置参数
-
在 C++ 中,可以使用
ros::param
或者ros::NodeHandle
来设置参数-
// 使用ros::param ros::param::set("/set_A",100); //全局,和命名空间以及节点名称无关 ros::param::set("set_B",100); //相对,参考命名空间 ros::param::set("~set_C",100); //私有,参考命名空间与节点名称
-
运行时,假设设置的 namespace 为 xxx,节点名称为 yyy,使用 rosparam list 查看
-
/set_A /xxx/set_B /xxx/yyy/set_C
-
//使用ros::NodeHandle ros::NodeHandle nh; nh.setParam("/nh_A",100); //全局,和命名空间以及节点名称无关 nh.setParam("nh_B",100); //相对,参考命名空间 ros::NodeHandle nh_private("~"); nh_private.setParam("nh_C",100);//私有,参考命名空间与节点名称
-
/nh_A /xxx/nh_B /xxx/yyy/nh_C
-
-
在python中,可以使用
rospy.set_param
-
rospy.set_param("/py_A",100) #全局,和命名空间以及节点名称无关 rospy.set_param("py_B",100) #相对,参考命名空间 rospy.set_param("~py_C",100) #私有,参考命名空间与节点名称
-
/py_A /xxx/py_B /xxx/yyy/py_C
-
-
-
-
ROS分布式通信 #TODO
-
TF2坐标变换
-
坐标消息
-
在坐标转换实现中常用的 msg:
geometry_msgs/TransformStamped
和geometry_msgs/PointStamped
-
rosmsg info geometry_msgs/TransformStamped
,geometry_msgs/TransformStamped
是ROS中用于传输坐标变换信息的消息类型。它包含了一个坐标变换的完整信息,包括变换的平移和旋转以及与之相关的时间戳、坐标系 -
std_msgs/Header header #头信息 uint32 seq #|-- 序列号,确保消息的顺序传递以及检测丢失的消息 time stamp #|-- 时间戳,数据同步和历史数据分析 string frame_id #|-- 坐标 ID,正确处理数据和在不同坐标系 string child_frame_id #子坐标系的 id geometry_msgs/Transform transform #坐标信息 geometry_msgs/Vector3 translation #偏移量 float64 x #|-- X 方向的偏移量 float64 y #|-- Y 方向的偏移量 float64 z #|-- Z 方向上的偏移量 geometry_msgs/Quaternion rotation #四元数,表示旋转 float64 x float64 y float64 z float64 w
-
rosmsg info geometry_msgs/PointStamped
,geometry_msgs/PointStamped
是ROS中用于传输带有时间戳的三维点信息的消息类型。它在geometry_msgs
包中定义,用于表示一个带有时间戳的三维点 -
std_msgs/Header header #头 uint32 seq #|-- 序号 time stamp #|-- 时间戳 string frame_id #|-- 所属坐标系的 id geometry_msgs/Point point #点坐标 float64 x #|-- x y z 坐标 float64 y float64 z
-
-
TF2基本使用方法,广播、监听和转换坐标变换的功能
-
//导入头文件 #include <tf2_ros/transform_broadcaster.h> #include <tf2_ros/transform_listener.h> #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
-
广播坐标变换: 使用
TransformBroadcaster
可以广播坐标变换。通过广播,可以将坐标变换发送给ROS系统中的其他节点-
//内置函数 构造函数: tf2_ros::TransformBroadcaster()//创建一个广播器对象。 广播坐标变换: sendTransform(const geometry_msgs::TransformStamped &transformStamped)//广播坐标变换消息。你需要创建一个 geometry_msgs::TransformStamped 消息,将坐标变换信息填入并传递给这个函数。
-
// 创建TransformBroadcaster实例 tf2_ros::TransformBroadcaster tf_broadcaster; // 创建TransformStamped消息 geometry_msgs::TransformStamped transformStamped; // 设置变换信息 // 广播坐标变换消息 tf_broadcaster.sendTransform(transformStamped);
-
-
监听坐标变换: 使用
TransformListener
可以监听其他节点广播的坐标变换-
//内置函数 构造函数: tf2_ros::TransformListener(const tf2_ros::Buffer &buffer) //创建一个监听器对象,需要传入一个 tf2_ros::Buffer 对象,用于存储坐标变换信息。 查询坐标变换: lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time) //在指定时间查询从源坐标系到目标坐标系的坐标变换。如果查询成功,返回 geometry_msgs::TransformStamped 消息,如果失败,会抛出 tf2::TransformException 异常
-
// 创建TransformListener实例 tf2_ros::TransformListener tf_listener(buffer); // 创建输入数据 geometry_msgs::PointStamped input_point; // 设置输入数据信息 // 转换点到目标坐标系 geometry_msgs::PointStamped output_point; if (buffer.transform(input_point, output_point, "target_frame")) { // 处理转换后的点 }
-
-
TransformBuffer
(变换缓存): 变换缓存用于存储和管理坐标变换。在监听和查询坐标变换时,使用TransformBuffer
可以避免频繁查询TF,提高性能-
//内置函数 构造函数: tf2_ros::TransformBuffer():创建一个空的变换缓存对象。 查询坐标变换: lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time):在指定时间查询从源坐标系到目标坐标系的坐标变换。 canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, ros::Duration timeout):检查是否可以从源坐标系到目标坐标系的坐标变换。 查询是否存在坐标变换信息: canTransform(const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, ros::Duration timeout):检查是否可以从源坐标系到目标坐标系的坐标变换,并且指定了固定坐标系。 清空变换缓存: clear():清空变换缓存中的所有坐标变换信息。 设置使用独立线程: setUsingDedicatedThread(bool use_dedicated_thread):设置是否使用独立的线程来处理坐标变换查询。 设置坐标变换信息过期时间: setTransformExpirationDuration(const ros::Duration &duration):设置坐标变换信息的过期时间。 获取所有坐标系名称: getFrameStrings(std::string &frame_authority):获取所有存在的坐标系名称。 插入坐标变换: setTransform(const geometry_msgs::TransformStamped &transform):将坐标变换信息插入到变换缓存中。 插入多个坐标变换: setTransforms(const std::vector<geometry_msgs::TransformStamped> &transforms, const ros::Time &time, const std::string &authority):批量插入多个坐标变换信息。 数据类型转换: transformStampedToEigen(const geometry_msgs::TransformStamped &transformStamped):将 geometry_msgs::TransformStamped 转换为 Eigen::Isometry3d。
-
// 创建TransformBuffer实例 tf2_ros::Buffer buffer; tf2_ros::TransformListener tf_listener(buffer); // 查询坐标变换 geometry_msgs::TransformStamped transformStamped; try { transformStamped = buffer.lookupTransform("target_frame", "source_frame", ros::Time(0)); // 处理变换 } catch (tf2::TransformException &ex) { ROS_WARN("Transform exception: %s", ex.what()); }
-
-
数据类型转换: TF2提供了一些方便的函数用于坐标变换的数据类型转换,如旋转矩阵到四元数、四元数到欧拉角等
-
#include <tf2/convert.h> tf2::Quaternion quaternion; quaternion.setRPY(0.1, 0.2, 0.3); // 设置旋转角度 tf2::Matrix3x3 rotation_matrix(quaternion); tf2::Quaternion converted_quaternion; rotation_matrix.getRotation(converted_quaternion); // 进行其他数据类型转换操作
-
-
其他内置函数
-
坐标变换函数: tf2::doTransform(const PointT &in, PointT &out, const geometry_msgs::TransformStamped &transformStamped):将输入数据从一个坐标系转换到另一个坐标系,并将结果存储在输出变量 out 中。 坐标变换查询函数: tf2_ros::Buffer::lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time):在指定时间查询从源坐标系到目标坐标系的坐标变换。 tf2_ros::Buffer::canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, ros::Duration timeout):检查是否可以从源坐标系到目标坐标系的坐标变换。 坐标变换缓存函数: tf2_ros::TransformBuffer::clear():清空变换缓存中的所有坐标变换信息。 tf2_ros::TransformBuffer::setTransform(const geometry_msgs::TransformStamped &transform):将坐标变换信息插入到变换缓存中。 数据类型转换函数: tf2::fromMsg(const geometry_msgs::TransformStamped &msg, tf2::Transform &bt):将 geometry_msgs::TransformStamped 转换为 tf2::Transform。 tf2::toMsg(const tf2::Transform &bt, geometry_msgs::TransformStamped &msg):将 tf2::Transform 转换为 geometry_msgs::TransformStamped。 四元数操作函数: tf2::Quaternion::setRPY(double roll, double pitch, double yaw):设置四元数的欧拉角。 tf2::Quaternion::normalize():将四元数归一化。 矩阵操作函数: tf2::Matrix3x3::getRPY(double &roll, double &pitch, double &yaw, unsigned int solution_number=1) const:从旋转矩阵中获取欧拉角
-
-
-
五、项目和实践
-
URDF
文件-
URDF (Unified Robot Description Format) 是一种用于描述机器人模型的XML文件格式。它是ROS(机器人操作系统)中常用的一种文件格式,用于表示机器人的结构、关节、传感器、连接关系等信息。URDF文件可用于仿真、控制、运动规划等任务。
-
#urdf_to_graphiz: 将URDF文件转换为Graphviz可视化格式,用于可视化URDF模型的结构。 rosrun urdfdom urdf_to_graphiz your_robot.urdf #check_urdf: 检查URDF文件的语法和结构是否正确 check_urdf your_robot.urdf #rosparam get <param_name>: 获取在参数服务器上存储的URDF参数值 rosparam get /robot_description #robot_state_publisher:一个ROS软件包,用于将URDF模型的状态发布到ROS的TF变换框架,使得可以在RViz中显示机械臂的运动 rosrun robot_state_publisher robot_state_publisher #spawn_model: 在Gazebo仿真中加载URDF模型 roslaunch gazebo_ros spawn_model.launch urdf:=/path/to/your_robot.urdf
-
<robot>
:整个机器人模型的根标签,包含机器人的基本信息,子标签:name
:机器人的名称-
<robot name="my_robot"> <!-- 在这里定义机器人的链接、关节、传感器等部分 --> </robot>
-
-
<link>
:描述机器人的各个组成部分的属性。嵌套的标签:<visual>
、<collision>
、<inertial>
等-
<link name="link_name"> <!-- 可视化外观 --> <visual> <!-- 定义可视化外观的几何形状 --> <geometry> <!-- 几何形状的类型,如box、cylinder、mesh等 --> </geometry> <!-- 可选:定义材质的颜色、纹理等信息 --> <material name="material_name"> <!-- 定义颜色或纹理 --> </material> </visual> <!-- 碰撞信息 --> <collision> <!-- 定义用于碰撞检测的几何形状 --> <geometry> <!-- 几何形状的类型,如box、cylinder、mesh等 --> </geometry> </collision> <!-- 惯性信息 --> <inertial> <!-- 链接的质量 --> <mass value="0.1"/> <!-- 链接的惯性矩阵 --> <inertia ixx="0.01" iyy="0.01" izz="0.01"/> <!-- 惯性坐标系的原点 --> <origin rpy="0 0 0" xyz="0 0 0"/> </inertial> </link>
-
-
<joint>
:描述连接不同链接之间的关节属性,嵌套的标签:<parent>
、<child>
、<axis>
、<limit>
、<origin>
等-
<joint name="joint_name" type="joint_type"> <!--type有revolute(旋转关节)、continuous(连续旋转关节)、prismatic(移动关节)、fixed(固定关节)等--> <!-- 父链接 --> <parent link="parent_link_name"/> <!-- 子链接 --> <child link="child_link_name"/> <!-- 轴信息 --> <axis xyz="0 0 1"/> <!-- 关节的角度范围限制 --> <limit effort="10" velocity="1.0" lower="-1.57" upper="1.57"/> <!--effort:关节的最大扭矩。velocity:关节的最大运动速度。lower:关节的最小角度(或位移)限制。upper:关节的最大角度(或位移)限制--> <!-- 关节初始角度 --> <origin rpy="0 0 0" xyz="0 0 0"/> </joint>
-
-
<sensor>
:描述机器人上的传感器属性。-
<sensor name="camera_sensor" type="camera"> <camera> <!-- 定义相机参数,如分辨率、视场等 --> </camera> </sensor> <sensor name="laser_sensor" type="ray"> <ray> <!-- 定义激光雷达参数,如扫描角度、最大距离等 --> </ray> </sensor> <sensor name="imu_sensor" type="imu"> <imu> <!-- 定义IMU参数,如噪声、偏置等 --> </imu> </sensor>
-
-
-
xacro
文件-
xacro
是 ROS 中一种XML格式的宏语言,用于更便捷地创建和维护URDF(Unified Robot Description Format)文件。它允许您在URDF文件中使用参数、条件、循环等功能,以减少冗余代码,提高代码可维护性,并支持更高级的模型构建。-
参数替换: 使用 xacro,您可以定义参数,并在URDF文件中使用这些参数。这使您能够轻松更改机器人模型的参数,而无需手动修改每个链接和关节。
-
条件和循环: xacro 支持条件判断和循环,可以根据不同情况生成不同的URDF代码。这对于构建具有复杂结构和变化的机器人模型非常有用。
-
包含其他文件: xacro 允许您在URDF文件中包含其他xacro文件,从而使代码模块化,易于组织和管理。
-
宏定义: xacro 允许您定义宏,将常用的代码块封装为可重用的模块,从而减少代码重复。
-
参数传递: 在 xacro 文件之间传递参数,使得您可以在多个URDF文件中共享相同的参数值。
-
-
#rosrun xacro xacro <input.xacro> > <output.urdf>: 将xacro文件转换为URDF文件 rosrun xacro xacro your_input.xacro > output.urdf #将xacro文件转换为URDF文件,并传递参数值给xacro。 rosrun xacro xacro your_input.xacro > output.urdf -param param_name:=param_value #将xacro文件转换为URDF文件并指定输出文件名。 rosrun xacro xacro your_input.xacro -o output.urdf #获取在参数服务器上存储的xacro参数值。 rosparam get /your_param_name #设置参数服务器上的xacro参数值 rosparam set /your_param_name param_value
-
语法详解
-
<xacro:property name="param_name" value="param_value"/> <!--参数定义-->
-
<link name="my_link"> <geometry> <box size="${param_value} ${param_value} ${param_value}"/> </geometry> </link> <!--参数使用-->
-
<xacro:if value="${condition}"> <!-- 仅当条件为真时生成这部分代码 --> </xacro:if> <!--条件判断-->
-
<xacro:foreach var="i" range="0 ${num_links}"> <link name="link_${i}"/> </xacro:foreach> <!--循环生成-->
-
<xacro:include filename="path_to_sub_robot.xacro"/> <!--包含其他文件-->
-
<xacro:def name="my_macro" param="${param}"> <!-- 宏的内容 --> </xacro:def> <!--宏定义-->
-
<xacro:call macro="my_macro" param="value"/> <!--宏使用-->
-
<xacro:macro name="sub_robot" param="${param}"> <!-- 定义参数 --> </xacro:macro> <!--参数传递-->
-
-