注:原笔记博客写于2023年秋天,文中一些参考了CSDN的教程链接几乎都失效了,无奈只好删除了很多内容。
2023秋
这是笔记本,不是教程。
几位耶jiweiyecau@163.com
安装
安装虚拟机或双系统
安装虚拟机
虚拟机使用教程
虚拟机VMware Workstation Pro v16.0.0使用教程 - 苏木川的文章 - 知乎
ubuntu安装
使用虚拟机的安装
CSDN【VMware安装Ubuntu20(图文教程,超详细)】
安装语言最好先设置为英语en(us),后期再改回中文cn(zh),以避免潜在的问题。
此处在设置磁盘大小时,应该设置大一些,50GB以上
- 快照
为虚拟机拍摄快照可以保存虚拟机的当前状态,使您能够重复返回到同一状态。拍摄快照时,Workstation Pro 会捕捉虚拟机的完整状态。 -
克隆
克隆功能以当前虚拟机客户端为模板,快速生成新的副本虚拟机客户端。 创建虚拟机后,可以将其克隆为模板。模板是虚拟机的主副本,可用于创建随时可用的虚拟机。可对模板进行更改(例如在客户机操作系统中安装附加软件),而保留原始虚拟机。 模板创建后无法进行修改。要更改现有模板,必须先将其转换为虚拟机,进行需要的更改,再将虚拟机转换回模板。要保留模板的原始状态,请将模板克隆为模板。 -
主机与虚拟机共享文件
参阅:https://zhuanlan.zhihu.com/p/43920548
系统根目录下:/mnt/hgfs/ -
虚拟机网络连接设置
虚拟机可以有三种网络连接形式:桥接模式(指虚拟机有单独的ip地址可以访问外部网络),NAT模式(指虚拟机使用主机的ip地址,可以访问外部网络),仅主机模式(指虚拟机只能与主机连接,不可访问外部网络)。下面我们主要关注如何访问github.com
设置网络连接形式为桥接模式,主机使用代理,例如使用ClashForWindows,找到ip地址及端口号,将ip地址及端口号在虚拟机的 网络设置-网络代理 中设置为相同,即可。
使用双系统的安装
警告:前方巨坑!可能存在问题
B站机器人工匠阿杰【Windows 和 Ubuntu 双系统的安装和卸载】
不建议按此教程设置磁盘分区!
安装语言最好先设置为英语en(us),后期再改回中文cn(zh),以避免潜在的问题。
Linux/ubuntu系统使用入门
鱼香ROS【Linux与Ubuntu系统介绍】
B站机器人工匠阿杰【从没接触过Ubuntu,如何上手ROS开发】-ubuntu使用入门
菜鸟教程【Linux 常用命令学习】
40个最常用的Linux命令行大全 - Haiyuan Kwong的文章 - 知乎
Linux 之 Vim 命令使用(详细总结) - hepingfly的文章 - 知乎
精通 VIM ,此文就够了 - zempty的文章 - 知乎
# 常用指令
sudo apt update # 更新软件包列表
sudo apt upgrade # 将软件包升级到最新版本
ros2安装
ROS2版本选择
ros2有不同的发行版本,与ubuntu各版本有对应关系,不能装错。现在一般选择ubuntu22.04和Humble。
鱼香ROS一键安装法(推荐)
强烈推荐鱼香ROS提供的一键安装法,可以避免大量不必要的麻烦。
wget http://fishros.com/install -O fishros && . fishros
官方安装法(不推荐)
参阅:
docs.ros.org/en/humble/Installation
另可参阅:
刘思培个人博客-1.1 安装ros2
鱼香ROS-3.动手安装ROS2
其他必要的配置
安装VScode
方法一:系统自带software应用安装
打开Ubuntu Software
sudo apt install snap # 安装snap工具,系统可能已经自带
sudo snap install --classic code # 安装VS Code
方法三:鱼香ros一键安装
wget http://fishros.com/install -O fishros && . fishros
# 输入密码后,输入7选择一键安装VsCode
安装其他插件和编译工具等
sudo apt install ros-humble-turtlesim # 安装海龟功能包
# 安装make编译工具
sudo apt install make
# 安装cmake
sudo apt install cmake
# 安装构建工具colcon
sudo apt-get install python3-colcon-common-extensions
# 安装图形界面可视化工具RQT
sudo apt install ros-humble-rqt*
# 安装依赖工具,使用鱼香ros提供的国内版,选择一键配置rosdep即可
wget http://fishros.com/install -O fishros && . fishros
# 设置始终执行该脚本文件,使ros2的软件包可在所有打开的新终端中使用
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
备注:colcon是ROS编译工具catkin_make、catkin_make_isolated、catkin_tools和ament_tools的迭代品。
参考:https://design.ros2.org/articles/build_tool.html
colcon的使用:鱼香ros【colcon构建工具命令参数】另请参阅本文档第3章。
# 机器人运动控制
sudo apt-get install ros-humble-teleop-twist-keyboard
ros2 run teleop_twist_keyboard teleop_twist_keyboard
# 安装tf树插件
sudo apt install ros-humble-rqt-tf-tree
双系统下的VPN问题
由于历史和现实的原因,机器人和计算机科学领域有大量高价值资料仅在外网可以获取到。
安装双系统时,需要在ubuntu下实现外网访问。
参考方法:
方法一:浏览器插件
AdGuard VPN,这款插件注册登录后每月有少量的免费流量,足够访问github使用了。
clash for windows可以在Linux下使用。
CFW原始安装包位置:
ClashForWindows Releases
对于 Ubuntu, 一般使用 clash-linux-amd64 版本。
参考:在linux下使用clash for windows
语言和输入法的调整
很遗憾,搜狗输入法暂时并不支持ubuntu22.04
建议使用iBus框架下智能拼音输入法,详情请参考下面的链接,请注意ubuntu22.04目前还无法安装搜狗输入法。参照下面的方法设置中文输入法:
在Ubuntu20.04中安装中文输入法 - dandelion的文章 - 知乎
安装和配置Git
安装和配置git
sudo apt update
sudo apt upgrade # 将软件包升级到最新版本
# 安装git
sudo apt install git
# 查看git版本,检查安装结果
git --version
# git配置
git config --global user.name "Your Name"
git config --global user.email "youremail@yourdomain.com"
# 验证git配置结果
git config --list
# 配置SSH
ssh-keygen -t rsa -C "这里换上你的邮箱"
# 回车3-4次
# 命令执行结束之后,home目录下面会生成.ssh目录
配置SSH时,执行命令后需要进行3次或4次确认:
- 确认秘钥的保存路径(如果不需要改路径则直接回车);
- 如果上一步置顶的保存路径下已经有秘钥文件,则需要确认是否覆盖(如果之前的秘钥不再需要则直接回车覆盖,如需要则手动拷贝到其他目录后再覆盖);
- 创建密码(如果不需要密码则直接回车);
- 确认密码;
命令执行结束之后,home目录下面会生成.ssh目录。默认密钥文件路径在~/.ssh,id_rsa 是私钥文件,id_rsa.pub 是公钥文件。
将公钥添加到 Github,将 id_rsa.pub 文件内容全部复制,登陆到 GitHub 上,右上角小头像 ->Setting->SSH and GPG keys 中,点击 new SSH key。
ssh -T git@github.com #测试是否配置成功
# 使用Git,请参照其他教程
git add xxx
git commit -m "xxxxxx"
git push origin master
参考:
Git官方文档
ubuntu git 环境搭建以及通过 SSH 连接 Github - 上海老金的文章 - 知乎
机器人相关软件安装
仿真软件gazebo
# 安装gazebo仿真软件
sudo apt install gazebo
# 安装gazebo-ros功能包(所有)
sudo apt install ros-humble-gazebo-*
# 安装gazebo_ros插件
sudo apt install ros-humble-gazebo-ros
# 测试是否安装成功
gazebo --verbose -s libgazebo_ros_init.so -s libgazebo_ros_factory.so
# 安装gazebo模型库(可选)
cd ~/.gazebo && wget https://gitee.com/ohhuo/scripts/raw/master/gazebo_model.py && python3 gazebo_model.py
建图SLAM工具cartographer
sudo apt install ros-humble-cartographer
sudo apt install ros-humble-cartographer-ros
# 查看cartographer源码
git clone https://ghproxy.com/https://github.com/ros2/cartographer.git -b ros2
git clone https://ghproxy.com/https://github.com/ros2/cartographer_ros.git -b ros2
导航NAV2框架
# 安装nav2
sudo apt install ros-humble-nav2-*
# 检查安装结果
ros2 pkg list | grep navigation2
# 查看nav2源码,结果为navigation2
git clone https://ghproxy.com/https://github.com/ros-planning/navigation2.git -b humble
可能出现的报错问题
报错:找不到“rclcpp"/找不到"rclpy"
将鼠标靠近报错的波形曲线,点击“快速修复”,选择编辑IncludePath设置,编辑c_pp_properties.json文件,将ros相关的文件路径添加进去即可。
需要的代码如下,注意ros安装的版本,这里是humble
,
"/opt/ros/humble/include/**"
修改为:
source /opt/ros/humble/setup.bash
报错:setup.py install is deprecated. Use build and pip……
pip install setuptools==58.2.0
ros官方论坛对此有讨论:
SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools
gazebo 无响应
gazebo在上一次关闭时未能被正确地关闭,导致下一次再启动时报错 [Err] [Master.cc:96] EXCEPTION: Unable to start server[bind: Address already in use]. There is probably another Gazebo process running.
解决办法:重启系统。使用终端打开gazebo时仅在终端ctrl+c关闭,以避免关闭异常。
或者:使用 ps
和 grep
命令查找残留的 Gazebo 进程,然后使用 kill
命令终止这些进程。
首先使用 ps aux
和 grep
查找 Gazebo 相关的进程:
ps aux | grep gazebo
输出可能类似于:
user 1234 0.0 0.1 123456 12345 ? S 12:34 0:00 /usr/bin/gzserver ...
user 5678 0.0 0.1 234567 23456 ? S 12:34 0:00 /usr/bin/gzclient ...
user 9101 0.0 0.0 1234 1234 pts/1 S+ 12:35 0:00 grep --color=auto gazebo
终止 Gazebo 进程:
kill -9 1234 5678
即可解决。
ROS2常用指令和部分基本概念
命令行CLI(Command-Line Interface)
节点node
节点概念: - 每个节点负责一个模块化的任务。 - 节点之间通过四种方式通信:话题topic,服务service,动作action,参数parameters 。 - 节点是可以独立运行的可执行文件。即使节点没有收到或发出数据,它也是可以独立运行的。但正常工作时需要获取到有效数据。 - 节点可以是分布式的,这对大型项目很有用。 - 设计时,节点间除了必要的通信外,应该尽可能减少彼此的耦合,便于管理。
A node is a participant in the ROS 2 graph, which uses a client library to communicate with other nodes. Nodes can communicate with other nodes within the same process, in a different process, or on a different machine. Nodes are typically the unit of computation in a ROS graph; each node should do one logical thing.
Nodes can publish to named topics to deliver data to other nodes, or subscribe to named topics to get data from other nodes. They can also act as a service client to have another node perform a computation on their behalf, or as a service server to provide functionality to other nodes. For long-running computations, a node can act as an action client to perform it, or as an action server to have another node perform it. Nodes can provide configurable parameters to change behavior during run-time.
Connections between nodes are established through a distributed discovery process.
官方文档:Basic Concepts - Nodes
官方文档:Understanding nodes
# 运行节点
ros2 run <package_name> <executable_name>
# 示例
ros2 run turtlesim turtlesim_node # 运行海龟
# 查看节点列表
ros2 node list
# 查看节点信息
ros2 node info <node_name>
# 示例
ros2 node info /turtlesim # 查看/turtlesim节点的详细信息
# 重映射节点名称
ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle
# 运行节点时设置参数
ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_level:=10
话题topic
ros2 topic -h
ros2 topic list
ros2 topic list -t
ros2 topic info /chatter
ros2 topic echo /chatter # 查看话题数据
ros2 topic hz /turtle1/pose # 查看话题发布频率
# 查看消息类型
ros2 interface show std_msgs/msg/String
# ros2 topic pub topic_name msg_type msg_data args
# 手动发布话题消息,--once是一个可选参数,表示发布一条消息然后退出,若要以频率n HZ发布则使用--rate n
ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
# 示例2
ros2 topic pub /chatter std_msgs/msg/String 'data: "123"'
话题概念:
- 话题通信是发布/订阅模型。
- 节点可以发布任意数量的不同话题,并且可以同时订阅任意数量的不同话题。
- 在明确话题名称和数据类型的前提下,可以是任意话题的发布者,也可以是任意话题的订阅者。发布者和订阅者使用的话题名称和消息类型必须匹配。
- 话题是异步通信。
- 1对1,1对n,n对1(同一个话题可以有多个发布者),n对n,也可以订阅自身发布的话题。
# 关系可视化
rqt_graph
服务service
服务Service:
- Service是客户端-服务端模型(请求-响应模型)。
- 作为服务端的节点只能有一个,作为客户端的节点可以任意数量。
- 一对一或一对多通信,保证数据发布源唯一。
- Service是同步通信。
ros2 service list # 查看服务列表
ros2 service list -t # 查看服务列表
#ros2 service type service_name
ros2 service type /spawn # 查看服务接口类型
ros2 service find turtlesim/srv/Spawn # 查找特定接口类型的所有服务
# 手动调用服务
#ros2 service call service_name service_type service_data args
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5,b: 10}"
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"
动作action
ros2 action list
ros2 action list -t
# ros2 action info action_name
ros2 action info /turtle1/rotate_absolute
#ros2 action send_goal action_name action_type action_data
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.6}"
# 示例2,增加feedback
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.5}" --feedback
- 作为动作客户端的节点将目标发送到动作服务端节点,作为动作服务端的节点确认目标并进行实时反馈,最后返回结果。
- 动作是一种应用层的通信机制,适用于长时间运行的任务。
- 动作由三个部分组成:一个目标、一个结果和反馈。
- 基于一个话题和两个服务来实现的。
- 动作与服务的区别在于,动作提供稳定的反馈,而服务返回单个响应。
- 一对多通信,和服务一样,动作通信中的客户端可以有多个,大家都可以发送动作请求,但是服务端只能有一个。
- 动作有实时反馈,是同步通信。
另请参阅:
ROS 2设计文章系列之二十一——动作(Actions) - 深圳季连AIGRAPHX的文章 - 知乎
通信接口interface
ros2 interface list # 查看通信接口列表
ros2 interface show action_mags/msg/GoalInfo # 查看接口消息类型
# ros2 interface package package_name
ros2 interface package turtlesim # 查看功能包中的通信接口
除了参数之外,话题、服务和动作都支持自定义接口,每一种通信方式所适用的场景各不相同,所定义的接口也被分为话题接口、服务接口、动作接口三种。
话题接口 xxx.msg
# xxx.msg
int64 num
服务接口 xxx.srv
# xxx.srv
#请求
int64 a
int64 b
---
#响应
int64 sum
动作接口 xxx.action
# xxx.action
int32 order
---
int32[] sequence
---
int32[] partial_sequence
基础数据类型
bool
byte
char
float32,float64
int8,uint8
int16,uint16
int32,uint32
int64,uint64
string
参数parameter
参数的组成由名字和值(键值组成)
ros2 param list # 查看参数列表
# ros2 param get node_name parameter_name
ros2 param get /turtlesim background_g # 获取参数值
# ros2 param describe <node_name> <param_name>
ros2 param describe /turtlesim background_b
# ros2 param set <node_name> <parameter_name> <value>
ros2 param set /turtlesim background_g 150 # 设置参数值
# ros2 param dump <node_name>
ros2 param dump /turtlesim
#示例2 增加文件名
ros2 param dump /turtlesim > turtlesim.yaml # 保存参数到文件turtlesim.yaml
# 查看文件
cat ./turtlesim.yaml
# ros2 param load node_name parameter_file
ros2 param load /turtlesim ./turtlesim.yaml # 加载文件参数值
#ros2 param load /turtlesim turtlesim.yaml
Each parameter consists of a key, a value, and a descriptor. The key is a string and the value is one of the following types: bool, int64, float64, string, byte[], bool[], int64[], float64[] or string[]. By default all descriptors are empty, but can contain parameter descriptions, value ranges, type information, and additional constraints.
参阅官方文档:
https://docs.ros.org/en/humble/Concepts/Basic/About-Parameters.html
创建功能包
前置指令
# Replace ".bash" with your shell if you're not using bash
# Possible values are: setup.bash, setup.sh, setup.zsh
source /opt/ros/humble/setup.bash
参考官方文档:创建功能包
Developing a ROS 2 package
ROS 2入门教程——2.2 创建您的第一个ROS 2软件包 - 深圳季连AIGRAPHX的文章 - 知乎
ROS2工作空间
Source the setup files
ROS 2入门教程——2.3 编写一个简单的发布者和订阅者(C++) - 深圳季连AIGRAPHX的文章 - 知乎
Creating a package
文件目录层级
文件目录层级图示
--name_ws
--src
--功能包1
--节点1.1
--节点1.2
--功能包2
--节点2.1
--节点2.2
在工作空间中有一个src文件夹,并在其中创建软件包。一个工作空间下可以有多个功能包,一个功能包可以有多个节点(可执行文件)存在。每个功能包都位于各自的文件夹中,这些文件夹放置在工作空间的src文件夹中。功能包不能嵌套。
编译与构建知识基础
参阅附录一和附录二,了解编译过程、g++编译器、make和CMake基本概念,学习CMakeList.txt基本语法,了解构建的概念。
参阅官方文档:Developing a ROS 2 package
package有3类:Python,C++,Combined C++ and Python。
编译方式:ament_python,cmake,ament_cmake。
官方【ros index功能包列表】
安装已发布的功能包:
sudo apt install ros-<version>-package_name
安装依赖(linux)
rosdep install -i --from-path src --rosdistro humble -y
ros2 pkg --指令列表 | |
create | Create a new ROS2 package |
executable | Output a list of package specific executables |
list | Output a list of available packages |
prefix | Output the prefix path of a package输出某个包所在的路径前缀 |
xml | Output the XML of the package manifest or a specific tag列出包的清单描述文件 |
# 部分示例
ros2 pkg create <package-name> --build-type {cmake,ament_cmake,ament_python} --dependencies <依赖名字>
ros2 pkg executables
ros2 pkg executables turtlesim
ros2 pkg list
ros2 pkg prefix <package-name>
python
创建功能包指令(ament_python)
重要:在scr目录下执行指令
# 在src目录下
# ros2 pkg create --build-type ament_python <package_name>
ros2 pkg create --build-type ament_python --node-name my_node my_package
# 官方指令
ros2 pkg create <pkg-name> --dependencies [deps] --build-type ament_python
# 更多的参数
cd chapt3/chapt3_ws/src
ros2 pkg create example_service_rclpy --build-type ament_python --dependencies rclpy example_interfaces --node-name service_server_02
# --node-name 只支持一个节点文件
目录空间示例
--proj_ws
--src
--package_name
--package_name
--_ _init_ _.py
--node.py
--package.xml
--resource
--package_name
--setup.cfg
--setup.py
--test
--test_copyright.py
--test_flake8.py
--test_pep257.py
值得关注的文件:
- package.xml文件——包含有关该软件包的元信息
- setup.py文件——包含如何安装该软件包的指令
- setup.cfg文件——当某个软件包具有可执行文件时需要此文件,以便ros2 run命令能找到这些可执行文件
- /
——与软件包名称同名的一个目录,ROS 2工具用它来寻找该软件包,该目录包含__init.__py文件
定制package.xml文件
修改package.xml文件。
<!--这申明了当该软件包的代码被执行时需要rclcpp和std_msgs库。-->
<depend>rclpy</depend>
<depend>std_msgs</depend>
添加入口点setup.py
# setup.py
entry_points={
'console_scripts': [
'my_script = my_package.my_script:main'
],
},
# 示例
entry_points={
'console_scripts': [
"node_02 = example_py.node_02:main"
],
},
#c console_scripts是个数组
C++
创建功能包指令(ament_cmake)
# 在src 目录下
# ros2 pkg create --build-type ament_cmake <package_name>
ros2 pkg create --build-type ament_cmake --node-name my_node my_package
# 官方指令
ros2 pkg create <pkg-name> --dependencies [deps] --build-type ament_cmake
目录空间示例
--proj_ws
--src
--package_name
--CMakeList.txt
--include
--package_name
--src
--node.cpp
--package.xml
定制CMakeList.txt
CMakeList.txt:
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
ament_target_dependencies(<executable-name> [dependencies])
# 示例,参考附录二
add_executable(node_01 src/node_01.cpp)
ament_target_dependencies(node_01 rclcpp)
# Install launch files
install(
DIRECTORY launch
DESTINATION share/${PROJECT_NAME}
)
# Install nodes
install(
TARGETS [node-names]
DESTINATION lib/${PROJECT_NAME}
)
构建运行
在构建之前检查缺少的依赖项
# 工作空间下
rosdep install -i --from-path src --rosdistro <distro> -y
colcon build
source install/setup.bash
ros2 run my_package my_node
# 仅构建指定包
colcon build --packages-select YOUR_PKG_NAME
节点和话题
重要:编写节点时,导入消息接口的流程
- 在CMakeLists.txt中导入,先find_packages再ament_target_dependencies。
- 在packages.xml中导入,具体是添加depend标签并将消息接口写入。
- 在代码中导入,C++中是#include"消息功能包/xxx/xxx.hpp"。
另请参阅:
Writing a simple publisher and subscriber (C++)
https://github.com/ros2/examples/tree/humble/rclcpp/topics
cmake_minimum_required(VERSION 3.5)
project(examples_rclcpp_minimal_publisher)
# 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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(publisher_lambda lambda.cpp)
ament_target_dependencies(publisher_lambda rclcpp std_msgs)
add_executable(publisher_member_function member_function.cpp)
ament_target_dependencies(publisher_member_function rclcpp std_msgs)
add_executable(publisher_member_function_with_type_adapter member_function_with_type_adapter.cpp)
ament_target_dependencies(publisher_member_function_with_type_adapter rclcpp std_msgs)
add_executable(publisher_member_function_with_unique_network_flow_endpoints member_function_with_unique_network_flow_endpoints.cpp)
ament_target_dependencies(publisher_member_function_with_unique_network_flow_endpoints rclcpp std_msgs)
add_executable(publisher_wait_for_all_acked member_function_with_wait_for_all_acked.cpp)
ament_target_dependencies(publisher_wait_for_all_acked rclcpp std_msgs)
add_executable(publisher_not_composable not_composable.cpp)
ament_target_dependencies(publisher_not_composable rclcpp std_msgs)
install(TARGETS
publisher_lambda
publisher_member_function
publisher_member_function_with_type_adapter
publisher_member_function_with_unique_network_flow_endpoints
publisher_wait_for_all_acked
publisher_not_composable
DESTINATION lib/${PROJECT_NAME}
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
Launch文件
参阅:
Tutorials【Launching nodes】
Tutorials【Creating a launch file】
古月居【Launch:多节点启动与配置脚本】
范子琦博客【ROS2——教你写新版Launch文件】
CSDN博客【ros2 launch 用法以及一些基础功能函数的示例】
前置操作:创建Launch文件
文件目录
cd proj_ws/src/my_package
mkdir launch
cd launch
touch xxxx.launch.py
参阅:https://docs.ros.org/en/dashing/Tutorials/Launch-system.html#ros-2-launch-system
C++ package
ament_package() 前面加上以下内容,才能在share文件夹中找到launch文件和config文件。
If you are creating a C++ package, we will only be adjusting the CMakeLists.txt file by adding:
# Install launch files.
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)
install(DIRECTORY
config
DESTINATION share/${PROJECT_NAME}/
)
to the end of the file (but before ament_package() ).
Python Packages
# For Python packages, your directory should look like this:
src/
py_launch_example/
launch/
package.xml
py_launch_example/
resource/
setup.cfg
setup.py
test/
In order for colcon to find the launch files, we need to inform Python’s setup tools of our launch files using the data_files parameter of setup.
# setup.py
import os
from glob import glob
from setuptools import setup
package_name = 'py_launch_example'
setup(
# Other parameters ...
data_files=[
# ... Other data files
# Include all launch files.
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*launch.[pxy][yma]*')))
]
)
# 其他参考
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
(os.path.join('share', package_name, 'urdf'), glob('urdf/**')),
(os.path.join('share', package_name, 'world'), glob('world/**')),
],
Writing the launch file
加载节点(node)示例
# simple.launch.py
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='learning_topic', # 节点所在的功能包
executable='topic_helloworld_pub', # 节点的可执行文件
),
Node( # 配置一个节点的启动
package='learning_topic', # 节点所在的功能包
executable='topic_helloworld_sub', # 节点的可执行文件名
),
])
Your launch file should define the generate_launch_description() which returns a launch.LaunchDescription() to be used by the ros2 launch verb. 模板:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
])
重映射示例
# remapping.launch.py
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
namespace='turtlesim1', # 节点所在的命名空间
executable='turtlesim_node', # 节点的可执行文件名
name='sim' # 对节点重新命名
),
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
namespace='turtlesim2', # 节点所在的命名空间
executable='turtlesim_node', # 节点的可执行文件名
name='sim' # 对节点重新命名
),
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
executable='mimic', # 节点的可执行文件名
name='mimic', # 对节点重新命名
remappings=[ # 资源重映射列表
('/input/pose', '/turtlesim1/turtle1/pose'),
('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
]
)
])
# 最后一个节点也来自turtlesim软件包,但其可执行文件不同,其可执行文件为mimic。
# 将/input/pose话题名修改为/turtlesim1/turtle1/pose
# 将/output/cmd_vel话题名修改为/turtlesim2/turtle1/cmd_vel
节点mimic的/input/pose话题被重映射到/turtlesim1/turtle1/pose,而其/output/cmd_vel话题被重映射到/turtlesim2/turtle1/cmd_vel。这意味着mimic节点将会订阅/turtlesim1/sim的位姿话题并为/turtlesim2/sim的速度指令话题的订阅而重新发布该话题。换句话说,turtlesim2将会模仿turtlesim1的动作。
命令行示例
原命令行:
ros2 run rviz2 rviz2 -d <PACKAGE-PATH>/rviz/turtle_rviz.rviz
对应Launch语句:
# rviz.launch.py
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
rviz_config = os.path.join( # 找到配置文件的完整路径
get_package_share_directory('learning_launch'),
'rviz',
'turtle_rviz.rviz'
)
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='rviz2', # 节点所在的功能包
executable='rviz2', # 节点的可执行文件名
name='rviz2', # 对节点重新命名
arguments=['-d', rviz_config] # 加载命令行参数
)
])
调用shell
使用ExecuteProcess调用shell命令
example_cmd = ExecuteProcess(
cmd=['some-cmd', 'some-cmd'], #命令,用逗号隔开
additional_env={'EXAMPLE_PATH': path}, #可以添加临时的环境变量
output='screen'
)
ld.add_action(example_cmd)
参数(parameter)配置示例
# parameters.launch.py
from launch import LaunchDescription # launch文件的描述类
from launch.actions import DeclareLaunchArgument # 声明launch文件内使用的Argument类
from launch.substitutions import LaunchConfiguration, TextSubstitution
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
background_r_launch_arg = DeclareLaunchArgument(
'background_r', default_value=TextSubstitution(text='0') # 创建一个Launch文件内参数(arg)background_r
)
background_g_launch_arg = DeclareLaunchArgument(
'background_g', default_value=TextSubstitution(text='84') # 创建一个Launch文件内参数(arg)background_g
)
background_b_launch_arg = DeclareLaunchArgument(
'background_b', default_value=TextSubstitution(text='122') # 创建一个Launch文件内参数(arg)background_b
)
return LaunchDescription([ # 返回launch文件的描述信息
background_r_launch_arg, # 调用以上创建的参数(arg)
background_g_launch_arg,
background_b_launch_arg,
Node( # 配置一个节点的启动
package='turtlesim',
executable='turtlesim_node', # 节点所在的功能包
name='sim', # 对节点重新命名
parameters=[{ # ROS参数列表
'background_r': LaunchConfiguration('background_r'), # 创建参数background_r
'background_g': LaunchConfiguration('background_g'), # 创建参数background_g
'background_b': LaunchConfiguration('background_b'), # 创建参数background_b
}]
),
])
调用参数文件
# learning_launch/parameters_yaml.launch.py
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
config = os.path.join( # 找到参数文件的完整路径
get_package_share_directory('learning_launch'),
'config',
'turtlesim.yaml'
)
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
executable='turtlesim_node', # 节点的可执行文件名
namespace='turtlesim2', # 节点所在的命名空间
name='sim', # 对节点重新命名
parameters=[config] # 加载参数文件
)
])
launch文件嵌套示例
# namespaces.launch.py
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch.actions import IncludeLaunchDescription # 节点启动的描述类
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import GroupAction # launch文件中的执行动作
from launch_ros.actions import PushRosNamespace # ROS命名空间配置
def generate_launch_description(): # 自动生成launch文件的函数
parameter_yaml = IncludeLaunchDescription( # 包含指定路径下的另外一个launch文件
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('learning_launch'), 'launch'),
'/parameters_nonamespace.launch.py'])
)
parameter_yaml_with_namespace = GroupAction( # 对指定launch文件中启动的功能加上命名空间
actions=[
PushRosNamespace('turtlesim2'),
parameter_yaml]
)
return LaunchDescription([ # 返回launch文件的描述信息
parameter_yaml_with_namespace
])
官方完整示例:
http://docs.ros.org/en/humble/How-To-Guides/Launch-file-different-formats.html
运行launch文件
ros2 launch <package_name> <launch_file_name>
For packages with launch files, it is a good idea to add an exec_depend dependency on the ros2launch package in your package’s package.xml
<exec_depend>ros2launch</exec_depend>
设置参数
To set the arguments that are passed to the launch file, you should use key:=value syntax. For example, you can set the value of background_r in the following way:
ros2 launch <package_name> <launch_file_name> background_r:=255
加载Gazebo
gazebo提供的功能节点spwan_entity:
# load_urdf_into_gazebo.launch.py
world_file_path = 'worlds/neighborhood.world'
pkg_path = os.path.join(get_package_share_directory(package_name))
world_path = os.path.join(pkg_path, world_file_path)
# Include the Gazebo launch file,
# provided by the gazebo_ros package
mbot = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory(package_name),'launch','mbot.launch.py'
)]), launch_arguments={'use_sim_time': 'true', 'world':world_path}.items())
gazebo = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')]),
)
# Run the spawner node from the gazebo_ros package.
# The entity name doesn't really matter if you only have a single robot.
spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py',
arguments=['-topic', 'robot_description',
'-entity', 'mbot',
'-x', spawn_x_val,
'-y', spawn_y_val,
'-z', spawn_z_val,
'-Y', spawn_yaw_val],
output='screen')
# Launch them all!
return LaunchDescription([
mbot,
gazebo,
spawn_entity,
])
# 加载世界模型
gazebo_world_path = os.path.join(pkg_share, 'world/fishbot.world')
# Start Gazebo server
start_gazebo_cmd = ExecuteProcess(
cmd=['gazebo', '--verbose','-s', 'libgazebo_ros_init.so', '-s', 'libgazebo_ros_factory.so', gazebo_world_path],
output='screen')
配置Launch文件的完整说明
ROS2中的URDF系列教程(七):ROS 2中如何将URDF加载到Gazebo - 深圳季连AIGRAPHX的文章 - 知乎
加载rviz2
rviz是一个三维可视化平台,用于数据可视化。
rviz_config_file_path = 'rviz/urdf_gazebo_config.rviz'
default_rviz_config_path = os.path.join(pkg_share, rviz_config_file_path)
declare_rviz_config_file_cmd = DeclareLaunchArgument(
name='rviz_config_file',
default_value=default_rviz_config_path,
description='Full path to the RVIZ config file to use')
declare_use_rviz_cmd = DeclareLaunchArgument(
name='use_rviz',
default_value='True',
description='Whether to start RVIZ')
# Launch RViz
start_rviz_cmd = Node(
package='rviz2',
executable='rviz2',
name='rviz2',
output='screen',
arguments=['-d', rviz_config_file])
ld.add_action(declare_rviz_config_file_cmd)
ld.add_action(declare_use_rviz_cmd)
ld.add_action(start_rviz_cmd)
附录一:前置知识--程序编译过程
GCC编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello。这个翻译过程分为四个阶段:预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。执行这四个阶段的程序(预处理器、编译器、汇编器、和链接器)一起构成了编译系统。
# 预处理Preprocessing
gcc -E test.c -o test.i
# 编译Compilation
gcc -S test.i -o test.s
# 汇编Assemble
gcc -c test.s -o test.o
# 链接Linking
gcc test.o -o test
预处理(Preprocessing)
目标文件常常按照特定格式来组织,在linux下,它是ELF格式(Executable Linkable Format,可执行可链接格式),而在windows下是PE(Portable Executable,可移植可执行)。
- 预处理器(cpp)将所有的#define删除,并且展开所有的宏定义。
- 处理所有的条件预编译指令,比如#if、#ifdef、#elif、#else、#endif等。
- 处理#include预编译指令,将被包含的文件直接插入到预编译指令的位置。
- 删除所有的注释。
- 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
- 保留所有的#pragma编译器指令,因为编译器需要使用它们。
- 使用gcc -E hello.c -o hello.i命令来进行预处理, 预处理得到的另一个程序通常是以.i作为文件扩展名。
经过预处理之后代码体积会大很多,相当于可执行文件一倍大小。预处理之后的程序还是文本,可以用文本编辑器打开。
编译阶段(Compilation)
编译器(ccl)将预处理完的(.i) 临时文件hello.i进行一系列的词法分析、语法分析、语义分析和优化,转换为具有汇编级指令(低级代码)的汇编文件 (.s)hello.s。
汇编语言为不同高级语言的不同编译器提供了通用的输出语言。
编译过程可分为6步:扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成、目标代码优化。
- 词法分析:扫描器(Scanner)将源代的字符序列分割成一系列的记号(Token)。lex工具可实现词法扫描。
- 语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)。yacc工具可实现语法分析(yacc: Yet Another Compiler Compiler)。
- 语义分析:静态语义(在编译器可以确定的语义)、动态语义(只能在运行期才能确定的语义)。
- 源代码优化:源代码优化器(Source Code Optimizer),将整个语法书转化为中间代码(Intermediate Code)(中间代码是与目标机器和运行环境无关的)。中间代码使得编译器被分为前端和后端。编译器前端负责产生机器无关的中间代码;编译器后端将中间代码转化为目标机器代码。
- 目标代码生成:代码生成器(Code Generator).
- 目标代码优化:目标代码优化器(Target Code Optimizer)。
整个程序代码由编译器软件一次性解析(语法分析),并通过终端窗口告诉我们源代码中存在的任何语法错误或警告。编译成汇编文件任然是文本文件,大小已经非常小了,没有像预处理的时候文件大小这么臃肿。
汇编阶段(Assemble)
汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中,hello.o是一个二进制文件。
链接阶段(Linking)
链接过程使用链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
链接是由叫链接器(linker)的程序自动执行的。
链接使得分离编译(separate compilation)成为可能,我们不用将一个大型的应用程序组织成一个巨大的源文件,而是可以把它分解成为更小、更好管理的模块,可以独立的修改和编译这些模块。当我们改变这些模块中的一个时,只需要简单的重新编译它,并重新链接应用,而不必重新编译其他文件。
编译示例
// Simple Hello World program in C
#include<stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
执行编译
gcc -save-temps hello.c -o compilation
-save-temps
选项会保留所有编译过程中产生的中间文件,总共会生成四个文件。- hello.i 预处理器产生的文件
- hello.s 编译器编译后产生的文件
- hello.o 汇编程序翻译后的目标文件
- hello.exe 可执行文件(Linux系统会产生hello.out文件)
链接库
在实际应用中,有些公共代码需要反复使用,就把这些代码编译成为“库”文件。
库文件中包含函数的实现。 静态库:在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
共享库与静态库不同,共享库在链接间段只在可执行文件中设置使用的库,运行时由操作系统动态加载到内存上执行。
共享库是在运行程序时才动态加载库方法,若删除共享库,则程序运行时进行动态加载库方法时找不见共享库,程序将无法执行。共享库由于运行要动态加载库文件,则运行速度慢,但程序体积小,方便版本升级,程序不用重新编译。
不过,如果仅有.a或.so库文件,那么我们并不知道里面的函数到底是什么,调用的形式又是什么样。为了使用这个库,我们需要提供一个头文件,说明这些库里都有些什么。因此,对于库的使用者,只要拿到了头文件和库文件,就可以调用这个库了。
参考引用
程序详细编译过程(预处理、编译、汇编、链接) - YaoJ1aHao的文章 - 知乎
C语言的编译过程详解 - Lion-Zwart的文章 - 知乎
GCC编译过程(预处理->编译->汇编->链接) - 程序猿编码的文章 - 知乎
引自CSDN【gcc/g++ 链接库的编译与链接】
浅谈静态库和动态库 - 守望的文章 - 知乎
C++静态库与动态库深入研究——静态库篇! - C语言编程俱乐部的文章 - 知乎
Linux—静态库与共享库——详解
附录二:前置知识--编译器
在windows下,一般使用Microsoft提供的VS系列IDE即可,功能强大,使用方便。Linux系统编译C++时多用g++,g++的功能是将包含了代码的文本文件编译(预处理、编译、汇编、链接)成可执行的文件。
集成开发环境(Integrated Development Environment,IDE)
实际开发中,除了编译器是必须的工具,我们往往还需要很多其他辅助软件,例如:
- 编辑器:用来编写代码,并且给代码着色,以方便阅读;
- 代码提示器:输入部分代码,即可提示全部代码,加速代码的编写过程;
- 调试器:观察程序的每一个运行步骤,发现程序的逻辑错误;
- 项目管理工具:对程序涉及到的所有资源进行管理,包括源文件、图片、视频、第三方库等;
- 漂亮的界面:各种按钮、面板、菜单、窗口等控件整齐排布,操作更方便。
这些工具通常被打包在一起,统一发布和安装,例如 Visual Studio、Dev C++、Xcode、Visual C++ 6.0、C-Free、Code::Blocks 等,它们统称为集成开发环境(IDE,Integrated Development Environment)。在实际开发中,我一般也是使用集成开发环境,而不是单独地使用编译器。
通常 IDE 仅限于一种编码语言或框架。主流的IDE有:
Visual Studio,Sublime Text 3,Vim(命令行软件),IntelliJ IDEA,Xcode IDE(面向apple),PyCharm(python),Microsoft Visual C++等
GCC/G++是什么
GNU编译器集合(GNU Compiler Collection,GCC)是一个能够编译多种语言的编译器,如c++、C、Objective-C、Java和Fortran。GCC开发是由Richard Stallman作为GNU项目的一部分进行的。
GCC指令:
# 现在我们有源文件hello.c,下面是一些gcc的使用示例:
gcc -E hello.c -o hello.i 对hello.c文件进行预处理,生成了hello.i 文件
gcc -S hello.i -o hello.s 对预处理文件进行编译,生成了汇编文件
gcc -c hello.s -o hello.o 对汇编文件进行编译,生成了目标文件
gcc hello.o -o hello 对目标文件进行链接,生成可执行文件
gcc hello.c -o hello 直接编译链接成可执行目标文件
gcc -c hello.c 或 gcc -c hello.c -o hello.o 编译生成可重定位目标文件
G++是什么 GNU提供了C++的优化编译器,也就是众所周知的G++。在编译阶段,G++调用GCC,因此G++是完整的编译器。
关于gcc与g++
- 对于c文件,gcc与g++在代码规范的情况下,是完全等价的。
- 对于cpp文件,在预处理、编译、汇编这三部分,gcc和g++也是等价的,前提是这三个步骤一起做,或者你在中间继续能够体现cpp的文件名。
- 在涉及c++的标准库时,gcc无法链接到这些库,必须加上-lstdc++ 选项,相比之下,不如直接使用g++来得方便快捷。
- g++就是gcc以默认c++的方式进行编译,然后链接的时候加上了一些c++的库。
MinGW 就是 GCC 的 Windows 移植版本。
自由软件基金会(FSF)和GUN
FSF -- The Free Software Foundation
The Free Software Foundation (FSF) is a nonprofit with a worldwide mission to promote computer user freedom.
https://www.fsf.org/
FSF(自由软件基金会)是一个非盈利组织。使命是在全球范围内促进计算机用户的自由,捍卫所有软件用户的权利。FSF开发了GNU自由软件操作系统。 “自由软件基金会(FSF)是一个非盈利组织。我们的使命是在全球范围内促进计算机用户的自由。我们捍卫所有软件用户的权利。”
GUN项目
https://www.gnu.org/
GNU是一个类Unix操作系统。
make
代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
我们的程序只有一个源文件时,直接就可以用gcc命令编译它。但是,程序包含很多个源文件时,用gcc命令逐个去编译时,就很容易混乱而且工作量大,所以出现了下面make工具。
斯图亚特·费尔德曼(Stuart Feldman)在1977年在贝尔实验室(Bell Labs)里制作了这个软件。2003年,斯图亚特·费尔德曼因发明了这样一个重要的工具而接受了美国计算机协会(ACM)颁发的软件系统奖。
make只是一个根据指定的Shell命令进行构建的工具。它的规则很简单,你规定要构建哪个文件、它依赖哪些源文件,当那些文件有变动时,如何重新构建它。
make通过读取“makefile”的文件以自动化建构软件。make是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。make工具就根据makefile中的命令进行编译和链接的。makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。
许多现代软件的开发中(如Microsoft Visual Studio),集成开发环境已经取代make,但是在Unix环境中,仍然有许多工程师采用make来协助软件开发。
cmake
cmake通过调用CMakeLists.txt直接生成Makefile,更加便捷。
CMake是一个跨平台工具,CMakelists.txt是linux和windows通用的,利用cmake,可以根据CMakelist.txt在不同的操作系统上产生不同的自动编译脚本文件。
CMake 的所有操作都是通过编辑 CMakeLists.txt 来完成的。
参阅cmake官网:https://cmake.org/
cmake详细语法和介绍请参阅附录二第6节参考引用部分的链接。
必须掌握的内容如下:
# cmake_minimum_required 指定使用 CMake 的最低版本号
cmake_minimum_required(VERSION 3.10)
# set the project name
project(Tutorial)
# add the executable 需要指定生成可执行文件的名称和相关源文件
add_executable(Tutorial tutorial.cxx)
# 使用 find_package() 命令找到包
find_package(Qt4 4.7.0 REQUIRED) # CMake provides a Qt4 find-module
# 优化
add_executable(${PROJECT_NAME} tutorial.cpp)
# 生成可执行文件需要指定相关的源文件,如果有多个,那么就用空格隔开
add_executable(${PROJECT_NAME} a.cpp b.cpp c.cpp)
# 也可以用一个变量来表示这多个源文件
# set 命令指定 SRC_LIST 变量来表示多个源文件
# 用${var_name} 获取变量的值。
set(SRC_LIST a.cpp b.cpp c.cpp)
add_executable(${PROJECT_NAME}${SRC_LIST})
# target_link_libraries - 为target(目标) 添加需要动态链接库
target_link_libraries(<target> ... <item>... ...)
#设置要链接的库文件的名称
target_link_libraries(first_node rclcpp rcutils)
# 链接
TARGET_LINK_LIBRARIES(${PROJECT_NAME}${PROJECT_SOURCE_DIR}/lib/hello.lib)
注意:
link_libraries用在add_executable之前,target_link_libraries用在add_executable之后
参阅:
官方文档中文【目标链接库target_link_libraries】
随着现代的集成开发环境(IDE)的诞生,特别是非Unix的平台上,很多程序员不再手动管理依靠关系检查,甚至不用去管哪些文件是这个项目的一部分,而是把这些任务交给了他们的开发环境去做。类似的,很多现代的编程语言有自己特别的高效的依赖关系的设置方法。
cmake使用流程:
先创建cpp文件,text01.cpp
#include <iostream>
using namespace std;
int main()
{
cout<<"welcome to VS code world!"<<endl;
return 0;
}
再编写CMakeLists.txt文件
cmake_minimum_required(VERSION 3.15)
# set the project name
project(Tutorial)
# add the executable
add_executable(Tutorial text01.cpp)
打开终端
mkdir build
cd build
cmake ..
make
如果是windows平台下,默认编译器是vs,如需使用gcc/g++编译器则需要安装mingw,指定gcc/g++编译器,指定编译器的指令为
cmake -G"MinGW Makefiles" ..
注:创建build文件夹的目的是隔离源代码和cmake产生的中间文件。
参考引用
- 什么是IDE(集成开发环境)? - 情感专家的文章 - 知乎
- g++是干什么用的 学c++一定要用这个么? - 果冻虾仁的回答 - 知乎
- 博客文章【Linux编译工具:gcc入门】
- 编译器GCC与G++的区别 - 柯学計算的文章 - 知乎
- CSDN【帮你分清什么是GNU、GCC、gcc、g++】
- CSDN博客【构建工具 make 简介】
- 阮一峰的网络日志:make命令教程
- CSDN博客【构建工具 make 简介】
- 5分钟理解make/makefile/cmake/nmake - Chuck的文章 - 知乎
cmake教程
- CMake 良心教程,教你从入门到入魂 - 程序员阿德的文章 - 知乎
- 官方文档【CMake Tutorial】
- 《CMake Cookbook中文版》
- CMake 简易入门教程 - 雨语鱼的文章 - 知乎
- 重要:cmake官方手册中文版