ROS2与C++入门教程-在C++包里增加python支持
ROS2与C++入门教程-在C++包里增加python支持
说明:
- 介绍如何在C++包增加Python支持,实现通过C++节点发布话题信息,通过Python节点接受话题信息
- 一般情况下都是C++或Python都独立的包,这样对于各自管理的节点也很方便。
- 但是有些情况也例外,如果C++包里想同时增加Python也是支持的。步骤也多一些
步骤:
- 新建包my_cpp_py_pkg
cd ~/dev_ws/src
ros2 pkg create my_cpp_py_pkg --build-type ament_cmake
- 内容如下:
my_cpp_py_pkg/
├── CMakeLists.txt
├── include
│ └── my_cpp_py_pkg
├── package.xml
└── src
- 增加cpp节点和头文件
cd my_cpp_py_pkg/
touch src/cpp_node.cpp
touch include/my_cpp_py_pkg/cpp_talker.hpp
- cpp_talker.hpp内容如下:
#include <chrono>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
- cpp_node.cpp需要增加引入头文件,增加如下内容cpp_talker.cpp
#include "my_cpp_py_pkg/cpp_talker.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<std_msgs::msg::String>("topic", 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);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
- 增加python节点和模块导入
- 新建pyton目录
mkdir my_cpp_py_pkg
touch my_cpp_py_pkg/__init__.py
mkdir scripts
- 新建python文件
touch my_cpp_py_pkg/module_to_import.py
touch scripts/py_listener.py
- module_to_import.py内容如下:
def listener_write(data) :
my_open = open("/tmp/my_write.txt", 'w')
#打开/tmp路径下的my_write.txt文件,采用写入模式
#若文件不存在,创建,若存在,清空并写入
my_open.write(data)
#在文件中写入一个字符串
my_open.write('\n')
my_open.close()
- py_listener.py内容如下:
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
from my_cpp_py_pkg.module_to_import import listener_write
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
self.subscription #
def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
listener_write(msg.data)
def main(args=None):
rclpy.init(args=args)
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
minimal_subscriber.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
- 重要提示:您必须首先在 py_listener.py 文件中添加一个行:
#!/usr/bin/env python3
- 你不增加这一行,用ros2 run运用就会出错。
- 同时要增加执行权限
chmod +x scripts/py_listener.py
- 如果要导入模块,可以在py_listener.py增加如下行。
from my_cpp_py_pkg.module_to_import import listener_write
- 最终的结构如下:
my_cpp_py_pkg/
# --> package info, configuration, and compilation
├── CMakeLists.txt
├── package.xml
# --> Python stuff
├── my_cpp_py_pkg
│ ├── __init__.py
│ └── module_to_import.py
├── scripts
│ └── py_listener.py
# --> Cpp stuff
├── include
│ └── my_cpp_py_pkg
│ └── cpp_talker.hpp
└── src
└── cpp_talker.cpp
- 配置package.xml
- 内容如下:
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>my_cpp_py_pkg</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="your@email.com">Name</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>ament_cmake_python</buildtool_depend>
<depend>rclcpp</depend>
<depend>rclpy</depend>
<depend>std_msgs</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
- 增加<buildtool_depend>ament_cmake_python</buildtool_depend>行和
rclpy ,支持python使用。 - 注意:在标准的 Python 包中,你应该有 ament_python,而不是 ament_cmake_python。 确保不要混合使用这 2 个。
- 使用 ament_cmake_python 意味着我们将能够使用 cmake 设置我们的 Python 内容。
- 配置CMakeLists.txt
- 内容如下:
cmake_minimum_required(VERSION 3.5)
project(my_cpp_py_pkg)
# 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 dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclpy REQUIRED)
find_package(std_msgs REQUIRED)
# Include Cpp "include" directory
include_directories(include)
# Create Cpp executable
add_executable(cpp_talker src/cpp_talker.cpp)
ament_target_dependencies(cpp_executable rclcpp)
# Install Cpp executables
install(TARGETS
cpp_talker
DESTINATION lib/${PROJECT_NAME}
)
# Install Python modules
ament_python_install_package(${PROJECT_NAME})
# Install Python executables
install(PROGRAMS
scripts/py_listener.py
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
- 注意其中三个部分: 依赖部分,CPP部分和Python部分
- 依赖部分
# Find dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclpy REQUIRED)
find_package(std_msgs REQUIRED)
- CPP部分
# Include Cpp "include" directory
include_directories(include)
# Create Cpp executable
add_executable(cpp_talker src/cpp_talker.cpp)
ament_target_dependencies(cpp_talker rclcpp)
# Install Cpp executables
install(TARGETS
cpp_talker
DESTINATION lib/${PROJECT_NAME}
)
- python部分
# Install Python modules
ament_python_install_package(${PROJECT_NAME})
# Install Python executables
install(PROGRAMS
scripts/py_listener.py
DESTINATION lib/${PROJECT_NAME}
)
使用 ament_python_install_package(${PROJECT_NAME}) 安装任何 Python 模块(在此示例中:my_cpp_py_pkg/ 文件夹下的文件),以便您可以从这个或另一个包中找到它们。
然后,我们安装 scripts/py_listener.py 文件。 我们将此文件放在 install lib/ 文件夹中,该文件夹与 ROS2 Cpp 节点的文件夹相同。 因此,所有 Cpp/Python 可执行文件都将位于同一位置。
对于您需要安装的任何新 Python 脚本,只需在此处添加新行。
编译包
cd ~/dev_ws/
colcon build --symlink-install --packages-select my_cpp_py_pkg
- 执行cpp发布话题信息
ros2 run my_cpp_py_pkg cpp_talker
- 效果如下:
$ ros2 run my_cpp_py_pkg cpp_talker
[INFO] [1651803573.152324876] [minimal_publisher]: Publishing: 'Hello, world! 0'
[INFO] [1651803573.652296360] [minimal_publisher]: Publishing: 'Hello, world! 1'
[INFO] [1651803574.152555806] [minimal_publisher]: Publishing: 'Hello, world! 2'
[INFO] [1651803574.652385533] [minimal_publisher]: Publishing: 'Hello, world! 3'
[INFO] [1651803575.152389750] [minimal_publisher]: Publishing: 'Hello, world! 4'
- 执行python接受话题信息
ros2 run my_cpp_py_pkg py_listener.py
- 效果如下:
$ ros2 run my_cpp_py_pkg py_listener.py
[INFO] [1651803635.112644593] [minimal_subscriber]: I heard: "Hello, world! 8"
[INFO] [1651803635.597138764] [minimal_subscriber]: I heard: "Hello, world! 9"
[INFO] [1651803636.097224630] [minimal_subscriber]: I heard: "Hello, world! 10"
[INFO] [1651803636.597222975] [minimal_subscriber]: I heard: "Hello, world! 11"
[INFO] [1651803637.096938082] [minimal_subscriber]: I heard: "Hello, world! 12"
[INFO] [1651803637.596770711] [minimal_subscriber]: I heard: "Hello, world! 13"
- 重要提示:如果您希望使用 --symlink-install 选项进行编译(这样您就可以修改和重新运行脚本而无需重新编译),您必须使用 chmod +x 使您的脚本可执行。
- 否则当你尝试运行你的节点时,你会得到这个错误:“No executable found”。
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号