Robot Operating System——创建可执行文件项目的步骤

2024-08-21 06:28

本文主要是介绍Robot Operating System——创建可执行文件项目的步骤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大纲

  • 初始化环境
  • 创建Package
  • 代码
  • 添加依赖(package.xml)
  • 修改编译描述
    • find_package寻找依赖库
    • 指定代码路径和编译类型(可执行文件/动态库)
    • 链接依赖的库
    • 完整文件
  • 编译
  • 测试
  • 总结
  • 参考资料

之前我们看到ROS2中,有的Node的实现逻辑存在于动态库中,而动态库又有隐式加载和手动加载等几种模式。这些例子都比较复杂。本文将介绍如何从0到1创建一个最简单的工程,其Node都在可执行文件中,以保证过程的清晰。

初始化环境

在《Robot Operating System——深度解析自动隐式加载动态库的运行模式》一文中,我们展现了ROS2可执行文件的链接指令。可以看到它依赖了很多ROS2环境相关的动态库,所以我们在创建工程之前也要初始化环境。

source /opt/ros/jazzy/setup.bash

关于环境的安装可以参见《Robot Operating System——Ubuntu上以二进制形式安装环境》。

创建Package

ros2 pkg create --build-type ament_cmake --license Apache-2.0 two_node_pipeline

在这里插入图片描述
可以看到ros2帮我们创建好了相关的目录结构
在这里插入图片描述
剩下的事就是我们要填充这个工程。

代码

在two_node_pipeline/src目录下新建一个main.cpp文件。
代码我们直接借用https://github.com/ros2/demos/blob/jazzy/intra_process_demo/src/cyclic_pipeline/cyclic_pipeline.cpp的源码。它直接在一个可执行文件中编译了两个Node。

// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.#include <chrono>
#include <cinttypes>
#include <cstdio>
#include <memory>
#include <string>
#include <utility>#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/int32.hpp"using namespace std::chrono_literals;// Node that produces messages.
struct Producer : public rclcpp::Node
{Producer(const std::string & name, const std::string & output): Node(name, rclcpp::NodeOptions().use_intra_process_comms(true)){// Create a publisher on the output topic.pub_ = this->create_publisher<std_msgs::msg::Int32>(output, 10);std::weak_ptr<std::remove_pointer<decltype(pub_.get())>::type> captured_pub = pub_;// Create a timer which publishes on the output topic at ~1Hz.auto callback = [captured_pub]() -> void {auto pub_ptr = captured_pub.lock();if (!pub_ptr) {return;}static int32_t count = 0;std_msgs::msg::Int32::UniquePtr msg(new std_msgs::msg::Int32());msg->data = count++;printf("Published message with value: %d, and address: 0x%" PRIXPTR "\n", msg->data,reinterpret_cast<std::uintptr_t>(msg.get()));pub_ptr->publish(std::move(msg));};timer_ = this->create_wall_timer(1s, callback);}rclcpp::Publisher<std_msgs::msg::Int32>::SharedPtr pub_;rclcpp::TimerBase::SharedPtr timer_;
};// Node that consumes messages.
struct Consumer : public rclcpp::Node
{Consumer(const std::string & name, const std::string & input): Node(name, rclcpp::NodeOptions().use_intra_process_comms(true)){// Create a subscription on the input topic which prints on receipt of new messages.sub_ = this->create_subscription<std_msgs::msg::Int32>(input,10,[](std_msgs::msg::Int32::UniquePtr msg) {printf(" Received message with value: %d, and address: 0x%" PRIXPTR "\n", msg->data,reinterpret_cast<std::uintptr_t>(msg.get()));});}rclcpp::Subscription<std_msgs::msg::Int32>::SharedPtr sub_;
};int main(int argc, char * argv[])
{setvbuf(stdout, NULL, _IONBF, BUFSIZ);rclcpp::init(argc, argv);rclcpp::executors::SingleThreadedExecutor executor;auto producer = std::make_shared<Producer>("producer", "number");auto consumer = std::make_shared<Consumer>("consumer", "number");executor.add_node(producer);executor.add_node(consumer);executor.spin();rclcpp::shutdown();return 0;
}

添加依赖(package.xml)

package.xml 是 ROS 2 包的元数据文件,定义了包的基本信息和依赖关系。

打开two_node_pipeline/package.xml,添加代码中include头文件(#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp")所依赖的其他库。

  <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>two_node_pipeline</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="f304646673@gmail.com">fangliang</maintainer><license>Apache-2.0</license><buildtool_depend>ament_cmake</buildtool_depend><depend>rclcpp</depend><depend>std_msgs</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>

修改编译描述

find_package寻找依赖库

再打开two_node_pipeline/CMakeLists.txt中添加上述头文件(#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp")所依赖的库

find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

在 CMake 中,find_package 命令用于查找并加载外部包或库。它的主要作用如下:

  • 查找包:find_package 会在系统中查找指定的包或库,并加载其配置文件。这些配置文件通常包含包的路径、库文件、头文件等信息。

  • 设置变量:如果找到包,find_package 会设置一些变量,这些变量可以在后续的 CMake 脚本中使用。例如,<PackageName>_FOUND 变量会被设置为 TRUE,表示找到了包。

  • 导入目标:一些包会定义 CMake 导入目标(imported targets),这些目标可以直接在 target_link_libraries 等命令中使用。

指定代码路径和编译类型(可执行文件/动态库)

设定编译结果名称

set(EXECUTABLE_NAME "two_node_pipeline")

指定编译结果是可执行文件

# Collect all source files in this directory
file(GLOB SOURCES "src/*.cpp")# Add the executable target
add_executable(${EXECUTABLE_NAME} ${SOURCES})

链接依赖的库

最后将代码中用到的库(#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/int32.hpp")链接到可执行文件中。

ament_target_dependencies(${EXECUTABLE_NAME} rclcpp std_msgs)

完整文件

cmake_minimum_required(VERSION 3.8)
project(two_node_pipeline)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)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)set(EXECUTABLE_NAME "two_node_pipeline")# Collect all source files in this directory
file(GLOB SOURCES "src/*.cpp")# Add the executable target
add_executable(${EXECUTABLE_NAME} ${SOURCES})ament_target_dependencies(${EXECUTABLE_NAME} 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 filesset(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 filesset(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies()
endif()ament_package()

编译

cd two_node_pipeline/build
cmake ..
make

在这里插入图片描述

测试

./two_node_pipeline 

在这里插入图片描述

总结

  1. 初始化环境source /opt/ros/jazzy/setup.bash,以保证ROS2的基础动态库路径在系统PATH中。
  2. 通过`ros2 pkg create --build-type ament_cmake --license Apache-2.0 <YOUR-Folder-Name>'创建目录结构和基础文件。
  3. 填充代码。
  4. package.xml中添加代码中显式依赖的库。
  5. CMakeLists.txt中寻找和链接代码中显式依赖的库。

参考资料

  • https://docs.ros.org/en/rolling/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html#new-directory

这篇关于Robot Operating System——创建可执行文件项目的步骤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092378

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”

SpringBoot项目是如何启动

启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refresh 加载 IOC容器,加载所有的自动配置类,创建容器在这个过程

Maven创建项目中的groupId, artifactId, 和 version的意思

文章目录 groupIdartifactIdversionname groupId 定义:groupId 是 Maven 项目坐标的第一个部分,它通常表示项目的组织或公司的域名反转写法。例如,如果你为公司 example.com 开发软件,groupId 可能是 com.example。作用:groupId 被用来组织和分组相关的 Maven artifacts,这样可以避免