ROS2 NODE 简单搭建

The Robot Operating System (ROS) is a set of software libraries and tools for building robot applications. From drivers and state-of-the-art algorithms to powerful developer tools, ROS has the open source tools you need for your next robotics project.

以上内容来自于ROS2-Rolling官网

ROS之于我来说有如下作用:

  • 录制ROSBAG包,可以完美还原实车的环境(DDS通讯正常的情况下)
  • 可以DEBUG TOPIC信号,PLOTJUGGLER、RVIZ等ROS自带的工具可以将数据拆开来看,逐帧分析。
  • 可以回灌算法,如果调度写得合理,完全可以媲美公司级中间件调度。

下面就来说一说ROS2回灌节点的简单搭建:

.
├── CMakeLists.txt
├── inc
│   ├── conv
│   │   ├── img_conv.h
│   │   └── psd_conv.h
│   ├── psd_gaga.h
│   └── ros2_all_msgs.h
├── package.xml
└── src
    └── psd_gaga.cpp

ROS具有一个重要的功能:负责收发数据。在我的项目里,主要作用是:收上一个节点的模型的输出信息,跑自己的核心算法,将自己算法的输出发送出去。ROS可以做到比较精准地调度(按一定周期)核心算法。

如上所示,psd_gaga.cpp和psd_gaga.h构成了ros2 node的主要框架。

如果你打算和我一起搭建ROS2 NODE,必须使用ubuntu20.04以上的版本(ROS2的要求)。

首先来看CMakeLists.txt,让我们能有个宏观的概念。

cmake_minimum_required(VERSION 3.16)
project(psd_gaga)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)

set(ALGO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../..)

set(INC_PATH ${ALGO_PATH} ${ALGO_BASE_PATH} ${ROS2_BASE_PATH} ${OpenCV_INCLUDE_DIRS})

include_directories(${INC_PATH} )
link_directories(${ALGO_PATH}/build)

find_package(ament_cmake REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rclcpp REQUIRED)

find_package(rosidl_default_generators REQUIRED)
find_package(cv_bridge REQUIRED)
find_package(image_transport REQUIRED)


add_executable(psd_gaga src/psd_gaga.cpp ../../visualization/visualize.cpp)
target_link_libraries(psd_gaga algo_.so ${OpenCV_LIBS}) 
ament_target_dependencies(psd_gaga rclcpp std_msgs rosidl_default_generators cv_bridge image_transport)

install(TARGETS xxx
  DESTINATION lib/${PROJECT_NAME})

ament_package()

如上所示,cmake_minimum_required project set 等常用的宏在此不做过多解释,有需要了解的朋友可以点此访问CMake官方手册。ros提供了ament_cmake的包供cmake使用,我使用的命令依赖ament_cmake的为ament_package,其作用为安装当前project到指定位置,方便其他包依赖此project的使用find package(),其实自定义的ros msg也是这个道理,当我们写完一个msg并完成了colcon build编译,在其他项目里可直接使用find package(xxx_msg)

ament_cmake提供的另一个命令是ament_target_dependencies,其作用相当于cmake中的target_link_libraries,即为某个目标连接库。

当理解完上述内容后,即可开始着手代码,首先来看main函数,其存放于psd_gaga.cpp中

int main(int argc, char **argv)
{
  auto options = rclcpp::InitOptions().auto_initialize_logging(false);
  rclcpp::init(argc, argv, options);
  std::shared_ptr<rclcpp::Node> node_ptr    = std::make_shared<rclcpp::Node>("psd_gaga", rclcpp::NodeOptions().allow_undeclared_parameters(true).automatically_declare_parameters_from_overrides(true));
  std::shared_ptr<PSD_GAGA>     sp_psd_gaga = std::make_shared<PSD_GAGA>(node_ptr);

  std::chrono::duration<int, std::ratio<1, 1000>> period{66};
  auto timer = node_ptr->create_wall_timer(period, std::bind(&PSD_GAGA::algo_run, sp_psd_gaga.get()));
  while (true)
  {
    rclcpp::spin_some(node_ptr);
    usleep(1);
  }
  return 0;
}

auto options = rclcpp::InitOptions().auto_initialize_logging(false);是为了屏蔽ros2中自带的spd_log日志工具,由于我在自己的算法中引入了spd_log,两次init会导致程序崩溃。

std::shared_ptr<rclcpp::Node> node_ptr = std::make_shared<rclcpp::Node>("psd_gaga", rclcpp::NodeOptions().allow_undeclared_parameters(true).automatically_declare_parameters_from_overrides(true));创建一个基础节点,用于塞到自己node的初始化参数中。

auto timer = node_ptr->create_wall_timer(period, std::bind(&PSD_GAGA::algo_run, sp_psd_gaga.get()));创建定时器,按一个period周期调用run函数。

调度数据已经讲完,那收发数据是如何进行的。由于算法是运行在C++中的,而ros2 msg拥有自己的struct->*.msg,而后它对.msg编译生成一堆.hpp .h供msg创造者使用,这就引出一个问题,不同形式的msg怎么传递呢?

答案是,没办法传递,必须通过convert函数将其转换。在收到数据后将msg转换成c++ struct,在处理完输出后将c++ struct转换成msg再发送出去。

由于源码中涉及到过多的私人信息,计划写一个Node父类将框架搭建好后再公开。


已发布

分类

, ,

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注