ros2编程入门

简介

  • ros2基于ros
  • 在ros的基础上进行了去中心化(roscore)的升级
  • ros2使用component的概念
    • 写法上有很大改变
  • catkin_make 换成了 ament_cmake (CMakeList.txt的写法上有较多的改变)
    • ament如下
    find_package(ament_cmake REQUIRED)
    find_package(rclcpp REQUIRED)
    find_package(rclcpp_components REQUIRED)
    find_package(std_msgs REQUIRED)

    ament_target_dependencies(composition_nodes rclcpp rclcpp_components std_msgs)

    ament_package()
  • package.xml 的写法变化
  <buildtool_depend>ament_cmakebuildtool_depend>

  <build_depend>rclcppbuild_depend>
  <build_depend>rclcpp_componentsbuild_depend>
  <build_depend>std_msgsbuild_depend>

  <exec_depend>rclcppexec_depend>
  <exec_depend>rclcpp_componentsexec_depend>
  <exec_depend>std_msgsexec_depend>

  <test_depend>ament_lint_autotest_depend>
  <test_depend>ament_lint_commontest_depend>

  <export>
    <build_type>ament_cmakebuild_type>
  export>
  • python的写法

Practice

  1. Pre:
    1. colcon 包组织工具
    2. 安装colcon: sudo apt install python3-colcon-common-extensions
    3. 在src 的同级目录 colcon build 进行编译所有
      1. 编译选定的包 colcon --packages-select YOUR_PKG_NAME 可多个
      2. colcon build --packages-ignore YOUR_PKG_NAME 忽略指定包,可以多个
      3. colcon build --symlink-install (表示编译时如果 install 中文件已经存在于 src 或者 build 文件夹中,就用超链接指向该文件,避免浪费空间,也可以实现同步更新)
      4. –merge-install 命令: 简化编译路径前缀
      5. –parallel-workers NUMBER 要并行处理的最大作业数, 默认值是逻辑 CPU 内核数
      6. –cmake-args -DCMAKE_BUILD_TYPE=Release 表示传入cmake编译选项参数
      7. colcon test 测试编译好的包
      8. 运行前环境变量设置: ./install/setup.bash
  • 参考 博客

添加自定义的msg包

  1. 使用添加包的命令cmd ros2 pkg create my_msg --build-type ament_cmake
  2. cd my_msg & mkdir msg
  3. 修改CMakeList.txt:

   find_package(sensor_msgs REQUIRED) # add dependence of sensor_msg

   find_package(rosidl_default_generators REQUIRED) # add generator for generating msg source files
         
   set(msg_files
   "msg/MyInfo.msg"
   "msg/Num.msg"
   )
   rosidl_generate_interfaces(${PROJECT_NAME}
   ${msg_files}
   # ADD_LINTER_TESTS
   DEPENDENCIES sensor_msgs
   ) # add generate source files like .h/.hpp etc

   ament_export_dependencies(rosidl_default_runtime)
   # export .so 
  1. 修改package.xml

  <depend>sensor_msgsdepend> 

  <buildtool_depend>rosidl_default_generatorsbuildtool_depend>

  <exec_depend>rosidl_default_runtimeexec_depend>

  <member_of_group>rosidl_interface_packagesmember_of_group>

自定义msg消息收发py

  1. 使用命令创建包(节点): ros2 pkg create my_node --build-type ament_python --dependencies rclpy

    • 以py3_tools 为例子,命令行自动创建之后会生成如下node文件(到对应的node目录,tree 查看)ros2编程入门_第1张图片
  2. 在上面生成的my_node/my_node 中添加python源文件

    1. ep:
import rclpy
from rclpy.node import Node

from my_msg.msg import Num    # CHANGE


class MinimalPublisher(Node):

    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(Num, 'topic', 10)     # CHANGE
        timer_period = 0.5
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = Num()                                           # CHANGE
        msg.num = self.i                                      # CHANGE
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%d"' % msg.num)  # CHANGE
        self.i += 1


def main(args=None):
    rclpy.init(args=args)

    minimal_publisher = MinimalPublisher()

    rclpy.spin(minimal_publisher)

    minimal_publisher.destroy_node()
    rclpy.shutdown()

  1. 修改配置文件 my_node/setup.py
    1. 在 entry_points={‘console_scripts’: [],}中添加节点位置
    2. 写法: “pkgname_show=my_node.python_filename:func”
  2. 编译节点
    1. cd 2 workspace
    2. cmd: source install/setup.bash
    3. checkout the pkg exist: ros2 pkg list | grep my_node
  3. run node
    1. cmd: ros2 run my_node pkgname_show
  4. 添加自定义的消息
    1. 在python文件中直接引入模块: from my_msg.msg import Num
    2. 在package.xml中添加编译运行依赖:

  <build_depend>my_msgbuild_depend>
  <exec_depend>my_msgexec_depend>
  1. subscribe 源文件
