ROS2——零基础入门到实战全网最全QuickStart指南

1. 环境搭建

环境搭建参考以下两篇文档

基础环境搭建

cyclonedds替换及共享内存使用

2. ros2基本框架

3. ros2通信的四种方式

3.1 话题topics

3.1.1 概念

话题采用的是发布者-订阅者模型

话题是ROS中节点交换消息的总线,节点可以订阅/发布任意数量的话题。数据通过publish节点发送到所有订阅了这个topic的subcriber节点

3.1.2 测试

  1. 查看topic列表
ros2 topic list -t

  1. 查看topic内容回显
ros2 topic echo /chatter

  1. 查看topic信息
ros2 topic info /chatter

  1. 发布topic信息
ros2 topic pub --once /chatter std_msgs/msg/String "{123456test}"
ros2 topic pub --rate 1 /chatter std_msgs/msg/String "{data: '123456test'}"

3.2 服务services

3.2.1 概念

服务基于**请求和响应模型**,对具体调用的客户端提供数据,由Service发起请求,Client接收后应答Response,适用于短时间的同步任务,发起任务后,Client会阻塞等待响应。

3.2.2 测试

  1. 查看service列表
ros2 service list
ros2 service list -t

  1. 查找指定type对应的service
ros2 service find rcl_interfaces/srv/GetParameterTypes

  1. 通过service发送数据
ros2 service call /listener/set_parameters_atomically rcl_interfaces/srv/SetParametersAtomically "{parameters: [{name: 'use_sim_time', value: {type: 1, bool_value: true}}]}"

3.3 动作action

3.3.1 概念

动作Action建立在话题和服务之上,并且Action是可抢占的,可以在执行时取消,主要用于长期、异步运行的任务。

3.3.2 测试

3.4 参数parameters

3.4.1 概念

参数是节点的配置,每个节点维护自己的参数,参数可以是整数、浮点数、布尔、字符串和列表

3.4.2 测试

  1. 查看param列表
ros2 param list

  1. 设置指定param值
ros2 param set /listener use_sim_time False

  1. 获取指定param值
ros2 param get /listener use_sim_time

  1. param列表转存
ros2 param dump /listener

  1. param文件加载
ros2 param load /listener listener.yaml

4. 基本概念

4.1 节点

4.1.1 概念

ros2中每个节点代表一个单独的模块,例如一个用于控制电机,一个用于精光测距。每个节点可以通过话题、服务、动作或参数向其他节点发送和接收数据

4.1.2 测试

  1. 在两个终端中分别运行ros2节点
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener

可以看到两个节点在正常通信

  1. 在另外一个终端中查看已有节点信息
ros2 node list

可以看到当前的两个节点,分别为listener和talker

  1. ros节点重映射
ros2 run demo_nodes_cpp talker --ros-args --remap __node:=my_talker

此时能看到三个节点,包括重映射的my_talker

  1. 查看节点详细信息
ros2 node info my_talker

4.2 domain ID

1)在同一个物理网络中,ros2基于Domain ID切分为若干个逻辑网络。

2)在同一域(domain)中的ROS 2节点可以被自由发现并通信,在不同域中则不能互通。

3)所有的ROS 2节点默认使用domain ID 0。

4)为避免消息混淆,同网络内运行ROS 2的不同组的设备应该使用不同的domain ID

5. 常用工具

5.1 bag数据记录和回放

bag可以用于记录和回放话题topic的数据,便于分享操作数据给其他人,以及复现问题

# bag记录指定topic数据
ros2 bag record <topic_name>
# bag记录多个topic数据
ros2 bag record -o <bag_file_name> <topic_name1> <topic_name2>
ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose
# bag回放记录的数据
ros2 bag play <bag_file_name>
ros2 bag play rosbag2_2025_01_21-16_49_40
# bag查看包信息
ros2 bag info <bag_file_name>
ros2 bag info rosbag2_2025_01_21-16_49_40/

6. ros2 demo

这里以topic话题的demo为例,其他的demo大同小异

6.1 如何从0开始创建工程

# 使能环境变量
source /opt/ros/foxy/setup.bash

# 创建工作目录
mkdir -p /mnt/ros2/quicktron_example/src
cd /mnt/ros2/quicktron_example/src

# 创建example_topic包,其中包含一个node(sub_node 订阅节点)
ros2 pkg create --build-type ament_cmake --node-name sub_node example_topic
# 创建另外一个node(pub_node 发布节点)
touch  src/example_topic/src/pub_node.cpp

