ROS架构
分布式系统设计
ROS采用独特的分布式架构设计,其核心思想是将机器人系统分解为多个独立运行的节点(Node)。这种设计模式带来三大优势:
核心通信机制
通信方式 |
传输协议 |
典型应用场景 |
Topic(话题) |
发布/订阅 |
持续数据流(如传感器数据) |
Service(服务) |
请求/响应 |
即时指令执行(如启停控制) |
Action(动作) |
状态反馈 |
长时任务(如导航到目标点) |
环境准备与基础概念
ROS 2开发环境要求
-
Ubuntu 22.04
-
ROS 2 Humble
-
Python 3.8+
-
colcon构建工具
sudo apt install python3-colcon-common-extensions
基础概念
功能包(Package)
功能包是ROS的原子单元,用于组织代码和资源。每个功能包通常包含一个特定功能或模块的代码、配置文件、启动文件等。
一个典型的功能包目录结构如下:
package_name/
├── CMakeLists.txt
├── package.xml
├── src/
├── include/
├── launch/
├── msg/
├── srv/
├── action/
└── scripts/
各目录的功能如下:
节点(Node)
节点是ROS中的可执行进程,负责执行特定的任务。节点之间通过话题(Topic)、服务(Service)或动作(Action)进行通信。
在功能包的src/目录下创建C++或Python文件,从而创建相应的节点,例如my_node.cpp或my_node.py。
工作空间(Workspace)
工作空间是ROS开发的容器,用于组织和管理多个功能包。典型的工作空间结构如下:
workspace/
├── src/
├── install/
├── log/
└── build/
其中各目录的功能如下:
-
src/:存放所有功能包的源代码。
-
install/:存放编译后的可执行文件和库。
-
log/:存放日志文件。
-
build/:存放编译过程中生成的中间文件。
Python开发流程
以下是基于python的详细开发流程,包括功能包创建、包结构说明、节点开发以及编译配置等。
创建Python功能包
在ROS 2中,使用以下命令创建一个Python功能包:
source /opt/tros/humble/setup.bash
ros2 pkg create --build-type ament_python demo_py --dependencies rclpy std_msgs
创建的包结构
创建的功能包结构如下:
文件说明:
demo_py/:功能包的根目录。
-
demo_py/:Python模块目录,与功能包同名。
-
package.xml:功能包的元数据文件,包含名称、版本、依赖等信息。
-
setup.cfg:配置Python包的安装方式。
-
setup.py:定义Python包的构建和安装规则。
Python节点开发示例
以下是一个简单的Python节点示例,发布消息到ROS 2话题。
# node_demo.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class Talker(Node):
def __init__(self):
super().__init__('py_talker')
self.publisher = self.create_publisher(String, 'topic', 10)
self.timer = self.create_timer(1.0, self.timer_callback)
self.count = 0
def timer_callback(self):
msg = String()
msg.data = f'Hello ROS2: {self.count}'
self.publisher.publish(msg)
self.get_logger().info(f'Published: {msg.data}')
self.count += 1
def main(args=None):
rclpy.init(args=args)
node = Talker()
rclpy.spin(node)
rclpy.shutdown()
if __name__ == '__main__':
main()
代码说明:
Talker类:继承自Node,表示一个ROS 2节点。
-
create_publisher:创建一个发布者,发布String类型的消息到topic话题。
-
create_timer:创建一个定时器,每1秒触发一次timer_callback。
-
timer_callback:定时器回调函数,发布消息并打印日志。
main函数:初始化ROS 2,创建节点并运行。
配置编译规则
在ROS 2中,Python节点的编译和安装规则通过setup.py文件配置。
# setup.py关键配置
entry_points={
'console_scripts': [
'py_node = demo_py.node_demo:main',
],
}
编译和运行节点
编译功能包
在工作空间根目录下运行以下命令:
colcon build --packages-select demo_py
编译完成后的目录如下:
节点测试
首先我们运行创建的py_node节点。
#加载工作空间环境
source install/setup.bash
#运行节点
ros2 run demo_py py_node
输出如下:
可以看到每隔一秒会发布一个“Hello ROS2”的信息。
之后我们创建一个新的终端,查看我们创建的节点是否能够正常工作。首先查看话题列表
#查看话题列表
ros2 topic list
可以看到当前存在topic话题,之后查看话题内容
#查看话题内容
ros2 topic echo /topic
可以看到,当前话题中能够接收到我们创建的节点发送的信息,说明我们的节点运行功能正常。
C++开发流程
在ROS 2中,使用C++开发功能包和节点的流程与Python类似,但涉及更多的编译配置。以下是详细的C++开发全流程,包括功能包创建、节点开发、包结构说明以及编译配置。
创建C++功能包
使用以下命令创建一个C++功能包:
ros2 pkg create --build-type ament_cmake demo_cpp \--dependencies rclcpp std_msgs
创建的包结构
创建的功能包结构如下:
文件说明:
-
CMakeLists.txt:定义C++项目的编译规则。
-
include/:存放C++头文件。
-
src/:存放C++源代码文件。
-
package.xml:功能包的元数据文件,包含名称、版本、依赖等信息。
C++节点开发示例
以下是一个简单的C++节点示例,在src目录下创建cpp_node.cpp文件,订阅ROS 2话题并打印接收到的消息。
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class Listener : public rclcpp::Node {
public:
Listener() : Node("cpp_listener") {
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10,
[this](const std_msgs::msg::String::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "Received: '%s'",
msg->data.c_str());
});
}
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<Listener>());
rclcpp::shutdown();
return 0;
}
代码说明:
-
Listener类:继承自Node,表示一个ROS 2节点。
-
create_subscription:创建一个订阅者,订阅String类型的消息。
-
回调函数:接收到消息后打印日志。
-
main函数:初始化ROS 2,创建节点并运行。
配置编译规则
在ROS 2中,C++节点的编译规则通过CMakeLists.txt文件配置。CMakeLists.txt 关键配置如下
cmake_minimum_required(VERSION 3.8)
project(demo_cpp)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(cpp_node src/cpp_node.cpp)
ament_target_dependencies(cpp_node rclcpp std_msgs)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
代码说明:
编译和运行节点
使用colcon 构建工具编译功能包
colcon build --symlink-install
其中,--symlink-install参数为:使用符号链接而不是复制文件。
之后运行节点
source install/setup.bash
ros2 run demo_cpp cpp_node
运行结果如下:
可以看到,此时能够正常接收到上面python节点发送的信息,说明我们的cpp_node节点能够正常工作。
|