import rclpy
from rclpy.node import Node

from my_msg.msg import Num  


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            Num,
            'topic',
            self.listener_callback,
            10)
        self.subscription  # prevent unused variable warning

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%d"' % msg.num)


def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()

  1. 添加入口名同上方式

自定义msg消息收发cpp

  1. 初始化创建pkg命令:
    1. cd src
    2. ros2 pkg create pub_sub_demo_cpp --build-type ament_cmake --dependencies rclcpp std_msgs sensor_msg
  2. 创建节点源文件
#include 
#include 
#include 
#include 

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

#include "util/msg/num.hpp"

using namespace std::chrono_literals;

/* This example creates a subclass of Node and uses std::bind() to register a
 * member function as a callback from the timer. */

class MinimalPublisher : public rclcpp::Node
{
public:
  // MinimalPublisher()
  // : Node("minimal_publisher"), count_(0)
  // {
  //   publisher_ = this->create_publisher("topic", 10);
  //   timer_ = this->create_wall_timer(
  //   500ms, std::bind(&MinimalPublisher::timer_callback, this));
  // }

  MinimalPublisher()
      : Node("minimal_publisher"), count_(0)
  {
    publisher_ = this->create_publisher("/test/NumMsg", 10);
    timer_ = this->create_wall_timer(
        500ms, std::bind(&MinimalPublisher::timer_callback, this));
  }

private:
  // void timer_callback()
  // {
  //   auto message = std_msgs::msg::String();
  //   message.data = "Hello, world! " + std::to_string(count_++);
  //   RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
  //   publisher_->publish(message);
  // }
  void timer_callback()
  {
    auto message = util::msg::Num();
    message.num_test = 3;
    // RCLCPP_INFO(this->get_logger(), "Publishing: '%f'", message.num_test.c_str());
    std::cout << "running talker" << std::endl;
    publisher_->publish(message);
  }
  rclcpp::TimerBase::SharedPtr timer_;
  // rclcpp::Publisher::SharedPtr publisher_;
  rclcpp::Publisher::SharedPtr publisher_;
  size_t count_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared());
  rclcpp::shutdown();
  return 0;
}

#include 

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

#include "util/msg/num.hpp"
using std::placeholders::_1;

class MinimalSubscriber : public rclcpp::Node
{
  // public:
  //   MinimalSubscriber()
  //   : Node("minimal_subscriber")
  //   {
  //     subscription_ = this->create_subscription(
  //     "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
  //   }

  // private:
  //   void topic_callback(const std_msgs::msg::String & msg) const
  //   {
  //     RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg.data.c_str());
  //   }
  //   rclcpp::Subscription::SharedPtr subscription_;

public:
  MinimalSubscriber()
      : Node("minimal_subscriber")
  {
    subscription_ = this->create_subscription(
        "/test/NumMsg", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
  }

private:
  void topic_callback(const util::msg::Num &msg) const
  {
    RCLCPP_INFO(this->get_logger(), "I heard: '%ld'", msg.num_test);
  }
  rclcpp::Subscription::SharedPtr subscription_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared());
  rclcpp::shutdown();
  return 0;
}

  1. CMakeList修改
    1. find_package(my_msg REQUIRED) # add self-defined msg pacakge
    2. add_executable(listener src/subscriber_member_function.cpp) #
    3. ament_target_dependencies(talker rclcpp std_msgs util) # 设置编译依赖
    4. install() 中添加 listener
  2. package.xml (同上python版的信息添加)
  3. 参考博客
  4. 也可参考官方示例
  5. cd … && colcon build 编译,source install/setup.bash 设置环境变量,然后运行

problem log

  • conda 环境与ros2环境的冲突,可能导致import rclpy 失败,解决: conda deactivate 关闭conda虚拟环境 (这个问题出现在直接运行python文件,非编译后运行)
  • 自定义消息编译报错,没有 em 模块, pip install empy解决
  • 修改完py文件后,运行显示和之前一样, 需要重新编译再运行,方能更新

你可能感兴趣的:(工具使用技巧,python)