6.2 如何在工程中添加两个节点

  1. 编辑pub_node.cpp
#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std::chrono_literals;


/// 继承自ros2节点核心类 rclcpp::Node
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0) ///< node名为minimal_publisher
{
    /// 创建publish,消息类型为std_msgs::msg::String,topic名为example_topic,消息队列最大深度为10
    publisher_ = this->create_publisher<std_msgs::msg::String>("example_topic", 10);
    /// 创建定时任务,500MS执行一次
    timer_ = this->create_wall_timer(
        500ms, std::bind(&MinimalPublisher::timer_callback, this));
}

private:
void timer_callback()
{
    auto message = std_msgs::msg::String();
    message.data = "Hello, world! " + std::to_string(count_++);
    RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
    publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};

int main(int argc, char * argv[])
{
    /// 初始化ros2系统
    rclcpp::init(argc, argv);
    /// 节点开始运行,阻塞直到被终止
    rclcpp::spin(std::make_shared<MinimalPublisher>());
    /// 终止节点运行,清理资源
    rclcpp::shutdown();
    return 0;
}
  1. 编辑sub_node.cpp
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;

/// 继承自ros2节点核心类 rclcpp::Node
class MinimalSubscriber : public rclcpp::Node
{
  public:
    MinimalSubscriber()
    : Node("minimal_subscriber")
    { 
        ///创建subscript,消息类型为std_msgs::msg::String,topic名为example_topic
        subscription_ = this->create_subscription<std_msgs::msg::String>(
        "example_topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
    }

  private:
    void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
    {
        RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
    }
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};

int main(int argc, char * argv[])
{
    /// 初始化ros2系统
    rclcpp::init(argc, argv);
    /// 节点开始运行,阻塞直到被终止
    rclcpp::spin(std::make_shared<MinimalSubscriber>());
    /// 终止节点运行,清理资源
    rclcpp::shutdown();
    return 0;
}
  1. 更改package.xml,添加依赖项

主要更改的是以下内容,添加rclcpp及std_msgs的依赖:

<description>Examples of minimal publisher/subscriber using rclcpp</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>

<depend>rclcpp</depend>
<depend>std_msgs</depend>

更改后的完整内容如下:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>example_topic</name>
  <version>0.0.0</version>
  <description>Examples of minimal publisher/subscriber using rclcpp</description>
  <maintainer email="you@email.com">Your Name</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

