ros2笔记-2.5.1 面向对象编程
面向对象
编程思想主要是面向过程、面向对象、函数式几种。
涉及的概念:
类、抽象、封装、继承、多态。这里没有展开。
python 版本
新建节点代码
还是上一节基础上,再demo_python_pkg 包下面新建person_node.py
class PersonNode:
def __init__(self,name_val: str,age_val: int) -> None:
self.name = name_val
self.age = age_val
def eat(self,food_name: str):
print(f"{self.name},{self.age}岁,爱吃{food_name}")
def main():
node = PersonNode('张三',18)
node.eat('鱼香肉丝')
定义了一个类PersonNode,属性eat
注册
接着修改setup.py
entry_points={
'console_scripts': [
'python_node = demo_python_pkg.python_node:main',
'person_node = demo_python_pkg.person_node:main'
],
},
增加新加的节点入口函数。
编译测试
执行colcon build.
加载环境变量,
执行
bohu@bohu-TM1701:~/2/2_ws$ colcon build
Starting >>> demo_cpp_pkg
Finished <<< demo_cpp_pkg [0.18s]
Starting >>> demo_python_pkg
Finished <<< demo_python_pkg [1.61s]
Summary: 2 packages finished [2.13s]
bohu@bohu-TM1701:~/2/2_ws$ source install/setup.bash
bohu@bohu-TM1701:~/2/2_ws$ ros2 run demo_python_pkg person_node
张三,18岁,爱吃鱼香肉丝
其中__init__方法在创建该类的对象时候会被调用。当要给该类添加属性时,一般会通过__init__方法的参数来传递初始值。可以打个日志
bohu@bohu-TM1701:~/2/2_ws$ ros2 run demo_python_pkg person_node
PersonNode 的 __init__被调用了
张三,18岁,爱吃鱼香肉丝
继承
新建writer_node.py
from demo_python_pkg.person_node import PersonNode
class WriterNode(PersonNode):
def __init__(self,name:str,age:int,book_val: str) -> None:
print('WriterNode 的 __init__被调用了')
#调用父类的init
super().__init__(name,age)
self.book = book_val
def main():
node = WriterNode('张三',18,'ros2 机器人开发')
node.eat('鱼香肉丝')
注册节点
修改setup.py
entry_points={
'console_scripts': [
'python_node = demo_python_pkg.python_node:main',
'person_node = demo_python_pkg.person_node:main',
'writer_node = demo_python_pkg.writer_node:main'
],
},
重新构建运行
bohu@bohu-TM1701:~/2/2_ws$ ros2 run demo_python_pkg writer_node
WriterNode 的 __init__被调用了
PersonNode 的 __init__被调用了
张三,18岁,爱吃鱼香肉丝
可以看到WriterNode成功继承类PersonNode的属性和方法。
接下来,我们尝试把PersonNode 变成真正的ROS2节点,修改如下
import rclpy
from rclpy.node import Node
class PersonNode(Node):
def __init__(self,node_name:str,name_val: str,age_val: int) -> None:
print('PersonNode 的 __init__被调用了')
super().__init__(node_name)
self.name = name_val
self.age = age_val
def eat(self,food_name: str):
#print(f"{self.name},{self.age}岁,爱吃{food_name}")
self.get_logger().info(f"{self.name},{self.age}岁,爱吃{food_name}")
def main():
rclpy.init()
node = PersonNode('zhangsan','张三',18)
node.eat('鱼香肉丝')
rclpy.spin(node)
rclpy.shutdown()
重新运行,注意日志部分换成了ros2 的logger. 可以看到成功输出日志,新开终端也能看到节点。
C++ 版本
编写节点代码
在demo_cpp_pkg 下面新建person_node.cpp
#include <string>
#include "rclcpp/rclcpp.hpp"
class PersonNode : public rclcpp::Node
{
private:
//声明
std::string name_;
int age_;
public:
PersonNode(const std::string &node_name,const std::string &name,const int &age):Node(node_name)/*调用父类的构造函数 */
{
this->name_ = name;
this->age_ = age;
};
void eat(const std::string & food_name)
{
RCLCPP_INFO(get_logger(),"我是%s,今年%d岁,爱吃%s",name_.c_str(),age_,food_name.c_str());
}
};
int main(int argc, char **argv)
{
rclcpp::init(argc,argv);
auto node = std::make_shared<PersonNode>("cpp_node","李四",18);
RCLCPP_INFO(node->get_logger(),"你好 c++节点");
node->eat("鱼香ros");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
开头是头文件。接着是使用class 定义了PersonNode类,继承了Node节点。内部private 定义类2个属性。
public 定义构造函数PersonNode,并传入节点名称、姓名、和年龄作为参数,其中参数传递采用了静态引用方式。前面的const 表示不能通过引用对目标变量的值进行修改。
接下来是eat方法,内部调用类ros2的日志模块来输出。里面有c_str()方式适配C风格类型的字符串。
main函数与之前类似,构造的节点是PersonNode的对象,并赋值给node,然后调用node的eat方法和ros2的相关方法。
编译
修改CMakeLists.txt,添加person_node节点。
cmake_minimum_required(VERSION 3.8)
project(demo_cpp_pkg)
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)
# 查找rclcpp头文件和库文件的路径
find_package(rclcpp REQUIRED)
add_executable(cpp_node src/cpp_node.cpp)
add_executable(person_node src/person_node.cpp)
# 给可执行文件包含头文件
# target_include_directories(cpp_node PUBLIC ${rclcpp_INCLUDE_DIRS})
# 给可执行文件链接库文件
# target_link_libraries(cpp_node ${rclcpp_LIBRARIES})
ament_target_dependencies(cpp_node rclcpp)
ament_target_dependencies(person_node rclcpp)
install(TARGETS cpp_node person_node
DESTINATION lib/${PROJECT_NAME}
)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
构建
colcon build
加载环境变量,运行节点
bohu@bohu-TM1701:~/2/2_ws$ colcon build
Starting >>> demo_cpp_pkg
Finished <<< demo_cpp_pkg [4.65s]
Starting >>> demo_python_pkg
Finished <<< demo_python_pkg [1.43s]
Summary: 2 packages finished [6.43s]
bohu@bohu-TM1701:~/2/2_ws$ source install/setup.bash
bohu@bohu-TM1701:~/2/2_ws$ ros2 run demo_cpp_pkg person_node
[INFO] [1736046779.467568587] [cpp_node]: 你好 c++节点
[INFO] [1736046779.467701782] [cpp_node]: 我是张三,今年18岁,爱吃鱼香ros
C++ \python 的语法还是不熟悉,我跟着视频巧了一遍代码,其中一点小差错就编译不过。少个括号或者双引号写成单引号诸如此类。折腾半天。还是欠缺很多基础。