ROS2(Robot Operating System 2)是一个开源的机器人中间件框架,提供了许多工具、库和驱动程序,能够帮助开发者快速构建复杂的机器人系统。ROS2 是 ROS1 的继任者,具有更高的实时性、安全性和更好的支持分布式系统。
本文将从 ROS2 的基础概念入手,带你一步步走向实际应用,并通过代码示例介绍如何使用 ROS2 开发机器人程序,覆盖主题包括 ROS2 环境搭建、基础通信、机器人控制、传感器数据处理等。
一、ROS2 环境搭建
在开始编写 ROS2 代码之前,首先需要在本地机器上搭建 ROS2 环境。本文以 ROS2 Humble 版本为例,适用于 Ubuntu 22.04。
1. 安装 ROS2 Humble
- 步骤1:设置仓库源
sudo apt update && sudo apt upgrade -y
sudo apt install curl gnupg2 lsb-release
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key | sudo tee /etc/apt/trusted.gpg.d/ros.asc
sudo sh -c 'echo "deb [arch=amd64] http://packages.ros.org/ros2/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros2-latest.list'
- 步骤2:安装 ROS2 基础版本
sudo apt update
sudo apt install ros-humble-desktop
- 步骤3:配置环境变量
source /opt/ros/humble/setup.bash
可以将其加入到 ~/.bashrc
文件中,这样每次打开终端时自动加载环境变量。
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
- 步骤4:安装 ROS2 工具
sudo apt install python3-colcon-common-extensions
二、创建 ROS2 工作空间
工作空间是 ROS2 的基础组织结构,所有的包和节点都保存在工作空间中。
1. 创建 ROS2 工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
source install/setup.bash
2. 创建 ROS2 包
cd ~/ros2_ws/src
ros2 pkg create my_robot_package --build-type ament_cmake
这将创建一个名为 my_robot_package
的包,使用 ament_cmake
作为构建工具。你可以根据需要选择其他构建类型,如 ament_python
。
三、ROS2 通信机制:Publisher 和 Subscriber
ROS2 使用发布-订阅机制(Publisher-Subscriber)进行节点之间的通信。一个节点发布数据,其他节点订阅并处理数据。
1. 创建 Publisher 节点
// my_robot_package/src/publisher_node.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class PublisherNode : public rclcpp::Node
{
public:
PublisherNode() : Node("publisher_node")
{
publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);
timer_ = this->create_wall_timer(
std::chrono::seconds(1), std::bind(&PublisherNode::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, ROS2!";
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<PublisherNode>());
rclcpp::shutdown();
return 0;
}
- 在该代码中,
PublisherNode
每秒发布一次"Hello, ROS2!"
字符串消息。
2. 创建 Subscriber 节点
// my_robot_package/src/subscriber_node.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class SubscriberNode : public rclcpp::Node
{
public:
SubscriberNode() : Node("subscriber_node")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"chatter", 10, std::bind(&SubscriberNode::topic_callback, this, std::placeholders::_1));
}
private:
void topic_callback(const std_msgs::msg::String::SharedPtr msg)
{
RCLCPP_INFO(this->get_logger(), "Received: '%s'", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SubscriberNode>());
rclcpp::shutdown();
return 0;
}
- 该
SubscriberNode
节点会订阅chatter
话题,并打印接收到的消息。
3. 编译和运行
- 编译代码
cd ~/ros2_ws
colcon build
source install/setup.bash
- 运行 Publisher 节点
ros2 run my_robot_package publisher_node
- 运行 Subscriber 节点
ros2 run my_robot_package subscriber_node
此时,subscriber_node
会收到 publisher_node
发布的 "Hello, ROS2!"
消息,并在终端打印。
四、机器人控制:使用服务 (Service) 和客户端 (Client)
ROS2 还支持通过服务 (Service) 和客户端 (Client) 进行同步通信。
1. 创建 Service 节点
// my_robot_package/src/service_node.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_srvs/srv/empty.hpp"
class ServiceNode : public rclcpp::Node
{
public:
ServiceNode() : Node("service_node")
{
service_ = this->create_service<std_srvs::srv::Empty>("clear",
std::bind(&ServiceNode::handle_service, this, std::placeholders::_1, std::placeholders::_2));
}
private:
void handle_service(const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<std_srvs::srv::Empty::Request> request,
const std::shared_ptr<std_srvs::srv::Empty::Response> response)
{
RCLCPP_INFO(this->get_logger(), "Service request received");
}
rclcpp::Service<std_srvs::srv::Empty>::SharedPtr service_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ServiceNode>());
rclcpp::shutdown();
return 0;
}
- 该服务节点提供一个名为
clear
的服务,客户端可以向它发送请求。
2. 创建 Client 节点
// my_robot_package/src/client_node.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_srvs/srv/empty.hpp"
class ClientNode : public rclcpp::Node
{
public:
ClientNode() : Node("client_node")
{
client_ = this->create_client<std_srvs::srv::Empty>("clear");
while (!client_->wait_for_service(std::chrono::seconds(1)))
{
if (!rclcpp::ok())
{
RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for service.");
return;
}
RCLCPP_INFO(this->get_logger(), "Waiting for service to be available...");
}
auto request = std::make_shared<std_srvs::srv::Empty::Request>();
auto future = client_->async_send_request(request);
if (future.wait_for(std::chrono::seconds(1)) == std::future_status::ready)
{
RCLCPP_INFO(this->get_logger(), "Service call successful");
}
}
private:
rclcpp::Client<std_srvs::srv::Empty>::SharedPtr client_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ClientNode>());
rclcpp::shutdown();
return 0;
}
- 该客户端节点向名为
clear
的服务发送请求,并等待服务的响应。
3. 编译和运行
cd ~/ros2_ws
colcon build
source install/setup.bash
- 运行 Service 节点
ros2 run my_robot_package service_node
- 运行 Client 节点
ros2 run my_robot_package client_node
五、总结
通过本教程,我们学习了如何从 ROS2 的
基础搭建开始,逐步进行 ROS2 节点的创建与通信,包括 Publisher-Subscriber 机制以及 Service-Client 机制。同时,我们也展示了如何控制机器人进行简单的任务。
在实际开发中,你可以通过 ROS2 与各种传感器、执行器等硬件设备进行交互,并构建更复杂的机器人系统。接下来,可以进一步学习如何处理机器人传感器数据(如图像、激光雷达数据等)以及如何进行路径规划、控制算法等高级功能。