  1. 更改CMakeLists.txt

主要更改的是以下内容,添加了两个节点的编译依赖,头文件包含,目标产物生成等

add_executable(sub_node src/sub_node.cpp)
add_executable(pub_node src/pub_node.cpp)

ament_target_dependencies(sub_node rclcpp std_msgs)
ament_target_dependencies(pub_node rclcpp std_msgs)

target_include_directories(sub_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

target_include_directories(pub_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

install(TARGETS 
  sub_node
  pub_node
  DESTINATION lib/${PROJECT_NAME})

更改后的完整内容如下:

cmake_minimum_required(VERSION 3.5)
project(example_topic)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

add_executable(sub_node src/sub_node.cpp)
add_executable(pub_node src/pub_node.cpp)

ament_target_dependencies(sub_node rclcpp std_msgs)
ament_target_dependencies(pub_node rclcpp std_msgs)

target_include_directories(sub_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

target_include_directories(pub_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

install(TARGETS 
  sub_node
  pub_node
  DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

6.3 如何进行工程编译与运行

cd /mnt/ros2/quicktron_example
# 使能工程local环境变量
. install/local_setup.bash
export CYCLONEDDS_URI=file:///opt/ros/cyclonedds/config/cyclonedds.xml
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
source /opt/ros/foxy/setup.bash
source /opt/ros/cyclonedds/setup.bash
# 编译并安装
colcon build --symlink-install

# 使用两个终端,一个终端运行sub,一个运行pub
source /opt/ros/foxy/setup.bash
. install/local_setup.bash
ros2 run example_topic sub_node

source /opt/ros/foxy/setup.bash
. install/local_setup.bash
ros2 run example_topic pub_node

运行结果如下:

使用ros2 topic list及ros2 node list查询可看到当前的节点及node

7. ros2常用命令

# source 环境变量
source /opt/ros/foxy/setup.bash
source /opt/ros/cyclonedds/setup.bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export CYCLONEDDS_URI=file:///opt/ros/cyclonedds/config/cyclonedds.xml

# 检查ros环境变量,版本
printenv | grep -i ROS
# 例如
ROS_VERSION=2
ROS_PYTHON_VERSION=3
ROS_DISTRO=foxy


# 编译并安装
colcon build --symlink-install
# 编译指定package
colcon build --packages-select example_topic
# 编译并安装到指定目录
colcon build --symlink-install --install-base /opt/ros/cyclonedds/

# 运行ros2节点
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener
# 查看ros2节点列表
ros2 node list
# 重映射节点
ros2 run demo_nodes_cpp talker --ros-args --remap __node:=my_talker
# 查看节点详细信息
ros2 node info /my_talker


# 查看话题列表
ros2 topic list
# 查看话题列表及数据类型
ros2 topic list -t
# 查看topic发送数据频率
ros2 topic hz /chatter
# 查看话题回显
ros2 topic echo /chatter
ros2 topic info /chatter
# 查看数据类型构成信息
ros2 interface show std_msgs/msg/String
# 向topic发送一条信息
ros2 topic pub --once /chatter std_msgs/msg/String "{data: '123456test'}"
# 以1HZ频率(1S)向topic发送一条信息
ros2 topic pub --rate1 /chatter std_msgs/msg/String "{data: '123456test'}"

# 查看service列表
ros2 service list
# 查看service列表及服务类型
ros2 service list -t
# 查看service类型
ros2 service type /talker/describe_parameters
# 查找特定类型service
ros2 service find rcl_interfaces/srv/GetParameterTypes
# service服务调用,修改参数
ros2 service call /listener/set_parameters_atomically rcl_interfaces/srv/SetParametersAtomically "{parameters: [{name: 'use_sim_time', value: {bool_value: true}}]}"

# 查看参数列表
ros2 param list
# 参数获取
ros2 param get <node_name> <parameter_name>
ros2 param get /listener use_sim_time
# 参数设置
ros2 param set <node_name> <parameter_name> <value>
ros2 param set /listener use_sim_time False
# 参数转存到文件
ros2 param dump <node_name>
ros2 param dump /listener
# 参数从文件加载
ros2 param load <node_name> <parameter_file>
ros2 param load /listener listener.yaml
# 节点启动时加载参数文件
ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>

# 查看动作列表
ros2 action list
ros2 action list -t
ros2 action info <action_name>
ros2 interface show <action_name>
ros2 action send_goal <action_name> <action_type> <values>

# bag记录指定topic数据
ros2 bag record <topic_name>
# bag记录多个topic数据
ros2 bag record -o <bag_file_name> <topic_name1> <topic_name2>
ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose
# bag回放记录的数据
ros2 bag play <bag_file_name>
ros2 bag play rosbag2_2025_01_21-16_49_40
# bag查看包信息
ros2 bag info <bag_file_name>
ros2 bag info rosbag2_2025_01_21-16_49_40/

### ThinkPHP 6.0 连接 PostgreSQL 数据库教程 在 ThinkPHP 6.0 中连接到 PostgreSQL 数据库涉及编辑配置文件并提供必要的连接参数。具体操作如下: #### 编辑数据库配置文件 找到项目的 `config/database.php` 文件,在此文件中定义与 PostgreSQL 相关的连接选项。以下是具体的配置实例[^1]。 ```php return [ // 设置默认使用的数据库连接 'default' => 'pgsql', // 定义多个数据库连接,这里只展示 pgsql 的部分 'connections' => [ 'pgsql' => [ // 数据库类型 'type' => env('database.type', 'pgsql'), // 主机地址 'hostname' => env('database.hostname', 'your_host'), // 数据库名 'database' => env('database.database', 'your_database_name'), // 用户名 'username' => env('database.username', 'your_username'), // 密码 'password' => env('database.password', 'your_password'), // 端口,默认为5432 'hostport' => env('database.hostport', '5432'), // 字符集 'charset' => env('database.charset', 'utf8') ], ] ]; ``` 这段代码展示了如何指定一个名为 `'pgsql'` 的连接,并设置了相应的属性来指向特定的 PostgreSQL 实例。注意使用了环境变量作为默认值,这有助于提高安全性并方便不同环境下部署时修改配置。 当存在主从服务器的情况下,如果两个服务器上的某些参数不一致,则需要分别为它们设定独立的部分;反之则只需共享同一组设置即可[^2]。 完成以上更改之后保存文件重启应用程序使新配置生效。此时应该能够成功建立同 PostgreSQL 数据库之间的通信链路。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值