ROS2
ros2 创建一个pkg
ros2 pkg create
1 | //生成的pkg结构 |
ros2 命令行
- 查看topic: ros2 topic list
- 查看topic详细信息: ros2 topic info
$ros2 topic pub
<msg/msg_type> //msg 是需要yaml格式
egs. ros2 topic pub /chatter std_msgs/String “data: Hello!”
ros2 topic echo
egs. ros2 topic echo /chatter
1 | $ ros2 service list //查看服务 |
ros2 param 参考
1 | $ ros2 param list //查看参数列表 |
ros2 action 参考
1 | $ros2 action list //查看动作 |
- lifecycle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16ros2 lifecycle nodes // 列出所有 LC 节点
ros2 lifecycle get <node> // 列出指定节点或所有 LC 节点的当前状态。
ros2 lifecycle list <node> // 列出指定节点可能的下一个状态和相应的转换调用(名称和 ID)。
ros2 lifecycle set <node> <transition> // 在 LC 节点上触发转换(按名称或 ID)。
// 可以调用的状态
● 配置(configure)
● 激活(activate)
● 停用(deactivate)
● 清理(cleanup)
● 关闭(shutdown)
ros2自定义消息
$ ros2 pkg create test_msgs //包名一定是xxx_xxx格式,不要是XX2XX格式
创建msg目录和文件
创建目录
$ mkdir -p test_msgs/msg //创建msg目录
编写*.msg文件
$ vim msg/TestMsgs.msg //首字母大写 后边生成的hpp文件名根这个名字有关。 [TestMsgs <–> test_msgs.hpp] [Testmsgs <–> testmsgs.hpp
// TestMsgs.msg内容:
int32 Num修改CMmakeList.txt 规则
1
2
3
4
5find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/TestMsgs.msg"
)修改package.xml规则
1
2
3
4
5<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>构建
$ colcon build
设置环境变量
$ source ./install/setup.bash
// 之后就可以查看时候设置到ros2的环境中了
ros2 msg show [tab自动补全] //如果发现有test_msgs/TestMsgs 就证明成功,之后在其他节点引用将用到测试自定义消息
1
2
3
4
5
6
7
8
9
10//消息使用格式:
<pkg_name>::msg::<*.msg文件名>
test_msgs::msg::TestMsgs tms = test_msgs::msg::TestMsgs();//就是一个数据结构,实际应该是解析成一个对象(我猜的)
//访问结构成员
tms.num
// 头文件引用格式
XXX 消息
XXXmsgs.msg
1
2
3std_msgs/Header header
string msg_type
string msg_dataXXXmsgsarray.msg
1
2
3
4std_msgs/Header header
XXX_msgs/msg/XXXmsgs[] msgs //这个需要系统先有XXX_msgs/msg/XXXmsgs
//也就是说 依赖的消息要先编译好加载到系统里去
ROS2 错误
1 | //ros2 没有使用init初始化 |
1 |
|
-DXXX_AP_PATH=/share/XXX-CORE/core
core/develop_jay[ros2]
构建
- 工程依赖:
data_stream_framework 依赖ros2_XXX_msg/XXX_msgs, ros2_XXX_msg/XXX_msgs_array, XXX_api,
构建控制脚本为.cmake/ros2build.cmake。//构建过程中需要的依赖可以再该脚本中增加/修改。典型依赖是protobuf_util.so
再依赖工程下有build_alone.sh构建脚本,构建需要修改-DXXX_AP_PATH=/share/XXX-CORE/core变量
- 构建ro2 msgs
其中ros2_XXX_msg/XXX_msgs_array 依赖 ros2_XXX_msg/XXX_msgs工程,用户需依次构建[构建指令:colcon build],每个工程构建完并source/install/setup.bash将自定义消息加载到ros2系统,
- 查询ros2 msg加载成功
$ros2 msg list //出现XXX_msg/xx/xx 和 XXX_msg_array/xx/xx 即表示成功
- 构建XXX_api
使用工程下build_alone.sh //注意修改-DXXX_AP_PATH=/share/XXX-CORE/core变量
- 构建data_stream_framework
使用工程下build_alone.sh //注意修改-DXXX_AP_PATH=/share/XXX-CORE/core变量
构建环境:
docker image:172.16.8.120/XXX/XXX0.8:v1.0.9
构建平台:
x64-ros2
测试
测试demo
demo目录下.cc文件测试yaml
data_stream_framwork/Debug/conf
server使用test_copy_server client使用test_copy_client
pub/sub使用test
功能层软件构建方法
copy XXX_api/pacakge.xml YOUP_PORJECT_DIR
修改
XXX 中XXX=CMakeLists.txt中project(NAME)NAME. copy XXX_api/build_alone.sh YOU_PROJECT_DIR
修改build_alone.sh中-DXXX_AP_PATH=/YOU_PROJECT_DIR/core
bash build_alone.sh //即可构建功能层软件,构建成功会在Debug下生成目标文件。
可能的错误
找不到protobuf_util头文件
在ros2build.cmake中有指定protobuf_util的头文件和lib,用户需要指定该路径,两种方法1. 你可以指定已经构建好的protobuf-util[x64]; 2. 你可以使用common/develop_jay直接在172.16.8.120/XXX/XXX0.8:v1.0.9下构建后指定该路径找不到jsoncpp头文件
apt-get install libjsoncpp-dev
core/.cmake/ros2build.cmake下指定protobuf_utils路径
#protobuf_utils
list(APPEND protobuf_utils_INCLUDE_DIR
/share/XXX-COMMON/common/protobuf_utils/protobuf_utils_cpp/include
/share/XXX-COMMON/common/protobuf_utils/protobuf_utils_cpp/pb_src
)
list(APPEND protobuf_utils_LIBRARIES
/share/XXX-COMMON/common/protobuf_utils/protobuf_utils_cpp/Debug/lib/libprotobuf_utils.so
)
ros2 rcl logger
1 | //Logger |
ros2 rclcpp executor 事件循环
// 将node添加到executor中(publisher subcriptiion service client)
- executor.add_node(){
weak_nodes_; //添加node
guard_conditions_; //添加node 的 guard_conditions
然后在spin循环中先查找any_exec [subscription_handles_,service_handles_,client_handles_,timer_handles_,waitable_handles_],如果exec_存在,则执行对应的回调,如果不存在,collect_entities,设置wait_set_然后使用rcl_wait监控wait_set_, 如果有fd[rmw_subscriptions,rmw_guard_conditions,rmw_services,rmw_clients,rmw_events]被触发,然后根据wait_set_清理无关实体[比如说waitable_handles_中没有数据的(IPM)[ipm中is_ready(wait_set)中wait_set无用,直接检测buffer_->has_data()]],然后继续获取any_exec,获取到exec后执行exec对应的回调。
}
- ros2/rmw_fastrtps/rmw_wait.cpp:29:check_wait_set_for_data
第38行:data的获取
第39行:custom_subscriber_into->listener_->hasData();// 需要分析多线程竞争条件 predicate
ros2 发布和订阅逻辑
发布数据的时候,发布者会判断intra_process_is_enabled_, 如果使用ipm则继续判断是否多个订阅者订阅一个发布者,如果有多个订阅者,则将msg转为shared_ptr 然后发布