有东西但不多
0. 前言
ROS是一个分布式的进程(也就是节点)框架,这些进程被封装在易于被分享和发布的程序包和功能包集中。
1. ROS/ROS2
1.1 概念碎片
- LTS:long term support ,一般指长期支持的版本;
- LTS 版本意味着更稳定,Latest 版本意味着键兼更多的platforms和拥有更新更多的ROS packages;
- 尽管已经有了LTS版本,每年还是会发布新版本;
- ROS版本与操作系统版、工具包版本(如QT、PCL、openCV等)、软件版本等相关性很大,建议新手使用推荐的 tier 1,否者容易出现 issues;
- tier 1:官方推荐的运行某ROS版本的指定操作系统和工具包版本:please read REP-2000;
- 在Docker上安装ROS:https://hub.docker.com/_/ros/
- ROS? ROS2? ROS已被ROS2取代;
- ROS官方文档: https://wiki.ros.org/
- ROS2官方文档:https://docs.ros.org/,注意前缀与ROS的不同!
1.2 ROS2安装
建议:如果必须用ROS2否则安装ROS;
if installing on a desktop PC, install ROS Desktop-Full, on a companion computer ROS-Base is enough。
官方教程:https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html#uninstall
1.3 ROS安装
建议安装ROS Noetic Ninjemys 版本;
if installing on a desktop PC, install ROS Desktop-Full, on a companion computer ROS-Base is enough;
建议在wsl上安装,wsl安装Ubuntu-20.04;
官方教程:https://wiki.ros.org/cn/ROS/Installation
- 配置Ubuntu软件仓库:基本上不需要更改!可跳过此步骤直接安装ROS!
页面配置:https://help.ubuntu.com/community/Repositories/Ubuntu
命令行配置:https://help.ubuntu.com/community/Repositories/CommandLine - 安装:https://wiki.ros.org/cn/ROS/Installation
- 使用文档:https://wiki.ros.org/
可以切换成中文页面;
2. ROS知识点
为什么提出ROS?
为了实现分布式!
为了进程间方便的信息共享!
便于软件包的共享!
ROS是一个分布式的进程(也就是节点)框架,每个节点cpp文件可以具有一个while死循环,运行多个节点可模拟多进程的特性。
2.1 知识点碎片
- ROS中最重要的一个概念就是软件包,理解软件包可以减小理解ROS其他概念的壁垒。软件包的介绍请看本文第3小节。
- 计算图(Computation Graph):是一个由ROS进程组成的点对点网络,它们能够共同处理数据。ROS的基本计算图概念有节点(Nodes)、主节点(Master)、参数服务器(Parameter Server)、消息(Messages)、服务(Services)、话题(Topics)和包(Bags),它们都以不同的方式向图(Graph)提供数据。
- 节点(Nodes):节点可以看作是一个可执行程序运行后在ROS中的存在形式,它可以通过ROS来与其他节点进行通信。
- 消息(Messages):订阅或发布话题时所使用的ROS数据类型。
- 话题(Topics):节点可以将消息发布到话题,或通过订阅话题来接收消息。
- 主节点(Master):ROS的命名服务,例如帮助节点发现彼此。
- rosout:在ROS中相当于stdout/stderr(标准输出/标准错误)。
- roscore:主节点 + rosout + 参数服务器(会在以后介绍)。
- roscore是你在运行所有ROS程序前首先要运行的命令。
- 从帮助文档中选择性观看: tutorials and demos
- 如果你在查找和使用ROS软件包方面遇到了问题,请检查环境变量是否配置正确:
printenv | grep ROS
若没有正确配置则要手动source一下:source /opt/ros//setup.bash 如 source /opt/ros/noetic/setup.bash - 使用catkin_make命令编译软件包可以看成:在标准CMake工作流程中依次调用了cmake和make。catkin_make 是一个命令行工具,它简化了标准catkin工作流程。你可以认为catkin_make是在标准CMake工作流程中依次调用了cmake和make。如果你不熟悉什么是标准CMake工作流程,可以认为是以下几个步骤:
- catkin_make的高级用法。
- catkin文档
2.2 节点(node)
- roscore
是你在运行所有ROS程序前首先要运行的命令。 - rosnode
rosnode list :列出当前运行的所有节点;
rosnode --help - /rosout节点
在ROS中相当于stdout/stderr,标准输出/标准错误。 - rosrun
可以让你用包名直接运行软件包内的节点,而不需要知道包的路径。
用法:rosrun <包名> <可执行程序名> <__参数名>:=<参数值>
- 节点名
节点名在可执行程序的ros::init(argc, argv, "nodeName");
语句中被初始化为"nodeName"。
注意:可执行程序就是节点、可执行程序名就是节点名等这些说法都是不准确的!因为只有当可执行程序执行到ros::init(argc, argv, "nodeName");
语句时,该程序才会被初始化为节点,而可执行程序的名称和该语句中的"nodeName"
并不一定相同! - 重新分配节点名称
使用__name
参数可在启动节点程序时重命名节点名称。如:rosrun turtlesim turtlesim_node __name:=my_turtle
。 - 查看节点相关信息
rosnode info nodeName
- 清理节点列表
rosnode cleanup
- ping 某个节点
rosnode ping nodeName
- 节点程序分析
这里所谓的节点程序指的是被初始化(ros::init())为节点的可执行程序!例如:
下面是一个示例:#include "ros/ros.h" int main(int argc, char **argv) { ... ros::init(argc, argv, "nodeName"); //将main函数初始化为ROS节点!并登记在ros系统中,取名nodeName ... while(ros::ok()) //可选!! {...} return 0; }
#include "ros/ros.h" #include "std_msgs/String.h" #include <sstream> int main(int argc, char **argv) { ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);//广播一个主题! ros::Rate loop_rate(10);//节点循环频率 int count = 0; while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << "hello world " << count; msg.data = ss.str(); ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg);//往主题发布msg! ros::spinOnce();//处理该节点所有主题订阅的回调函数! loop_rate.sleep();//休眠、挂起直到下一个执行周期到达! ++count; } return 0; }
2.3 主题(Topics)
-
主题(Topics):节点可以将消息发布到话题,或通过订阅话题来接收消息
-
多对多通讯
-
查看节点间的主题发布与订阅:rqt_graph 工具或 rqt
-
rostopic echo [topic]
显示在某个话题上发布的数据 -
rostopic 空格 双击 tab 键
查看可用选项 -
rostopic list
列出当前已被订阅和发布的所有话题
rostopic list [option]
rostopic list -h/-b/-p/-s/-v -
rostopic type
查看某主题发布的的message类型
rostopic type [topic]
rostopic type /turtle1/cmd_vel -
rosmsg show
查看某message的详细信息
rosmsg show [message]
rosmsg show geometry_msgs/Twist -
rostopic pub
把自定义数据发布到主题上
rostopic pub [topic] [msg_type] [args]
rostopic pub --help
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist - - ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’
其中,这一选项(两个破折号 – )用来告诉选项解析器,表明之后的参数都不是选项。如果参数前有破折号(-)比如负数,那么这是必需的。
参数’[2.0, 0.0, 0.0]’ '[0.0, 0.0, 1.8]'是用YAML语法表示的,语法介绍请参考:YAML命令行文档 -
rostopic hz
报告发布到主题数据发布的速率
rostopic hz [topic]
rostopic hz /turtle1/pose -
rqt_plot
rqt_plot命令可以在滚动时间图上显示发布到某个话题上的数据
请参考:https://wiki.ros.org/cn/ROS/Tutorials/UnderstandingTopics
2.4 服务
- 除了主题的发布和订阅,服务(Services)是节点之间通讯的另一种方式。服务允许节点发送一个请求(request)并获得一个响应(response)。
- 一对一通讯
- rosservice list
输出活跃服务的信息 - rosservice type
输出服务的类型,查看请求某服务时是否需要参数 ,若是empty(空)则表明调用这个服务时不需要参数
rosservice type [service]
rosservice type /clear
查看类型的具体数据结构:rossrv show [data type]
rosservice type /spawn | rossrv show - rosservice call
请求某服务、用给定的参数调用服务
rosservice call [service] [args]
请求无参数的服务:rosservice call /clear
请求有参数的服务:rosservice call /spawn 2 2 0.2 “” - rosservice find
按服务的类型查找服务 - rosservice uri
输出服务的ROSRPC uri
2.5 Parameter Server
Parameter server 为节点而服务,用于存储节点的参数!
Parameter Server中存储的参数遵守ROS命名约定。也就是说Parameter Server中的参数名会以主题和节点的命名空间为层次结构。
Parameter Server
2.6 rosparam
- rosparam能让我们在ROS参数服务器(Parameter Server)上存储和操作数据。参数服务器能够存储整型(integer)、浮点(float)、布尔(boolean)、字典(dictionaries)和列表(list)等数据类型。rosparam使用YAML标记语言的语法。一般而言,YAML的表述很自然:1是整型,1.0是浮点型,one是字符串,true是布尔型,[1, 2, 3]是整型组成的列表,{a: b, c: d}是字典。
- rosparam list
列出当前服务器上的所有参数 - rosparam set
设置参数服务器中的某参数
rosparam set [param_name]
rosparam set /turtlesim/background_r 150
使设置的参数生效:rosservice call /clear - rosparam get
获取某参数的当前值
rosparam get [param_name]
rosparam get /turtlesim/background_g
显示所有参数的值:rosparam get / - rosparam load
从文件中加载参数
rosparam load [file_name] [namespace] - rosparam dump
向文件中转储参数
rosparam dump [file_name] [namespace]
rosparam dump params.yaml - rosparam delete
删除参数
rosparam delete [file_name]
2.7 Remapping Arguments
参数重命名!参数赋值!
rosrun rospy_tutorials talker chatter:=/wg/chatter
rosrun rospy_tutorials talker _param:=1.0
2.8 使用 rqt_console 和 rqt_logger_level 进行调试
- rqt_console连接到了ROS的日志框架,以显示节点的输出信息。rqt_logger_level允许我们在节点运行时改变输出信息的详细级别,包括Debug、Info、Warn和Error`
- rosrun rqt_console rqt_console
- rosrun rqt_logger_level rqt_logger_level
- https://wiki.ros.org/cn/ROS/Tutorials/UsingRqtconsoleRoslaunch
2.9 使用 rosrun、roslaunch 来启动节点
-
rosrun、roslaunch 的作用都是:启动包中的可执行程序,并将这些可执行程序初始化成为ROS节点!
-
注意:可执行程序就是节点、可执行程序名就是节点名等这些说法都是不准确的!因为只有当可执行程序执行到
ros::init(argc, argv, "nodeName");
语句时,该程序才会被初始化为节点,而可执行程序的名称和该语句中的"nodeName"
并不一定相同! -
rosrun用法:
rosrun <包名> <可执行程序名>
-
roslaunch 用法:
roslaunch <package> <filename.launch>
filename.launch中的node标签:<node name=新取的节点名 pkg=包名 type=可执行程序名 />
-
https://wiki.ros.org/rosbash#rosrun
https://wiki.ros.org/roslaunch/XML
2.10 使用 rosed 在ROS中编辑文件
- rosed默认的编辑器是vim。其实Ubuntu默认还有一个初学者更友好的编辑器gedit,你可以把下面这行加到~/.bashrc文件中来更改默认编辑器:export EDITOR=‘gedit-w’
- rosed是rosbash套件的一部分。利用它可以直接通过软件包名编辑包中的文件,而无需键入完整路径。
- rosed [package_name] [filename]
rosed roscpp Logger.msg - Tab补全
在不知道准确文件名的情况下,你也可以轻松地查看和编辑包中的所有文件
rosed [package_name] < tab >< tab >
rosed roscpp < tab >< tab >
2.11 消息(msg)
一些概念
- .msg文件本质是文本文件,用于描述ROS消息的字段,用于帮助生成对应的.cpp或.py源代码。
- .msg文件一般存放在软件包的msg目录下,msg文件就是简单的文本文件,每行都有一个字段类型和字段名称。可以使用的类型包括:
int8, int16, int32, int64 (以及 uint*)
float32, float64
string
time, duration
其他 msg 文件
variable-length array[] 和 fixed-length array[C]
Header 它含有时间戳和ROS中广泛使用的坐标帧信息,一般定在第一行 - 例如:
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
其中,使用了Header、字符串原语和其他两个消息的示例: 上面是一个msg文件的样例,它使用了Header,string,和其他另外两个消息的类型。 - 消息格式的完整规范在消息描述语言中。
创建消息
-
1)创建一个.msg文件
roscd beginner_tutorials
mkdir msg
echo “int64 num” > msg/Num.msg -
2)编辑.msg文件
rosed beginner_tutorials Num.msg
添加:
string first_name
string last_name
uint8 age
uint32 score -
3)启用 message_generation 功能
修改 beginner_tutorials / package.xml 文件,如果没有则添加,如果被注释了则取消注释:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend> -
4)为 find_package 添加 message_generation 依赖项
在CMakeLists.txt中查找find_package,在末尾添加message_generation,其他不变:
find_package(catkin REQUIRED COMPONENTS
…
message_generation
) -
5)确保导出消息运行时的依赖关系
在 CMakeLists.txt 中找到catkin_package,取消该行的注释,并加入一项 message_runtime :
-
6)手动添加.msg文件
在 CMakeLists.txt 中找到 add_message_files,取消注释,并将 Message1.msg、Message2.msg修改成(1)中创建的msg名称,如Num.msg :
add_message_files(
FILES
Num.msg
) -
7)确保CMake知道何时需要重新配置项目
在ROS Groovy及早期版本中:注释generate_messages()
在ROS Hydro及更新版本中:
在 CMakeLists.txt 中找到 generate_messages,取消注释:
generate_messages(
DEPENDENCIES
std_msgs
) -
8)重新编译软件包以生成 msg
cd ~/ros_learn_ws
catkin_make -
9)查看生成的消息
rosmsg show [message type]
rosmsg show beginner_tutorials/Num
或:rosmsg show Num
rosmsg -h
rosmsg show -h
2.12 创建服务
一些概念
- .srv文件描述一个服务。它由两部分组成:请求(request)和响应(response)。
- 与.msg类似,.srv也用于帮助生成对应的.cpp或.py源代码。
- .srv文件则存放在srv目录下。
- srv文件和msg文件一样,只是它们包含两个部分:请求和响应。这两部分用一条 “- - - ” 线隔开。下面是一个.srv文件的示例,其中,A和B是请求时的输入参数, Sum是响应结果:
创建服务
-
1)创建一个.srv文件
roscd beginner_tutorials
mkdir srv
echo “int64 A” > srv/MySrv.srv -
2)编辑.srv文件
rosed beginner_tutorials MySrv.srv
编辑:
-
3)启用 message_generation 功能
修改 beginner_tutorials / package.xml 文件,如果没有则添加,如果被注释了则取消注释:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend> -
4)为 find_package 添加 message_generation 依赖项
在CMakeLists.txt中查找find_package,在末尾添加message_generation,其他不变:
find_package(catkin REQUIRED COMPONENTS
…
message_generation
) -
5)确保导出消息运行时的依赖关系
在 CMakeLists.txt 中找到catkin_package,取消该行的注释,并加入一项 message_runtime :
-
6)手动添加.srv文件
在 CMakeLists.txt 中找到 add_service_files,取消注释,并将 Service1.srv、Service2.srv 修改成(1)中创建的srv名称,如MySrv.srv:
add_service_files(
FILES
MySrv.srv
) -
7)确保CMake知道何时需要重新配置项目
在ROS Groovy及早期版本中:注释generate_messages( )
在ROS Hydro及更新版本中:
在 CMakeLists.txt 中找到 generate_messages,取消注释:
generate_messages(
DEPENDENCIES
std_msgs
) -
8)重新编译软件包以生成 msg
cd ~/ros_learn_ws
catkin_make -
9)查看生成的消息
rossrv show < service type >
rossrv show beginner_tutorials/MySrv
或 rossrv show MySrv
待续…20231207, 学习MavSDK去了…
2.13 catkin_make
- catkin_make用于编译catkin工作空间中的所有软件包。catkin_make 是一个命令行工具,它简化了标准catkin工作流程。你可以认为catkin_make是在标准CMake工作流程中依次调用了cmake和make。如果你不熟悉什么是标准CMake工作流程,可以认为是以下几个步骤:
- catkin_make的高级用法。
- catkin文档
- catkin_make在编译软件包时的两种用法:
- 用于初始化catkin工作空间,是开发软件包的第一步!
- 用于编译catkin工作空间中的所有软件包!
3. 软件包
一些概念
- Package?ROS package?catkin package?
- 什么是软件包?为什么要使用软件包?
将与某个项目相关的所有ros节点、主题、消息、脚本都统一在同一个工作目录中进行开发,这个目录最后被打包成一个软件包(Pakage),这样便于项目文件的统一管理以及软件包的发布和共享。
包是ROS中组织软件的主要单元。包可能包含ROS运行时进程(节点)、依赖ROS的库、数据集、配置文件或任何其他有用的组织在一起的内容。包是ROS中最具原子性的构建项和发布项。这意味着你能构建和发布的最细粒度的东西就是一个包。 - 软件包必须创建在catkin工作空间中。
- 软件包可以被:创建、编译、安装、使用、发布。
- 编译和安装后,ros就可以使用这个软件包,所谓的使用是指:
- 1)运行这个软件包中的节点。
- 2)使用这个软件包中的主题和msg。
- 3)使用这个软件包提供的服务等。
- 如何创建、构建自己的软件包?换另一种说法就是:如何将自己现有的 cmake C++项目构建成一个软件包?详细请查看本文第3小节。例如catkin_create_pkg?catkin_make?
- 使用catkin_make命令编译软件包可以看成:在标准CMake工作流程中依次调用了cmake和make。catkin_make 是一个命令行工具,它简化了标准catkin工作流程。你可以认为catkin_make是在标准CMake工作流程中依次调用了cmake和make。如果你不熟悉什么是标准CMake工作流程,可以认为是以下几个步骤:
- catkin_make的高级用法。
软件包的文件类型
软件包的文件类型包括:
- 节点cpp文件(main函数所在);
- 库文件(C++库,python库);
- 可执行文件(编译后的可执行节点);
- package.xml,
软件包的描述。它用于定义软件包之间的依赖关系,并记录有关软件包的元信息,如版本、维护者、许可证等。 - CMakeLists.txt
软件包的生命周期
- 1)项目需求分析
- 2)开始研发任务
- 3)创建 catkin 工作空间(工作目录),假设目录名为catkin-ws;
- 4)在catkin-ws中创建一个或多个软件包(package);
- 5)根据项目需求完善软件包的功能:编写C++节点、主题、消息、脚本等文件;
- 6)编译软件包;
- 7)安装软件包;
- 8)在本地ROS环境中使用该软件包:(1)运行该软件包中的节点。(2)使用该软件包的主题、消息等;
- 9)发布软件包,提供给其他开发者使用;
- 10)其他开发者下载并安装该软件包;
- 11)其他开发者运行该包中的节点;
- 12)其他开发者在开发自己的节点cpp时引用该软件包的头文件,订阅该包的主题、接收该包的主题消息、向该包的主题发布消息等…
软件包的命令工具
- 查看软件包的所在路径:
rospack find pkgName
- 切换到软件包目录:
roscd pkgName
- 查看软件包目录中的文件:
rosls pkgName
- 查看包的依赖关系
rospack depends1 pkgName #或查看package.xml roscd pkgName cat package.xml
- 检测所有嵌套的依赖包:
rospack depends pkgName
- 包名或节点名,可以Tab补全。
- 安装软件包的所有依赖包,仅限于ROS依赖包!
rosdep
语法说明
元包(metapackage)
元包是多个软件包的集合,可以看作是一个“广义软件包”,它的编译方法和普通软件包相同。它相当于一个“包含很多个软件包目录的父目录”!当然这种说法并不准确。
如何构建自己的软件包?
换另一种说法就是:如何将自己现有的 cmake C++项目构建成一个软件包?
-
首先,务必先弄清楚catkin工作空间中的目录结构、文件类型:
- 软件包目录必须要创建在catkin工作空间中,一个catkin工作空间可以创建多个软件包(软件包目录),看实际需要。
- catkin工作空间结构、软件包目录结构如下图所示:
-
使用catkin_create_pkg命令来创建一个软件包(暂时不包含任何cpp文件,只有基本架构文件)
可参考:https://wiki.ros.org/cn/ROS/Tutorials/BuildingPackagesmkdir -p ~/ros_learn_ws/src cd ~/ros_learn_ws/src catkin_create_pkg beginner_tutorials std_msgs rospy roscpp cd ~/ros_learn_ws # 编译catkin工作空间中的所有软件包 catkin_make source ~/ros_learn_ws/devel/setup.bash printenv | grep ROS
使用catkin_create_pkg命令生成的软件包目录如beginner_tutorials实际上是一个cmake C++项目目录,目录中有xxx.cpp、xxx.h、CMakeLists.txt,此外还有标志着软件包目录的文件 package.xml!而xxx.cpp中有库文件,最重要的是还有一个最后唯一被编译成可执行文件的顶层cpp(即ROS中的节点cpp文件,包含一个main函数和一个while死循环)。 -
简化package.xml的冗余项:https://wiki.ros.org/cn/ROS/Tutorials/CreatingPackage
-
编译软件包
编译catkin工作空间中的所有软件包:
具体是指catkin工作空间的src目录下的所有软件包。cd ~/ros_learn_ws catkin_make
catkin工作空间下的src是默认的软件包源码存放位置,如果软件包的源码不在src,则catkin_make应该这样用:
catkin_make --source my_src
。
只编译某个包:catkin_make -DCMAKE_BUILD_TYPE=Release --pkg visp_ros
。 -
如何将自己现有的 cmake C++项目构建成一个软件包?
- 1)新建一个catkin工作空间并初始化:
mkdir -p catkin-ws/src cd catkin-ws catkin_make
- 2)将新建的catkin工作空间添加到ROS环境中:
source catkin_ws/devel/setup.bash
- 3)移动自己现有的C++项目到src中,这一步需要将项目文件拆分成一个或多个软件包的形式。
- 4)编辑各软件包目录中的顶层CMakeLists.txt:
vim catkin-ws/src/pkg1/CMakeLists.txt vim catkin-ws/src/pkg2/CMakeLists.txt
- 5)编辑各软件包目录中的package.xml:
vim catkin-ws/src/pkg1/package.xml vim catkin-ws/src/pkg2/package.xml
- 6)编辑catkin工作空间中的顶层CMakeLists.txt:
vim catkin-ws/src/CMakeLists.txt
- 7)编译catkin工作空间中的所有软件包:
cd catkin-ws catkin_make
- 1)新建一个catkin工作空间并初始化:
-
参考资料
https://wiki.ros.org/cn/ROS/Tutorials/BuildingPackages
手动创建ROS package
在官网搜索可用的软件包
- 1)官方地址:ROS Index
- 2)先选中对应的ROS版本:
- 3)搜索软件包(注意ROS版本)
- 4)查看软件包的使用文档、开发文档
4.1)使用文档
包搜索后点进去的页面就是使用文档,需要关注的点为:
4.2)开发文档:
查找已安装、安装、卸载
- 默认安装位置
使用apt、rosdep安装ROS软件包时的默认安装路径:/opt/ros/<ros-distros>/
其中<ros-distros>
是指ROS版本名,如/opt/ros/noetic/
。 - 查看已安装
dpkg -l ros-*
- 安装
知道包的全名可使用apt安装
使用rosdep安装package.xml中指明的依赖包apt-get install ros-<ros-distros>-pkgName
注意:需要先安装rosdepcd ~/catkin_ws sudo rosdep init rosdep update rosdep install --from-paths src --ignore-src --rosdistro $ROS_DISTRO
- 卸载
- 法1)进
/opt/ros/<ros-distros>/
删除包的相关文件。 - 法2)
sudo apt-get --purge remove ros-<ros-distros>-pkgName
如sudo apt-get --purge remove ros-noetic-roscpp
- 法1)进
4. nodelet
帮助文档:https://wiki.ros.org/nodelet/Tutorials
5. ROS2知识点
- The ROS 1 bridge can connect topics from ROS 1 to ROS 2 and vice-versa. See the dedicated documentation on how to build and use the ROS 1 bridge.
- 从帮助文档中选择性观看: tutorials and demos
待续…
6. 问题合集
- 如果roscore运行后没有初始化,很有可能是网络配置的问题。参见网络配置 - 单机器配置。
- 如果roscore不能初始化并提示缺少权限,可能是因为~/.ros目录属于root用户(只有root用户才能访问),可以用以下命令递归地更改该目录的所有权:
$ sudo chown -R <your_username> ~/.ros - 当打开一个新的终端时,环境将会重置,/.bashrc文件将会生效。如果你在运行rosnode等命令时出现一些问题,那么可能需要将一些环境设置文件添加到/.bashrc或手动source一下。
- catkin: command not found
https://blog.csdn.net/weixin_58045467/article/details/126511275 - 关于:the rosdep view is empty: call ‘sudo rosdep init’ and ‘rosdep update’
以及 rosdep: command not found
https://blog.csdn.net/qq_44339029/article/details/130494206
sudo apt install python3-rosdep
sudo rosdep init
rosdep update
7. 解决问题的途径
参考:https://wiki.ros.org/Support
- ROS 新闻,不用于发布问题:http://discourse.ros.org
- Troubleshooting
- FAQ
- Robotics Stack Exchange
- 其他:https://wiki.ros.org/cn/community
8. ROS 与 Ardupilot
- ArduPilot功能可以通过ROS进行扩展;
- 推荐使用ROS Noetic 版本,而非ROS2;
- 对于ROS2,目Humble是唯一支持的ROS2版本;
9. ROS with SITL
系统环境:win11,wsl2,Ubuntu20.04
- 安装ROS
https://blog.csdn.net/weixin_43321489/article/details/134681758 - 安装MAVROS
https://ardupilot.org/dev/docs/ros-install.html#installing-mavros - 初始化ROS工作空间(ros需要工作空间)
创建一个目录ardupilot_ros_ws/src,并初始化:mkdir -p ardupilot_ros_ws/src cd ardupilot_ws catkin init cd src
- 启动SITL仿真,并添加一个UDP Forwarding: 127.0.0.1:14550
cd ~/code/ardupilot/ArduCopter sim_vehicle.py -v ArduCopter --console --map -w --out=127.0.0.1:14550
- 启动MAVROS并通过UDP连接到SITL
1)新建一个新的bash terminal
2)拷贝一个.launch文件进工作空间并修改连接方式
将代码的第一行改为UDP连接:cd ~/ardupilot_ros_ws/src/ mkdir launch cd launch roscp mavros apm.launch apm.launch sudo apt-get install gedit gedit apm.launch
改为:<arg name="fcu_url" default="/dev/ttyACM0:57600" />
保存并退出。<arg name="fcu_url" default="udp://127.0.0.1:14550@14555" />
- 使用roslaunch 命令启动相关的ROS节点以连接到SITL
cd ~/ardupilot_ros_ws/src/launch roslaunch apm.launch
- 启动rqt工具以查看MAVROS与SITL的连接状态,通过MAVROS节点、主题、消息等控制SITL中的飞机
1)新建一个新的bash terminal;
2)输入命令
3)通过MAVROS查看飞机状态cd ~/ardupilot_ros_ws rqt
plugins ~> topics ~> topics monitor ~> 勾选下面的topic可以看到通过MAVROS获取的飞机的位置信息:
4)通过MAVROS操控飞机切换GUIDED模式、解锁、起飞
plugins ~> services ~> services caller ~>
10. mavros 软件包
使用文档:https://index.ros.org/p/mavros/github-mavlink-mavros/#noetic-overview
开发文档:https://wiki.ros.org/mavros#Usage
知识碎片
- 可以串口、TCP、UDP连接到飞控;
- 关于坐标系
飞控使用的是NED坐标系,ROS系统使用的是ENU坐标系,注意转换关系;
坐标转换实现在:src/lib/ftf_frame_conversions.cpp 、src/lib/ftf_quaternion_utils.cpp 中; - mavros_extras – extra plugins & node for mavros
- 要看懂mavros 的使用先回ros的基本使用;
- mavros 文档中并没有现成的例子可用和借鉴;
待续…
11. visp_ros 软件包
一个visp团队开发和维护的用于实现IBVS视觉伺服的ROS软件包,小编对这个visp_ros包的实践记录请参考Jetson Orin Nano 后篇。
待续…
12. 开发知识点
ros::spinOnce() 和 ros::spin()
ROS中的ros::spinOnce()和ros::spin()函数都是用于监听节点订阅的所有主题的消息池并处理消息回调函数。
ros::spinOnce()
:监听节点订阅的所有主题的消息池,如果监听到消息池中有新的消息,则会调用该主题对应的回调函数,然后返回继续执行ros::spinOnce()之后的程序,如果监听不到任何新消息则直接返回!一般spinOnce()放在while循环中。ros::spin()
:持续监听节点订阅的所有主题的消息池,如果监听到消息池中有新的消息,则会调用该主题对应的回调函数,然后持续监听和执行回调函数,不会返回执行ros::spin()之后的程序,直到程序结束,所以ros::spin()函数后面不能有其他语句,除了return 0。一般不允许spin()放在while循环中。- 代码示例
发送节点:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);//1000是消息池的大小
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
loop_rate.sleep();
++count;
}
return 0;
}
spin接收节点:
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
ros::spin();
return 0;
}
spinOnce接收节点:
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
/*...TODO...*/
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter", 2, chatterCallback);
ros::Rate loop_rate(5);
while (ros::ok())
{
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}